blob: 1dfa488e67ff905fa09e4ae4d1507aeb36f26aec [file] [log] [blame]
Sangbeom Kim5bccae62013-11-12 15:11:04 -08001/*
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;
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -080034 struct regmap *regmap;
Sangbeom Kim5bccae62013-11-12 15:11:04 -080035 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
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -080092 ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &data);
Sangbeom Kim5bccae62013-11-12 15:11:04 -080093 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
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800101 ret = regmap_write(info->regmap, SEC_RTC_UDR_CON, data);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800102 if (ret < 0) {
103 dev_err(info->dev, "failed to write update reg(%d)\n", ret);
104 return ret;
105 }
106
107 do {
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800108 ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &data);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800109 } 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
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800119 ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &data);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800120 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
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800129 ret = regmap_write(info->regmap, SEC_RTC_UDR_CON, data);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800130 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 {
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800137 ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &data);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800138 } 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
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800181 ret = regmap_bulk_read(info->regmap, SEC_RTC_SEC, data, 8);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800182 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
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800229 ret = regmap_raw_write(info->regmap, SEC_RTC_SEC, data, 8);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800230 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
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800245 ret = regmap_bulk_read(info->regmap, SEC_ALARM0_SEC, data, 8);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800246 if (ret < 0)
247 return ret;
248
249 switch (info->device_type) {
250 case S5M8763X:
251 s5m8763_data_to_tm(data, &alrm->time);
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800252 ret = regmap_read(info->regmap, SEC_ALARM0_CONF, &val);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800253 if (ret < 0)
254 return ret;
255
256 alrm->enabled = !!val;
257
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800258 ret = regmap_read(info->regmap, SEC_RTC_STATUS, &val);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800259 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;
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800281 ret = regmap_read(info->regmap, SEC_RTC_STATUS, &val);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800282 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
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800304 ret = regmap_bulk_read(info->regmap, SEC_ALARM0_SEC, data, 8);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800305 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:
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800315 ret = regmap_write(info->regmap, SEC_ALARM0_CONF, 0);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800316 break;
317
318 case S5M8767X:
319 for (i = 0; i < 7; i++)
320 data[i] &= ~ALARM_ENABLE_MASK;
321
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800322 ret = regmap_raw_write(info->regmap, SEC_ALARM0_SEC, data, 8);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800323 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
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800344 ret = regmap_bulk_read(info->regmap, SEC_ALARM0_SEC, data, 8);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800345 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;
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800356 ret = regmap_write(info->regmap, SEC_ALARM0_CONF, alarm0_conf);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800357 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
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800371 ret = regmap_raw_write(info->regmap, SEC_ALARM0_SEC, data, 8);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800372 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
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800413 ret = regmap_raw_write(info->regmap, SEC_ALARM0_SEC, data, 8);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800414 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;
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800458 ret = regmap_update_bits(info->regmap, SEC_WTSR_SMPL_CNTL,
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800459 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;
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800469 ret = regmap_update_bits(info->regmap, SEC_WTSR_SMPL_CNTL,
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800470 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
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800484 ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &tp_read);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800485 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;
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800496 ret = regmap_raw_write(info->regmap, SEC_ALARM0_CONF, data, 2);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800497 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
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800518 ret = regmap_update_bits(info->regmap, SEC_RTC_UDR_CON,
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800519 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;
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800545 info->regmap = s5m87xx->regmap;
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800546 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);
Geert Uytterhoeven5ccb7d72013-12-12 17:12:25 -0800599 regmap_read(info->regmap, SEC_WTSR_SMPL_CNTL, &val);
Sangbeom Kim5bccae62013-11-12 15:11:04 -0800600 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");