1fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee/*
2fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee * RTC driver for Maxim MAX77686
3fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee *
4fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee * Copyright (C) 2012 Samsung Electronics Co.Ltd
5fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee *
6fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee *  based on rtc-max8997.c
7fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee *
8fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee *  This program is free software; you can redistribute  it and/or modify it
9fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee *  under  the terms of  the GNU General  Public License as published by the
10fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee *  Free Software Foundation;  either version 2 of the  License, or (at your
11fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee *  option) any later version.
12fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee *
13fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee */
14fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
15fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/slab.h>
16fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/rtc.h>
17fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/delay.h>
18fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/mutex.h>
19fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/module.h>
20fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/platform_device.h>
21fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/mfd/max77686-private.h>
22fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/irqdomain.h>
23fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#include <linux/regmap.h>
24fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
25fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee/* RTC Control Register */
26fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define BCD_EN_SHIFT			0
27ac60bf31210f7b388ea2c1de62ef573a45f49a0fJingoo Han#define BCD_EN_MASK			(1 << BCD_EN_SHIFT)
28fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define MODEL24_SHIFT			1
29fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define MODEL24_MASK			(1 << MODEL24_SHIFT)
30fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee/* RTC Update Register1 */
31fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define RTC_UDR_SHIFT			0
32fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define RTC_UDR_MASK			(1 << RTC_UDR_SHIFT)
33fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define RTC_RBUDR_SHIFT			4
34fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define RTC_RBUDR_MASK			(1 << RTC_RBUDR_SHIFT)
35fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee/* RTC Hour register */
36fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define HOUR_PM_SHIFT			6
37fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define HOUR_PM_MASK			(1 << HOUR_PM_SHIFT)
38fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee/* RTC Alarm Enable */
39fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define ALARM_ENABLE_SHIFT		7
40fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define ALARM_ENABLE_MASK		(1 << ALARM_ENABLE_SHIFT)
41fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
42fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee#define MAX77686_RTC_UPDATE_DELAY	16
43fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
44fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeenum {
45fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	RTC_SEC = 0,
46fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	RTC_MIN,
47fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	RTC_HOUR,
48fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	RTC_WEEKDAY,
49fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	RTC_MONTH,
50fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	RTC_YEAR,
51fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	RTC_DATE,
52fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	RTC_NR_TIME
53fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee};
54fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
55fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestruct max77686_rtc_info {
56fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct device		*dev;
57fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct max77686_dev	*max77686;
58fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct i2c_client	*rtc;
59fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct rtc_device	*rtc_dev;
60fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct mutex		lock;
61fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
62fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct regmap		*regmap;
63fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
64fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	int virq;
65fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	int rtc_24hr_mode;
66fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee};
67fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
68fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeenum MAX77686_RTC_OP {
69fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	MAX77686_RTC_WRITE,
70fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	MAX77686_RTC_READ,
71fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee};
72fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
73fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
74fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				   int rtc_24hr_mode)
75fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{
76fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	tm->tm_sec = data[RTC_SEC] & 0x7f;
77fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	tm->tm_min = data[RTC_MIN] & 0x7f;
78fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (rtc_24hr_mode)
79fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		tm->tm_hour = data[RTC_HOUR] & 0x1f;
80fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	else {
81fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		tm->tm_hour = data[RTC_HOUR] & 0x0f;
82fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		if (data[RTC_HOUR] & HOUR_PM_MASK)
83fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee			tm->tm_hour += 12;
84fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
85fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
86a20cd88e20e59ce11ebca84fac769654193c51e0Javier Martinez Canillas	/* Only a single bit is set in data[], so fls() would be equivalent */
87a20cd88e20e59ce11ebca84fac769654193c51e0Javier Martinez Canillas	tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f) - 1;
88fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	tm->tm_mday = data[RTC_DATE] & 0x1f;
89fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
90fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100;
91fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	tm->tm_yday = 0;
92fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	tm->tm_isdst = 0;
93fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}
94fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
95fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
96fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{
97fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	data[RTC_SEC] = tm->tm_sec;
98fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	data[RTC_MIN] = tm->tm_min;
99fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	data[RTC_HOUR] = tm->tm_hour;
100fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	data[RTC_WEEKDAY] = 1 << tm->tm_wday;
101fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	data[RTC_DATE] = tm->tm_mday;
102fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	data[RTC_MONTH] = tm->tm_mon + 1;
103cdf5f4ac63785e48d93137566d003d6c839b1259Sachin Kamat	data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0;
104fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
105fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (tm->tm_year < 100) {
106fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		pr_warn("%s: MAX77686 RTC cannot handle the year %d."
107fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee			"Assume it's 2000.\n", __func__, 1900 + tm->tm_year);
108fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		return -EINVAL;
109fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
110fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	return 0;
111fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}
112fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
113fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_update(struct max77686_rtc_info *info,
114fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	enum MAX77686_RTC_OP op)
115fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{
116fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	int ret;
117fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	unsigned int data;
118fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
119fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (op == MAX77686_RTC_WRITE)
120fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		data = 1 << RTC_UDR_SHIFT;
121fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	else
122fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		data = 1 << RTC_RBUDR_SHIFT;
123fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
124fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = regmap_update_bits(info->max77686->rtc_regmap,
125fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				 MAX77686_RTC_UPDATE0, data, data);
126fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0)
127fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n",
128fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				__func__, ret, data);
129fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	else {
130fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		/* Minimum 16ms delay required before RTC update. */
131fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		msleep(MAX77686_RTC_UPDATE_DELAY);
132fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
133fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
134fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	return ret;
135fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}
136fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
137fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm)
138fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{
139fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct max77686_rtc_info *info = dev_get_drvdata(dev);
140fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	u8 data[RTC_NR_TIME];
141fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	int ret;
142fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
143fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	mutex_lock(&info->lock);
144fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
145fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = max77686_rtc_update(info, MAX77686_RTC_READ);
146fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0)
147fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto out;
148fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
149fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = regmap_bulk_read(info->max77686->rtc_regmap,
150fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				MAX77686_RTC_SEC, data, RTC_NR_TIME);
151fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0) {
152fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__,	ret);
153fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto out;
154fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
155fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
156fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	max77686_rtc_data_to_tm(data, tm, info->rtc_24hr_mode);
157fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
158fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = rtc_valid_tm(tm);
159fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
160fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeout:
161fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	mutex_unlock(&info->lock);
162fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	return ret;
163fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}
164fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
165fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm)
166fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{
167fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct max77686_rtc_info *info = dev_get_drvdata(dev);
168fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	u8 data[RTC_NR_TIME];
169fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	int ret;
170fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
171fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = max77686_rtc_tm_to_data(tm, data);
172fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0)
173fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		return ret;
174fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
175fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	mutex_lock(&info->lock);
176fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
177fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = regmap_bulk_write(info->max77686->rtc_regmap,
178fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				 MAX77686_RTC_SEC, data, RTC_NR_TIME);
179fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0) {
180fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__,
181fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				ret);
182fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto out;
183fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
184fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
185fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
186fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
187fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeout:
188fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	mutex_unlock(&info->lock);
189fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	return ret;
190fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}
191fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
192fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
193fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{
194fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct max77686_rtc_info *info = dev_get_drvdata(dev);
195fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	u8 data[RTC_NR_TIME];
196fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	unsigned int val;
197fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	int i, ret;
198fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
199fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	mutex_lock(&info->lock);
200fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
201fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = max77686_rtc_update(info, MAX77686_RTC_READ);
202fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0)
203fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto out;
204fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
205fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = regmap_bulk_read(info->max77686->rtc_regmap,
206fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				 MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
207fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0) {
208fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
209fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				__func__, __LINE__, ret);
210fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto out;
211fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
212fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
213fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	max77686_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
214fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
215fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	alrm->enabled = 0;
216fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	for (i = 0; i < RTC_NR_TIME; i++) {
217fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		if (data[i] & ALARM_ENABLE_MASK) {
218fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee			alrm->enabled = 1;
219fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee			break;
220fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		}
221fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
222fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
223fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	alrm->pending = 0;
2241748cbf7f7c464593232cde914f5a103181a83b5Sangjung Woo	ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS2, &val);
225fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0) {
2261748cbf7f7c464593232cde914f5a103181a83b5Sangjung Woo		dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n",
227fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				__func__, __LINE__, ret);
228fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto out;
229fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
230fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
231fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (val & (1 << 4)) /* RTCA1 */
232fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		alrm->pending = 1;
233fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
234fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeout:
235fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	mutex_unlock(&info->lock);
236fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	return 0;
237fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}
238fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
239fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_stop_alarm(struct max77686_rtc_info *info)
240fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{
241fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	u8 data[RTC_NR_TIME];
242fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	int ret, i;
243fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct rtc_time tm;
244fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
245fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (!mutex_is_locked(&info->lock))
246fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
247fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
248fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = max77686_rtc_update(info, MAX77686_RTC_READ);
249fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0)
250fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto out;
251fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
252fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = regmap_bulk_read(info->max77686->rtc_regmap,
253fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				 MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
254fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0) {
255fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
256fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				__func__, ret);
257fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto out;
258fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
259fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
260fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode);
261fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
262fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	for (i = 0; i < RTC_NR_TIME; i++)
263fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		data[i] &= ~ALARM_ENABLE_MASK;
264fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
265fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = regmap_bulk_write(info->max77686->rtc_regmap,
266fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				 MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
267fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0) {
268fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
269fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				__func__, ret);
270fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto out;
271fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
272fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
273fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
274fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeout:
275fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	return ret;
276fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}
277fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
278fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_start_alarm(struct max77686_rtc_info *info)
279fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{
280fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	u8 data[RTC_NR_TIME];
281fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	int ret;
282fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct rtc_time tm;
283fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
284fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (!mutex_is_locked(&info->lock))
285fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
286fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
287fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = max77686_rtc_update(info, MAX77686_RTC_READ);
288fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0)
289fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto out;
290fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
291fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = regmap_bulk_read(info->max77686->rtc_regmap,
292fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				 MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
293fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0) {
294fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
295fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				__func__, ret);
296fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto out;
297fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
298fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
299fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode);
300fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
301fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT);
302fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT);
303fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT);
304fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK;
305fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (data[RTC_MONTH] & 0xf)
306fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT);
307fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (data[RTC_YEAR] & 0x7f)
308fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT);
309fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (data[RTC_DATE] & 0x1f)
310fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT);
311fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
312fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = regmap_bulk_write(info->max77686->rtc_regmap,
313fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				 MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
314fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0) {
315fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
316fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				__func__, ret);
317fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto out;
318fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
319fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
320fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
321fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeout:
322fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	return ret;
323fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}
324fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
325fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
326fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{
327fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct max77686_rtc_info *info = dev_get_drvdata(dev);
328fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	u8 data[RTC_NR_TIME];
329fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	int ret;
330fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
331fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = max77686_rtc_tm_to_data(&alrm->time, data);
332fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0)
333fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		return ret;
334fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
335fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	mutex_lock(&info->lock);
336fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
337fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = max77686_rtc_stop_alarm(info);
338fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0)
339fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto out;
340fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
341fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = regmap_bulk_write(info->max77686->rtc_regmap,
342fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				 MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
343fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
344fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0) {
345fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
346fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				__func__, ret);
347fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto out;
348fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
349fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
350fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
351fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0)
352fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto out;
353fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
354fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (alrm->enabled)
355fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		ret = max77686_rtc_start_alarm(info);
356fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeout:
357fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	mutex_unlock(&info->lock);
358fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	return ret;
359fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}
360fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
361fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_alarm_irq_enable(struct device *dev,
362fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee					unsigned int enabled)
363fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{
364fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct max77686_rtc_info *info = dev_get_drvdata(dev);
365fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	int ret;
366fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
367fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	mutex_lock(&info->lock);
368fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (enabled)
369fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		ret = max77686_rtc_start_alarm(info);
370fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	else
371fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		ret = max77686_rtc_stop_alarm(info);
372fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	mutex_unlock(&info->lock);
373fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
374fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	return ret;
375fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}
376fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
377fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic irqreturn_t max77686_rtc_alarm_irq(int irq, void *data)
378fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{
379fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct max77686_rtc_info *info = data;
380fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
381fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	dev_info(info->dev, "%s:irq(%d)\n", __func__, irq);
382fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
383fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
384fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
385fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	return IRQ_HANDLED;
386fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}
387fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
388fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic const struct rtc_class_ops max77686_rtc_ops = {
389fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	.read_time = max77686_rtc_read_time,
390fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	.set_time = max77686_rtc_set_time,
391fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	.read_alarm = max77686_rtc_read_alarm,
392fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	.set_alarm = max77686_rtc_set_alarm,
393fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	.alarm_irq_enable = max77686_rtc_alarm_irq_enable,
394fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee};
395fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
396fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_init_reg(struct max77686_rtc_info *info)
397fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{
398fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	u8 data[2];
399fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	int ret;
400fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
401fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	/* Set RTC control register : Binary mode, 24hour mdoe */
402fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
403fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
404fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
405fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	info->rtc_24hr_mode = 1;
406fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
407fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = regmap_bulk_write(info->max77686->rtc_regmap, MAX77686_RTC_CONTROLM, data, 2);
408fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0) {
409fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
410fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee				__func__, ret);
411fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		return ret;
412fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
413fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
414fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
415fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	return ret;
416fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}
417fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
418fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic int max77686_rtc_probe(struct platform_device *pdev)
419fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee{
420fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent);
421fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	struct max77686_rtc_info *info;
4226f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas	int ret;
423fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
4243cebeb53d921c2079be0f1bf20f8cae68c20ecc0Jingoo Han	dev_info(&pdev->dev, "%s\n", __func__);
425fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
4260f64f853fc622a0b0c7ab255f8605ae40aa45d84Jingoo Han	info = devm_kzalloc(&pdev->dev, sizeof(struct max77686_rtc_info),
4270f64f853fc622a0b0c7ab255f8605ae40aa45d84Jingoo Han				GFP_KERNEL);
428fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (!info)
429fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		return -ENOMEM;
430fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
431fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	mutex_init(&info->lock);
432fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	info->dev = &pdev->dev;
433fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	info->max77686 = max77686;
434fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	info->rtc = max77686->rtc;
4356f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas
436fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	platform_set_drvdata(pdev, info);
437fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
438fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	ret = max77686_rtc_init_reg(info);
439fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
440fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (ret < 0) {
441fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret);
442fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto err_rtc;
443fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
444fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
445fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	device_init_wakeup(&pdev->dev, 1);
446fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
447f56950ec3a8dc093db724bf1c1611a12c85fb260Jingoo Han	info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77686-rtc",
448f56950ec3a8dc093db724bf1c1611a12c85fb260Jingoo Han					&max77686_rtc_ops, THIS_MODULE);
449fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
450fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	if (IS_ERR(info->rtc_dev)) {
451fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		ret = PTR_ERR(info->rtc_dev);
452fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
453fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		if (ret == 0)
454fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee			ret = -EINVAL;
455fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto err_rtc;
456fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	}
4576f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas
4581745d6d3bc181800ba2e0930ab15432b3e2755ffJavier Martinez Canillas	if (!max77686->rtc_irq_data) {
4591745d6d3bc181800ba2e0930ab15432b3e2755ffJavier Martinez Canillas		ret = -EINVAL;
4601745d6d3bc181800ba2e0930ab15432b3e2755ffJavier Martinez Canillas		dev_err(&pdev->dev, "%s: no RTC regmap IRQ chip\n", __func__);
4611745d6d3bc181800ba2e0930ab15432b3e2755ffJavier Martinez Canillas		goto err_rtc;
4621745d6d3bc181800ba2e0930ab15432b3e2755ffJavier Martinez Canillas	}
4631745d6d3bc181800ba2e0930ab15432b3e2755ffJavier Martinez Canillas
4646f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas	info->virq = regmap_irq_get_virq(max77686->rtc_irq_data,
4656f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas					 MAX77686_RTCIRQ_RTCA1);
4666f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas	if (!info->virq) {
467ad819039f1aa5c5179ecdfb035ed2864d93e741eSachin Kamat		ret = -ENXIO;
468fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		goto err_rtc;
469ad819039f1aa5c5179ecdfb035ed2864d93e741eSachin Kamat	}
470fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
4716f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas	ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL,
4726f1c1e71d933f58a6248f1681aededdd407f32a8Javier Martinez Canillas				max77686_rtc_alarm_irq, 0, "rtc-alarm1", info);
473ad819039f1aa5c5179ecdfb035ed2864d93e741eSachin Kamat	if (ret < 0)
474fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
475fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee			info->virq, ret);
476fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
477fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leeerr_rtc:
478fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	return ret;
479fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee}
480fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
481e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson#ifdef CONFIG_PM_SLEEP
482e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Andersonstatic int max77686_rtc_suspend(struct device *dev)
483e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson{
484e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson	if (device_may_wakeup(dev)) {
485e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson		struct max77686_rtc_info *info = dev_get_drvdata(dev);
486e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson
487e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson		return enable_irq_wake(info->virq);
488e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson	}
489e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson
490e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson	return 0;
491e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson}
492e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson
493e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Andersonstatic int max77686_rtc_resume(struct device *dev)
494e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson{
495e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson	if (device_may_wakeup(dev)) {
496e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson		struct max77686_rtc_info *info = dev_get_drvdata(dev);
497e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson
498e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson		return disable_irq_wake(info->virq);
499e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson	}
500e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson
501e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson	return 0;
502e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson}
503e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson#endif
504e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson
505e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Andersonstatic SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops,
506e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson			 max77686_rtc_suspend, max77686_rtc_resume);
507e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson
508fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic const struct platform_device_id rtc_id[] = {
509fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	{ "max77686-rtc", 0 },
510fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	{},
511fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee};
512fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
513fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Leestatic struct platform_driver max77686_rtc_driver = {
514fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	.driver		= {
515fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		.name	= "max77686-rtc",
516fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee		.owner	= THIS_MODULE,
517e7f7fc73693e0a9de693f261d63aa681f7979c33Doug Anderson		.pm	= &max77686_rtc_pm_ops,
518fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	},
519fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	.probe		= max77686_rtc_probe,
520fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee	.id_table	= rtc_id,
521fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee};
522fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
5230c58ff587738c25e4402a51df6575230e7f099e1Jingoo Hanmodule_platform_driver(max77686_rtc_driver);
524fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa Lee
525fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa LeeMODULE_DESCRIPTION("Maxim MAX77686 RTC driver");
526f5b1d3c5d022aeb994f94ed3372102e057925c6aJingoo HanMODULE_AUTHOR("Chiwoong Byun <woong.byun@samsung.com>");
527fca1dd031a28da74db3df4921dc36fa78941c99fJonghwa LeeMODULE_LICENSE("GPL");
528