blob: 1f501b6fc3145292bb82370ee098ca6db6e7cea8 [file] [log] [blame]
Jonghwa Leefca1dd02013-02-21 16:44:26 -08001/*
2 * RTC driver for Maxim MAX77686
3 *
4 * Copyright (C) 2012 Samsung Electronics Co.Ltd
5 *
6 * based on rtc-max8997.c
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14
Joe Perchesa737e832015-04-16 12:46:14 -070015#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16
Jonghwa Leefca1dd02013-02-21 16:44:26 -080017#include <linux/slab.h>
18#include <linux/rtc.h>
19#include <linux/delay.h>
20#include <linux/mutex.h>
21#include <linux/module.h>
22#include <linux/platform_device.h>
23#include <linux/mfd/max77686-private.h>
24#include <linux/irqdomain.h>
25#include <linux/regmap.h>
26
27/* RTC Control Register */
28#define BCD_EN_SHIFT 0
Jingoo Hanac60bf32013-04-29 16:18:31 -070029#define BCD_EN_MASK (1 << BCD_EN_SHIFT)
Jonghwa Leefca1dd02013-02-21 16:44:26 -080030#define MODEL24_SHIFT 1
31#define MODEL24_MASK (1 << MODEL24_SHIFT)
32/* RTC Update Register1 */
33#define RTC_UDR_SHIFT 0
34#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT)
35#define RTC_RBUDR_SHIFT 4
36#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT)
Jonghwa Leefca1dd02013-02-21 16:44:26 -080037/* RTC Hour register */
38#define HOUR_PM_SHIFT 6
39#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT)
40/* RTC Alarm Enable */
41#define ALARM_ENABLE_SHIFT 7
42#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT)
43
Jonghwa Leefca1dd02013-02-21 16:44:26 -080044enum {
45 RTC_SEC = 0,
46 RTC_MIN,
47 RTC_HOUR,
48 RTC_WEEKDAY,
49 RTC_MONTH,
50 RTC_YEAR,
51 RTC_DATE,
52 RTC_NR_TIME
53};
54
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -030055struct max77686_rtc_driver_data {
56 /* Minimum usecs needed for a RTC update */
57 unsigned long delay;
58 /* Mask used to read RTC registers value */
59 u8 mask;
Javier Martinez Canillas90a56982016-01-27 00:36:41 -030060 /* Registers offset to I2C addresses map */
61 const unsigned int *map;
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -030062};
63
Jonghwa Leefca1dd02013-02-21 16:44:26 -080064struct max77686_rtc_info {
65 struct device *dev;
66 struct max77686_dev *max77686;
67 struct i2c_client *rtc;
68 struct rtc_device *rtc_dev;
69 struct mutex lock;
70
71 struct regmap *regmap;
72
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -030073 const struct max77686_rtc_driver_data *drv_data;
74
Jonghwa Leefca1dd02013-02-21 16:44:26 -080075 int virq;
76 int rtc_24hr_mode;
77};
78
79enum MAX77686_RTC_OP {
80 MAX77686_RTC_WRITE,
81 MAX77686_RTC_READ,
82};
83
Javier Martinez Canillas90a56982016-01-27 00:36:41 -030084/* These are not registers but just offsets that are mapped to addresses */
85enum max77686_rtc_reg_offset {
86 REG_RTC_CONTROLM = 0,
87 REG_RTC_CONTROL,
88 REG_RTC_UPDATE0,
89 REG_WTSR_SMPL_CNTL,
90 REG_RTC_SEC,
91 REG_RTC_MIN,
92 REG_RTC_HOUR,
93 REG_RTC_WEEKDAY,
94 REG_RTC_MONTH,
95 REG_RTC_YEAR,
96 REG_RTC_DATE,
97 REG_ALARM1_SEC,
98 REG_ALARM1_MIN,
99 REG_ALARM1_HOUR,
100 REG_ALARM1_WEEKDAY,
101 REG_ALARM1_MONTH,
102 REG_ALARM1_YEAR,
103 REG_ALARM1_DATE,
104 REG_ALARM2_SEC,
105 REG_ALARM2_MIN,
106 REG_ALARM2_HOUR,
107 REG_ALARM2_WEEKDAY,
108 REG_ALARM2_MONTH,
109 REG_ALARM2_YEAR,
110 REG_ALARM2_DATE,
111 REG_RTC_END,
112};
113
114/* Maps RTC registers offset to the MAX77686 register addresses */
115static const unsigned int max77686_map[REG_RTC_END] = {
116 [REG_RTC_CONTROLM] = MAX77686_RTC_CONTROLM,
117 [REG_RTC_CONTROL] = MAX77686_RTC_CONTROL,
118 [REG_RTC_UPDATE0] = MAX77686_RTC_UPDATE0,
119 [REG_WTSR_SMPL_CNTL] = MAX77686_WTSR_SMPL_CNTL,
120 [REG_RTC_SEC] = MAX77686_RTC_SEC,
121 [REG_RTC_MIN] = MAX77686_RTC_MIN,
122 [REG_RTC_HOUR] = MAX77686_RTC_HOUR,
123 [REG_RTC_WEEKDAY] = MAX77686_RTC_WEEKDAY,
124 [REG_RTC_MONTH] = MAX77686_RTC_MONTH,
125 [REG_RTC_YEAR] = MAX77686_RTC_YEAR,
126 [REG_RTC_DATE] = MAX77686_RTC_DATE,
127 [REG_ALARM1_SEC] = MAX77686_ALARM1_SEC,
128 [REG_ALARM1_MIN] = MAX77686_ALARM1_MIN,
129 [REG_ALARM1_HOUR] = MAX77686_ALARM1_HOUR,
130 [REG_ALARM1_WEEKDAY] = MAX77686_ALARM1_WEEKDAY,
131 [REG_ALARM1_MONTH] = MAX77686_ALARM1_MONTH,
132 [REG_ALARM1_YEAR] = MAX77686_ALARM1_YEAR,
133 [REG_ALARM1_DATE] = MAX77686_ALARM1_DATE,
134 [REG_ALARM2_SEC] = MAX77686_ALARM2_SEC,
135 [REG_ALARM2_MIN] = MAX77686_ALARM2_MIN,
136 [REG_ALARM2_HOUR] = MAX77686_ALARM2_HOUR,
137 [REG_ALARM2_WEEKDAY] = MAX77686_ALARM2_WEEKDAY,
138 [REG_ALARM2_MONTH] = MAX77686_ALARM2_MONTH,
139 [REG_ALARM2_YEAR] = MAX77686_ALARM2_YEAR,
140 [REG_ALARM2_DATE] = MAX77686_ALARM2_DATE,
141};
142
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300143static const struct max77686_rtc_driver_data max77686_drv_data = {
144 .delay = 16000,
145 .mask = 0x7f,
Javier Martinez Canillas90a56982016-01-27 00:36:41 -0300146 .map = max77686_map,
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300147};
148
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800149static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300150 struct max77686_rtc_info *info)
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800151{
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300152 u8 mask = info->drv_data->mask;
153
154 tm->tm_sec = data[RTC_SEC] & mask;
155 tm->tm_min = data[RTC_MIN] & mask;
156 if (info->rtc_24hr_mode)
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800157 tm->tm_hour = data[RTC_HOUR] & 0x1f;
158 else {
159 tm->tm_hour = data[RTC_HOUR] & 0x0f;
160 if (data[RTC_HOUR] & HOUR_PM_MASK)
161 tm->tm_hour += 12;
162 }
163
Javier Martinez Canillasa20cd882014-10-13 15:53:03 -0700164 /* Only a single bit is set in data[], so fls() would be equivalent */
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300165 tm->tm_wday = ffs(data[RTC_WEEKDAY] & mask) - 1;
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800166 tm->tm_mday = data[RTC_DATE] & 0x1f;
167 tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300168 tm->tm_year = (data[RTC_YEAR] & mask) + 100;
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800169 tm->tm_yday = 0;
170 tm->tm_isdst = 0;
171}
172
173static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
174{
175 data[RTC_SEC] = tm->tm_sec;
176 data[RTC_MIN] = tm->tm_min;
177 data[RTC_HOUR] = tm->tm_hour;
178 data[RTC_WEEKDAY] = 1 << tm->tm_wday;
179 data[RTC_DATE] = tm->tm_mday;
180 data[RTC_MONTH] = tm->tm_mon + 1;
Sachin Kamatcdf5f4a2013-07-03 15:05:55 -0700181 data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0;
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800182
183 if (tm->tm_year < 100) {
Joe Perchesa737e832015-04-16 12:46:14 -0700184 pr_warn("RTC cannot handle the year %d. Assume it's 2000.\n",
185 1900 + tm->tm_year);
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800186 return -EINVAL;
187 }
188 return 0;
189}
190
191static int max77686_rtc_update(struct max77686_rtc_info *info,
192 enum MAX77686_RTC_OP op)
193{
194 int ret;
195 unsigned int data;
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300196 unsigned long delay = info->drv_data->delay;
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800197
198 if (op == MAX77686_RTC_WRITE)
199 data = 1 << RTC_UDR_SHIFT;
200 else
201 data = 1 << RTC_RBUDR_SHIFT;
202
203 ret = regmap_update_bits(info->max77686->rtc_regmap,
Javier Martinez Canillas90a56982016-01-27 00:36:41 -0300204 info->drv_data->map[REG_RTC_UPDATE0],
205 data, data);
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800206 if (ret < 0)
207 dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n",
208 __func__, ret, data);
209 else {
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300210 /* Minimum delay required before RTC update. */
211 usleep_range(delay, delay * 2);
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800212 }
213
214 return ret;
215}
216
217static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm)
218{
219 struct max77686_rtc_info *info = dev_get_drvdata(dev);
220 u8 data[RTC_NR_TIME];
221 int ret;
222
223 mutex_lock(&info->lock);
224
225 ret = max77686_rtc_update(info, MAX77686_RTC_READ);
226 if (ret < 0)
227 goto out;
228
229 ret = regmap_bulk_read(info->max77686->rtc_regmap,
Javier Martinez Canillas90a56982016-01-27 00:36:41 -0300230 info->drv_data->map[REG_RTC_SEC],
231 data, ARRAY_SIZE(data));
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800232 if (ret < 0) {
233 dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, ret);
234 goto out;
235 }
236
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300237 max77686_rtc_data_to_tm(data, tm, info);
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800238
239 ret = rtc_valid_tm(tm);
240
241out:
242 mutex_unlock(&info->lock);
243 return ret;
244}
245
246static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm)
247{
248 struct max77686_rtc_info *info = dev_get_drvdata(dev);
249 u8 data[RTC_NR_TIME];
250 int ret;
251
252 ret = max77686_rtc_tm_to_data(tm, data);
253 if (ret < 0)
254 return ret;
255
256 mutex_lock(&info->lock);
257
258 ret = regmap_bulk_write(info->max77686->rtc_regmap,
Javier Martinez Canillas90a56982016-01-27 00:36:41 -0300259 info->drv_data->map[REG_RTC_SEC],
260 data, ARRAY_SIZE(data));
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800261 if (ret < 0) {
262 dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__,
263 ret);
264 goto out;
265 }
266
267 ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
268
269out:
270 mutex_unlock(&info->lock);
271 return ret;
272}
273
274static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
275{
276 struct max77686_rtc_info *info = dev_get_drvdata(dev);
277 u8 data[RTC_NR_TIME];
278 unsigned int val;
Javier Martinez Canillas90a56982016-01-27 00:36:41 -0300279 const unsigned int *map = info->drv_data->map;
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800280 int i, ret;
281
282 mutex_lock(&info->lock);
283
284 ret = max77686_rtc_update(info, MAX77686_RTC_READ);
285 if (ret < 0)
286 goto out;
287
288 ret = regmap_bulk_read(info->max77686->rtc_regmap,
Javier Martinez Canillas90a56982016-01-27 00:36:41 -0300289 map[REG_ALARM1_SEC], data, ARRAY_SIZE(data));
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800290 if (ret < 0) {
291 dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
292 __func__, __LINE__, ret);
293 goto out;
294 }
295
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300296 max77686_rtc_data_to_tm(data, &alrm->time, info);
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800297
298 alrm->enabled = 0;
Javier Martinez Canillas862f9452016-01-27 00:36:38 -0300299 for (i = 0; i < ARRAY_SIZE(data); i++) {
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800300 if (data[i] & ALARM_ENABLE_MASK) {
301 alrm->enabled = 1;
302 break;
303 }
304 }
305
306 alrm->pending = 0;
Sangjung Woo1748cbf2013-09-11 14:24:21 -0700307 ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS2, &val);
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800308 if (ret < 0) {
Sangjung Woo1748cbf2013-09-11 14:24:21 -0700309 dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n",
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800310 __func__, __LINE__, ret);
311 goto out;
312 }
313
314 if (val & (1 << 4)) /* RTCA1 */
315 alrm->pending = 1;
316
317out:
318 mutex_unlock(&info->lock);
Javier Martinez Canillas7cdffeb2016-01-27 00:36:37 -0300319 return ret;
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800320}
321
322static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info)
323{
324 u8 data[RTC_NR_TIME];
325 int ret, i;
326 struct rtc_time tm;
Javier Martinez Canillas90a56982016-01-27 00:36:41 -0300327 const unsigned int *map = info->drv_data->map;
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800328
329 if (!mutex_is_locked(&info->lock))
330 dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
331
332 ret = max77686_rtc_update(info, MAX77686_RTC_READ);
333 if (ret < 0)
334 goto out;
335
336 ret = regmap_bulk_read(info->max77686->rtc_regmap,
Javier Martinez Canillas90a56982016-01-27 00:36:41 -0300337 map[REG_ALARM1_SEC], data, ARRAY_SIZE(data));
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800338 if (ret < 0) {
339 dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
340 __func__, ret);
341 goto out;
342 }
343
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300344 max77686_rtc_data_to_tm(data, &tm, info);
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800345
Javier Martinez Canillas862f9452016-01-27 00:36:38 -0300346 for (i = 0; i < ARRAY_SIZE(data); i++)
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800347 data[i] &= ~ALARM_ENABLE_MASK;
348
349 ret = regmap_bulk_write(info->max77686->rtc_regmap,
Javier Martinez Canillas90a56982016-01-27 00:36:41 -0300350 map[REG_ALARM1_SEC], data, ARRAY_SIZE(data));
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800351 if (ret < 0) {
352 dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
353 __func__, ret);
354 goto out;
355 }
356
357 ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
358out:
359 return ret;
360}
361
362static int max77686_rtc_start_alarm(struct max77686_rtc_info *info)
363{
364 u8 data[RTC_NR_TIME];
365 int ret;
366 struct rtc_time tm;
Javier Martinez Canillas90a56982016-01-27 00:36:41 -0300367 const unsigned int *map = info->drv_data->map;
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800368
369 if (!mutex_is_locked(&info->lock))
370 dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
371
372 ret = max77686_rtc_update(info, MAX77686_RTC_READ);
373 if (ret < 0)
374 goto out;
375
376 ret = regmap_bulk_read(info->max77686->rtc_regmap,
Javier Martinez Canillas90a56982016-01-27 00:36:41 -0300377 map[REG_ALARM1_SEC], data, ARRAY_SIZE(data));
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800378 if (ret < 0) {
379 dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
380 __func__, ret);
381 goto out;
382 }
383
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300384 max77686_rtc_data_to_tm(data, &tm, info);
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800385
386 data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT);
387 data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT);
388 data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT);
389 data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK;
390 if (data[RTC_MONTH] & 0xf)
391 data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT);
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300392 if (data[RTC_YEAR] & info->drv_data->mask)
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800393 data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT);
394 if (data[RTC_DATE] & 0x1f)
395 data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT);
396
397 ret = regmap_bulk_write(info->max77686->rtc_regmap,
Javier Martinez Canillas90a56982016-01-27 00:36:41 -0300398 map[REG_ALARM1_SEC], data, ARRAY_SIZE(data));
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800399 if (ret < 0) {
400 dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
401 __func__, ret);
402 goto out;
403 }
404
405 ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
406out:
407 return ret;
408}
409
410static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
411{
412 struct max77686_rtc_info *info = dev_get_drvdata(dev);
413 u8 data[RTC_NR_TIME];
414 int ret;
415
416 ret = max77686_rtc_tm_to_data(&alrm->time, data);
417 if (ret < 0)
418 return ret;
419
420 mutex_lock(&info->lock);
421
422 ret = max77686_rtc_stop_alarm(info);
423 if (ret < 0)
424 goto out;
425
426 ret = regmap_bulk_write(info->max77686->rtc_regmap,
Javier Martinez Canillas90a56982016-01-27 00:36:41 -0300427 info->drv_data->map[REG_ALARM1_SEC],
428 data, ARRAY_SIZE(data));
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800429
430 if (ret < 0) {
431 dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
432 __func__, ret);
433 goto out;
434 }
435
436 ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
437 if (ret < 0)
438 goto out;
439
440 if (alrm->enabled)
441 ret = max77686_rtc_start_alarm(info);
442out:
443 mutex_unlock(&info->lock);
444 return ret;
445}
446
447static int max77686_rtc_alarm_irq_enable(struct device *dev,
448 unsigned int enabled)
449{
450 struct max77686_rtc_info *info = dev_get_drvdata(dev);
451 int ret;
452
453 mutex_lock(&info->lock);
454 if (enabled)
455 ret = max77686_rtc_start_alarm(info);
456 else
457 ret = max77686_rtc_stop_alarm(info);
458 mutex_unlock(&info->lock);
459
460 return ret;
461}
462
463static irqreturn_t max77686_rtc_alarm_irq(int irq, void *data)
464{
465 struct max77686_rtc_info *info = data;
466
467 dev_info(info->dev, "%s:irq(%d)\n", __func__, irq);
468
469 rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
470
471 return IRQ_HANDLED;
472}
473
474static const struct rtc_class_ops max77686_rtc_ops = {
475 .read_time = max77686_rtc_read_time,
476 .set_time = max77686_rtc_set_time,
477 .read_alarm = max77686_rtc_read_alarm,
478 .set_alarm = max77686_rtc_set_alarm,
479 .alarm_irq_enable = max77686_rtc_alarm_irq_enable,
480};
481
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800482static int max77686_rtc_init_reg(struct max77686_rtc_info *info)
483{
484 u8 data[2];
485 int ret;
486
487 /* Set RTC control register : Binary mode, 24hour mdoe */
488 data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
489 data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
490
491 info->rtc_24hr_mode = 1;
492
Javier Martinez Canillas862f9452016-01-27 00:36:38 -0300493 ret = regmap_bulk_write(info->max77686->rtc_regmap,
Javier Martinez Canillas90a56982016-01-27 00:36:41 -0300494 info->drv_data->map[REG_RTC_CONTROLM],
495 data, ARRAY_SIZE(data));
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800496 if (ret < 0) {
497 dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
498 __func__, ret);
499 return ret;
500 }
501
502 ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
503 return ret;
504}
505
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800506static int max77686_rtc_probe(struct platform_device *pdev)
507{
508 struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent);
509 struct max77686_rtc_info *info;
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300510 const struct platform_device_id *id = platform_get_device_id(pdev);
Javier Martinez Canillas6f1c1e72014-07-04 22:24:04 +0200511 int ret;
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800512
Jingoo Han3cebeb52013-02-21 16:45:24 -0800513 dev_info(&pdev->dev, "%s\n", __func__);
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800514
Jingoo Han0f64f852013-04-29 16:18:30 -0700515 info = devm_kzalloc(&pdev->dev, sizeof(struct max77686_rtc_info),
516 GFP_KERNEL);
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800517 if (!info)
518 return -ENOMEM;
519
520 mutex_init(&info->lock);
521 info->dev = &pdev->dev;
522 info->max77686 = max77686;
523 info->rtc = max77686->rtc;
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300524 info->drv_data = (const struct max77686_rtc_driver_data *)
525 id->driver_data;
Javier Martinez Canillas6f1c1e72014-07-04 22:24:04 +0200526
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800527 platform_set_drvdata(pdev, info);
528
529 ret = max77686_rtc_init_reg(info);
530
531 if (ret < 0) {
532 dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret);
533 goto err_rtc;
534 }
535
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800536 device_init_wakeup(&pdev->dev, 1);
537
Jingoo Hanf56950e2013-04-29 16:19:05 -0700538 info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77686-rtc",
539 &max77686_rtc_ops, THIS_MODULE);
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800540
541 if (IS_ERR(info->rtc_dev)) {
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800542 ret = PTR_ERR(info->rtc_dev);
543 dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
544 if (ret == 0)
545 ret = -EINVAL;
546 goto err_rtc;
547 }
Javier Martinez Canillas6f1c1e72014-07-04 22:24:04 +0200548
Javier Martinez Canillas1745d6d2014-10-13 15:52:59 -0700549 if (!max77686->rtc_irq_data) {
550 ret = -EINVAL;
551 dev_err(&pdev->dev, "%s: no RTC regmap IRQ chip\n", __func__);
552 goto err_rtc;
553 }
554
Javier Martinez Canillas6f1c1e72014-07-04 22:24:04 +0200555 info->virq = regmap_irq_get_virq(max77686->rtc_irq_data,
556 MAX77686_RTCIRQ_RTCA1);
557 if (!info->virq) {
Sachin Kamatad819032013-04-29 16:20:12 -0700558 ret = -ENXIO;
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800559 goto err_rtc;
Sachin Kamatad819032013-04-29 16:20:12 -0700560 }
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800561
Javier Martinez Canillas6f1c1e72014-07-04 22:24:04 +0200562 ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL,
563 max77686_rtc_alarm_irq, 0, "rtc-alarm1", info);
Sachin Kamatad819032013-04-29 16:20:12 -0700564 if (ret < 0)
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800565 dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
566 info->virq, ret);
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800567
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800568err_rtc:
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800569 return ret;
570}
571
Doug Andersone7f7fc72014-10-13 15:52:55 -0700572#ifdef CONFIG_PM_SLEEP
573static int max77686_rtc_suspend(struct device *dev)
574{
575 if (device_may_wakeup(dev)) {
576 struct max77686_rtc_info *info = dev_get_drvdata(dev);
577
578 return enable_irq_wake(info->virq);
579 }
580
581 return 0;
582}
583
584static int max77686_rtc_resume(struct device *dev)
585{
586 if (device_may_wakeup(dev)) {
587 struct max77686_rtc_info *info = dev_get_drvdata(dev);
588
589 return disable_irq_wake(info->virq);
590 }
591
592 return 0;
593}
594#endif
595
596static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops,
597 max77686_rtc_suspend, max77686_rtc_resume);
598
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800599static const struct platform_device_id rtc_id[] = {
Javier Martinez Canillas01ea01b2016-01-27 00:36:40 -0300600 { "max77686-rtc", .driver_data = (kernel_ulong_t)&max77686_drv_data, },
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800601 {},
602};
Javier Martinez Canillas2d0cca02015-05-13 17:18:01 +0200603MODULE_DEVICE_TABLE(platform, rtc_id);
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800604
605static struct platform_driver max77686_rtc_driver = {
606 .driver = {
607 .name = "max77686-rtc",
Doug Andersone7f7fc72014-10-13 15:52:55 -0700608 .pm = &max77686_rtc_pm_ops,
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800609 },
610 .probe = max77686_rtc_probe,
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800611 .id_table = rtc_id,
612};
613
Jingoo Han0c58ff52013-04-29 16:18:28 -0700614module_platform_driver(max77686_rtc_driver);
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800615
616MODULE_DESCRIPTION("Maxim MAX77686 RTC driver");
Jingoo Hanf5b1d3c2013-04-29 16:18:29 -0700617MODULE_AUTHOR("Chiwoong Byun <woong.byun@samsung.com>");
Jonghwa Leefca1dd02013-02-21 16:44:26 -0800618MODULE_LICENSE("GPL");