diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-10-28 11:26:12 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-28 11:26:12 -0400 |
commit | 7a9787e1eba95a166265e6a260cf30af04ef0a99 (patch) | |
tree | e730a4565e0318140d2fbd2f0415d18a339d7336 /drivers/rtc/rtc-twl4030.c | |
parent | 41b9eb264c8407655db57b60b4457fe1b2ec9977 (diff) | |
parent | 0173a3265b228da319ceb9c1ec6a5682fd1b2d92 (diff) |
Merge commit 'v2.6.28-rc2' into x86/pci-ioapic-boot-irq-quirks
Diffstat (limited to 'drivers/rtc/rtc-twl4030.c')
-rw-r--r-- | drivers/rtc/rtc-twl4030.c | 564 |
1 files changed, 564 insertions, 0 deletions
diff --git a/drivers/rtc/rtc-twl4030.c b/drivers/rtc/rtc-twl4030.c new file mode 100644 index 000000000000..abe87a4d2665 --- /dev/null +++ b/drivers/rtc/rtc-twl4030.c | |||
@@ -0,0 +1,564 @@ | |||
1 | /* | ||
2 | * rtc-twl4030.c -- TWL4030 Real Time Clock interface | ||
3 | * | ||
4 | * Copyright (C) 2007 MontaVista Software, Inc | ||
5 | * Author: Alexandre Rusev <source@mvista.com> | ||
6 | * | ||
7 | * Based on original TI driver twl4030-rtc.c | ||
8 | * Copyright (C) 2006 Texas Instruments, Inc. | ||
9 | * | ||
10 | * Based on rtc-omap.c | ||
11 | * Copyright (C) 2003 MontaVista Software, Inc. | ||
12 | * Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com> | ||
13 | * Copyright (C) 2006 David Brownell | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * as published by the Free Software Foundation; either version | ||
18 | * 2 of the License, or (at your option) any later version. | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/types.h> | ||
25 | #include <linux/rtc.h> | ||
26 | #include <linux/bcd.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | |||
30 | #include <linux/i2c/twl4030.h> | ||
31 | |||
32 | |||
33 | /* | ||
34 | * RTC block register offsets (use TWL_MODULE_RTC) | ||
35 | */ | ||
36 | #define REG_SECONDS_REG 0x00 | ||
37 | #define REG_MINUTES_REG 0x01 | ||
38 | #define REG_HOURS_REG 0x02 | ||
39 | #define REG_DAYS_REG 0x03 | ||
40 | #define REG_MONTHS_REG 0x04 | ||
41 | #define REG_YEARS_REG 0x05 | ||
42 | #define REG_WEEKS_REG 0x06 | ||
43 | |||
44 | #define REG_ALARM_SECONDS_REG 0x07 | ||
45 | #define REG_ALARM_MINUTES_REG 0x08 | ||
46 | #define REG_ALARM_HOURS_REG 0x09 | ||
47 | #define REG_ALARM_DAYS_REG 0x0A | ||
48 | #define REG_ALARM_MONTHS_REG 0x0B | ||
49 | #define REG_ALARM_YEARS_REG 0x0C | ||
50 | |||
51 | #define REG_RTC_CTRL_REG 0x0D | ||
52 | #define REG_RTC_STATUS_REG 0x0E | ||
53 | #define REG_RTC_INTERRUPTS_REG 0x0F | ||
54 | |||
55 | #define REG_RTC_COMP_LSB_REG 0x10 | ||
56 | #define REG_RTC_COMP_MSB_REG 0x11 | ||
57 | |||
58 | /* RTC_CTRL_REG bitfields */ | ||
59 | #define BIT_RTC_CTRL_REG_STOP_RTC_M 0x01 | ||
60 | #define BIT_RTC_CTRL_REG_ROUND_30S_M 0x02 | ||
61 | #define BIT_RTC_CTRL_REG_AUTO_COMP_M 0x04 | ||
62 | #define BIT_RTC_CTRL_REG_MODE_12_24_M 0x08 | ||
63 | #define BIT_RTC_CTRL_REG_TEST_MODE_M 0x10 | ||
64 | #define BIT_RTC_CTRL_REG_SET_32_COUNTER_M 0x20 | ||
65 | #define BIT_RTC_CTRL_REG_GET_TIME_M 0x40 | ||
66 | |||
67 | /* RTC_STATUS_REG bitfields */ | ||
68 | #define BIT_RTC_STATUS_REG_RUN_M 0x02 | ||
69 | #define BIT_RTC_STATUS_REG_1S_EVENT_M 0x04 | ||
70 | #define BIT_RTC_STATUS_REG_1M_EVENT_M 0x08 | ||
71 | #define BIT_RTC_STATUS_REG_1H_EVENT_M 0x10 | ||
72 | #define BIT_RTC_STATUS_REG_1D_EVENT_M 0x20 | ||
73 | #define BIT_RTC_STATUS_REG_ALARM_M 0x40 | ||
74 | #define BIT_RTC_STATUS_REG_POWER_UP_M 0x80 | ||
75 | |||
76 | /* RTC_INTERRUPTS_REG bitfields */ | ||
77 | #define BIT_RTC_INTERRUPTS_REG_EVERY_M 0x03 | ||
78 | #define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M 0x04 | ||
79 | #define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M 0x08 | ||
80 | |||
81 | |||
82 | /* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */ | ||
83 | #define ALL_TIME_REGS 6 | ||
84 | |||
85 | /*----------------------------------------------------------------------*/ | ||
86 | |||
87 | /* | ||
88 | * Supports 1 byte read from TWL4030 RTC register. | ||
89 | */ | ||
90 | static int twl4030_rtc_read_u8(u8 *data, u8 reg) | ||
91 | { | ||
92 | int ret; | ||
93 | |||
94 | ret = twl4030_i2c_read_u8(TWL4030_MODULE_RTC, data, reg); | ||
95 | if (ret < 0) | ||
96 | pr_err("twl4030_rtc: Could not read TWL4030" | ||
97 | "register %X - error %d\n", reg, ret); | ||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * Supports 1 byte write to TWL4030 RTC registers. | ||
103 | */ | ||
104 | static int twl4030_rtc_write_u8(u8 data, u8 reg) | ||
105 | { | ||
106 | int ret; | ||
107 | |||
108 | ret = twl4030_i2c_write_u8(TWL4030_MODULE_RTC, data, reg); | ||
109 | if (ret < 0) | ||
110 | pr_err("twl4030_rtc: Could not write TWL4030" | ||
111 | "register %X - error %d\n", reg, ret); | ||
112 | return ret; | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * Cache the value for timer/alarm interrupts register; this is | ||
117 | * only changed by callers holding rtc ops lock (or resume). | ||
118 | */ | ||
119 | static unsigned char rtc_irq_bits; | ||
120 | |||
121 | /* | ||
122 | * Enable timer and/or alarm interrupts. | ||
123 | */ | ||
124 | static int set_rtc_irq_bit(unsigned char bit) | ||
125 | { | ||
126 | unsigned char val; | ||
127 | int ret; | ||
128 | |||
129 | val = rtc_irq_bits | bit; | ||
130 | ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); | ||
131 | if (ret == 0) | ||
132 | rtc_irq_bits = val; | ||
133 | |||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * Disable timer and/or alarm interrupts. | ||
139 | */ | ||
140 | static int mask_rtc_irq_bit(unsigned char bit) | ||
141 | { | ||
142 | unsigned char val; | ||
143 | int ret; | ||
144 | |||
145 | val = rtc_irq_bits & ~bit; | ||
146 | ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); | ||
147 | if (ret == 0) | ||
148 | rtc_irq_bits = val; | ||
149 | |||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | static inline int twl4030_rtc_alarm_irq_set_state(int enabled) | ||
154 | { | ||
155 | int ret; | ||
156 | |||
157 | if (enabled) | ||
158 | ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); | ||
159 | else | ||
160 | ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); | ||
161 | |||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | static inline int twl4030_rtc_irq_set_state(int enabled) | ||
166 | { | ||
167 | int ret; | ||
168 | |||
169 | if (enabled) | ||
170 | ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); | ||
171 | else | ||
172 | ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); | ||
173 | |||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * Gets current TWL4030 RTC time and date parameters. | ||
179 | * | ||
180 | * The RTC's time/alarm representation is not what gmtime(3) requires | ||
181 | * Linux to use: | ||
182 | * | ||
183 | * - Months are 1..12 vs Linux 0-11 | ||
184 | * - Years are 0..99 vs Linux 1900..N (we assume 21st century) | ||
185 | */ | ||
186 | static int twl4030_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
187 | { | ||
188 | unsigned char rtc_data[ALL_TIME_REGS + 1]; | ||
189 | int ret; | ||
190 | u8 save_control; | ||
191 | |||
192 | ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); | ||
193 | if (ret < 0) | ||
194 | return ret; | ||
195 | |||
196 | save_control |= BIT_RTC_CTRL_REG_GET_TIME_M; | ||
197 | |||
198 | ret = twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG); | ||
199 | if (ret < 0) | ||
200 | return ret; | ||
201 | |||
202 | ret = twl4030_i2c_read(TWL4030_MODULE_RTC, rtc_data, | ||
203 | REG_SECONDS_REG, ALL_TIME_REGS); | ||
204 | |||
205 | if (ret < 0) { | ||
206 | dev_err(dev, "rtc_read_time error %d\n", ret); | ||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | tm->tm_sec = bcd2bin(rtc_data[0]); | ||
211 | tm->tm_min = bcd2bin(rtc_data[1]); | ||
212 | tm->tm_hour = bcd2bin(rtc_data[2]); | ||
213 | tm->tm_mday = bcd2bin(rtc_data[3]); | ||
214 | tm->tm_mon = bcd2bin(rtc_data[4]) - 1; | ||
215 | tm->tm_year = bcd2bin(rtc_data[5]) + 100; | ||
216 | |||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | static int twl4030_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
221 | { | ||
222 | unsigned char save_control; | ||
223 | unsigned char rtc_data[ALL_TIME_REGS + 1]; | ||
224 | int ret; | ||
225 | |||
226 | rtc_data[1] = bin2bcd(tm->tm_sec); | ||
227 | rtc_data[2] = bin2bcd(tm->tm_min); | ||
228 | rtc_data[3] = bin2bcd(tm->tm_hour); | ||
229 | rtc_data[4] = bin2bcd(tm->tm_mday); | ||
230 | rtc_data[5] = bin2bcd(tm->tm_mon + 1); | ||
231 | rtc_data[6] = bin2bcd(tm->tm_year - 100); | ||
232 | |||
233 | /* Stop RTC while updating the TC registers */ | ||
234 | ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); | ||
235 | if (ret < 0) | ||
236 | goto out; | ||
237 | |||
238 | save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M; | ||
239 | twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG); | ||
240 | if (ret < 0) | ||
241 | goto out; | ||
242 | |||
243 | /* update all the time registers in one shot */ | ||
244 | ret = twl4030_i2c_write(TWL4030_MODULE_RTC, rtc_data, | ||
245 | REG_SECONDS_REG, ALL_TIME_REGS); | ||
246 | if (ret < 0) { | ||
247 | dev_err(dev, "rtc_set_time error %d\n", ret); | ||
248 | goto out; | ||
249 | } | ||
250 | |||
251 | /* Start back RTC */ | ||
252 | save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M; | ||
253 | ret = twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG); | ||
254 | |||
255 | out: | ||
256 | return ret; | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * Gets current TWL4030 RTC alarm time. | ||
261 | */ | ||
262 | static int twl4030_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) | ||
263 | { | ||
264 | unsigned char rtc_data[ALL_TIME_REGS + 1]; | ||
265 | int ret; | ||
266 | |||
267 | ret = twl4030_i2c_read(TWL4030_MODULE_RTC, rtc_data, | ||
268 | REG_ALARM_SECONDS_REG, ALL_TIME_REGS); | ||
269 | if (ret < 0) { | ||
270 | dev_err(dev, "rtc_read_alarm error %d\n", ret); | ||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | /* some of these fields may be wildcard/"match all" */ | ||
275 | alm->time.tm_sec = bcd2bin(rtc_data[0]); | ||
276 | alm->time.tm_min = bcd2bin(rtc_data[1]); | ||
277 | alm->time.tm_hour = bcd2bin(rtc_data[2]); | ||
278 | alm->time.tm_mday = bcd2bin(rtc_data[3]); | ||
279 | alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1; | ||
280 | alm->time.tm_year = bcd2bin(rtc_data[5]) + 100; | ||
281 | |||
282 | /* report cached alarm enable state */ | ||
283 | if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) | ||
284 | alm->enabled = 1; | ||
285 | |||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | static int twl4030_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) | ||
290 | { | ||
291 | unsigned char alarm_data[ALL_TIME_REGS + 1]; | ||
292 | int ret; | ||
293 | |||
294 | ret = twl4030_rtc_alarm_irq_set_state(0); | ||
295 | if (ret) | ||
296 | goto out; | ||
297 | |||
298 | alarm_data[1] = bin2bcd(alm->time.tm_sec); | ||
299 | alarm_data[2] = bin2bcd(alm->time.tm_min); | ||
300 | alarm_data[3] = bin2bcd(alm->time.tm_hour); | ||
301 | alarm_data[4] = bin2bcd(alm->time.tm_mday); | ||
302 | alarm_data[5] = bin2bcd(alm->time.tm_mon + 1); | ||
303 | alarm_data[6] = bin2bcd(alm->time.tm_year - 100); | ||
304 | |||
305 | /* update all the alarm registers in one shot */ | ||
306 | ret = twl4030_i2c_write(TWL4030_MODULE_RTC, alarm_data, | ||
307 | REG_ALARM_SECONDS_REG, ALL_TIME_REGS); | ||
308 | if (ret) { | ||
309 | dev_err(dev, "rtc_set_alarm error %d\n", ret); | ||
310 | goto out; | ||
311 | } | ||
312 | |||
313 | if (alm->enabled) | ||
314 | ret = twl4030_rtc_alarm_irq_set_state(1); | ||
315 | out: | ||
316 | return ret; | ||
317 | } | ||
318 | |||
319 | #ifdef CONFIG_RTC_INTF_DEV | ||
320 | |||
321 | static int twl4030_rtc_ioctl(struct device *dev, unsigned int cmd, | ||
322 | unsigned long arg) | ||
323 | { | ||
324 | switch (cmd) { | ||
325 | case RTC_AIE_OFF: | ||
326 | return twl4030_rtc_alarm_irq_set_state(0); | ||
327 | case RTC_AIE_ON: | ||
328 | return twl4030_rtc_alarm_irq_set_state(1); | ||
329 | case RTC_UIE_OFF: | ||
330 | return twl4030_rtc_irq_set_state(0); | ||
331 | case RTC_UIE_ON: | ||
332 | return twl4030_rtc_irq_set_state(1); | ||
333 | |||
334 | default: | ||
335 | return -ENOIOCTLCMD; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | #else | ||
340 | #define omap_rtc_ioctl NULL | ||
341 | #endif | ||
342 | |||
343 | static irqreturn_t twl4030_rtc_interrupt(int irq, void *rtc) | ||
344 | { | ||
345 | unsigned long events = 0; | ||
346 | int ret = IRQ_NONE; | ||
347 | int res; | ||
348 | u8 rd_reg; | ||
349 | |||
350 | #ifdef CONFIG_LOCKDEP | ||
351 | /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which | ||
352 | * we don't want and can't tolerate. Although it might be | ||
353 | * friendlier not to borrow this thread context... | ||
354 | */ | ||
355 | local_irq_enable(); | ||
356 | #endif | ||
357 | |||
358 | res = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); | ||
359 | if (res) | ||
360 | goto out; | ||
361 | /* | ||
362 | * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG. | ||
363 | * only one (ALARM or RTC) interrupt source may be enabled | ||
364 | * at time, we also could check our results | ||
365 | * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM] | ||
366 | */ | ||
367 | if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M) | ||
368 | events |= RTC_IRQF | RTC_AF; | ||
369 | else | ||
370 | events |= RTC_IRQF | RTC_UF; | ||
371 | |||
372 | res = twl4030_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M, | ||
373 | REG_RTC_STATUS_REG); | ||
374 | if (res) | ||
375 | goto out; | ||
376 | |||
377 | /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1 | ||
378 | * needs 2 reads to clear the interrupt. One read is done in | ||
379 | * do_twl4030_pwrirq(). Doing the second read, to clear | ||
380 | * the bit. | ||
381 | * | ||
382 | * FIXME the reason PWR_ISR1 needs an extra read is that | ||
383 | * RTC_IF retriggered until we cleared REG_ALARM_M above. | ||
384 | * But re-reading like this is a bad hack; by doing so we | ||
385 | * risk wrongly clearing status for some other IRQ (losing | ||
386 | * the interrupt). Be smarter about handling RTC_UF ... | ||
387 | */ | ||
388 | res = twl4030_i2c_read_u8(TWL4030_MODULE_INT, | ||
389 | &rd_reg, TWL4030_INT_PWR_ISR1); | ||
390 | if (res) | ||
391 | goto out; | ||
392 | |||
393 | /* Notify RTC core on event */ | ||
394 | rtc_update_irq(rtc, 1, events); | ||
395 | |||
396 | ret = IRQ_HANDLED; | ||
397 | out: | ||
398 | return ret; | ||
399 | } | ||
400 | |||
401 | static struct rtc_class_ops twl4030_rtc_ops = { | ||
402 | .ioctl = twl4030_rtc_ioctl, | ||
403 | .read_time = twl4030_rtc_read_time, | ||
404 | .set_time = twl4030_rtc_set_time, | ||
405 | .read_alarm = twl4030_rtc_read_alarm, | ||
406 | .set_alarm = twl4030_rtc_set_alarm, | ||
407 | }; | ||
408 | |||
409 | /*----------------------------------------------------------------------*/ | ||
410 | |||
411 | static int __devinit twl4030_rtc_probe(struct platform_device *pdev) | ||
412 | { | ||
413 | struct rtc_device *rtc; | ||
414 | int ret = 0; | ||
415 | int irq = platform_get_irq(pdev, 0); | ||
416 | u8 rd_reg; | ||
417 | |||
418 | if (irq < 0) | ||
419 | return irq; | ||
420 | |||
421 | rtc = rtc_device_register(pdev->name, | ||
422 | &pdev->dev, &twl4030_rtc_ops, THIS_MODULE); | ||
423 | if (IS_ERR(rtc)) { | ||
424 | ret = -EINVAL; | ||
425 | dev_err(&pdev->dev, "can't register RTC device, err %ld\n", | ||
426 | PTR_ERR(rtc)); | ||
427 | goto out0; | ||
428 | |||
429 | } | ||
430 | |||
431 | platform_set_drvdata(pdev, rtc); | ||
432 | |||
433 | ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); | ||
434 | |||
435 | if (ret < 0) | ||
436 | goto out1; | ||
437 | |||
438 | if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M) | ||
439 | dev_warn(&pdev->dev, "Power up reset detected.\n"); | ||
440 | |||
441 | if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M) | ||
442 | dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n"); | ||
443 | |||
444 | /* Clear RTC Power up reset and pending alarm interrupts */ | ||
445 | ret = twl4030_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG); | ||
446 | if (ret < 0) | ||
447 | goto out1; | ||
448 | |||
449 | ret = request_irq(irq, twl4030_rtc_interrupt, | ||
450 | IRQF_TRIGGER_RISING, | ||
451 | rtc->dev.bus_id, rtc); | ||
452 | if (ret < 0) { | ||
453 | dev_err(&pdev->dev, "IRQ is not free.\n"); | ||
454 | goto out1; | ||
455 | } | ||
456 | |||
457 | /* Check RTC module status, Enable if it is off */ | ||
458 | ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG); | ||
459 | if (ret < 0) | ||
460 | goto out2; | ||
461 | |||
462 | if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) { | ||
463 | dev_info(&pdev->dev, "Enabling TWL4030-RTC.\n"); | ||
464 | rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M; | ||
465 | ret = twl4030_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG); | ||
466 | if (ret < 0) | ||
467 | goto out2; | ||
468 | } | ||
469 | |||
470 | /* init cached IRQ enable bits */ | ||
471 | ret = twl4030_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG); | ||
472 | if (ret < 0) | ||
473 | goto out2; | ||
474 | |||
475 | return ret; | ||
476 | |||
477 | |||
478 | out2: | ||
479 | free_irq(irq, rtc); | ||
480 | out1: | ||
481 | rtc_device_unregister(rtc); | ||
482 | out0: | ||
483 | return ret; | ||
484 | } | ||
485 | |||
486 | /* | ||
487 | * Disable all TWL4030 RTC module interrupts. | ||
488 | * Sets status flag to free. | ||
489 | */ | ||
490 | static int __devexit twl4030_rtc_remove(struct platform_device *pdev) | ||
491 | { | ||
492 | /* leave rtc running, but disable irqs */ | ||
493 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
494 | int irq = platform_get_irq(pdev, 0); | ||
495 | |||
496 | mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); | ||
497 | mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); | ||
498 | |||
499 | free_irq(irq, rtc); | ||
500 | |||
501 | rtc_device_unregister(rtc); | ||
502 | platform_set_drvdata(pdev, NULL); | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | static void twl4030_rtc_shutdown(struct platform_device *pdev) | ||
507 | { | ||
508 | mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M | | ||
509 | BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); | ||
510 | } | ||
511 | |||
512 | #ifdef CONFIG_PM | ||
513 | |||
514 | static unsigned char irqstat; | ||
515 | |||
516 | static int twl4030_rtc_suspend(struct platform_device *pdev, pm_message_t state) | ||
517 | { | ||
518 | irqstat = rtc_irq_bits; | ||
519 | |||
520 | /* REVISIT alarm may need to wake us from sleep */ | ||
521 | mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M | | ||
522 | BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); | ||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | static int twl4030_rtc_resume(struct platform_device *pdev) | ||
527 | { | ||
528 | set_rtc_irq_bit(irqstat); | ||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | #else | ||
533 | #define twl4030_rtc_suspend NULL | ||
534 | #define twl4030_rtc_resume NULL | ||
535 | #endif | ||
536 | |||
537 | MODULE_ALIAS("platform:twl4030_rtc"); | ||
538 | |||
539 | static struct platform_driver twl4030rtc_driver = { | ||
540 | .probe = twl4030_rtc_probe, | ||
541 | .remove = __devexit_p(twl4030_rtc_remove), | ||
542 | .shutdown = twl4030_rtc_shutdown, | ||
543 | .suspend = twl4030_rtc_suspend, | ||
544 | .resume = twl4030_rtc_resume, | ||
545 | .driver = { | ||
546 | .owner = THIS_MODULE, | ||
547 | .name = "twl4030_rtc", | ||
548 | }, | ||
549 | }; | ||
550 | |||
551 | static int __init twl4030_rtc_init(void) | ||
552 | { | ||
553 | return platform_driver_register(&twl4030rtc_driver); | ||
554 | } | ||
555 | module_init(twl4030_rtc_init); | ||
556 | |||
557 | static void __exit twl4030_rtc_exit(void) | ||
558 | { | ||
559 | platform_driver_unregister(&twl4030rtc_driver); | ||
560 | } | ||
561 | module_exit(twl4030_rtc_exit); | ||
562 | |||
563 | MODULE_AUTHOR("Texas Instruments, MontaVista Software"); | ||
564 | MODULE_LICENSE("GPL"); | ||