aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorAshish Jangam <ashish.jangam@kpitcummins.com>2012-12-17 19:02:53 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-17 20:15:21 -0500
commit6920d996e3fee4ac5dcb7d34cb290b6f67bb69d0 (patch)
tree5011cebaa414fb857e7e03b2023d226fcc9f6f11 /drivers/rtc
parent04a373fdc9b0cbb4f076dd0e6c6433dc3bc48724 (diff)
rtc: DA9055 RTC driver
A driver for the DA9055 PMIC. This has a dependency upon the DA9055 MFD core. Functionally tested on Samsung SMDKV6410. Signed-off-by: David Dajun Chen <dchen@diasemi.com> Signed-off-by: Ashish Jangam <ashish.jangam@kpitcummins.com> Cc: Samuel Ortiz <sameo@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig10
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-da9055.c413
3 files changed, 424 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 5bb031461d75..d0cea02b5dfc 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -609,6 +609,16 @@ config RTC_DRV_DA9052
609 Say y here to support the RTC driver for Dialog Semiconductor 609 Say y here to support the RTC driver for Dialog Semiconductor
610 DA9052-BC and DA9053-AA/Bx PMICs. 610 DA9052-BC and DA9053-AA/Bx PMICs.
611 611
612config RTC_DRV_DA9055
613 tristate "Dialog Semiconductor DA9055 RTC"
614 depends on MFD_DA9055
615 help
616 If you say yes here you will get support for the
617 RTC of the Dialog DA9055 PMIC.
618
619 This driver can also be built as a module. If so, the module
620 will be called rtc-da9055
621
612config RTC_DRV_EFI 622config RTC_DRV_EFI
613 tristate "EFI RTC" 623 tristate "EFI RTC"
614 depends on IA64 624 depends on IA64
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 59e2132a1c14..c3f62c80dc06 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
29obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o 29obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
30obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o 30obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o
31obj-$(CONFIG_RTC_DRV_DA9052) += rtc-da9052.o 31obj-$(CONFIG_RTC_DRV_DA9052) += rtc-da9052.o
32obj-$(CONFIG_RTC_DRV_DA9055) += rtc-da9055.o
32obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o 33obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o
33obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o 34obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o
34obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o 35obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o
diff --git a/drivers/rtc/rtc-da9055.c b/drivers/rtc/rtc-da9055.c
new file mode 100644
index 000000000000..96bafc5c3bf8
--- /dev/null
+++ b/drivers/rtc/rtc-da9055.c
@@ -0,0 +1,413 @@
1/*
2 * Real time clock driver for DA9055
3 *
4 * Copyright(c) 2012 Dialog Semiconductor Ltd.
5 *
6 * Author: Dajun Dajun Chen <dajun.chen@diasemi.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 */
14
15#include <linux/module.h>
16#include <linux/platform_device.h>
17#include <linux/rtc.h>
18
19#include <linux/mfd/da9055/core.h>
20#include <linux/mfd/da9055/reg.h>
21#include <linux/mfd/da9055/pdata.h>
22
23struct da9055_rtc {
24 struct rtc_device *rtc;
25 struct da9055 *da9055;
26 int alarm_enable;
27};
28
29static int da9055_rtc_enable_alarm(struct da9055_rtc *rtc, bool enable)
30{
31 int ret;
32 if (enable) {
33 ret = da9055_reg_update(rtc->da9055, DA9055_REG_ALARM_Y,
34 DA9055_RTC_ALM_EN,
35 DA9055_RTC_ALM_EN);
36 if (ret != 0)
37 dev_err(rtc->da9055->dev, "Failed to enable ALM: %d\n",
38 ret);
39 rtc->alarm_enable = 1;
40 } else {
41 ret = da9055_reg_update(rtc->da9055, DA9055_REG_ALARM_Y,
42 DA9055_RTC_ALM_EN, 0);
43 if (ret != 0)
44 dev_err(rtc->da9055->dev,
45 "Failed to disable ALM: %d\n", ret);
46 rtc->alarm_enable = 0;
47 }
48 return ret;
49}
50
51static irqreturn_t da9055_rtc_alm_irq(int irq, void *data)
52{
53 struct da9055_rtc *rtc = data;
54
55 da9055_rtc_enable_alarm(rtc, 0);
56 rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
57
58 return IRQ_HANDLED;
59}
60
61static int da9055_read_alarm(struct da9055 *da9055, struct rtc_time *rtc_tm)
62{
63 int ret;
64 uint8_t v[5];
65
66 ret = da9055_group_read(da9055, DA9055_REG_ALARM_MI, 5, v);
67 if (ret != 0) {
68 dev_err(da9055->dev, "Failed to group read ALM: %d\n", ret);
69 return ret;
70 }
71
72 rtc_tm->tm_year = (v[4] & DA9055_RTC_ALM_YEAR) + 100;
73 rtc_tm->tm_mon = (v[3] & DA9055_RTC_ALM_MONTH) - 1;
74 rtc_tm->tm_mday = v[2] & DA9055_RTC_ALM_DAY;
75 rtc_tm->tm_hour = v[1] & DA9055_RTC_ALM_HOUR;
76 rtc_tm->tm_min = v[0] & DA9055_RTC_ALM_MIN;
77
78 return rtc_valid_tm(rtc_tm);
79}
80
81static int da9055_set_alarm(struct da9055 *da9055, struct rtc_time *rtc_tm)
82{
83 int ret;
84 uint8_t v[2];
85
86 rtc_tm->tm_year -= 100;
87 rtc_tm->tm_mon += 1;
88
89 ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MI,
90 DA9055_RTC_ALM_MIN, rtc_tm->tm_min);
91 if (ret != 0) {
92 dev_err(da9055->dev, "Failed to write ALRM MIN: %d\n", ret);
93 return ret;
94 }
95
96 v[0] = rtc_tm->tm_hour;
97 v[1] = rtc_tm->tm_mday;
98
99 ret = da9055_group_write(da9055, DA9055_REG_ALARM_H, 2, v);
100 if (ret < 0)
101 return ret;
102
103 ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MO,
104 DA9055_RTC_ALM_MONTH, rtc_tm->tm_mon);
105 if (ret < 0)
106 dev_err(da9055->dev, "Failed to write ALM Month:%d\n", ret);
107
108 ret = da9055_reg_update(da9055, DA9055_REG_ALARM_Y,
109 DA9055_RTC_ALM_YEAR, rtc_tm->tm_year);
110 if (ret < 0)
111 dev_err(da9055->dev, "Failed to write ALM Year:%d\n", ret);
112
113 return ret;
114}
115
116static int da9055_rtc_get_alarm_status(struct da9055 *da9055)
117{
118 int ret;
119
120 ret = da9055_reg_read(da9055, DA9055_REG_ALARM_Y);
121 if (ret < 0) {
122 dev_err(da9055->dev, "Failed to read ALM: %d\n", ret);
123 return ret;
124 }
125 ret &= DA9055_RTC_ALM_EN;
126 return (ret > 0) ? 1 : 0;
127}
128
129static int da9055_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
130{
131 struct da9055_rtc *rtc = dev_get_drvdata(dev);
132 uint8_t v[6];
133 int ret;
134
135 ret = da9055_reg_read(rtc->da9055, DA9055_REG_COUNT_S);
136 if (ret < 0)
137 return ret;
138
139 /*
140 * Registers are only valid when RTC_READ
141 * status bit is asserted
142 */
143 if (!(ret & DA9055_RTC_READ))
144 return -EBUSY;
145
146 ret = da9055_group_read(rtc->da9055, DA9055_REG_COUNT_S, 6, v);
147 if (ret < 0) {
148 dev_err(rtc->da9055->dev, "Failed to read RTC time : %d\n",
149 ret);
150 return ret;
151 }
152
153 rtc_tm->tm_year = (v[5] & DA9055_RTC_YEAR) + 100;
154 rtc_tm->tm_mon = (v[4] & DA9055_RTC_MONTH) - 1;
155 rtc_tm->tm_mday = v[3] & DA9055_RTC_DAY;
156 rtc_tm->tm_hour = v[2] & DA9055_RTC_HOUR;
157 rtc_tm->tm_min = v[1] & DA9055_RTC_MIN;
158 rtc_tm->tm_sec = v[0] & DA9055_RTC_SEC;
159
160 return rtc_valid_tm(rtc_tm);
161}
162
163static int da9055_rtc_set_time(struct device *dev, struct rtc_time *tm)
164{
165 struct da9055_rtc *rtc;
166 uint8_t v[6];
167
168 rtc = dev_get_drvdata(dev);
169
170 v[0] = tm->tm_sec;
171 v[1] = tm->tm_min;
172 v[2] = tm->tm_hour;
173 v[3] = tm->tm_mday;
174 v[4] = tm->tm_mon + 1;
175 v[5] = tm->tm_year - 100;
176
177 return da9055_group_write(rtc->da9055, DA9055_REG_COUNT_S, 6, v);
178}
179
180static int da9055_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
181{
182 int ret;
183 struct rtc_time *tm = &alrm->time;
184 struct da9055_rtc *rtc = dev_get_drvdata(dev);
185
186 ret = da9055_read_alarm(rtc->da9055, tm);
187
188 if (ret)
189 return ret;
190
191 alrm->enabled = da9055_rtc_get_alarm_status(rtc->da9055);
192
193 return 0;
194}
195
196static int da9055_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
197{
198 int ret;
199 struct rtc_time *tm = &alrm->time;
200 struct da9055_rtc *rtc = dev_get_drvdata(dev);
201
202 ret = da9055_rtc_enable_alarm(rtc, 0);
203 if (ret < 0)
204 return ret;
205
206 ret = da9055_set_alarm(rtc->da9055, tm);
207 if (ret)
208 return ret;
209
210 ret = da9055_rtc_enable_alarm(rtc, 1);
211
212 return ret;
213}
214
215static int da9055_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
216{
217 struct da9055_rtc *rtc = dev_get_drvdata(dev);
218
219 return da9055_rtc_enable_alarm(rtc, enabled);
220}
221
222static const struct rtc_class_ops da9055_rtc_ops = {
223 .read_time = da9055_rtc_read_time,
224 .set_time = da9055_rtc_set_time,
225 .read_alarm = da9055_rtc_read_alarm,
226 .set_alarm = da9055_rtc_set_alarm,
227 .alarm_irq_enable = da9055_rtc_alarm_irq_enable,
228};
229
230static int __init da9055_rtc_device_init(struct da9055 *da9055,
231 struct da9055_pdata *pdata)
232{
233 int ret;
234
235 /* Enable RTC and the internal Crystal */
236 ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B,
237 DA9055_RTC_EN, DA9055_RTC_EN);
238 if (ret < 0)
239 return ret;
240 ret = da9055_reg_update(da9055, DA9055_REG_EN_32K,
241 DA9055_CRYSTAL_EN, DA9055_CRYSTAL_EN);
242 if (ret < 0)
243 return ret;
244
245 /* Enable RTC in Power Down mode */
246 ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B,
247 DA9055_RTC_MODE_PD, DA9055_RTC_MODE_PD);
248 if (ret < 0)
249 return ret;
250
251 /* Enable RTC in Reset mode */
252 if (pdata && pdata->reset_enable) {
253 ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B,
254 DA9055_RTC_MODE_SD,
255 DA9055_RTC_MODE_SD <<
256 DA9055_RTC_MODE_SD_SHIFT);
257 if (ret < 0)
258 return ret;
259 }
260
261 /* Disable the RTC TICK ALM */
262 ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MO,
263 DA9055_RTC_TICK_WAKE_MASK, 0);
264 if (ret < 0)
265 return ret;
266
267 return 0;
268}
269
270static int da9055_rtc_probe(struct platform_device *pdev)
271{
272 struct da9055_rtc *rtc;
273 struct da9055_pdata *pdata = NULL;
274 int ret, alm_irq;
275
276 rtc = devm_kzalloc(&pdev->dev, sizeof(struct da9055_rtc), GFP_KERNEL);
277 if (!rtc)
278 return -ENOMEM;
279
280 rtc->da9055 = dev_get_drvdata(pdev->dev.parent);
281 pdata = rtc->da9055->dev->platform_data;
282 platform_set_drvdata(pdev, rtc);
283
284 ret = da9055_rtc_device_init(rtc->da9055, pdata);
285 if (ret < 0)
286 goto err_rtc;
287
288 ret = da9055_reg_read(rtc->da9055, DA9055_REG_ALARM_Y);
289 if (ret < 0)
290 goto err_rtc;
291
292 if (ret & DA9055_RTC_ALM_EN)
293 rtc->alarm_enable = 1;
294
295 device_init_wakeup(&pdev->dev, 1);
296
297 rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
298 &da9055_rtc_ops, THIS_MODULE);
299 if (IS_ERR(rtc->rtc)) {
300 ret = PTR_ERR(rtc->rtc);
301 goto err_rtc;
302 }
303
304 alm_irq = platform_get_irq_byname(pdev, "ALM");
305 alm_irq = regmap_irq_get_virq(rtc->da9055->irq_data, alm_irq);
306 ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL,
307 da9055_rtc_alm_irq,
308 IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
309 "ALM", rtc);
310 if (ret != 0)
311 dev_err(rtc->da9055->dev, "irq registration failed: %d\n", ret);
312
313err_rtc:
314 return ret;
315
316}
317
318static int da9055_rtc_remove(struct platform_device *pdev)
319{
320 struct da9055_rtc *rtc = pdev->dev.platform_data;
321
322 rtc_device_unregister(rtc->rtc);
323 platform_set_drvdata(pdev, NULL);
324
325 return 0;
326}
327
328#ifdef CONFIG_PM
329/* Turn off the alarm if it should not be a wake source. */
330static int da9055_rtc_suspend(struct device *dev)
331{
332 struct platform_device *pdev = to_platform_device(dev);
333 struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev);
334 int ret;
335
336 if (!device_may_wakeup(&pdev->dev)) {
337 /* Disable the ALM IRQ */
338 ret = da9055_rtc_enable_alarm(rtc, 0);
339 if (ret < 0)
340 dev_err(&pdev->dev, "Failed to disable RTC ALM\n");
341 }
342
343 return 0;
344}
345
346/* Enable the alarm if it should be enabled (in case it was disabled to
347 * prevent use as a wake source).
348 */
349static int da9055_rtc_resume(struct device *dev)
350{
351 struct platform_device *pdev = to_platform_device(dev);
352 struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev);
353 int ret;
354
355 if (!device_may_wakeup(&pdev->dev)) {
356 if (rtc->alarm_enable) {
357 ret = da9055_rtc_enable_alarm(rtc, 1);
358 if (ret < 0)
359 dev_err(&pdev->dev,
360 "Failed to restart RTC ALM\n");
361 }
362 }
363
364 return 0;
365}
366
367/* Unconditionally disable the alarm */
368static int da9055_rtc_freeze(struct device *dev)
369{
370 struct platform_device *pdev = to_platform_device(dev);
371 struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev);
372 int ret;
373
374 ret = da9055_rtc_enable_alarm(rtc, 0);
375 if (ret < 0)
376 dev_err(&pdev->dev, "Failed to freeze RTC ALMs\n");
377
378 return 0;
379
380}
381#else
382#define da9055_rtc_suspend NULL
383#define da9055_rtc_resume NULL
384#define da9055_rtc_freeze NULL
385#endif
386
387static const struct dev_pm_ops da9055_rtc_pm_ops = {
388 .suspend = da9055_rtc_suspend,
389 .resume = da9055_rtc_resume,
390
391 .freeze = da9055_rtc_freeze,
392 .thaw = da9055_rtc_resume,
393 .restore = da9055_rtc_resume,
394
395 .poweroff = da9055_rtc_suspend,
396};
397
398static struct platform_driver da9055_rtc_driver = {
399 .probe = da9055_rtc_probe,
400 .remove = da9055_rtc_remove,
401 .driver = {
402 .name = "da9055-rtc",
403 .owner = THIS_MODULE,
404 .pm = &da9055_rtc_pm_ops,
405 },
406};
407
408module_platform_driver(da9055_rtc_driver);
409
410MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
411MODULE_DESCRIPTION("RTC driver for Dialog DA9055 PMIC");
412MODULE_LICENSE("GPL");
413MODULE_ALIAS("platform:da9055-rtc");