15e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee/*
25e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee * RTC driver for Maxim MAX8997
35e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee *
45e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee * Copyright (C) 2013 Samsung Electronics Co.Ltd
55e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee *
65e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee *  based on rtc-max8998.c
75e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee *
85e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee *  This program is free software; you can redistribute  it and/or modify it
95e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee *  under  the terms of  the GNU General  Public License as published by the
105e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee *  Free Software Foundation;  either version 2 of the  License, or (at your
115e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee *  option) any later version.
125e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee *
135e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee */
145e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
155e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#include <linux/slab.h>
165e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#include <linux/rtc.h>
175e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#include <linux/delay.h>
185e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#include <linux/mutex.h>
195e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#include <linux/module.h>
205e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#include <linux/platform_device.h>
215e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#include <linux/mfd/max8997-private.h>
225e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#include <linux/irqdomain.h>
235e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
245e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee/* Module parameter for WTSR function control */
255e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic int wtsr_en = 1;
265e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leemodule_param(wtsr_en, int, 0444);
27a895d57da04a4a24cda996e1a72425ff7e7e6c22Masanari IidaMODULE_PARM_DESC(wtsr_en, "Watchdog Timeout & Software Reset (default=on)");
285e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee/* Module parameter for SMPL function control */
295e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic int smpl_en = 1;
305e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leemodule_param(smpl_en, int, 0444);
315e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa LeeMODULE_PARM_DESC(smpl_en, "Sudden Momentary Power Loss (default=on)");
325e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
335e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee/* RTC Control Register */
345e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define BCD_EN_SHIFT			0
355e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define BCD_EN_MASK			(1 << BCD_EN_SHIFT)
365e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define MODEL24_SHIFT			1
375e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define MODEL24_MASK			(1 << MODEL24_SHIFT)
385e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee/* RTC Update Register1 */
395e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define RTC_UDR_SHIFT			0
405e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define RTC_UDR_MASK			(1 << RTC_UDR_SHIFT)
415e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee/* WTSR and SMPL Register */
425e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define WTSRT_SHIFT			0
435e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define SMPLT_SHIFT			2
445e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define WTSR_EN_SHIFT			6
455e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define SMPL_EN_SHIFT			7
465e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define WTSRT_MASK			(3 << WTSRT_SHIFT)
475e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define SMPLT_MASK			(3 << SMPLT_SHIFT)
485e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define WTSR_EN_MASK			(1 << WTSR_EN_SHIFT)
495e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define SMPL_EN_MASK			(1 << SMPL_EN_SHIFT)
505e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee/* RTC Hour register */
515e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define HOUR_PM_SHIFT			6
525e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define HOUR_PM_MASK			(1 << HOUR_PM_SHIFT)
535e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee/* RTC Alarm Enable */
545e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define ALARM_ENABLE_SHIFT		7
555e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee#define ALARM_ENABLE_MASK		(1 << ALARM_ENABLE_SHIFT)
565e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
575e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leeenum {
585e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	RTC_SEC = 0,
595e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	RTC_MIN,
605e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	RTC_HOUR,
615e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	RTC_WEEKDAY,
625e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	RTC_MONTH,
635e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	RTC_YEAR,
645e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	RTC_DATE,
655e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	RTC_NR_TIME
665e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee};
675e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
685e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestruct max8997_rtc_info {
695e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	struct device		*dev;
705e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	struct max8997_dev	*max8997;
715e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	struct i2c_client	*rtc;
725e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	struct rtc_device	*rtc_dev;
735e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	struct mutex		lock;
745e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	int virq;
755e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	int rtc_24hr_mode;
765e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee};
775e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
785e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic void max8997_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
795e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				   int rtc_24hr_mode)
805e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
815e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	tm->tm_sec = data[RTC_SEC] & 0x7f;
825e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	tm->tm_min = data[RTC_MIN] & 0x7f;
835e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (rtc_24hr_mode)
845e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		tm->tm_hour = data[RTC_HOUR] & 0x1f;
855e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	else {
865e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		tm->tm_hour = data[RTC_HOUR] & 0x0f;
875e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		if (data[RTC_HOUR] & HOUR_PM_MASK)
885e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee			tm->tm_hour += 12;
895e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
905e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
915e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	tm->tm_wday = fls(data[RTC_WEEKDAY] & 0x7f) - 1;
925e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	tm->tm_mday = data[RTC_DATE] & 0x1f;
935e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
945e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100;
955e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	tm->tm_yday = 0;
965e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	tm->tm_isdst = 0;
975e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
985e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
995e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic int max8997_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
1005e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
1015e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	data[RTC_SEC] = tm->tm_sec;
1025e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	data[RTC_MIN] = tm->tm_min;
1035e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	data[RTC_HOUR] = tm->tm_hour;
1045e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	data[RTC_WEEKDAY] = 1 << tm->tm_wday;
1055e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	data[RTC_DATE] = tm->tm_mday;
1065e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	data[RTC_MONTH] = tm->tm_mon + 1;
107f887a9de5522487debc7601595f4ef791572c044Sachin Kamat	data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0;
1085e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1095e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (tm->tm_year < 100) {
1105e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		pr_warn("%s: MAX8997 RTC cannot handle the year %d."
1115e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee			"Assume it's 2000.\n", __func__, 1900 + tm->tm_year);
1125e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		return -EINVAL;
1135e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
1145e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	return 0;
1155e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
1165e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1175e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic inline int max8997_rtc_set_update_reg(struct max8997_rtc_info *info)
1185e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
1195e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	int ret;
1205e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1215e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_write_reg(info->rtc, MAX8997_RTC_UPDATE1,
1225e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee						RTC_UDR_MASK);
1235e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0)
1245e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(info->dev, "%s: fail to write update reg(%d)\n",
1255e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				__func__, ret);
1265e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	else {
1275e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		/* Minimum 16ms delay required before RTC update.
1285e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		 * Otherwise, we may read and update based on out-of-date
1295e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		 * value */
1305e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		msleep(20);
1315e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
1325e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1335e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	return ret;
1345e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
1355e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1365e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic int max8997_rtc_read_time(struct device *dev, struct rtc_time *tm)
1375e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
1385e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	struct max8997_rtc_info *info = dev_get_drvdata(dev);
1395e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	u8 data[RTC_NR_TIME];
1405e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	int ret;
1415e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1425e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	mutex_lock(&info->lock);
1435e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_bulk_read(info->rtc, MAX8997_RTC_SEC, RTC_NR_TIME, data);
1445e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	mutex_unlock(&info->lock);
1455e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1465e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0) {
1475e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__,
1485e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				ret);
1495e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		return ret;
1505e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
1515e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1525e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	max8997_rtc_data_to_tm(data, tm, info->rtc_24hr_mode);
1535e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1545e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	return rtc_valid_tm(tm);
1555e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
1565e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1575e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic int max8997_rtc_set_time(struct device *dev, struct rtc_time *tm)
1585e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
1595e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	struct max8997_rtc_info *info = dev_get_drvdata(dev);
1605e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	u8 data[RTC_NR_TIME];
1615e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	int ret;
1625e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1635e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_rtc_tm_to_data(tm, data);
1645e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0)
1655e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		return ret;
1665e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1675e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	mutex_lock(&info->lock);
1685e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1695e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_bulk_write(info->rtc, MAX8997_RTC_SEC, RTC_NR_TIME, data);
1705e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0) {
1715e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__,
1725e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				ret);
1735e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		goto out;
1745e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
1755e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1765e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_rtc_set_update_reg(info);
1775e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leeout:
1785e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	mutex_unlock(&info->lock);
1795e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	return ret;
1805e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
1815e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1825e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic int max8997_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
1835e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
1845e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	struct max8997_rtc_info *info = dev_get_drvdata(dev);
1855e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	u8 data[RTC_NR_TIME];
1865e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	u8 val;
1875e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	int i, ret;
1885e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1895e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	mutex_lock(&info->lock);
1905e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1915e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
1925e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee			data);
1935e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0) {
1945e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
1955e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				__func__, __LINE__, ret);
1965e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		goto out;
1975e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
1985e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
1995e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	max8997_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
2005e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2015e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	alrm->enabled = 0;
2025e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	for (i = 0; i < RTC_NR_TIME; i++) {
2035e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		if (data[i] & ALARM_ENABLE_MASK) {
2045e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee			alrm->enabled = 1;
2055e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee			break;
2065e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		}
2075e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
2085e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2095e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	alrm->pending = 0;
2105e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_read_reg(info->max8997->i2c, MAX8997_REG_STATUS1, &val);
2115e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0) {
2125e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(info->dev, "%s:%d fail to read status1 reg(%d)\n",
2135e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				__func__, __LINE__, ret);
2145e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		goto out;
2155e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
2165e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2175e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (val & (1 << 4)) /* RTCA1 */
2185e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		alrm->pending = 1;
2195e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2205e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leeout:
2215e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	mutex_unlock(&info->lock);
2225e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	return 0;
2235e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
2245e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2255e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic int max8997_rtc_stop_alarm(struct max8997_rtc_info *info)
2265e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
2275e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	u8 data[RTC_NR_TIME];
2285e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	int ret, i;
2295e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2305e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (!mutex_is_locked(&info->lock))
2315e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
2325e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2335e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
2345e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				data);
2355e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0) {
2365e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
2375e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				__func__, ret);
2385e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		goto out;
2395e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
2405e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2415e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	for (i = 0; i < RTC_NR_TIME; i++)
2425e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		data[i] &= ~ALARM_ENABLE_MASK;
2435e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2445e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
2455e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				 data);
2465e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0) {
2475e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
2485e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				__func__, ret);
2495e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		goto out;
2505e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
2515e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2525e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_rtc_set_update_reg(info);
2535e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leeout:
2545e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	return ret;
2555e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
2565e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2575e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic int max8997_rtc_start_alarm(struct max8997_rtc_info *info)
2585e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
2595e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	u8 data[RTC_NR_TIME];
2605e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	int ret;
2615e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2625e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (!mutex_is_locked(&info->lock))
2635e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
2645e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2655e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
2665e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				data);
2675e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0) {
2685e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
2695e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				__func__, ret);
2705e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		goto out;
2715e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
2725e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2735e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT);
2745e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT);
2755e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT);
2765e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK;
2775e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (data[RTC_MONTH] & 0xf)
2785e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT);
2795e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (data[RTC_YEAR] & 0x7f)
2805e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT);
2815e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (data[RTC_DATE] & 0x1f)
2825e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT);
2835e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2845e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
2855e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				 data);
2865e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0) {
2875e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
2885e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				__func__, ret);
2895e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		goto out;
2905e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
2915e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
2925e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_rtc_set_update_reg(info);
2935e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leeout:
2945e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	return ret;
2955e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
2965e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic int max8997_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
2975e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
2985e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	struct max8997_rtc_info *info = dev_get_drvdata(dev);
2995e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	u8 data[RTC_NR_TIME];
3005e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	int ret;
3015e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3025e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_rtc_tm_to_data(&alrm->time, data);
3035e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0)
3045e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		return ret;
3055e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3065e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	dev_info(info->dev, "%s: %d-%02d-%02d %02d:%02d:%02d\n", __func__,
3075e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee			data[RTC_YEAR] + 2000, data[RTC_MONTH], data[RTC_DATE],
3085e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee			data[RTC_HOUR], data[RTC_MIN], data[RTC_SEC]);
3095e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3105e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	mutex_lock(&info->lock);
3115e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3125e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_rtc_stop_alarm(info);
3135e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0)
3145e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		goto out;
3155e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3165e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
3175e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				data);
3185e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0) {
3195e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
3205e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				__func__, ret);
3215e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		goto out;
3225e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
3235e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3245e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_rtc_set_update_reg(info);
3255e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0)
3265e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		goto out;
3275e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3285e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (alrm->enabled)
3295e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		ret = max8997_rtc_start_alarm(info);
3305e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leeout:
3315e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	mutex_unlock(&info->lock);
3325e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	return ret;
3335e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
3345e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3355e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic int max8997_rtc_alarm_irq_enable(struct device *dev,
3365e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee					unsigned int enabled)
3375e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
3385e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	struct max8997_rtc_info *info = dev_get_drvdata(dev);
3395e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	int ret;
3405e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3415e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	mutex_lock(&info->lock);
3425e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (enabled)
3435e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		ret = max8997_rtc_start_alarm(info);
3445e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	else
3455e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		ret = max8997_rtc_stop_alarm(info);
3465e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	mutex_unlock(&info->lock);
3475e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3485e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	return ret;
3495e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
3505e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3515e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic irqreturn_t max8997_rtc_alarm_irq(int irq, void *data)
3525e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
3535e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	struct max8997_rtc_info *info = data;
3545e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3555e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	dev_info(info->dev, "%s:irq(%d)\n", __func__, irq);
3565e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3575e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
3585e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3595e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	return IRQ_HANDLED;
3605e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
3615e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3625e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic const struct rtc_class_ops max8997_rtc_ops = {
3635e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	.read_time = max8997_rtc_read_time,
3645e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	.set_time = max8997_rtc_set_time,
3655e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	.read_alarm = max8997_rtc_read_alarm,
3665e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	.set_alarm = max8997_rtc_set_alarm,
3675e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	.alarm_irq_enable = max8997_rtc_alarm_irq_enable,
3685e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee};
3695e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3705e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic void max8997_rtc_enable_wtsr(struct max8997_rtc_info *info, bool enable)
3715e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
3725e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	int ret;
3735e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	u8 val, mask;
3745e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3755e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (!wtsr_en)
3765e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		return;
3775e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3785e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (enable)
3795e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT);
3805e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	else
3815e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		val = 0;
3825e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3835e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	mask = WTSR_EN_MASK | WTSRT_MASK;
3845e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3855e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	dev_info(info->dev, "%s: %s WTSR\n", __func__,
3865e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee			enable ? "enable" : "disable");
3875e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3885e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_update_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, val, mask);
3895e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0) {
3905e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n",
3915e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				__func__, ret);
3925e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		return;
3935e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
3945e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3955e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	max8997_rtc_set_update_reg(info);
3965e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
3975e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
3985e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic void max8997_rtc_enable_smpl(struct max8997_rtc_info *info, bool enable)
3995e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
4005e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	int ret;
4015e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	u8 val, mask;
4025e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4035e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (!smpl_en)
4045e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		return;
4055e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4065e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (enable)
4075e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT);
4085e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	else
4095e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		val = 0;
4105e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4115e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	mask = SMPL_EN_MASK | SMPLT_MASK;
4125e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4135e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	dev_info(info->dev, "%s: %s SMPL\n", __func__,
4145e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee			enable ? "enable" : "disable");
4155e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4165e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_update_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, val, mask);
4175e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0) {
4185e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n",
4195e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				__func__, ret);
4205e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		return;
4215e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
4225e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4235e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	max8997_rtc_set_update_reg(info);
4245e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4255e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	val = 0;
4265e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	max8997_read_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, &val);
4275e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	pr_info("%s: WTSR_SMPL(0x%02x)\n", __func__, val);
4285e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
4295e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4305e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic int max8997_rtc_init_reg(struct max8997_rtc_info *info)
4315e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
4325e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	u8 data[2];
4335e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	int ret;
4345e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4355e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	/* Set RTC control register : Binary mode, 24hour mdoe */
4365e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
4375e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
4385e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4395e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	info->rtc_24hr_mode = 1;
4405e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4415e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_bulk_write(info->rtc, MAX8997_RTC_CTRLMASK, 2, data);
4425e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0) {
4435e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
4445e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				__func__, ret);
4455e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		return ret;
4465e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
4475e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4485e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_rtc_set_update_reg(info);
4495e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	return ret;
4505e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
4515e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4525e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic int max8997_rtc_probe(struct platform_device *pdev)
4535e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
4545e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent);
4555e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	struct max8997_rtc_info *info;
4565e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	int ret, virq;
4575e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4585e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	info = devm_kzalloc(&pdev->dev, sizeof(struct max8997_rtc_info),
4595e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee			GFP_KERNEL);
4605e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (!info)
4615e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		return -ENOMEM;
4625e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4635e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	mutex_init(&info->lock);
4645e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	info->dev = &pdev->dev;
4655e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	info->max8997 = max8997;
4665e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	info->rtc = max8997->rtc;
4675e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4685e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	platform_set_drvdata(pdev, info);
4695e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4705e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	ret = max8997_rtc_init_reg(info);
4715e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4725e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (ret < 0) {
4735e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret);
4745e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		return ret;
4755e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
4765e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4775e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	max8997_rtc_enable_wtsr(info, true);
4785e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	max8997_rtc_enable_smpl(info, true);
4795e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4805e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	device_init_wakeup(&pdev->dev, 1);
4815e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4824ce903cc91534916a3b342bae91c30ba777190fdJingoo Han	info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max8997-rtc",
4834ce903cc91534916a3b342bae91c30ba777190fdJingoo Han					&max8997_rtc_ops, THIS_MODULE);
4845e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4855e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (IS_ERR(info->rtc_dev)) {
4865e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		ret = PTR_ERR(info->rtc_dev);
4875e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
4885e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		return ret;
4895e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
4905e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
4915e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	virq = irq_create_mapping(max8997->irq_domain, MAX8997_PMICIRQ_RTCA1);
4925e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	if (!virq) {
4935e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(&pdev->dev, "Failed to create mapping alarm IRQ\n");
494406dc00407edfa75c97123c7f8653e850358fb72Sachin Kamat		ret = -ENXIO;
4955e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		goto err_out;
4965e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	}
4975e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	info->virq = virq;
4985e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
499c1879fe80c61f3be6f2ddb82509c2e7f92a484feJingoo Han	ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
500c1879fe80c61f3be6f2ddb82509c2e7f92a484feJingoo Han				max8997_rtc_alarm_irq, 0,
5015e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee				"rtc-alarm0", info);
502406dc00407edfa75c97123c7f8653e850358fb72Sachin Kamat	if (ret < 0)
5035e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
5045e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee			info->virq, ret);
5055e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
5065e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leeerr_out:
5075e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	return ret;
5085e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
5095e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
5105e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic void max8997_rtc_shutdown(struct platform_device *pdev)
5115e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee{
5125e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	struct max8997_rtc_info *info = platform_get_drvdata(pdev);
5135e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
5145e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	max8997_rtc_enable_wtsr(info, false);
5155e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	max8997_rtc_enable_smpl(info, false);
5165e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee}
5175e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
5185e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic const struct platform_device_id rtc_id[] = {
5195e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	{ "max8997-rtc", 0 },
5205e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	{},
5215e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee};
5225e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
5235e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leestatic struct platform_driver max8997_rtc_driver = {
5245e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	.driver		= {
5255e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		.name	= "max8997-rtc",
5265e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee		.owner	= THIS_MODULE,
5275e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	},
5285e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	.probe		= max8997_rtc_probe,
5295e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	.shutdown	= max8997_rtc_shutdown,
5305e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee	.id_table	= rtc_id,
5315e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee};
5325e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
5335e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Leemodule_platform_driver(max8997_rtc_driver);
5345e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa Lee
5355e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa LeeMODULE_DESCRIPTION("Maxim MAX8997 RTC driver");
5365e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa LeeMODULE_AUTHOR("<ms925.kim@samsung.com>");
5375e0b2704a1d5c246c8282303bbc952cba17f94fcJonghwa LeeMODULE_LICENSE("GPL");
538