diff options
author | Haavard Skinnemoen <haavard.skinnemoen@atmel.com> | 2009-03-27 11:14:38 -0400 |
---|---|---|
committer | Haavard Skinnemoen <haavard.skinnemoen@atmel.com> | 2009-03-27 11:14:38 -0400 |
commit | b92efa9abffc4a634cd2e7a0f81f8aa6310d67c9 (patch) | |
tree | 9847508d9b8d4e585f90db4a453bfbc3700c997e /drivers/rtc | |
parent | a16fffdd8eb95ebab7dc22414896fe6493951e0e (diff) | |
parent | be0ea69674ed95e1e98cb3687a241badc756d228 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into avr32-arch
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 6 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-at91sam9.c | 4 | ||||
-rw-r--r-- | drivers/rtc/rtc-au1xxx.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-dm355evm.c | 175 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1390.c | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-omap.c | 4 | ||||
-rw-r--r-- | drivers/rtc/rtc-pxa.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-sh.c | 246 | ||||
-rw-r--r-- | drivers/rtc/rtc-twl4030.c | 2 |
10 files changed, 348 insertions, 95 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index cced4d108319..81450fbd8b12 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -241,6 +241,12 @@ config RTC_DRV_M41T80_WDT | |||
241 | If you say Y here you will get support for the | 241 | If you say Y here you will get support for the |
242 | watchdog timer in the ST M41T60 and M41T80 RTC chips series. | 242 | watchdog timer in the ST M41T60 and M41T80 RTC chips series. |
243 | 243 | ||
244 | config RTC_DRV_DM355EVM | ||
245 | tristate "TI DaVinci DM355 EVM RTC" | ||
246 | depends on MFD_DM355EVM_MSP | ||
247 | help | ||
248 | Supports the RTC firmware in the MSP430 on the DM355 EVM. | ||
249 | |||
244 | config RTC_DRV_TWL92330 | 250 | config RTC_DRV_TWL92330 |
245 | boolean "TI TWL92330/Menelaus" | 251 | boolean "TI TWL92330/Menelaus" |
246 | depends on MENELAUS | 252 | depends on MENELAUS |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 6e28021abb9d..0e697aa51caa 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -23,6 +23,7 @@ obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o | |||
23 | obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o | 23 | obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o |
24 | obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o | 24 | obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o |
25 | obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o | 25 | obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o |
26 | obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o | ||
26 | obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o | 27 | obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o |
27 | obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o | 28 | obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o |
28 | obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o | 29 | obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o |
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index d5e4e637ddec..86c61f143515 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c | |||
@@ -351,7 +351,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) | |||
351 | /* register irq handler after we know what name we'll use */ | 351 | /* register irq handler after we know what name we'll use */ |
352 | ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt, | 352 | ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt, |
353 | IRQF_DISABLED | IRQF_SHARED, | 353 | IRQF_DISABLED | IRQF_SHARED, |
354 | rtc->rtcdev->dev.bus_id, rtc); | 354 | dev_name(&rtc->rtcdev->dev), rtc); |
355 | if (ret) { | 355 | if (ret) { |
356 | dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS); | 356 | dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS); |
357 | rtc_device_unregister(rtc->rtcdev); | 357 | rtc_device_unregister(rtc->rtcdev); |
@@ -366,7 +366,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) | |||
366 | 366 | ||
367 | if (gpbr_readl(rtc) == 0) | 367 | if (gpbr_readl(rtc) == 0) |
368 | dev_warn(&pdev->dev, "%s: SET TIME!\n", | 368 | dev_warn(&pdev->dev, "%s: SET TIME!\n", |
369 | rtc->rtcdev->dev.bus_id); | 369 | dev_name(&rtc->rtcdev->dev)); |
370 | 370 | ||
371 | return 0; | 371 | return 0; |
372 | 372 | ||
diff --git a/drivers/rtc/rtc-au1xxx.c b/drivers/rtc/rtc-au1xxx.c index 8906a688e6a6..979ed0406ce9 100644 --- a/drivers/rtc/rtc-au1xxx.c +++ b/drivers/rtc/rtc-au1xxx.c | |||
@@ -81,7 +81,7 @@ static int __devinit au1xtoy_rtc_probe(struct platform_device *pdev) | |||
81 | if (au_readl(SYS_TOYTRIM) != 32767) { | 81 | if (au_readl(SYS_TOYTRIM) != 32767) { |
82 | /* wait until hardware gives access to TRIM register */ | 82 | /* wait until hardware gives access to TRIM register */ |
83 | t = 0x00100000; | 83 | t = 0x00100000; |
84 | while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S) && t--) | 84 | while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S) && --t) |
85 | msleep(1); | 85 | msleep(1); |
86 | 86 | ||
87 | if (!t) { | 87 | if (!t) { |
diff --git a/drivers/rtc/rtc-dm355evm.c b/drivers/rtc/rtc-dm355evm.c new file mode 100644 index 000000000000..58d4e18530da --- /dev/null +++ b/drivers/rtc/rtc-dm355evm.c | |||
@@ -0,0 +1,175 @@ | |||
1 | /* | ||
2 | * rtc-dm355evm.c - access battery-backed counter in MSP430 firmware | ||
3 | * | ||
4 | * Copyright (c) 2008 by David Brownell | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/rtc.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | |||
16 | #include <linux/i2c/dm355evm_msp.h> | ||
17 | |||
18 | |||
19 | /* | ||
20 | * The MSP430 firmware on the DM355 EVM uses a watch crystal to feed | ||
21 | * a 1 Hz counter. When a backup battery is supplied, that makes a | ||
22 | * reasonable RTC for applications where alarms and non-NTP drift | ||
23 | * compensation aren't important. | ||
24 | * | ||
25 | * The only real glitch is the inability to read or write all four | ||
26 | * counter bytes atomically: the count may increment in the middle | ||
27 | * of an operation, causing trouble when the LSB rolls over. | ||
28 | * | ||
29 | * This driver was tested with firmware revision A4. | ||
30 | */ | ||
31 | union evm_time { | ||
32 | u8 bytes[4]; | ||
33 | u32 value; | ||
34 | }; | ||
35 | |||
36 | static int dm355evm_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
37 | { | ||
38 | union evm_time time; | ||
39 | int status; | ||
40 | int tries = 0; | ||
41 | |||
42 | do { | ||
43 | /* | ||
44 | * Read LSB(0) to MSB(3) bytes. Defend against the counter | ||
45 | * rolling over by re-reading until the value is stable, | ||
46 | * and assuming the four reads take at most a few seconds. | ||
47 | */ | ||
48 | status = dm355evm_msp_read(DM355EVM_MSP_RTC_0); | ||
49 | if (status < 0) | ||
50 | return status; | ||
51 | if (tries && time.bytes[0] == status) | ||
52 | break; | ||
53 | time.bytes[0] = status; | ||
54 | |||
55 | status = dm355evm_msp_read(DM355EVM_MSP_RTC_1); | ||
56 | if (status < 0) | ||
57 | return status; | ||
58 | if (tries && time.bytes[1] == status) | ||
59 | break; | ||
60 | time.bytes[1] = status; | ||
61 | |||
62 | status = dm355evm_msp_read(DM355EVM_MSP_RTC_2); | ||
63 | if (status < 0) | ||
64 | return status; | ||
65 | if (tries && time.bytes[2] == status) | ||
66 | break; | ||
67 | time.bytes[2] = status; | ||
68 | |||
69 | status = dm355evm_msp_read(DM355EVM_MSP_RTC_3); | ||
70 | if (status < 0) | ||
71 | return status; | ||
72 | if (tries && time.bytes[3] == status) | ||
73 | break; | ||
74 | time.bytes[3] = status; | ||
75 | |||
76 | } while (++tries < 5); | ||
77 | |||
78 | dev_dbg(dev, "read timestamp %08x\n", time.value); | ||
79 | |||
80 | rtc_time_to_tm(le32_to_cpu(time.value), tm); | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int dm355evm_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
85 | { | ||
86 | union evm_time time; | ||
87 | unsigned long value; | ||
88 | int status; | ||
89 | |||
90 | rtc_tm_to_time(tm, &value); | ||
91 | time.value = cpu_to_le32(value); | ||
92 | |||
93 | dev_dbg(dev, "write timestamp %08x\n", time.value); | ||
94 | |||
95 | /* | ||
96 | * REVISIT handle non-atomic writes ... maybe just retry until | ||
97 | * byte[1] sticks (no rollover)? | ||
98 | */ | ||
99 | status = dm355evm_msp_write(time.bytes[0], DM355EVM_MSP_RTC_0); | ||
100 | if (status < 0) | ||
101 | return status; | ||
102 | |||
103 | status = dm355evm_msp_write(time.bytes[1], DM355EVM_MSP_RTC_1); | ||
104 | if (status < 0) | ||
105 | return status; | ||
106 | |||
107 | status = dm355evm_msp_write(time.bytes[2], DM355EVM_MSP_RTC_2); | ||
108 | if (status < 0) | ||
109 | return status; | ||
110 | |||
111 | status = dm355evm_msp_write(time.bytes[3], DM355EVM_MSP_RTC_3); | ||
112 | if (status < 0) | ||
113 | return status; | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static struct rtc_class_ops dm355evm_rtc_ops = { | ||
119 | .read_time = dm355evm_rtc_read_time, | ||
120 | .set_time = dm355evm_rtc_set_time, | ||
121 | }; | ||
122 | |||
123 | /*----------------------------------------------------------------------*/ | ||
124 | |||
125 | static int __devinit dm355evm_rtc_probe(struct platform_device *pdev) | ||
126 | { | ||
127 | struct rtc_device *rtc; | ||
128 | |||
129 | rtc = rtc_device_register(pdev->name, | ||
130 | &pdev->dev, &dm355evm_rtc_ops, THIS_MODULE); | ||
131 | if (IS_ERR(rtc)) { | ||
132 | dev_err(&pdev->dev, "can't register RTC device, err %ld\n", | ||
133 | PTR_ERR(rtc)); | ||
134 | return PTR_ERR(rtc); | ||
135 | } | ||
136 | platform_set_drvdata(pdev, rtc); | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static int __devexit dm355evm_rtc_remove(struct platform_device *pdev) | ||
142 | { | ||
143 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
144 | |||
145 | rtc_device_unregister(rtc); | ||
146 | platform_set_drvdata(pdev, NULL); | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * I2C is used to talk to the MSP430, but this platform device is | ||
152 | * exposed by an MFD driver that manages I2C communications. | ||
153 | */ | ||
154 | static struct platform_driver rtc_dm355evm_driver = { | ||
155 | .probe = dm355evm_rtc_probe, | ||
156 | .remove = __devexit_p(dm355evm_rtc_remove), | ||
157 | .driver = { | ||
158 | .owner = THIS_MODULE, | ||
159 | .name = "rtc-dm355evm", | ||
160 | }, | ||
161 | }; | ||
162 | |||
163 | static int __init dm355evm_rtc_init(void) | ||
164 | { | ||
165 | return platform_driver_register(&rtc_dm355evm_driver); | ||
166 | } | ||
167 | module_init(dm355evm_rtc_init); | ||
168 | |||
169 | static void __exit dm355evm_rtc_exit(void) | ||
170 | { | ||
171 | platform_driver_unregister(&rtc_dm355evm_driver); | ||
172 | } | ||
173 | module_exit(dm355evm_rtc_exit); | ||
174 | |||
175 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c index e54b5c619bdf..e01b955db077 100644 --- a/drivers/rtc/rtc-ds1390.c +++ b/drivers/rtc/rtc-ds1390.c | |||
@@ -122,7 +122,6 @@ static const struct rtc_class_ops ds1390_rtc_ops = { | |||
122 | 122 | ||
123 | static int __devinit ds1390_probe(struct spi_device *spi) | 123 | static int __devinit ds1390_probe(struct spi_device *spi) |
124 | { | 124 | { |
125 | struct rtc_device *rtc; | ||
126 | unsigned char tmp; | 125 | unsigned char tmp; |
127 | struct ds1390 *chip; | 126 | struct ds1390 *chip; |
128 | int res; | 127 | int res; |
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 2cbeb0794f14..bd1ce8e2bc18 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c | |||
@@ -377,13 +377,13 @@ static int __init omap_rtc_probe(struct platform_device *pdev) | |||
377 | 377 | ||
378 | /* handle periodic and alarm irqs */ | 378 | /* handle periodic and alarm irqs */ |
379 | if (request_irq(omap_rtc_timer, rtc_irq, IRQF_DISABLED, | 379 | if (request_irq(omap_rtc_timer, rtc_irq, IRQF_DISABLED, |
380 | rtc->dev.bus_id, rtc)) { | 380 | dev_name(&rtc->dev), rtc)) { |
381 | pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n", | 381 | pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n", |
382 | pdev->name, omap_rtc_timer); | 382 | pdev->name, omap_rtc_timer); |
383 | goto fail0; | 383 | goto fail0; |
384 | } | 384 | } |
385 | if (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED, | 385 | if (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED, |
386 | rtc->dev.bus_id, rtc)) { | 386 | dev_name(&rtc->dev), rtc)) { |
387 | pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n", | 387 | pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n", |
388 | pdev->name, omap_rtc_alarm); | 388 | pdev->name, omap_rtc_alarm); |
389 | goto fail1; | 389 | goto fail1; |
diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index bd56a033bfd0..bb8cc05605ac 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c | |||
@@ -485,7 +485,7 @@ static void __exit pxa_rtc_exit(void) | |||
485 | module_init(pxa_rtc_init); | 485 | module_init(pxa_rtc_init); |
486 | module_exit(pxa_rtc_exit); | 486 | module_exit(pxa_rtc_exit); |
487 | 487 | ||
488 | MODULE_AUTHOR("Robert Jarzmik"); | 488 | MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>"); |
489 | MODULE_DESCRIPTION("PXA27x/PXA3xx Realtime Clock Driver (RTC)"); | 489 | MODULE_DESCRIPTION("PXA27x/PXA3xx Realtime Clock Driver (RTC)"); |
490 | MODULE_LICENSE("GPL"); | 490 | MODULE_LICENSE("GPL"); |
491 | MODULE_ALIAS("platform:pxa-rtc"); | 491 | MODULE_ALIAS("platform:pxa-rtc"); |
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 1c3fc6b428e9..4898f7fe8518 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c | |||
@@ -28,7 +28,7 @@ | |||
28 | #include <asm/rtc.h> | 28 | #include <asm/rtc.h> |
29 | 29 | ||
30 | #define DRV_NAME "sh-rtc" | 30 | #define DRV_NAME "sh-rtc" |
31 | #define DRV_VERSION "0.2.0" | 31 | #define DRV_VERSION "0.2.1" |
32 | 32 | ||
33 | #define RTC_REG(r) ((r) * rtc_reg_size) | 33 | #define RTC_REG(r) ((r) * rtc_reg_size) |
34 | 34 | ||
@@ -99,56 +99,51 @@ struct sh_rtc { | |||
99 | unsigned short periodic_freq; | 99 | unsigned short periodic_freq; |
100 | }; | 100 | }; |
101 | 101 | ||
102 | static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id) | 102 | static int __sh_rtc_interrupt(struct sh_rtc *rtc) |
103 | { | 103 | { |
104 | struct sh_rtc *rtc = dev_id; | 104 | unsigned int tmp, pending; |
105 | unsigned int tmp; | ||
106 | |||
107 | spin_lock(&rtc->lock); | ||
108 | 105 | ||
109 | tmp = readb(rtc->regbase + RCR1); | 106 | tmp = readb(rtc->regbase + RCR1); |
107 | pending = tmp & RCR1_CF; | ||
110 | tmp &= ~RCR1_CF; | 108 | tmp &= ~RCR1_CF; |
111 | writeb(tmp, rtc->regbase + RCR1); | 109 | writeb(tmp, rtc->regbase + RCR1); |
112 | 110 | ||
113 | /* Users have requested One x Second IRQ */ | 111 | /* Users have requested One x Second IRQ */ |
114 | if (rtc->periodic_freq & PF_OXS) | 112 | if (pending && rtc->periodic_freq & PF_OXS) |
115 | rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); | 113 | rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); |
116 | 114 | ||
117 | spin_unlock(&rtc->lock); | 115 | return pending; |
118 | |||
119 | return IRQ_HANDLED; | ||
120 | } | 116 | } |
121 | 117 | ||
122 | static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) | 118 | static int __sh_rtc_alarm(struct sh_rtc *rtc) |
123 | { | 119 | { |
124 | struct sh_rtc *rtc = dev_id; | 120 | unsigned int tmp, pending; |
125 | unsigned int tmp; | ||
126 | |||
127 | spin_lock(&rtc->lock); | ||
128 | 121 | ||
129 | tmp = readb(rtc->regbase + RCR1); | 122 | tmp = readb(rtc->regbase + RCR1); |
123 | pending = tmp & RCR1_AF; | ||
130 | tmp &= ~(RCR1_AF | RCR1_AIE); | 124 | tmp &= ~(RCR1_AF | RCR1_AIE); |
131 | writeb(tmp, rtc->regbase + RCR1); | 125 | writeb(tmp, rtc->regbase + RCR1); |
132 | |||
133 | rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); | ||
134 | 126 | ||
135 | spin_unlock(&rtc->lock); | 127 | if (pending) |
128 | rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); | ||
136 | 129 | ||
137 | return IRQ_HANDLED; | 130 | return pending; |
138 | } | 131 | } |
139 | 132 | ||
140 | static irqreturn_t sh_rtc_periodic(int irq, void *dev_id) | 133 | static int __sh_rtc_periodic(struct sh_rtc *rtc) |
141 | { | 134 | { |
142 | struct sh_rtc *rtc = dev_id; | ||
143 | struct rtc_device *rtc_dev = rtc->rtc_dev; | 135 | struct rtc_device *rtc_dev = rtc->rtc_dev; |
144 | unsigned int tmp; | 136 | struct rtc_task *irq_task; |
145 | 137 | unsigned int tmp, pending; | |
146 | spin_lock(&rtc->lock); | ||
147 | 138 | ||
148 | tmp = readb(rtc->regbase + RCR2); | 139 | tmp = readb(rtc->regbase + RCR2); |
140 | pending = tmp & RCR2_PEF; | ||
149 | tmp &= ~RCR2_PEF; | 141 | tmp &= ~RCR2_PEF; |
150 | writeb(tmp, rtc->regbase + RCR2); | 142 | writeb(tmp, rtc->regbase + RCR2); |
151 | 143 | ||
144 | if (!pending) | ||
145 | return 0; | ||
146 | |||
152 | /* Half period enabled than one skipped and the next notified */ | 147 | /* Half period enabled than one skipped and the next notified */ |
153 | if ((rtc->periodic_freq & PF_HP) && (rtc->periodic_freq & PF_COUNT)) | 148 | if ((rtc->periodic_freq & PF_HP) && (rtc->periodic_freq & PF_COUNT)) |
154 | rtc->periodic_freq &= ~PF_COUNT; | 149 | rtc->periodic_freq &= ~PF_COUNT; |
@@ -157,16 +152,65 @@ static irqreturn_t sh_rtc_periodic(int irq, void *dev_id) | |||
157 | rtc->periodic_freq |= PF_COUNT; | 152 | rtc->periodic_freq |= PF_COUNT; |
158 | if (rtc->periodic_freq & PF_KOU) { | 153 | if (rtc->periodic_freq & PF_KOU) { |
159 | spin_lock(&rtc_dev->irq_task_lock); | 154 | spin_lock(&rtc_dev->irq_task_lock); |
160 | if (rtc_dev->irq_task) | 155 | irq_task = rtc_dev->irq_task; |
161 | rtc_dev->irq_task->func(rtc_dev->irq_task->private_data); | 156 | if (irq_task) |
157 | irq_task->func(irq_task->private_data); | ||
162 | spin_unlock(&rtc_dev->irq_task_lock); | 158 | spin_unlock(&rtc_dev->irq_task_lock); |
163 | } else | 159 | } else |
164 | rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); | 160 | rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); |
165 | } | 161 | } |
166 | 162 | ||
163 | return pending; | ||
164 | } | ||
165 | |||
166 | static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id) | ||
167 | { | ||
168 | struct sh_rtc *rtc = dev_id; | ||
169 | int ret; | ||
170 | |||
171 | spin_lock(&rtc->lock); | ||
172 | ret = __sh_rtc_interrupt(rtc); | ||
173 | spin_unlock(&rtc->lock); | ||
174 | |||
175 | return IRQ_RETVAL(ret); | ||
176 | } | ||
177 | |||
178 | static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) | ||
179 | { | ||
180 | struct sh_rtc *rtc = dev_id; | ||
181 | int ret; | ||
182 | |||
183 | spin_lock(&rtc->lock); | ||
184 | ret = __sh_rtc_alarm(rtc); | ||
185 | spin_unlock(&rtc->lock); | ||
186 | |||
187 | return IRQ_RETVAL(ret); | ||
188 | } | ||
189 | |||
190 | static irqreturn_t sh_rtc_periodic(int irq, void *dev_id) | ||
191 | { | ||
192 | struct sh_rtc *rtc = dev_id; | ||
193 | int ret; | ||
194 | |||
195 | spin_lock(&rtc->lock); | ||
196 | ret = __sh_rtc_periodic(rtc); | ||
167 | spin_unlock(&rtc->lock); | 197 | spin_unlock(&rtc->lock); |
168 | 198 | ||
169 | return IRQ_HANDLED; | 199 | return IRQ_RETVAL(ret); |
200 | } | ||
201 | |||
202 | static irqreturn_t sh_rtc_shared(int irq, void *dev_id) | ||
203 | { | ||
204 | struct sh_rtc *rtc = dev_id; | ||
205 | int ret; | ||
206 | |||
207 | spin_lock(&rtc->lock); | ||
208 | ret = __sh_rtc_interrupt(rtc); | ||
209 | ret |= __sh_rtc_alarm(rtc); | ||
210 | ret |= __sh_rtc_periodic(rtc); | ||
211 | spin_unlock(&rtc->lock); | ||
212 | |||
213 | return IRQ_RETVAL(ret); | ||
170 | } | 214 | } |
171 | 215 | ||
172 | static inline void sh_rtc_setpie(struct device *dev, unsigned int enable) | 216 | static inline void sh_rtc_setpie(struct device *dev, unsigned int enable) |
@@ -275,6 +319,25 @@ static int sh_rtc_proc(struct device *dev, struct seq_file *seq) | |||
275 | return 0; | 319 | return 0; |
276 | } | 320 | } |
277 | 321 | ||
322 | static inline void sh_rtc_setcie(struct device *dev, unsigned int enable) | ||
323 | { | ||
324 | struct sh_rtc *rtc = dev_get_drvdata(dev); | ||
325 | unsigned int tmp; | ||
326 | |||
327 | spin_lock_irq(&rtc->lock); | ||
328 | |||
329 | tmp = readb(rtc->regbase + RCR1); | ||
330 | |||
331 | if (!enable) | ||
332 | tmp &= ~RCR1_CIE; | ||
333 | else | ||
334 | tmp |= RCR1_CIE; | ||
335 | |||
336 | writeb(tmp, rtc->regbase + RCR1); | ||
337 | |||
338 | spin_unlock_irq(&rtc->lock); | ||
339 | } | ||
340 | |||
278 | static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | 341 | static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) |
279 | { | 342 | { |
280 | struct sh_rtc *rtc = dev_get_drvdata(dev); | 343 | struct sh_rtc *rtc = dev_get_drvdata(dev); |
@@ -291,9 +354,11 @@ static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | |||
291 | break; | 354 | break; |
292 | case RTC_UIE_OFF: | 355 | case RTC_UIE_OFF: |
293 | rtc->periodic_freq &= ~PF_OXS; | 356 | rtc->periodic_freq &= ~PF_OXS; |
357 | sh_rtc_setcie(dev, 0); | ||
294 | break; | 358 | break; |
295 | case RTC_UIE_ON: | 359 | case RTC_UIE_ON: |
296 | rtc->periodic_freq |= PF_OXS; | 360 | rtc->periodic_freq |= PF_OXS; |
361 | sh_rtc_setcie(dev, 1); | ||
297 | break; | 362 | break; |
298 | case RTC_IRQP_READ: | 363 | case RTC_IRQP_READ: |
299 | ret = put_user(rtc->rtc_dev->irq_freq, | 364 | ret = put_user(rtc->rtc_dev->irq_freq, |
@@ -356,18 +421,17 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
356 | tm->tm_sec--; | 421 | tm->tm_sec--; |
357 | #endif | 422 | #endif |
358 | 423 | ||
424 | /* only keep the carry interrupt enabled if UIE is on */ | ||
425 | if (!(rtc->periodic_freq & PF_OXS)) | ||
426 | sh_rtc_setcie(dev, 0); | ||
427 | |||
359 | dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " | 428 | dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " |
360 | "mday=%d, mon=%d, year=%d, wday=%d\n", | 429 | "mday=%d, mon=%d, year=%d, wday=%d\n", |
361 | __func__, | 430 | __func__, |
362 | tm->tm_sec, tm->tm_min, tm->tm_hour, | 431 | tm->tm_sec, tm->tm_min, tm->tm_hour, |
363 | tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday); | 432 | tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday); |
364 | 433 | ||
365 | if (rtc_valid_tm(tm) < 0) { | 434 | return rtc_valid_tm(tm); |
366 | dev_err(dev, "invalid date\n"); | ||
367 | rtc_time_to_tm(0, tm); | ||
368 | } | ||
369 | |||
370 | return 0; | ||
371 | } | 435 | } |
372 | 436 | ||
373 | static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm) | 437 | static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm) |
@@ -572,7 +636,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) | |||
572 | { | 636 | { |
573 | struct sh_rtc *rtc; | 637 | struct sh_rtc *rtc; |
574 | struct resource *res; | 638 | struct resource *res; |
575 | unsigned int tmp; | 639 | struct rtc_time r; |
576 | int ret; | 640 | int ret; |
577 | 641 | ||
578 | rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL); | 642 | rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL); |
@@ -585,26 +649,12 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) | |||
585 | ret = platform_get_irq(pdev, 0); | 649 | ret = platform_get_irq(pdev, 0); |
586 | if (unlikely(ret <= 0)) { | 650 | if (unlikely(ret <= 0)) { |
587 | ret = -ENOENT; | 651 | ret = -ENOENT; |
588 | dev_err(&pdev->dev, "No IRQ for period\n"); | 652 | dev_err(&pdev->dev, "No IRQ resource\n"); |
589 | goto err_badres; | 653 | goto err_badres; |
590 | } | 654 | } |
591 | rtc->periodic_irq = ret; | 655 | rtc->periodic_irq = ret; |
592 | 656 | rtc->carry_irq = platform_get_irq(pdev, 1); | |
593 | ret = platform_get_irq(pdev, 1); | 657 | rtc->alarm_irq = platform_get_irq(pdev, 2); |
594 | if (unlikely(ret <= 0)) { | ||
595 | ret = -ENOENT; | ||
596 | dev_err(&pdev->dev, "No IRQ for carry\n"); | ||
597 | goto err_badres; | ||
598 | } | ||
599 | rtc->carry_irq = ret; | ||
600 | |||
601 | ret = platform_get_irq(pdev, 2); | ||
602 | if (unlikely(ret <= 0)) { | ||
603 | ret = -ENOENT; | ||
604 | dev_err(&pdev->dev, "No IRQ for alarm\n"); | ||
605 | goto err_badres; | ||
606 | } | ||
607 | rtc->alarm_irq = ret; | ||
608 | 658 | ||
609 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | 659 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
610 | if (unlikely(res == NULL)) { | 660 | if (unlikely(res == NULL)) { |
@@ -646,47 +696,66 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) | |||
646 | } | 696 | } |
647 | 697 | ||
648 | rtc->rtc_dev->max_user_freq = 256; | 698 | rtc->rtc_dev->max_user_freq = 256; |
649 | rtc->rtc_dev->irq_freq = 1; | ||
650 | rtc->periodic_freq = 0x60; | ||
651 | 699 | ||
652 | platform_set_drvdata(pdev, rtc); | 700 | platform_set_drvdata(pdev, rtc); |
653 | 701 | ||
654 | /* register periodic/carry/alarm irqs */ | 702 | if (rtc->carry_irq <= 0) { |
655 | ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, IRQF_DISABLED, | 703 | /* register shared periodic/carry/alarm irq */ |
656 | "sh-rtc period", rtc); | 704 | ret = request_irq(rtc->periodic_irq, sh_rtc_shared, |
657 | if (unlikely(ret)) { | 705 | IRQF_DISABLED, "sh-rtc", rtc); |
658 | dev_err(&pdev->dev, | 706 | if (unlikely(ret)) { |
659 | "request period IRQ failed with %d, IRQ %d\n", ret, | 707 | dev_err(&pdev->dev, |
660 | rtc->periodic_irq); | 708 | "request IRQ failed with %d, IRQ %d\n", ret, |
661 | goto err_unmap; | 709 | rtc->periodic_irq); |
662 | } | 710 | goto err_unmap; |
711 | } | ||
712 | } else { | ||
713 | /* register periodic/carry/alarm irqs */ | ||
714 | ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, | ||
715 | IRQF_DISABLED, "sh-rtc period", rtc); | ||
716 | if (unlikely(ret)) { | ||
717 | dev_err(&pdev->dev, | ||
718 | "request period IRQ failed with %d, IRQ %d\n", | ||
719 | ret, rtc->periodic_irq); | ||
720 | goto err_unmap; | ||
721 | } | ||
663 | 722 | ||
664 | ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, IRQF_DISABLED, | 723 | ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, |
665 | "sh-rtc carry", rtc); | 724 | IRQF_DISABLED, "sh-rtc carry", rtc); |
666 | if (unlikely(ret)) { | 725 | if (unlikely(ret)) { |
667 | dev_err(&pdev->dev, | 726 | dev_err(&pdev->dev, |
668 | "request carry IRQ failed with %d, IRQ %d\n", ret, | 727 | "request carry IRQ failed with %d, IRQ %d\n", |
669 | rtc->carry_irq); | 728 | ret, rtc->carry_irq); |
670 | free_irq(rtc->periodic_irq, rtc); | 729 | free_irq(rtc->periodic_irq, rtc); |
671 | goto err_unmap; | 730 | goto err_unmap; |
672 | } | 731 | } |
673 | 732 | ||
674 | ret = request_irq(rtc->alarm_irq, sh_rtc_alarm, IRQF_DISABLED, | 733 | ret = request_irq(rtc->alarm_irq, sh_rtc_alarm, |
675 | "sh-rtc alarm", rtc); | 734 | IRQF_DISABLED, "sh-rtc alarm", rtc); |
676 | if (unlikely(ret)) { | 735 | if (unlikely(ret)) { |
677 | dev_err(&pdev->dev, | 736 | dev_err(&pdev->dev, |
678 | "request alarm IRQ failed with %d, IRQ %d\n", ret, | 737 | "request alarm IRQ failed with %d, IRQ %d\n", |
679 | rtc->alarm_irq); | 738 | ret, rtc->alarm_irq); |
680 | free_irq(rtc->carry_irq, rtc); | 739 | free_irq(rtc->carry_irq, rtc); |
681 | free_irq(rtc->periodic_irq, rtc); | 740 | free_irq(rtc->periodic_irq, rtc); |
682 | goto err_unmap; | 741 | goto err_unmap; |
742 | } | ||
683 | } | 743 | } |
684 | 744 | ||
685 | tmp = readb(rtc->regbase + RCR1); | 745 | /* everything disabled by default */ |
686 | tmp &= ~RCR1_CF; | 746 | rtc->periodic_freq = 0; |
687 | tmp |= RCR1_CIE; | 747 | rtc->rtc_dev->irq_freq = 0; |
688 | writeb(tmp, rtc->regbase + RCR1); | 748 | sh_rtc_setpie(&pdev->dev, 0); |
749 | sh_rtc_setaie(&pdev->dev, 0); | ||
750 | sh_rtc_setcie(&pdev->dev, 0); | ||
751 | |||
752 | /* reset rtc to epoch 0 if time is invalid */ | ||
753 | if (rtc_read_time(rtc->rtc_dev, &r) < 0) { | ||
754 | rtc_time_to_tm(0, &r); | ||
755 | rtc_set_time(rtc->rtc_dev, &r); | ||
756 | } | ||
689 | 757 | ||
758 | device_init_wakeup(&pdev->dev, 1); | ||
690 | return 0; | 759 | return 0; |
691 | 760 | ||
692 | err_unmap: | 761 | err_unmap: |
@@ -708,10 +777,13 @@ static int __devexit sh_rtc_remove(struct platform_device *pdev) | |||
708 | 777 | ||
709 | sh_rtc_setpie(&pdev->dev, 0); | 778 | sh_rtc_setpie(&pdev->dev, 0); |
710 | sh_rtc_setaie(&pdev->dev, 0); | 779 | sh_rtc_setaie(&pdev->dev, 0); |
780 | sh_rtc_setcie(&pdev->dev, 0); | ||
711 | 781 | ||
712 | free_irq(rtc->carry_irq, rtc); | ||
713 | free_irq(rtc->periodic_irq, rtc); | 782 | free_irq(rtc->periodic_irq, rtc); |
714 | free_irq(rtc->alarm_irq, rtc); | 783 | if (rtc->carry_irq > 0) { |
784 | free_irq(rtc->carry_irq, rtc); | ||
785 | free_irq(rtc->alarm_irq, rtc); | ||
786 | } | ||
715 | 787 | ||
716 | release_resource(rtc->res); | 788 | release_resource(rtc->res); |
717 | 789 | ||
diff --git a/drivers/rtc/rtc-twl4030.c b/drivers/rtc/rtc-twl4030.c index ad35f76c46b7..a6341e4f9a0f 100644 --- a/drivers/rtc/rtc-twl4030.c +++ b/drivers/rtc/rtc-twl4030.c | |||
@@ -426,7 +426,7 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev) | |||
426 | 426 | ||
427 | ret = request_irq(irq, twl4030_rtc_interrupt, | 427 | ret = request_irq(irq, twl4030_rtc_interrupt, |
428 | IRQF_TRIGGER_RISING, | 428 | IRQF_TRIGGER_RISING, |
429 | rtc->dev.bus_id, rtc); | 429 | dev_name(&rtc->dev), rtc); |
430 | if (ret < 0) { | 430 | if (ret < 0) { |
431 | dev_err(&pdev->dev, "IRQ is not free.\n"); | 431 | dev_err(&pdev->dev, "IRQ is not free.\n"); |
432 | goto out1; | 432 | goto out1; |