aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorVenu Byravarasu <vbyravarasu@nvidia.com>2012-10-04 20:13:55 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-05 14:05:02 -0400
commit0e783980b84e7253ba98552d092d1f45ed262d66 (patch)
tree7cc402699e588484b76aae12b9758c23125eb4b1 /drivers/rtc
parent477d30d787b969e4c11fc958077cc7954805e236 (diff)
rtc: tps65910: add RTC driver for TPS65910 PMIC RTC
TPS65910 PMIC is a MFD with RTC as one of the device. Adding RTC driver for supporting RTC device present inside TPS65910 PMIC. Only support for RTC alarm is implemented as part of this patch. Signed-off-by: Venu Byravarasu <vbyravarasu@nvidia.com> Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: Mark Brown <broonie@opensource.wolfsonmicro.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-tps65910.c352
3 files changed, 363 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index f87bfea6718c..6309df4e2654 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -335,6 +335,16 @@ config RTC_DRV_TWL4030
335 This driver can also be built as a module. If so, the module 335 This driver can also be built as a module. If so, the module
336 will be called rtc-twl. 336 will be called rtc-twl.
337 337
338config RTC_DRV_TPS65910
339 tristate "TI TPS65910 RTC driver"
340 depends on RTC_CLASS && MFD_TPS65910
341 help
342 If you say yes here you get support for the RTC on the
343 TPS65910 chips.
344
345 This driver can also be built as a module. If so, the module
346 will be called rtc-tps65910.
347
338config RTC_DRV_S35390A 348config RTC_DRV_S35390A
339 tristate "Seiko Instruments S-35390A" 349 tristate "Seiko Instruments S-35390A"
340 select BITREVERSE 350 select BITREVERSE
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 6056f71033db..5c8f106237da 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -107,6 +107,7 @@ obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o
107obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o 107obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
108obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o 108obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o
109obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o 109obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o
110obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o
110obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o 111obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o
111obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o 112obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
112obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o 113obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c
new file mode 100644
index 000000000000..7c4ca8605741
--- /dev/null
+++ b/drivers/rtc/rtc-tps65910.c
@@ -0,0 +1,352 @@
1/*
2 * rtc-tps65910.c -- TPS65910 Real Time Clock interface
3 *
4 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
5 * Author: Venu Byravarasu <vbyravarasu@nvidia.com>
6 *
7 * Based on original TI driver rtc-twl.c
8 * Copyright (C) 2007 MontaVista Software, Inc
9 * Author: Alexandre Rusev <source@mvista.com>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version
14 * 2 of the License, or (at your option) any later version.
15 */
16
17#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/init.h>
20#include <linux/module.h>
21#include <linux/types.h>
22#include <linux/rtc.h>
23#include <linux/bcd.h>
24#include <linux/platform_device.h>
25#include <linux/interrupt.h>
26#include <linux/mfd/tps65910.h>
27
28struct tps65910_rtc {
29 struct rtc_device *rtc;
30 /* To store the list of enabled interrupts */
31 u32 irqstat;
32};
33
34/* Total number of RTC registers needed to set time*/
35#define NUM_TIME_REGS (TPS65910_YEARS - TPS65910_SECONDS + 1)
36
37static int tps65910_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
38{
39 struct tps65910 *tps = dev_get_drvdata(dev->parent);
40 u8 val = 0;
41
42 if (enabled)
43 val = TPS65910_RTC_INTERRUPTS_IT_ALARM;
44
45 return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, val);
46}
47
48/*
49 * Gets current tps65910 RTC time and date parameters.
50 *
51 * The RTC's time/alarm representation is not what gmtime(3) requires
52 * Linux to use:
53 *
54 * - Months are 1..12 vs Linux 0-11
55 * - Years are 0..99 vs Linux 1900..N (we assume 21st century)
56 */
57static int tps65910_rtc_read_time(struct device *dev, struct rtc_time *tm)
58{
59 unsigned char rtc_data[NUM_TIME_REGS];
60 struct tps65910 *tps = dev_get_drvdata(dev->parent);
61 int ret;
62
63 /* Copy RTC counting registers to static registers or latches */
64 ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL,
65 TPS65910_RTC_CTRL_GET_TIME, TPS65910_RTC_CTRL_GET_TIME);
66 if (ret < 0) {
67 dev_err(dev, "RTC CTRL reg update failed with err:%d\n", ret);
68 return ret;
69 }
70
71 ret = regmap_bulk_read(tps->regmap, TPS65910_SECONDS, rtc_data,
72 NUM_TIME_REGS);
73 if (ret < 0) {
74 dev_err(dev, "reading from RTC failed with err:%d\n", ret);
75 return ret;
76 }
77
78 tm->tm_sec = bcd2bin(rtc_data[0]);
79 tm->tm_min = bcd2bin(rtc_data[1]);
80 tm->tm_hour = bcd2bin(rtc_data[2]);
81 tm->tm_mday = bcd2bin(rtc_data[3]);
82 tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
83 tm->tm_year = bcd2bin(rtc_data[5]) + 100;
84
85 return ret;
86}
87
88static int tps65910_rtc_set_time(struct device *dev, struct rtc_time *tm)
89{
90 unsigned char rtc_data[NUM_TIME_REGS];
91 struct tps65910 *tps = dev_get_drvdata(dev->parent);
92 int ret;
93
94 rtc_data[0] = bin2bcd(tm->tm_sec);
95 rtc_data[1] = bin2bcd(tm->tm_min);
96 rtc_data[2] = bin2bcd(tm->tm_hour);
97 rtc_data[3] = bin2bcd(tm->tm_mday);
98 rtc_data[4] = bin2bcd(tm->tm_mon + 1);
99 rtc_data[5] = bin2bcd(tm->tm_year - 100);
100
101 /* Stop RTC while updating the RTC time registers */
102 ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL,
103 TPS65910_RTC_CTRL_STOP_RTC, 0);
104 if (ret < 0) {
105 dev_err(dev, "RTC stop failed with err:%d\n", ret);
106 return ret;
107 }
108
109 /* update all the time registers in one shot */
110 ret = regmap_bulk_write(tps->regmap, TPS65910_SECONDS, rtc_data,
111 NUM_TIME_REGS);
112 if (ret < 0) {
113 dev_err(dev, "rtc_set_time error %d\n", ret);
114 return ret;
115 }
116
117 /* Start back RTC */
118 ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL,
119 TPS65910_RTC_CTRL_STOP_RTC, 1);
120 if (ret < 0)
121 dev_err(dev, "RTC start failed with err:%d\n", ret);
122
123 return ret;
124}
125
126/*
127 * Gets current tps65910 RTC alarm time.
128 */
129static int tps65910_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
130{
131 unsigned char alarm_data[NUM_TIME_REGS];
132 u32 int_val;
133 struct tps65910 *tps = dev_get_drvdata(dev->parent);
134 int ret;
135
136 ret = regmap_bulk_read(tps->regmap, TPS65910_SECONDS, alarm_data,
137 NUM_TIME_REGS);
138 if (ret < 0) {
139 dev_err(dev, "rtc_read_alarm error %d\n", ret);
140 return ret;
141 }
142
143 alm->time.tm_sec = bcd2bin(alarm_data[0]);
144 alm->time.tm_min = bcd2bin(alarm_data[1]);
145 alm->time.tm_hour = bcd2bin(alarm_data[2]);
146 alm->time.tm_mday = bcd2bin(alarm_data[3]);
147 alm->time.tm_mon = bcd2bin(alarm_data[4]) - 1;
148 alm->time.tm_year = bcd2bin(alarm_data[5]) + 100;
149
150 ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS, &int_val);
151 if (ret < 0)
152 return ret;
153
154 if (int_val & TPS65910_RTC_INTERRUPTS_IT_ALARM)
155 alm->enabled = 1;
156
157 return ret;
158}
159
160static int tps65910_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
161{
162 unsigned char alarm_data[NUM_TIME_REGS];
163 struct tps65910 *tps = dev_get_drvdata(dev->parent);
164 int ret;
165
166 ret = tps65910_rtc_alarm_irq_enable(dev, 0);
167 if (ret)
168 return ret;
169
170 alarm_data[0] = bin2bcd(alm->time.tm_sec);
171 alarm_data[1] = bin2bcd(alm->time.tm_min);
172 alarm_data[2] = bin2bcd(alm->time.tm_hour);
173 alarm_data[3] = bin2bcd(alm->time.tm_mday);
174 alarm_data[4] = bin2bcd(alm->time.tm_mon + 1);
175 alarm_data[5] = bin2bcd(alm->time.tm_year - 100);
176
177 /* update all the alarm registers in one shot */
178 ret = regmap_bulk_write(tps->regmap, TPS65910_ALARM_SECONDS,
179 alarm_data, NUM_TIME_REGS);
180 if (ret) {
181 dev_err(dev, "rtc_set_alarm error %d\n", ret);
182 return ret;
183 }
184
185 if (alm->enabled)
186 ret = tps65910_rtc_alarm_irq_enable(dev, 1);
187
188 return ret;
189}
190
191static irqreturn_t tps65910_rtc_interrupt(int irq, void *rtc)
192{
193 struct device *dev = rtc;
194 unsigned long events = 0;
195 struct tps65910 *tps = dev_get_drvdata(dev->parent);
196 struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev);
197 int ret;
198 u32 rtc_reg;
199
200 ret = regmap_read(tps->regmap, TPS65910_RTC_STATUS, &rtc_reg);
201 if (ret)
202 return IRQ_NONE;
203
204 if (rtc_reg & TPS65910_RTC_STATUS_ALARM)
205 events = RTC_IRQF | RTC_AF;
206
207 ret = regmap_write(tps->regmap, TPS65910_RTC_STATUS, rtc_reg);
208 if (ret)
209 return IRQ_NONE;
210
211 /* Notify RTC core on event */
212 rtc_update_irq(tps_rtc->rtc, 1, events);
213
214 return IRQ_HANDLED;
215}
216
217static const struct rtc_class_ops tps65910_rtc_ops = {
218 .read_time = tps65910_rtc_read_time,
219 .set_time = tps65910_rtc_set_time,
220 .read_alarm = tps65910_rtc_read_alarm,
221 .set_alarm = tps65910_rtc_set_alarm,
222 .alarm_irq_enable = tps65910_rtc_alarm_irq_enable,
223};
224
225static int __devinit tps65910_rtc_probe(struct platform_device *pdev)
226{
227 struct tps65910 *tps65910 = NULL;
228 struct tps65910_rtc *tps_rtc = NULL;
229 struct tps65910_board *pmic_plat_data;
230 int ret;
231 int irq;
232 u32 rtc_reg;
233
234 tps65910 = dev_get_drvdata(pdev->dev.parent);
235
236 tps_rtc = devm_kzalloc(&pdev->dev, sizeof(struct tps65910_rtc),
237 GFP_KERNEL);
238 if (!tps_rtc)
239 return -ENOMEM;
240
241 /* Clear pending interrupts */
242 ret = regmap_read(tps65910->regmap, TPS65910_RTC_STATUS, &rtc_reg);
243 if (ret < 0)
244 return ret;
245
246 ret = regmap_write(tps65910->regmap, TPS65910_RTC_STATUS, rtc_reg);
247 if (ret < 0)
248 return ret;
249
250 dev_dbg(&pdev->dev, "Enabling rtc-tps65910.\n");
251 rtc_reg = TPS65910_RTC_CTRL_STOP_RTC;
252 ret = regmap_write(tps65910->regmap, TPS65910_RTC_CTRL, rtc_reg);
253 if (ret < 0)
254 return ret;
255
256 pmic_plat_data = dev_get_platdata(tps65910->dev);
257 irq = pmic_plat_data->irq_base;
258 if (irq <= 0) {
259 dev_warn(&pdev->dev, "Wake up is not possible as irq = %d\n",
260 irq);
261 return ret;
262 }
263
264 irq += TPS65910_IRQ_RTC_ALARM;
265 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
266 tps65910_rtc_interrupt, IRQF_TRIGGER_LOW,
267 "rtc-tps65910", &pdev->dev);
268 if (ret < 0) {
269 dev_err(&pdev->dev, "IRQ is not free.\n");
270 return ret;
271 }
272 device_init_wakeup(&pdev->dev, 1);
273
274 tps_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
275 &tps65910_rtc_ops, THIS_MODULE);
276 if (IS_ERR(tps_rtc->rtc)) {
277 ret = PTR_ERR(tps_rtc->rtc);
278 dev_err(&pdev->dev, "RTC device register: err %d\n", ret);
279 return ret;
280 }
281
282 platform_set_drvdata(pdev, tps_rtc);
283
284 return 0;
285}
286
287/*
288 * Disable tps65910 RTC interrupts.
289 * Sets status flag to free.
290 */
291static int __devexit tps65910_rtc_remove(struct platform_device *pdev)
292{
293 /* leave rtc running, but disable irqs */
294 struct rtc_device *rtc = platform_get_drvdata(pdev);
295
296 tps65910_rtc_alarm_irq_enable(&rtc->dev, 0);
297
298 rtc_device_unregister(rtc);
299 return 0;
300}
301
302#ifdef CONFIG_PM_SLEEP
303
304static int tps65910_rtc_suspend(struct device *dev)
305{
306 struct tps65910 *tps = dev_get_drvdata(dev->parent);
307 u8 alarm = TPS65910_RTC_INTERRUPTS_IT_ALARM;
308 int ret;
309
310 /* Store current list of enabled interrupts*/
311 ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS,
312 &tps->rtc->irqstat);
313 if (ret < 0)
314 return ret;
315
316 /* Enable RTC ALARM interrupt only */
317 return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, alarm);
318}
319
320static int tps65910_rtc_resume(struct device *dev)
321{
322 struct tps65910 *tps = dev_get_drvdata(dev->parent);
323
324 /* Restore list of enabled interrupts before suspend */
325 return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS,
326 tps->rtc->irqstat);
327}
328
329static const struct dev_pm_ops tps65910_rtc_pm_ops = {
330 .suspend = tps65910_rtc_suspend,
331 .resume = tps65910_rtc_resume,
332};
333
334#define DEV_PM_OPS (&tps65910_rtc_pm_ops)
335#else
336#define DEV_PM_OPS NULL
337#endif
338
339static struct platform_driver tps65910_rtc_driver = {
340 .probe = tps65910_rtc_probe,
341 .remove = __devexit_p(tps65910_rtc_remove),
342 .driver = {
343 .owner = THIS_MODULE,
344 .name = "tps65910-rtc",
345 .pm = DEV_PM_OPS,
346 },
347};
348
349module_platform_driver(tps65910_rtc_driver);
350MODULE_ALIAS("platform:rtc-tps65910");
351MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
352MODULE_LICENSE("GPL");