diff options
author | Dave Kleikamp <shaggy@linux.vnet.ibm.com> | 2009-02-02 14:40:55 -0500 |
---|---|---|
committer | Dave Kleikamp <shaggy@linux.vnet.ibm.com> | 2009-02-02 14:40:55 -0500 |
commit | 8db0c5d5ef3ab99fe9e5151872b75f45c4282e3c (patch) | |
tree | da9759151e00221c58cdd9f4de893c0b08753670 /drivers/rtc | |
parent | 1ad53a98c927a9b5b1b57288ac0edec562fbcf8d (diff) | |
parent | 45c82b5a770be66845687a7d027c8b52946d59af (diff) |
Merge branch 'master' of /home/shaggy/git/linus-clean/
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 7 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-parisc.c | 3 | ||||
-rw-r--r-- | drivers/rtc/rtc-pcf50633.c | 344 | ||||
-rw-r--r-- | drivers/rtc/rtc-pxa.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-twl4030.c | 49 |
6 files changed, 369 insertions, 37 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 4ad831de41ad..cced4d108319 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -502,6 +502,13 @@ config RTC_DRV_WM8350 | |||
502 | This driver can also be built as a module. If so, the module | 502 | This driver can also be built as a module. If so, the module |
503 | will be called "rtc-wm8350". | 503 | will be called "rtc-wm8350". |
504 | 504 | ||
505 | config RTC_DRV_PCF50633 | ||
506 | depends on MFD_PCF50633 | ||
507 | tristate "NXP PCF50633 RTC" | ||
508 | help | ||
509 | If you say yes here you get support for the RTC subsystem of the | ||
510 | NXP PCF50633 used in embedded systems. | ||
511 | |||
505 | comment "on-CPU RTC drivers" | 512 | comment "on-CPU RTC drivers" |
506 | 513 | ||
507 | config RTC_DRV_OMAP | 514 | config RTC_DRV_OMAP |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 9a4340d48f26..6e28021abb9d 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -74,3 +74,4 @@ obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o | |||
74 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o | 74 | obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o |
75 | obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o | 75 | obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o |
76 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o | 76 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o |
77 | obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o | ||
diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c index 346d633655e7..c6bfa6fe1a2a 100644 --- a/drivers/rtc/rtc-parisc.c +++ b/drivers/rtc/rtc-parisc.c | |||
@@ -34,7 +34,8 @@ static int parisc_get_time(struct device *dev, struct rtc_time *tm) | |||
34 | static int parisc_set_time(struct device *dev, struct rtc_time *tm) | 34 | static int parisc_set_time(struct device *dev, struct rtc_time *tm) |
35 | { | 35 | { |
36 | struct parisc_rtc *p = dev_get_drvdata(dev); | 36 | struct parisc_rtc *p = dev_get_drvdata(dev); |
37 | unsigned long flags, ret; | 37 | unsigned long flags; |
38 | int ret; | ||
38 | 39 | ||
39 | spin_lock_irqsave(&p->lock, flags); | 40 | spin_lock_irqsave(&p->lock, flags); |
40 | ret = set_rtc_time(tm); | 41 | ret = set_rtc_time(tm); |
diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c new file mode 100644 index 000000000000..f4dd87e29075 --- /dev/null +++ b/drivers/rtc/rtc-pcf50633.c | |||
@@ -0,0 +1,344 @@ | |||
1 | /* NXP PCF50633 RTC Driver | ||
2 | * | ||
3 | * (C) 2006-2008 by Openmoko, Inc. | ||
4 | * Author: Balaji Rao <balajirrao@openmoko.org> | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Broken down from monstrous PCF50633 driver mainly by | ||
8 | * Harald Welte, Andy Green and Werner Almesberger | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/rtc.h> | ||
23 | #include <linux/bcd.h> | ||
24 | #include <linux/err.h> | ||
25 | |||
26 | #include <linux/mfd/pcf50633/core.h> | ||
27 | |||
28 | #define PCF50633_REG_RTCSC 0x59 /* Second */ | ||
29 | #define PCF50633_REG_RTCMN 0x5a /* Minute */ | ||
30 | #define PCF50633_REG_RTCHR 0x5b /* Hour */ | ||
31 | #define PCF50633_REG_RTCWD 0x5c /* Weekday */ | ||
32 | #define PCF50633_REG_RTCDT 0x5d /* Day */ | ||
33 | #define PCF50633_REG_RTCMT 0x5e /* Month */ | ||
34 | #define PCF50633_REG_RTCYR 0x5f /* Year */ | ||
35 | #define PCF50633_REG_RTCSCA 0x60 /* Alarm Second */ | ||
36 | #define PCF50633_REG_RTCMNA 0x61 /* Alarm Minute */ | ||
37 | #define PCF50633_REG_RTCHRA 0x62 /* Alarm Hour */ | ||
38 | #define PCF50633_REG_RTCWDA 0x63 /* Alarm Weekday */ | ||
39 | #define PCF50633_REG_RTCDTA 0x64 /* Alarm Day */ | ||
40 | #define PCF50633_REG_RTCMTA 0x65 /* Alarm Month */ | ||
41 | #define PCF50633_REG_RTCYRA 0x66 /* Alarm Year */ | ||
42 | |||
43 | enum pcf50633_time_indexes { | ||
44 | PCF50633_TI_SEC, | ||
45 | PCF50633_TI_MIN, | ||
46 | PCF50633_TI_HOUR, | ||
47 | PCF50633_TI_WKDAY, | ||
48 | PCF50633_TI_DAY, | ||
49 | PCF50633_TI_MONTH, | ||
50 | PCF50633_TI_YEAR, | ||
51 | PCF50633_TI_EXTENT /* always last */ | ||
52 | }; | ||
53 | |||
54 | struct pcf50633_time { | ||
55 | u_int8_t time[PCF50633_TI_EXTENT]; | ||
56 | }; | ||
57 | |||
58 | struct pcf50633_rtc { | ||
59 | int alarm_enabled; | ||
60 | int second_enabled; | ||
61 | |||
62 | struct pcf50633 *pcf; | ||
63 | struct rtc_device *rtc_dev; | ||
64 | }; | ||
65 | |||
66 | static void pcf2rtc_time(struct rtc_time *rtc, struct pcf50633_time *pcf) | ||
67 | { | ||
68 | rtc->tm_sec = bcd2bin(pcf->time[PCF50633_TI_SEC]); | ||
69 | rtc->tm_min = bcd2bin(pcf->time[PCF50633_TI_MIN]); | ||
70 | rtc->tm_hour = bcd2bin(pcf->time[PCF50633_TI_HOUR]); | ||
71 | rtc->tm_wday = bcd2bin(pcf->time[PCF50633_TI_WKDAY]); | ||
72 | rtc->tm_mday = bcd2bin(pcf->time[PCF50633_TI_DAY]); | ||
73 | rtc->tm_mon = bcd2bin(pcf->time[PCF50633_TI_MONTH]); | ||
74 | rtc->tm_year = bcd2bin(pcf->time[PCF50633_TI_YEAR]) + 100; | ||
75 | } | ||
76 | |||
77 | static void rtc2pcf_time(struct pcf50633_time *pcf, struct rtc_time *rtc) | ||
78 | { | ||
79 | pcf->time[PCF50633_TI_SEC] = bin2bcd(rtc->tm_sec); | ||
80 | pcf->time[PCF50633_TI_MIN] = bin2bcd(rtc->tm_min); | ||
81 | pcf->time[PCF50633_TI_HOUR] = bin2bcd(rtc->tm_hour); | ||
82 | pcf->time[PCF50633_TI_WKDAY] = bin2bcd(rtc->tm_wday); | ||
83 | pcf->time[PCF50633_TI_DAY] = bin2bcd(rtc->tm_mday); | ||
84 | pcf->time[PCF50633_TI_MONTH] = bin2bcd(rtc->tm_mon); | ||
85 | pcf->time[PCF50633_TI_YEAR] = bin2bcd(rtc->tm_year % 100); | ||
86 | } | ||
87 | |||
88 | static int | ||
89 | pcf50633_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) | ||
90 | { | ||
91 | struct pcf50633_rtc *rtc = dev_get_drvdata(dev); | ||
92 | int err; | ||
93 | |||
94 | if (enabled) | ||
95 | err = pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); | ||
96 | else | ||
97 | err = pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM); | ||
98 | |||
99 | if (err < 0) | ||
100 | return err; | ||
101 | |||
102 | rtc->alarm_enabled = enabled; | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int | ||
108 | pcf50633_rtc_update_irq_enable(struct device *dev, unsigned int enabled) | ||
109 | { | ||
110 | struct pcf50633_rtc *rtc = dev_get_drvdata(dev); | ||
111 | int err; | ||
112 | |||
113 | if (enabled) | ||
114 | err = pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_SECOND); | ||
115 | else | ||
116 | err = pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_SECOND); | ||
117 | |||
118 | if (err < 0) | ||
119 | return err; | ||
120 | |||
121 | rtc->second_enabled = enabled; | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int pcf50633_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
127 | { | ||
128 | struct pcf50633_rtc *rtc; | ||
129 | struct pcf50633_time pcf_tm; | ||
130 | int ret; | ||
131 | |||
132 | rtc = dev_get_drvdata(dev); | ||
133 | |||
134 | ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSC, | ||
135 | PCF50633_TI_EXTENT, | ||
136 | &pcf_tm.time[0]); | ||
137 | if (ret != PCF50633_TI_EXTENT) { | ||
138 | dev_err(dev, "Failed to read time\n"); | ||
139 | return -EIO; | ||
140 | } | ||
141 | |||
142 | dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n", | ||
143 | pcf_tm.time[PCF50633_TI_DAY], | ||
144 | pcf_tm.time[PCF50633_TI_MONTH], | ||
145 | pcf_tm.time[PCF50633_TI_YEAR], | ||
146 | pcf_tm.time[PCF50633_TI_HOUR], | ||
147 | pcf_tm.time[PCF50633_TI_MIN], | ||
148 | pcf_tm.time[PCF50633_TI_SEC]); | ||
149 | |||
150 | pcf2rtc_time(tm, &pcf_tm); | ||
151 | |||
152 | dev_dbg(dev, "RTC_TIME: %u.%u.%u %u:%u:%u\n", | ||
153 | tm->tm_mday, tm->tm_mon, tm->tm_year, | ||
154 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
155 | |||
156 | return rtc_valid_tm(tm); | ||
157 | } | ||
158 | |||
159 | static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
160 | { | ||
161 | struct pcf50633_rtc *rtc; | ||
162 | struct pcf50633_time pcf_tm; | ||
163 | int second_masked, alarm_masked, ret = 0; | ||
164 | |||
165 | rtc = dev_get_drvdata(dev); | ||
166 | |||
167 | dev_dbg(dev, "RTC_TIME: %u.%u.%u %u:%u:%u\n", | ||
168 | tm->tm_mday, tm->tm_mon, tm->tm_year, | ||
169 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
170 | |||
171 | rtc2pcf_time(&pcf_tm, tm); | ||
172 | |||
173 | dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n", | ||
174 | pcf_tm.time[PCF50633_TI_DAY], | ||
175 | pcf_tm.time[PCF50633_TI_MONTH], | ||
176 | pcf_tm.time[PCF50633_TI_YEAR], | ||
177 | pcf_tm.time[PCF50633_TI_HOUR], | ||
178 | pcf_tm.time[PCF50633_TI_MIN], | ||
179 | pcf_tm.time[PCF50633_TI_SEC]); | ||
180 | |||
181 | |||
182 | second_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_SECOND); | ||
183 | alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM); | ||
184 | |||
185 | if (!second_masked) | ||
186 | pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_SECOND); | ||
187 | if (!alarm_masked) | ||
188 | pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM); | ||
189 | |||
190 | /* Returns 0 on success */ | ||
191 | ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSC, | ||
192 | PCF50633_TI_EXTENT, | ||
193 | &pcf_tm.time[0]); | ||
194 | |||
195 | if (!second_masked) | ||
196 | pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_SECOND); | ||
197 | if (!alarm_masked) | ||
198 | pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); | ||
199 | |||
200 | return ret; | ||
201 | } | ||
202 | |||
203 | static int pcf50633_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
204 | { | ||
205 | struct pcf50633_rtc *rtc; | ||
206 | struct pcf50633_time pcf_tm; | ||
207 | int ret = 0; | ||
208 | |||
209 | rtc = dev_get_drvdata(dev); | ||
210 | |||
211 | alrm->enabled = rtc->alarm_enabled; | ||
212 | |||
213 | ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA, | ||
214 | PCF50633_TI_EXTENT, &pcf_tm.time[0]); | ||
215 | if (ret != PCF50633_TI_EXTENT) { | ||
216 | dev_err(dev, "Failed to read time\n"); | ||
217 | return -EIO; | ||
218 | } | ||
219 | |||
220 | pcf2rtc_time(&alrm->time, &pcf_tm); | ||
221 | |||
222 | return rtc_valid_tm(&alrm->time); | ||
223 | } | ||
224 | |||
225 | static int pcf50633_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
226 | { | ||
227 | struct pcf50633_rtc *rtc; | ||
228 | struct pcf50633_time pcf_tm; | ||
229 | int alarm_masked, ret = 0; | ||
230 | |||
231 | rtc = dev_get_drvdata(dev); | ||
232 | |||
233 | rtc2pcf_time(&pcf_tm, &alrm->time); | ||
234 | |||
235 | /* do like mktime does and ignore tm_wday */ | ||
236 | pcf_tm.time[PCF50633_TI_WKDAY] = 7; | ||
237 | |||
238 | alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM); | ||
239 | |||
240 | /* disable alarm interrupt */ | ||
241 | if (!alarm_masked) | ||
242 | pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM); | ||
243 | |||
244 | /* Returns 0 on success */ | ||
245 | ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSCA, | ||
246 | PCF50633_TI_EXTENT, &pcf_tm.time[0]); | ||
247 | |||
248 | if (!alarm_masked) | ||
249 | pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); | ||
250 | |||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | static struct rtc_class_ops pcf50633_rtc_ops = { | ||
255 | .read_time = pcf50633_rtc_read_time, | ||
256 | .set_time = pcf50633_rtc_set_time, | ||
257 | .read_alarm = pcf50633_rtc_read_alarm, | ||
258 | .set_alarm = pcf50633_rtc_set_alarm, | ||
259 | .alarm_irq_enable = pcf50633_rtc_alarm_irq_enable, | ||
260 | .update_irq_enable = pcf50633_rtc_update_irq_enable, | ||
261 | }; | ||
262 | |||
263 | static void pcf50633_rtc_irq(int irq, void *data) | ||
264 | { | ||
265 | struct pcf50633_rtc *rtc = data; | ||
266 | |||
267 | switch (irq) { | ||
268 | case PCF50633_IRQ_ALARM: | ||
269 | rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); | ||
270 | break; | ||
271 | case PCF50633_IRQ_SECOND: | ||
272 | rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); | ||
273 | break; | ||
274 | } | ||
275 | } | ||
276 | |||
277 | static int __devinit pcf50633_rtc_probe(struct platform_device *pdev) | ||
278 | { | ||
279 | struct pcf50633_subdev_pdata *pdata; | ||
280 | struct pcf50633_rtc *rtc; | ||
281 | |||
282 | |||
283 | rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); | ||
284 | if (!rtc) | ||
285 | return -ENOMEM; | ||
286 | |||
287 | pdata = pdev->dev.platform_data; | ||
288 | rtc->pcf = pdata->pcf; | ||
289 | platform_set_drvdata(pdev, rtc); | ||
290 | rtc->rtc_dev = rtc_device_register("pcf50633-rtc", &pdev->dev, | ||
291 | &pcf50633_rtc_ops, THIS_MODULE); | ||
292 | |||
293 | if (IS_ERR(rtc->rtc_dev)) { | ||
294 | kfree(rtc); | ||
295 | return PTR_ERR(rtc->rtc_dev); | ||
296 | } | ||
297 | |||
298 | pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM, | ||
299 | pcf50633_rtc_irq, rtc); | ||
300 | pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_SECOND, | ||
301 | pcf50633_rtc_irq, rtc); | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int __devexit pcf50633_rtc_remove(struct platform_device *pdev) | ||
307 | { | ||
308 | struct pcf50633_rtc *rtc; | ||
309 | |||
310 | rtc = platform_get_drvdata(pdev); | ||
311 | |||
312 | pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_ALARM); | ||
313 | pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_SECOND); | ||
314 | |||
315 | rtc_device_unregister(rtc->rtc_dev); | ||
316 | kfree(rtc); | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static struct platform_driver pcf50633_rtc_driver = { | ||
322 | .driver = { | ||
323 | .name = "pcf50633-rtc", | ||
324 | }, | ||
325 | .probe = pcf50633_rtc_probe, | ||
326 | .remove = __devexit_p(pcf50633_rtc_remove), | ||
327 | }; | ||
328 | |||
329 | static int __init pcf50633_rtc_init(void) | ||
330 | { | ||
331 | return platform_driver_register(&pcf50633_rtc_driver); | ||
332 | } | ||
333 | module_init(pcf50633_rtc_init); | ||
334 | |||
335 | static void __exit pcf50633_rtc_exit(void) | ||
336 | { | ||
337 | platform_driver_unregister(&pcf50633_rtc_driver); | ||
338 | } | ||
339 | module_exit(pcf50633_rtc_exit); | ||
340 | |||
341 | MODULE_DESCRIPTION("PCF50633 RTC driver"); | ||
342 | MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); | ||
343 | MODULE_LICENSE("GPL"); | ||
344 | |||
diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index cc7eb8767b82..bd56a033bfd0 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
28 | #include <linux/io.h> | 28 | #include <linux/io.h> |
29 | 29 | ||
30 | #include <mach/hardware.h> | ||
31 | |||
30 | #define TIMER_FREQ CLOCK_TICK_RATE | 32 | #define TIMER_FREQ CLOCK_TICK_RATE |
31 | #define RTC_DEF_DIVIDER (32768 - 1) | 33 | #define RTC_DEF_DIVIDER (32768 - 1) |
32 | #define RTC_DEF_TRIM 0 | 34 | #define RTC_DEF_TRIM 0 |
diff --git a/drivers/rtc/rtc-twl4030.c b/drivers/rtc/rtc-twl4030.c index 8ce5f74ee45b..ad35f76c46b7 100644 --- a/drivers/rtc/rtc-twl4030.c +++ b/drivers/rtc/rtc-twl4030.c | |||
@@ -120,7 +120,7 @@ static int twl4030_rtc_write_u8(u8 data, u8 reg) | |||
120 | static unsigned char rtc_irq_bits; | 120 | static unsigned char rtc_irq_bits; |
121 | 121 | ||
122 | /* | 122 | /* |
123 | * Enable timer and/or alarm interrupts. | 123 | * Enable 1/second update and/or alarm interrupts. |
124 | */ | 124 | */ |
125 | static int set_rtc_irq_bit(unsigned char bit) | 125 | static int set_rtc_irq_bit(unsigned char bit) |
126 | { | 126 | { |
@@ -128,6 +128,7 @@ static int set_rtc_irq_bit(unsigned char bit) | |||
128 | int ret; | 128 | int ret; |
129 | 129 | ||
130 | val = rtc_irq_bits | bit; | 130 | val = rtc_irq_bits | bit; |
131 | val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M; | ||
131 | ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); | 132 | ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); |
132 | if (ret == 0) | 133 | if (ret == 0) |
133 | rtc_irq_bits = val; | 134 | rtc_irq_bits = val; |
@@ -136,7 +137,7 @@ static int set_rtc_irq_bit(unsigned char bit) | |||
136 | } | 137 | } |
137 | 138 | ||
138 | /* | 139 | /* |
139 | * Disable timer and/or alarm interrupts. | 140 | * Disable update and/or alarm interrupts. |
140 | */ | 141 | */ |
141 | static int mask_rtc_irq_bit(unsigned char bit) | 142 | static int mask_rtc_irq_bit(unsigned char bit) |
142 | { | 143 | { |
@@ -151,7 +152,7 @@ static int mask_rtc_irq_bit(unsigned char bit) | |||
151 | return ret; | 152 | return ret; |
152 | } | 153 | } |
153 | 154 | ||
154 | static inline int twl4030_rtc_alarm_irq_set_state(int enabled) | 155 | static int twl4030_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) |
155 | { | 156 | { |
156 | int ret; | 157 | int ret; |
157 | 158 | ||
@@ -163,7 +164,7 @@ static inline int twl4030_rtc_alarm_irq_set_state(int enabled) | |||
163 | return ret; | 164 | return ret; |
164 | } | 165 | } |
165 | 166 | ||
166 | static inline int twl4030_rtc_irq_set_state(int enabled) | 167 | static int twl4030_rtc_update_irq_enable(struct device *dev, unsigned enabled) |
167 | { | 168 | { |
168 | int ret; | 169 | int ret; |
169 | 170 | ||
@@ -292,7 +293,7 @@ static int twl4030_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) | |||
292 | unsigned char alarm_data[ALL_TIME_REGS + 1]; | 293 | unsigned char alarm_data[ALL_TIME_REGS + 1]; |
293 | int ret; | 294 | int ret; |
294 | 295 | ||
295 | ret = twl4030_rtc_alarm_irq_set_state(0); | 296 | ret = twl4030_rtc_alarm_irq_enable(dev, 0); |
296 | if (ret) | 297 | if (ret) |
297 | goto out; | 298 | goto out; |
298 | 299 | ||
@@ -312,35 +313,11 @@ static int twl4030_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) | |||
312 | } | 313 | } |
313 | 314 | ||
314 | if (alm->enabled) | 315 | if (alm->enabled) |
315 | ret = twl4030_rtc_alarm_irq_set_state(1); | 316 | ret = twl4030_rtc_alarm_irq_enable(dev, 1); |
316 | out: | 317 | out: |
317 | return ret; | 318 | return ret; |
318 | } | 319 | } |
319 | 320 | ||
320 | #ifdef CONFIG_RTC_INTF_DEV | ||
321 | |||
322 | static int twl4030_rtc_ioctl(struct device *dev, unsigned int cmd, | ||
323 | unsigned long arg) | ||
324 | { | ||
325 | switch (cmd) { | ||
326 | case RTC_AIE_OFF: | ||
327 | return twl4030_rtc_alarm_irq_set_state(0); | ||
328 | case RTC_AIE_ON: | ||
329 | return twl4030_rtc_alarm_irq_set_state(1); | ||
330 | case RTC_UIE_OFF: | ||
331 | return twl4030_rtc_irq_set_state(0); | ||
332 | case RTC_UIE_ON: | ||
333 | return twl4030_rtc_irq_set_state(1); | ||
334 | |||
335 | default: | ||
336 | return -ENOIOCTLCMD; | ||
337 | } | ||
338 | } | ||
339 | |||
340 | #else | ||
341 | #define twl4030_rtc_ioctl NULL | ||
342 | #endif | ||
343 | |||
344 | static irqreturn_t twl4030_rtc_interrupt(int irq, void *rtc) | 321 | static irqreturn_t twl4030_rtc_interrupt(int irq, void *rtc) |
345 | { | 322 | { |
346 | unsigned long events = 0; | 323 | unsigned long events = 0; |
@@ -400,11 +377,12 @@ out: | |||
400 | } | 377 | } |
401 | 378 | ||
402 | static struct rtc_class_ops twl4030_rtc_ops = { | 379 | static struct rtc_class_ops twl4030_rtc_ops = { |
403 | .ioctl = twl4030_rtc_ioctl, | ||
404 | .read_time = twl4030_rtc_read_time, | 380 | .read_time = twl4030_rtc_read_time, |
405 | .set_time = twl4030_rtc_set_time, | 381 | .set_time = twl4030_rtc_set_time, |
406 | .read_alarm = twl4030_rtc_read_alarm, | 382 | .read_alarm = twl4030_rtc_read_alarm, |
407 | .set_alarm = twl4030_rtc_set_alarm, | 383 | .set_alarm = twl4030_rtc_set_alarm, |
384 | .alarm_irq_enable = twl4030_rtc_alarm_irq_enable, | ||
385 | .update_irq_enable = twl4030_rtc_update_irq_enable, | ||
408 | }; | 386 | }; |
409 | 387 | ||
410 | /*----------------------------------------------------------------------*/ | 388 | /*----------------------------------------------------------------------*/ |
@@ -422,7 +400,7 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev) | |||
422 | rtc = rtc_device_register(pdev->name, | 400 | rtc = rtc_device_register(pdev->name, |
423 | &pdev->dev, &twl4030_rtc_ops, THIS_MODULE); | 401 | &pdev->dev, &twl4030_rtc_ops, THIS_MODULE); |
424 | if (IS_ERR(rtc)) { | 402 | if (IS_ERR(rtc)) { |
425 | ret = -EINVAL; | 403 | ret = PTR_ERR(rtc); |
426 | dev_err(&pdev->dev, "can't register RTC device, err %ld\n", | 404 | dev_err(&pdev->dev, "can't register RTC device, err %ld\n", |
427 | PTR_ERR(rtc)); | 405 | PTR_ERR(rtc)); |
428 | goto out0; | 406 | goto out0; |
@@ -432,7 +410,6 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev) | |||
432 | platform_set_drvdata(pdev, rtc); | 410 | platform_set_drvdata(pdev, rtc); |
433 | 411 | ||
434 | ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); | 412 | ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); |
435 | |||
436 | if (ret < 0) | 413 | if (ret < 0) |
437 | goto out1; | 414 | goto out1; |
438 | 415 | ||
@@ -475,7 +452,6 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev) | |||
475 | 452 | ||
476 | return ret; | 453 | return ret; |
477 | 454 | ||
478 | |||
479 | out2: | 455 | out2: |
480 | free_irq(irq, rtc); | 456 | free_irq(irq, rtc); |
481 | out1: | 457 | out1: |
@@ -506,8 +482,9 @@ static int __devexit twl4030_rtc_remove(struct platform_device *pdev) | |||
506 | 482 | ||
507 | static void twl4030_rtc_shutdown(struct platform_device *pdev) | 483 | static void twl4030_rtc_shutdown(struct platform_device *pdev) |
508 | { | 484 | { |
509 | mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M | | 485 | /* mask timer interrupts, but leave alarm interrupts on to enable |
510 | BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); | 486 | power-on when alarm is triggered */ |
487 | mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); | ||
511 | } | 488 | } |
512 | 489 | ||
513 | #ifdef CONFIG_PM | 490 | #ifdef CONFIG_PM |