aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSangbeom Kim <sbkim73@samsung.com>2013-11-12 18:11:04 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-12 22:09:31 -0500
commit5bccae6ec4587044779f0b8e6fcb8f87db4181f0 (patch)
tree7296acf72c7d9cbf594ec3e9d40140f18ac9e363
parent5e0d12142e1cf5dc7a8a276fc1fe60b8a5ecb1d3 (diff)
rtc: s5m-rtc: add real-time clock driver for s5m8767
Add real-time clock driver for s5m8767. Signed-off-by: Sangbeom Kim <sbkim73@samsung.com> Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org> Cc: Todd Broch <tbroch@chromium.org> Cc: Mark Brown <broonie@kernel.org> Acked-by: Lee Jones <lee.jones@linaro.org> [mfd parts] Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/rtc/Kconfig10
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-s5m.c635
-rw-r--r--include/linux/mfd/samsung/core.h1
-rw-r--r--include/linux/mfd/samsung/rtc.h11
5 files changed, 658 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 9654aa3c05cb..4f48b9a26aa0 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -497,6 +497,16 @@ config RTC_DRV_RV3029C2
497 This driver can also be built as a module. If so, the module 497 This driver can also be built as a module. If so, the module
498 will be called rtc-rv3029c2. 498 will be called rtc-rv3029c2.
499 499
500config RTC_DRV_S5M
501 tristate "Samsung S5M series"
502 depends on MFD_SEC_CORE
503 help
504 If you say yes here you will get support for the
505 RTC of Samsung S5M PMIC series.
506
507 This driver can also be built as a module. If so, the module
508 will be called rtc-s5m.
509
500endif # I2C 510endif # I2C
501 511
502comment "SPI RTC drivers" 512comment "SPI RTC drivers"
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 2dff3d2009b5..9312e7965365 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -107,6 +107,7 @@ obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o
107obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o 107obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o
108obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o 108obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
109obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o 109obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
110obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o
110obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o 111obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
111obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o 112obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
112obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o 113obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c
new file mode 100644
index 000000000000..b7fd02bc0a14
--- /dev/null
+++ b/drivers/rtc/rtc-s5m.c
@@ -0,0 +1,635 @@
1/*
2 * Copyright (c) 2013 Samsung Electronics Co., Ltd
3 * http://www.samsung.com
4 *
5 * Copyright (C) 2013 Google, Inc
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <linux/module.h>
19#include <linux/i2c.h>
20#include <linux/slab.h>
21#include <linux/bcd.h>
22#include <linux/bitops.h>
23#include <linux/regmap.h>
24#include <linux/rtc.h>
25#include <linux/delay.h>
26#include <linux/platform_device.h>
27#include <linux/mfd/samsung/core.h>
28#include <linux/mfd/samsung/irq.h>
29#include <linux/mfd/samsung/rtc.h>
30
31struct s5m_rtc_info {
32 struct device *dev;
33 struct sec_pmic_dev *s5m87xx;
34 struct regmap *rtc;
35 struct rtc_device *rtc_dev;
36 int irq;
37 int device_type;
38 int rtc_24hr_mode;
39 bool wtsr_smpl;
40};
41
42static void s5m8767_data_to_tm(u8 *data, struct rtc_time *tm,
43 int rtc_24hr_mode)
44{
45 tm->tm_sec = data[RTC_SEC] & 0x7f;
46 tm->tm_min = data[RTC_MIN] & 0x7f;
47 if (rtc_24hr_mode) {
48 tm->tm_hour = data[RTC_HOUR] & 0x1f;
49 } else {
50 tm->tm_hour = data[RTC_HOUR] & 0x0f;
51 if (data[RTC_HOUR] & HOUR_PM_MASK)
52 tm->tm_hour += 12;
53 }
54
55 tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f);
56 tm->tm_mday = data[RTC_DATE] & 0x1f;
57 tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
58 tm->tm_year = (data[RTC_YEAR1] & 0x7f) + 100;
59 tm->tm_yday = 0;
60 tm->tm_isdst = 0;
61}
62
63static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data)
64{
65 data[RTC_SEC] = tm->tm_sec;
66 data[RTC_MIN] = tm->tm_min;
67
68 if (tm->tm_hour >= 12)
69 data[RTC_HOUR] = tm->tm_hour | HOUR_PM_MASK;
70 else
71 data[RTC_HOUR] = tm->tm_hour & ~HOUR_PM_MASK;
72
73 data[RTC_WEEKDAY] = 1 << tm->tm_wday;
74 data[RTC_DATE] = tm->tm_mday;
75 data[RTC_MONTH] = tm->tm_mon + 1;
76 data[RTC_YEAR1] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0;
77
78 if (tm->tm_year < 100) {
79 pr_err("s5m8767 RTC cannot handle the year %d.\n",
80 1900 + tm->tm_year);
81 return -EINVAL;
82 } else {
83 return 0;
84 }
85}
86
87static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info)
88{
89 int ret;
90 unsigned int data;
91
92 ret = regmap_read(info->rtc, SEC_RTC_UDR_CON, &data);
93 if (ret < 0) {
94 dev_err(info->dev, "failed to read update reg(%d)\n", ret);
95 return ret;
96 }
97
98 data |= RTC_TIME_EN_MASK;
99 data |= RTC_UDR_MASK;
100
101 ret = regmap_write(info->rtc, SEC_RTC_UDR_CON, data);
102 if (ret < 0) {
103 dev_err(info->dev, "failed to write update reg(%d)\n", ret);
104 return ret;
105 }
106
107 do {
108 ret = regmap_read(info->rtc, SEC_RTC_UDR_CON, &data);
109 } while ((data & RTC_UDR_MASK) && !ret);
110
111 return ret;
112}
113
114static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)
115{
116 int ret;
117 unsigned int data;
118
119 ret = regmap_read(info->rtc, SEC_RTC_UDR_CON, &data);
120 if (ret < 0) {
121 dev_err(info->dev, "%s: fail to read update reg(%d)\n",
122 __func__, ret);
123 return ret;
124 }
125
126 data &= ~RTC_TIME_EN_MASK;
127 data |= RTC_UDR_MASK;
128
129 ret = regmap_write(info->rtc, SEC_RTC_UDR_CON, data);
130 if (ret < 0) {
131 dev_err(info->dev, "%s: fail to write update reg(%d)\n",
132 __func__, ret);
133 return ret;
134 }
135
136 do {
137 ret = regmap_read(info->rtc, SEC_RTC_UDR_CON, &data);
138 } while ((data & RTC_UDR_MASK) && !ret);
139
140 return ret;
141}
142
143static void s5m8763_data_to_tm(u8 *data, struct rtc_time *tm)
144{
145 tm->tm_sec = bcd2bin(data[RTC_SEC]);
146 tm->tm_min = bcd2bin(data[RTC_MIN]);
147
148 if (data[RTC_HOUR] & HOUR_12) {
149 tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x1f);
150 if (data[RTC_HOUR] & HOUR_PM)
151 tm->tm_hour += 12;
152 } else {
153 tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f);
154 }
155
156 tm->tm_wday = data[RTC_WEEKDAY] & 0x07;
157 tm->tm_mday = bcd2bin(data[RTC_DATE]);
158 tm->tm_mon = bcd2bin(data[RTC_MONTH]);
159 tm->tm_year = bcd2bin(data[RTC_YEAR1]) + bcd2bin(data[RTC_YEAR2]) * 100;
160 tm->tm_year -= 1900;
161}
162
163static void s5m8763_tm_to_data(struct rtc_time *tm, u8 *data)
164{
165 data[RTC_SEC] = bin2bcd(tm->tm_sec);
166 data[RTC_MIN] = bin2bcd(tm->tm_min);
167 data[RTC_HOUR] = bin2bcd(tm->tm_hour);
168 data[RTC_WEEKDAY] = tm->tm_wday;
169 data[RTC_DATE] = bin2bcd(tm->tm_mday);
170 data[RTC_MONTH] = bin2bcd(tm->tm_mon);
171 data[RTC_YEAR1] = bin2bcd(tm->tm_year % 100);
172 data[RTC_YEAR2] = bin2bcd((tm->tm_year + 1900) / 100);
173}
174
175static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm)
176{
177 struct s5m_rtc_info *info = dev_get_drvdata(dev);
178 u8 data[8];
179 int ret;
180
181 ret = regmap_bulk_read(info->rtc, SEC_RTC_SEC, data, 8);
182 if (ret < 0)
183 return ret;
184
185 switch (info->device_type) {
186 case S5M8763X:
187 s5m8763_data_to_tm(data, tm);
188 break;
189
190 case S5M8767X:
191 s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode);
192 break;
193
194 default:
195 return -EINVAL;
196 }
197
198 dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__,
199 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday,
200 tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday);
201
202 return rtc_valid_tm(tm);
203}
204
205static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm)
206{
207 struct s5m_rtc_info *info = dev_get_drvdata(dev);
208 u8 data[8];
209 int ret = 0;
210
211 switch (info->device_type) {
212 case S5M8763X:
213 s5m8763_tm_to_data(tm, data);
214 break;
215 case S5M8767X:
216 ret = s5m8767_tm_to_data(tm, data);
217 break;
218 default:
219 return -EINVAL;
220 }
221
222 if (ret < 0)
223 return ret;
224
225 dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__,
226 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday,
227 tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday);
228
229 ret = regmap_raw_write(info->rtc, SEC_RTC_SEC, data, 8);
230 if (ret < 0)
231 return ret;
232
233 ret = s5m8767_rtc_set_time_reg(info);
234
235 return ret;
236}
237
238static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
239{
240 struct s5m_rtc_info *info = dev_get_drvdata(dev);
241 u8 data[8];
242 unsigned int val;
243 int ret, i;
244
245 ret = regmap_bulk_read(info->rtc, SEC_ALARM0_SEC, data, 8);
246 if (ret < 0)
247 return ret;
248
249 switch (info->device_type) {
250 case S5M8763X:
251 s5m8763_data_to_tm(data, &alrm->time);
252 ret = regmap_read(info->rtc, SEC_ALARM0_CONF, &val);
253 if (ret < 0)
254 return ret;
255
256 alrm->enabled = !!val;
257
258 ret = regmap_read(info->rtc, SEC_RTC_STATUS, &val);
259 if (ret < 0)
260 return ret;
261
262 break;
263
264 case S5M8767X:
265 s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
266 dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__,
267 1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon,
268 alrm->time.tm_mday, alrm->time.tm_hour,
269 alrm->time.tm_min, alrm->time.tm_sec,
270 alrm->time.tm_wday);
271
272 alrm->enabled = 0;
273 for (i = 0; i < 7; i++) {
274 if (data[i] & ALARM_ENABLE_MASK) {
275 alrm->enabled = 1;
276 break;
277 }
278 }
279
280 alrm->pending = 0;
281 ret = regmap_read(info->rtc, SEC_RTC_STATUS, &val);
282 if (ret < 0)
283 return ret;
284 break;
285
286 default:
287 return -EINVAL;
288 }
289
290 if (val & ALARM0_STATUS)
291 alrm->pending = 1;
292 else
293 alrm->pending = 0;
294
295 return 0;
296}
297
298static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info)
299{
300 u8 data[8];
301 int ret, i;
302 struct rtc_time tm;
303
304 ret = regmap_bulk_read(info->rtc, SEC_ALARM0_SEC, data, 8);
305 if (ret < 0)
306 return ret;
307
308 s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode);
309 dev_dbg(info->dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__,
310 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday,
311 tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday);
312
313 switch (info->device_type) {
314 case S5M8763X:
315 ret = regmap_write(info->rtc, SEC_ALARM0_CONF, 0);
316 break;
317
318 case S5M8767X:
319 for (i = 0; i < 7; i++)
320 data[i] &= ~ALARM_ENABLE_MASK;
321
322 ret = regmap_raw_write(info->rtc, SEC_ALARM0_SEC, data, 8);
323 if (ret < 0)
324 return ret;
325
326 ret = s5m8767_rtc_set_alarm_reg(info);
327
328 break;
329
330 default:
331 return -EINVAL;
332 }
333
334 return ret;
335}
336
337static int s5m_rtc_start_alarm(struct s5m_rtc_info *info)
338{
339 int ret;
340 u8 data[8];
341 u8 alarm0_conf;
342 struct rtc_time tm;
343
344 ret = regmap_bulk_read(info->rtc, SEC_ALARM0_SEC, data, 8);
345 if (ret < 0)
346 return ret;
347
348 s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode);
349 dev_dbg(info->dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__,
350 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday,
351 tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday);
352
353 switch (info->device_type) {
354 case S5M8763X:
355 alarm0_conf = 0x77;
356 ret = regmap_write(info->rtc, SEC_ALARM0_CONF, alarm0_conf);
357 break;
358
359 case S5M8767X:
360 data[RTC_SEC] |= ALARM_ENABLE_MASK;
361 data[RTC_MIN] |= ALARM_ENABLE_MASK;
362 data[RTC_HOUR] |= ALARM_ENABLE_MASK;
363 data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK;
364 if (data[RTC_DATE] & 0x1f)
365 data[RTC_DATE] |= ALARM_ENABLE_MASK;
366 if (data[RTC_MONTH] & 0xf)
367 data[RTC_MONTH] |= ALARM_ENABLE_MASK;
368 if (data[RTC_YEAR1] & 0x7f)
369 data[RTC_YEAR1] |= ALARM_ENABLE_MASK;
370
371 ret = regmap_raw_write(info->rtc, SEC_ALARM0_SEC, data, 8);
372 if (ret < 0)
373 return ret;
374 ret = s5m8767_rtc_set_alarm_reg(info);
375
376 break;
377
378 default:
379 return -EINVAL;
380 }
381
382 return ret;
383}
384
385static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
386{
387 struct s5m_rtc_info *info = dev_get_drvdata(dev);
388 u8 data[8];
389 int ret;
390
391 switch (info->device_type) {
392 case S5M8763X:
393 s5m8763_tm_to_data(&alrm->time, data);
394 break;
395
396 case S5M8767X:
397 s5m8767_tm_to_data(&alrm->time, data);
398 break;
399
400 default:
401 return -EINVAL;
402 }
403
404 dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__,
405 1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon,
406 alrm->time.tm_mday, alrm->time.tm_hour, alrm->time.tm_min,
407 alrm->time.tm_sec, alrm->time.tm_wday);
408
409 ret = s5m_rtc_stop_alarm(info);
410 if (ret < 0)
411 return ret;
412
413 ret = regmap_raw_write(info->rtc, SEC_ALARM0_SEC, data, 8);
414 if (ret < 0)
415 return ret;
416
417 ret = s5m8767_rtc_set_alarm_reg(info);
418 if (ret < 0)
419 return ret;
420
421 if (alrm->enabled)
422 ret = s5m_rtc_start_alarm(info);
423
424 return ret;
425}
426
427static int s5m_rtc_alarm_irq_enable(struct device *dev,
428 unsigned int enabled)
429{
430 struct s5m_rtc_info *info = dev_get_drvdata(dev);
431
432 if (enabled)
433 return s5m_rtc_start_alarm(info);
434 else
435 return s5m_rtc_stop_alarm(info);
436}
437
438static irqreturn_t s5m_rtc_alarm_irq(int irq, void *data)
439{
440 struct s5m_rtc_info *info = data;
441
442 rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
443
444 return IRQ_HANDLED;
445}
446
447static const struct rtc_class_ops s5m_rtc_ops = {
448 .read_time = s5m_rtc_read_time,
449 .set_time = s5m_rtc_set_time,
450 .read_alarm = s5m_rtc_read_alarm,
451 .set_alarm = s5m_rtc_set_alarm,
452 .alarm_irq_enable = s5m_rtc_alarm_irq_enable,
453};
454
455static void s5m_rtc_enable_wtsr(struct s5m_rtc_info *info, bool enable)
456{
457 int ret;
458 ret = regmap_update_bits(info->rtc, SEC_WTSR_SMPL_CNTL,
459 WTSR_ENABLE_MASK,
460 enable ? WTSR_ENABLE_MASK : 0);
461 if (ret < 0)
462 dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n",
463 __func__, ret);
464}
465
466static void s5m_rtc_enable_smpl(struct s5m_rtc_info *info, bool enable)
467{
468 int ret;
469 ret = regmap_update_bits(info->rtc, SEC_WTSR_SMPL_CNTL,
470 SMPL_ENABLE_MASK,
471 enable ? SMPL_ENABLE_MASK : 0);
472 if (ret < 0)
473 dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n",
474 __func__, ret);
475}
476
477static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info)
478{
479 u8 data[2];
480 unsigned int tp_read;
481 int ret;
482 struct rtc_time tm;
483
484 ret = regmap_read(info->rtc, SEC_RTC_UDR_CON, &tp_read);
485 if (ret < 0) {
486 dev_err(info->dev, "%s: fail to read control reg(%d)\n",
487 __func__, ret);
488 return ret;
489 }
490
491 /* Set RTC control register : Binary mode, 24hour mode */
492 data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
493 data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
494
495 info->rtc_24hr_mode = 1;
496 ret = regmap_raw_write(info->rtc, SEC_ALARM0_CONF, data, 2);
497 if (ret < 0) {
498 dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
499 __func__, ret);
500 return ret;
501 }
502
503 /* In first boot time, Set rtc time to 1/1/2012 00:00:00(SUN) */
504 if ((tp_read & RTC_TCON_MASK) == 0) {
505 dev_dbg(info->dev, "rtc init\n");
506 tm.tm_sec = 0;
507 tm.tm_min = 0;
508 tm.tm_hour = 0;
509 tm.tm_wday = 0;
510 tm.tm_mday = 1;
511 tm.tm_mon = 0;
512 tm.tm_year = 112;
513 tm.tm_yday = 0;
514 tm.tm_isdst = 0;
515 ret = s5m_rtc_set_time(info->dev, &tm);
516 }
517
518 ret = regmap_update_bits(info->rtc, SEC_RTC_UDR_CON,
519 RTC_TCON_MASK, tp_read | RTC_TCON_MASK);
520 if (ret < 0)
521 dev_err(info->dev, "%s: fail to update TCON reg(%d)\n",
522 __func__, ret);
523
524 return ret;
525}
526
527static int s5m_rtc_probe(struct platform_device *pdev)
528{
529 struct sec_pmic_dev *s5m87xx = dev_get_drvdata(pdev->dev.parent);
530 struct sec_platform_data *pdata = s5m87xx->pdata;
531 struct s5m_rtc_info *info;
532 int ret;
533
534 if (!pdata) {
535 dev_err(pdev->dev.parent, "Platform data not supplied\n");
536 return -ENODEV;
537 }
538
539 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
540 if (!info)
541 return -ENOMEM;
542
543 info->dev = &pdev->dev;
544 info->s5m87xx = s5m87xx;
545 info->rtc = s5m87xx->rtc;
546 info->device_type = s5m87xx->device_type;
547 info->wtsr_smpl = s5m87xx->wtsr_smpl;
548
549 switch (pdata->device_type) {
550 case S5M8763X:
551 info->irq = s5m87xx->irq_base + S5M8763_IRQ_ALARM0;
552 break;
553
554 case S5M8767X:
555 info->irq = s5m87xx->irq_base + S5M8767_IRQ_RTCA1;
556 break;
557
558 default:
559 ret = -EINVAL;
560 dev_err(&pdev->dev, "Unsupported device type: %d\n", ret);
561 return ret;
562 }
563
564 platform_set_drvdata(pdev, info);
565
566 ret = s5m8767_rtc_init_reg(info);
567
568 if (info->wtsr_smpl) {
569 s5m_rtc_enable_wtsr(info, true);
570 s5m_rtc_enable_smpl(info, true);
571 }
572
573 device_init_wakeup(&pdev->dev, 1);
574
575 info->rtc_dev = devm_rtc_device_register(&pdev->dev, "s5m-rtc",
576 &s5m_rtc_ops, THIS_MODULE);
577
578 if (IS_ERR(info->rtc_dev))
579 return PTR_ERR(info->rtc_dev);
580
581 ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
582 s5m_rtc_alarm_irq, 0, "rtc-alarm0",
583 info);
584 if (ret < 0)
585 dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
586 info->irq, ret);
587
588 return ret;
589}
590
591static void s5m_rtc_shutdown(struct platform_device *pdev)
592{
593 struct s5m_rtc_info *info = platform_get_drvdata(pdev);
594 int i;
595 unsigned int val = 0;
596 if (info->wtsr_smpl) {
597 for (i = 0; i < 3; i++) {
598 s5m_rtc_enable_wtsr(info, false);
599 regmap_read(info->rtc, SEC_WTSR_SMPL_CNTL, &val);
600 pr_debug("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val);
601 if (val & WTSR_ENABLE_MASK)
602 pr_emerg("%s: fail to disable WTSR\n",
603 __func__);
604 else {
605 pr_info("%s: success to disable WTSR\n",
606 __func__);
607 break;
608 }
609 }
610 }
611 /* Disable SMPL when power off */
612 s5m_rtc_enable_smpl(info, false);
613}
614
615static const struct platform_device_id s5m_rtc_id[] = {
616 { "s5m-rtc", 0 },
617};
618
619static struct platform_driver s5m_rtc_driver = {
620 .driver = {
621 .name = "s5m-rtc",
622 .owner = THIS_MODULE,
623 },
624 .probe = s5m_rtc_probe,
625 .shutdown = s5m_rtc_shutdown,
626 .id_table = s5m_rtc_id,
627};
628
629module_platform_driver(s5m_rtc_driver);
630
631/* Module information */
632MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
633MODULE_DESCRIPTION("Samsung S5M RTC driver");
634MODULE_LICENSE("GPL");
635MODULE_ALIAS("platform:s5m-rtc");
diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h
index 378ae8a04c6a..2d0c9071bcfb 100644
--- a/include/linux/mfd/samsung/core.h
+++ b/include/linux/mfd/samsung/core.h
@@ -51,6 +51,7 @@ struct sec_pmic_dev {
51 int ono; 51 int ono;
52 int type; 52 int type;
53 bool wakeup; 53 bool wakeup;
54 bool wtsr_smpl;
54}; 55};
55 56
56int sec_irq_init(struct sec_pmic_dev *sec_pmic); 57int sec_irq_init(struct sec_pmic_dev *sec_pmic);
diff --git a/include/linux/mfd/samsung/rtc.h b/include/linux/mfd/samsung/rtc.h
index 71597e20cddb..94b7cd6d8891 100644
--- a/include/linux/mfd/samsung/rtc.h
+++ b/include/linux/mfd/samsung/rtc.h
@@ -62,6 +62,11 @@ enum sec_rtc_reg {
62/* RTC Update Register1 */ 62/* RTC Update Register1 */
63#define RTC_UDR_SHIFT 0 63#define RTC_UDR_SHIFT 0
64#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) 64#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT)
65#define RTC_TCON_SHIFT 1
66#define RTC_TCON_MASK (1 << RTC_TCON_SHIFT)
67#define RTC_TIME_EN_SHIFT 3
68#define RTC_TIME_EN_MASK (1 << RTC_TIME_EN_SHIFT)
69
65/* RTC Hour register */ 70/* RTC Hour register */
66#define HOUR_PM_SHIFT 6 71#define HOUR_PM_SHIFT 6
67#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) 72#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT)
@@ -69,6 +74,12 @@ enum sec_rtc_reg {
69#define ALARM_ENABLE_SHIFT 7 74#define ALARM_ENABLE_SHIFT 7
70#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) 75#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT)
71 76
77#define SMPL_ENABLE_SHIFT 7
78#define SMPL_ENABLE_MASK (1 << SMPL_ENABLE_SHIFT)
79
80#define WTSR_ENABLE_SHIFT 6
81#define WTSR_ENABLE_MASK (1 << WTSR_ENABLE_SHIFT)
82
72enum { 83enum {
73 RTC_SEC = 0, 84 RTC_SEC = 0,
74 RTC_MIN, 85 RTC_MIN,