Commit 60e2b00ea200e1527668bfb766ecbdf578ad7de8
1 parent
858af58f67
Exists in
master
and in
6 other branches
rtc-puv3: using module_platform_driver()
This patch converts the driver to use the module_platform_driver() macro which makes the code smaller and a bit simpler. Signed-off-by: Axel Lin <axel.lin@gmail.com> Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
Showing 1 changed file with 1 additions and 15 deletions Inline Diff
drivers/rtc/rtc-puv3.c
1 | /* | 1 | /* |
2 | * RTC driver code specific to PKUnity SoC and UniCore ISA | 2 | * RTC driver code specific to PKUnity SoC and UniCore ISA |
3 | * | 3 | * |
4 | * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> | 4 | * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> |
5 | * Copyright (C) 2001-2010 Guan Xuetao | 5 | * Copyright (C) 2001-2010 Guan Xuetao |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/string.h> | 14 | #include <linux/string.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/rtc.h> | 18 | #include <linux/rtc.h> |
19 | #include <linux/bcd.h> | 19 | #include <linux/bcd.h> |
20 | #include <linux/clk.h> | 20 | #include <linux/clk.h> |
21 | #include <linux/log2.h> | 21 | #include <linux/log2.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
24 | #include <linux/io.h> | 24 | #include <linux/io.h> |
25 | 25 | ||
26 | #include <asm/irq.h> | 26 | #include <asm/irq.h> |
27 | #include <mach/hardware.h> | 27 | #include <mach/hardware.h> |
28 | 28 | ||
29 | static struct resource *puv3_rtc_mem; | 29 | static struct resource *puv3_rtc_mem; |
30 | 30 | ||
31 | static int puv3_rtc_alarmno = IRQ_RTCAlarm; | 31 | static int puv3_rtc_alarmno = IRQ_RTCAlarm; |
32 | static int puv3_rtc_tickno = IRQ_RTC; | 32 | static int puv3_rtc_tickno = IRQ_RTC; |
33 | 33 | ||
34 | static DEFINE_SPINLOCK(puv3_rtc_pie_lock); | 34 | static DEFINE_SPINLOCK(puv3_rtc_pie_lock); |
35 | 35 | ||
36 | /* IRQ Handlers */ | 36 | /* IRQ Handlers */ |
37 | static irqreturn_t puv3_rtc_alarmirq(int irq, void *id) | 37 | static irqreturn_t puv3_rtc_alarmirq(int irq, void *id) |
38 | { | 38 | { |
39 | struct rtc_device *rdev = id; | 39 | struct rtc_device *rdev = id; |
40 | 40 | ||
41 | writel(readl(RTC_RTSR) | RTC_RTSR_AL, RTC_RTSR); | 41 | writel(readl(RTC_RTSR) | RTC_RTSR_AL, RTC_RTSR); |
42 | rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF); | 42 | rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF); |
43 | return IRQ_HANDLED; | 43 | return IRQ_HANDLED; |
44 | } | 44 | } |
45 | 45 | ||
46 | static irqreturn_t puv3_rtc_tickirq(int irq, void *id) | 46 | static irqreturn_t puv3_rtc_tickirq(int irq, void *id) |
47 | { | 47 | { |
48 | struct rtc_device *rdev = id; | 48 | struct rtc_device *rdev = id; |
49 | 49 | ||
50 | writel(readl(RTC_RTSR) | RTC_RTSR_HZ, RTC_RTSR); | 50 | writel(readl(RTC_RTSR) | RTC_RTSR_HZ, RTC_RTSR); |
51 | rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF); | 51 | rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF); |
52 | return IRQ_HANDLED; | 52 | return IRQ_HANDLED; |
53 | } | 53 | } |
54 | 54 | ||
55 | /* Update control registers */ | 55 | /* Update control registers */ |
56 | static void puv3_rtc_setaie(int to) | 56 | static void puv3_rtc_setaie(int to) |
57 | { | 57 | { |
58 | unsigned int tmp; | 58 | unsigned int tmp; |
59 | 59 | ||
60 | pr_debug("%s: aie=%d\n", __func__, to); | 60 | pr_debug("%s: aie=%d\n", __func__, to); |
61 | 61 | ||
62 | tmp = readl(RTC_RTSR) & ~RTC_RTSR_ALE; | 62 | tmp = readl(RTC_RTSR) & ~RTC_RTSR_ALE; |
63 | 63 | ||
64 | if (to) | 64 | if (to) |
65 | tmp |= RTC_RTSR_ALE; | 65 | tmp |= RTC_RTSR_ALE; |
66 | 66 | ||
67 | writel(tmp, RTC_RTSR); | 67 | writel(tmp, RTC_RTSR); |
68 | } | 68 | } |
69 | 69 | ||
70 | static int puv3_rtc_setpie(struct device *dev, int enabled) | 70 | static int puv3_rtc_setpie(struct device *dev, int enabled) |
71 | { | 71 | { |
72 | unsigned int tmp; | 72 | unsigned int tmp; |
73 | 73 | ||
74 | pr_debug("%s: pie=%d\n", __func__, enabled); | 74 | pr_debug("%s: pie=%d\n", __func__, enabled); |
75 | 75 | ||
76 | spin_lock_irq(&puv3_rtc_pie_lock); | 76 | spin_lock_irq(&puv3_rtc_pie_lock); |
77 | tmp = readl(RTC_RTSR) & ~RTC_RTSR_HZE; | 77 | tmp = readl(RTC_RTSR) & ~RTC_RTSR_HZE; |
78 | 78 | ||
79 | if (enabled) | 79 | if (enabled) |
80 | tmp |= RTC_RTSR_HZE; | 80 | tmp |= RTC_RTSR_HZE; |
81 | 81 | ||
82 | writel(tmp, RTC_RTSR); | 82 | writel(tmp, RTC_RTSR); |
83 | spin_unlock_irq(&puv3_rtc_pie_lock); | 83 | spin_unlock_irq(&puv3_rtc_pie_lock); |
84 | 84 | ||
85 | return 0; | 85 | return 0; |
86 | } | 86 | } |
87 | 87 | ||
88 | /* Time read/write */ | 88 | /* Time read/write */ |
89 | static int puv3_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) | 89 | static int puv3_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) |
90 | { | 90 | { |
91 | rtc_time_to_tm(readl(RTC_RCNR), rtc_tm); | 91 | rtc_time_to_tm(readl(RTC_RCNR), rtc_tm); |
92 | 92 | ||
93 | pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n", | 93 | pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n", |
94 | rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, | 94 | rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, |
95 | rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); | 95 | rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); |
96 | 96 | ||
97 | return 0; | 97 | return 0; |
98 | } | 98 | } |
99 | 99 | ||
100 | static int puv3_rtc_settime(struct device *dev, struct rtc_time *tm) | 100 | static int puv3_rtc_settime(struct device *dev, struct rtc_time *tm) |
101 | { | 101 | { |
102 | unsigned long rtc_count = 0; | 102 | unsigned long rtc_count = 0; |
103 | 103 | ||
104 | pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n", | 104 | pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n", |
105 | tm->tm_year, tm->tm_mon, tm->tm_mday, | 105 | tm->tm_year, tm->tm_mon, tm->tm_mday, |
106 | tm->tm_hour, tm->tm_min, tm->tm_sec); | 106 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
107 | 107 | ||
108 | rtc_tm_to_time(tm, &rtc_count); | 108 | rtc_tm_to_time(tm, &rtc_count); |
109 | writel(rtc_count, RTC_RCNR); | 109 | writel(rtc_count, RTC_RCNR); |
110 | 110 | ||
111 | return 0; | 111 | return 0; |
112 | } | 112 | } |
113 | 113 | ||
114 | static int puv3_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) | 114 | static int puv3_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) |
115 | { | 115 | { |
116 | struct rtc_time *alm_tm = &alrm->time; | 116 | struct rtc_time *alm_tm = &alrm->time; |
117 | 117 | ||
118 | rtc_time_to_tm(readl(RTC_RTAR), alm_tm); | 118 | rtc_time_to_tm(readl(RTC_RTAR), alm_tm); |
119 | 119 | ||
120 | alrm->enabled = readl(RTC_RTSR) & RTC_RTSR_ALE; | 120 | alrm->enabled = readl(RTC_RTSR) & RTC_RTSR_ALE; |
121 | 121 | ||
122 | pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", | 122 | pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", |
123 | alrm->enabled, | 123 | alrm->enabled, |
124 | alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, | 124 | alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, |
125 | alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); | 125 | alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); |
126 | 126 | ||
127 | return 0; | 127 | return 0; |
128 | } | 128 | } |
129 | 129 | ||
130 | static int puv3_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) | 130 | static int puv3_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) |
131 | { | 131 | { |
132 | struct rtc_time *tm = &alrm->time; | 132 | struct rtc_time *tm = &alrm->time; |
133 | unsigned long rtcalarm_count = 0; | 133 | unsigned long rtcalarm_count = 0; |
134 | 134 | ||
135 | pr_debug("puv3_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", | 135 | pr_debug("puv3_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", |
136 | alrm->enabled, | 136 | alrm->enabled, |
137 | tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, | 137 | tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, |
138 | tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); | 138 | tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); |
139 | 139 | ||
140 | rtc_tm_to_time(tm, &rtcalarm_count); | 140 | rtc_tm_to_time(tm, &rtcalarm_count); |
141 | writel(rtcalarm_count, RTC_RTAR); | 141 | writel(rtcalarm_count, RTC_RTAR); |
142 | 142 | ||
143 | puv3_rtc_setaie(alrm->enabled); | 143 | puv3_rtc_setaie(alrm->enabled); |
144 | 144 | ||
145 | if (alrm->enabled) | 145 | if (alrm->enabled) |
146 | enable_irq_wake(puv3_rtc_alarmno); | 146 | enable_irq_wake(puv3_rtc_alarmno); |
147 | else | 147 | else |
148 | disable_irq_wake(puv3_rtc_alarmno); | 148 | disable_irq_wake(puv3_rtc_alarmno); |
149 | 149 | ||
150 | return 0; | 150 | return 0; |
151 | } | 151 | } |
152 | 152 | ||
153 | static int puv3_rtc_proc(struct device *dev, struct seq_file *seq) | 153 | static int puv3_rtc_proc(struct device *dev, struct seq_file *seq) |
154 | { | 154 | { |
155 | seq_printf(seq, "periodic_IRQ\t: %s\n", | 155 | seq_printf(seq, "periodic_IRQ\t: %s\n", |
156 | (readl(RTC_RTSR) & RTC_RTSR_HZE) ? "yes" : "no"); | 156 | (readl(RTC_RTSR) & RTC_RTSR_HZE) ? "yes" : "no"); |
157 | return 0; | 157 | return 0; |
158 | } | 158 | } |
159 | 159 | ||
160 | static int puv3_rtc_open(struct device *dev) | 160 | static int puv3_rtc_open(struct device *dev) |
161 | { | 161 | { |
162 | struct platform_device *pdev = to_platform_device(dev); | 162 | struct platform_device *pdev = to_platform_device(dev); |
163 | struct rtc_device *rtc_dev = platform_get_drvdata(pdev); | 163 | struct rtc_device *rtc_dev = platform_get_drvdata(pdev); |
164 | int ret; | 164 | int ret; |
165 | 165 | ||
166 | ret = request_irq(puv3_rtc_alarmno, puv3_rtc_alarmirq, | 166 | ret = request_irq(puv3_rtc_alarmno, puv3_rtc_alarmirq, |
167 | 0, "pkunity-rtc alarm", rtc_dev); | 167 | 0, "pkunity-rtc alarm", rtc_dev); |
168 | 168 | ||
169 | if (ret) { | 169 | if (ret) { |
170 | dev_err(dev, "IRQ%d error %d\n", puv3_rtc_alarmno, ret); | 170 | dev_err(dev, "IRQ%d error %d\n", puv3_rtc_alarmno, ret); |
171 | return ret; | 171 | return ret; |
172 | } | 172 | } |
173 | 173 | ||
174 | ret = request_irq(puv3_rtc_tickno, puv3_rtc_tickirq, | 174 | ret = request_irq(puv3_rtc_tickno, puv3_rtc_tickirq, |
175 | 0, "pkunity-rtc tick", rtc_dev); | 175 | 0, "pkunity-rtc tick", rtc_dev); |
176 | 176 | ||
177 | if (ret) { | 177 | if (ret) { |
178 | dev_err(dev, "IRQ%d error %d\n", puv3_rtc_tickno, ret); | 178 | dev_err(dev, "IRQ%d error %d\n", puv3_rtc_tickno, ret); |
179 | goto tick_err; | 179 | goto tick_err; |
180 | } | 180 | } |
181 | 181 | ||
182 | return ret; | 182 | return ret; |
183 | 183 | ||
184 | tick_err: | 184 | tick_err: |
185 | free_irq(puv3_rtc_alarmno, rtc_dev); | 185 | free_irq(puv3_rtc_alarmno, rtc_dev); |
186 | return ret; | 186 | return ret; |
187 | } | 187 | } |
188 | 188 | ||
189 | static void puv3_rtc_release(struct device *dev) | 189 | static void puv3_rtc_release(struct device *dev) |
190 | { | 190 | { |
191 | struct platform_device *pdev = to_platform_device(dev); | 191 | struct platform_device *pdev = to_platform_device(dev); |
192 | struct rtc_device *rtc_dev = platform_get_drvdata(pdev); | 192 | struct rtc_device *rtc_dev = platform_get_drvdata(pdev); |
193 | 193 | ||
194 | /* do not clear AIE here, it may be needed for wake */ | 194 | /* do not clear AIE here, it may be needed for wake */ |
195 | puv3_rtc_setpie(dev, 0); | 195 | puv3_rtc_setpie(dev, 0); |
196 | free_irq(puv3_rtc_alarmno, rtc_dev); | 196 | free_irq(puv3_rtc_alarmno, rtc_dev); |
197 | free_irq(puv3_rtc_tickno, rtc_dev); | 197 | free_irq(puv3_rtc_tickno, rtc_dev); |
198 | } | 198 | } |
199 | 199 | ||
200 | static const struct rtc_class_ops puv3_rtcops = { | 200 | static const struct rtc_class_ops puv3_rtcops = { |
201 | .open = puv3_rtc_open, | 201 | .open = puv3_rtc_open, |
202 | .release = puv3_rtc_release, | 202 | .release = puv3_rtc_release, |
203 | .read_time = puv3_rtc_gettime, | 203 | .read_time = puv3_rtc_gettime, |
204 | .set_time = puv3_rtc_settime, | 204 | .set_time = puv3_rtc_settime, |
205 | .read_alarm = puv3_rtc_getalarm, | 205 | .read_alarm = puv3_rtc_getalarm, |
206 | .set_alarm = puv3_rtc_setalarm, | 206 | .set_alarm = puv3_rtc_setalarm, |
207 | .proc = puv3_rtc_proc, | 207 | .proc = puv3_rtc_proc, |
208 | }; | 208 | }; |
209 | 209 | ||
210 | static void puv3_rtc_enable(struct platform_device *pdev, int en) | 210 | static void puv3_rtc_enable(struct platform_device *pdev, int en) |
211 | { | 211 | { |
212 | if (!en) { | 212 | if (!en) { |
213 | writel(readl(RTC_RTSR) & ~RTC_RTSR_HZE, RTC_RTSR); | 213 | writel(readl(RTC_RTSR) & ~RTC_RTSR_HZE, RTC_RTSR); |
214 | } else { | 214 | } else { |
215 | /* re-enable the device, and check it is ok */ | 215 | /* re-enable the device, and check it is ok */ |
216 | if ((readl(RTC_RTSR) & RTC_RTSR_HZE) == 0) { | 216 | if ((readl(RTC_RTSR) & RTC_RTSR_HZE) == 0) { |
217 | dev_info(&pdev->dev, "rtc disabled, re-enabling\n"); | 217 | dev_info(&pdev->dev, "rtc disabled, re-enabling\n"); |
218 | writel(readl(RTC_RTSR) | RTC_RTSR_HZE, RTC_RTSR); | 218 | writel(readl(RTC_RTSR) | RTC_RTSR_HZE, RTC_RTSR); |
219 | } | 219 | } |
220 | } | 220 | } |
221 | } | 221 | } |
222 | 222 | ||
223 | static int __devexit puv3_rtc_remove(struct platform_device *dev) | 223 | static int __devexit puv3_rtc_remove(struct platform_device *dev) |
224 | { | 224 | { |
225 | struct rtc_device *rtc = platform_get_drvdata(dev); | 225 | struct rtc_device *rtc = platform_get_drvdata(dev); |
226 | 226 | ||
227 | platform_set_drvdata(dev, NULL); | 227 | platform_set_drvdata(dev, NULL); |
228 | rtc_device_unregister(rtc); | 228 | rtc_device_unregister(rtc); |
229 | 229 | ||
230 | puv3_rtc_setpie(&dev->dev, 0); | 230 | puv3_rtc_setpie(&dev->dev, 0); |
231 | puv3_rtc_setaie(0); | 231 | puv3_rtc_setaie(0); |
232 | 232 | ||
233 | release_resource(puv3_rtc_mem); | 233 | release_resource(puv3_rtc_mem); |
234 | kfree(puv3_rtc_mem); | 234 | kfree(puv3_rtc_mem); |
235 | 235 | ||
236 | return 0; | 236 | return 0; |
237 | } | 237 | } |
238 | 238 | ||
239 | static int __devinit puv3_rtc_probe(struct platform_device *pdev) | 239 | static int __devinit puv3_rtc_probe(struct platform_device *pdev) |
240 | { | 240 | { |
241 | struct rtc_device *rtc; | 241 | struct rtc_device *rtc; |
242 | struct resource *res; | 242 | struct resource *res; |
243 | int ret; | 243 | int ret; |
244 | 244 | ||
245 | pr_debug("%s: probe=%p\n", __func__, pdev); | 245 | pr_debug("%s: probe=%p\n", __func__, pdev); |
246 | 246 | ||
247 | /* find the IRQs */ | 247 | /* find the IRQs */ |
248 | puv3_rtc_tickno = platform_get_irq(pdev, 1); | 248 | puv3_rtc_tickno = platform_get_irq(pdev, 1); |
249 | if (puv3_rtc_tickno < 0) { | 249 | if (puv3_rtc_tickno < 0) { |
250 | dev_err(&pdev->dev, "no irq for rtc tick\n"); | 250 | dev_err(&pdev->dev, "no irq for rtc tick\n"); |
251 | return -ENOENT; | 251 | return -ENOENT; |
252 | } | 252 | } |
253 | 253 | ||
254 | puv3_rtc_alarmno = platform_get_irq(pdev, 0); | 254 | puv3_rtc_alarmno = platform_get_irq(pdev, 0); |
255 | if (puv3_rtc_alarmno < 0) { | 255 | if (puv3_rtc_alarmno < 0) { |
256 | dev_err(&pdev->dev, "no irq for alarm\n"); | 256 | dev_err(&pdev->dev, "no irq for alarm\n"); |
257 | return -ENOENT; | 257 | return -ENOENT; |
258 | } | 258 | } |
259 | 259 | ||
260 | pr_debug("PKUnity_rtc: tick irq %d, alarm irq %d\n", | 260 | pr_debug("PKUnity_rtc: tick irq %d, alarm irq %d\n", |
261 | puv3_rtc_tickno, puv3_rtc_alarmno); | 261 | puv3_rtc_tickno, puv3_rtc_alarmno); |
262 | 262 | ||
263 | /* get the memory region */ | 263 | /* get the memory region */ |
264 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 264 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
265 | if (res == NULL) { | 265 | if (res == NULL) { |
266 | dev_err(&pdev->dev, "failed to get memory region resource\n"); | 266 | dev_err(&pdev->dev, "failed to get memory region resource\n"); |
267 | return -ENOENT; | 267 | return -ENOENT; |
268 | } | 268 | } |
269 | 269 | ||
270 | puv3_rtc_mem = request_mem_region(res->start, resource_size(res), | 270 | puv3_rtc_mem = request_mem_region(res->start, resource_size(res), |
271 | pdev->name); | 271 | pdev->name); |
272 | 272 | ||
273 | if (puv3_rtc_mem == NULL) { | 273 | if (puv3_rtc_mem == NULL) { |
274 | dev_err(&pdev->dev, "failed to reserve memory region\n"); | 274 | dev_err(&pdev->dev, "failed to reserve memory region\n"); |
275 | ret = -ENOENT; | 275 | ret = -ENOENT; |
276 | goto err_nores; | 276 | goto err_nores; |
277 | } | 277 | } |
278 | 278 | ||
279 | puv3_rtc_enable(pdev, 1); | 279 | puv3_rtc_enable(pdev, 1); |
280 | 280 | ||
281 | /* register RTC and exit */ | 281 | /* register RTC and exit */ |
282 | rtc = rtc_device_register("pkunity", &pdev->dev, &puv3_rtcops, | 282 | rtc = rtc_device_register("pkunity", &pdev->dev, &puv3_rtcops, |
283 | THIS_MODULE); | 283 | THIS_MODULE); |
284 | 284 | ||
285 | if (IS_ERR(rtc)) { | 285 | if (IS_ERR(rtc)) { |
286 | dev_err(&pdev->dev, "cannot attach rtc\n"); | 286 | dev_err(&pdev->dev, "cannot attach rtc\n"); |
287 | ret = PTR_ERR(rtc); | 287 | ret = PTR_ERR(rtc); |
288 | goto err_nortc; | 288 | goto err_nortc; |
289 | } | 289 | } |
290 | 290 | ||
291 | /* platform setup code should have handled this; sigh */ | 291 | /* platform setup code should have handled this; sigh */ |
292 | if (!device_can_wakeup(&pdev->dev)) | 292 | if (!device_can_wakeup(&pdev->dev)) |
293 | device_init_wakeup(&pdev->dev, 1); | 293 | device_init_wakeup(&pdev->dev, 1); |
294 | 294 | ||
295 | platform_set_drvdata(pdev, rtc); | 295 | platform_set_drvdata(pdev, rtc); |
296 | return 0; | 296 | return 0; |
297 | 297 | ||
298 | err_nortc: | 298 | err_nortc: |
299 | puv3_rtc_enable(pdev, 0); | 299 | puv3_rtc_enable(pdev, 0); |
300 | release_resource(puv3_rtc_mem); | 300 | release_resource(puv3_rtc_mem); |
301 | 301 | ||
302 | err_nores: | 302 | err_nores: |
303 | return ret; | 303 | return ret; |
304 | } | 304 | } |
305 | 305 | ||
306 | #ifdef CONFIG_PM | 306 | #ifdef CONFIG_PM |
307 | 307 | ||
308 | static int ticnt_save; | 308 | static int ticnt_save; |
309 | 309 | ||
310 | static int puv3_rtc_suspend(struct platform_device *pdev, pm_message_t state) | 310 | static int puv3_rtc_suspend(struct platform_device *pdev, pm_message_t state) |
311 | { | 311 | { |
312 | /* save RTAR for anyone using periodic interrupts */ | 312 | /* save RTAR for anyone using periodic interrupts */ |
313 | ticnt_save = readl(RTC_RTAR); | 313 | ticnt_save = readl(RTC_RTAR); |
314 | puv3_rtc_enable(pdev, 0); | 314 | puv3_rtc_enable(pdev, 0); |
315 | return 0; | 315 | return 0; |
316 | } | 316 | } |
317 | 317 | ||
318 | static int puv3_rtc_resume(struct platform_device *pdev) | 318 | static int puv3_rtc_resume(struct platform_device *pdev) |
319 | { | 319 | { |
320 | puv3_rtc_enable(pdev, 1); | 320 | puv3_rtc_enable(pdev, 1); |
321 | writel(ticnt_save, RTC_RTAR); | 321 | writel(ticnt_save, RTC_RTAR); |
322 | return 0; | 322 | return 0; |
323 | } | 323 | } |
324 | #else | 324 | #else |
325 | #define puv3_rtc_suspend NULL | 325 | #define puv3_rtc_suspend NULL |
326 | #define puv3_rtc_resume NULL | 326 | #define puv3_rtc_resume NULL |
327 | #endif | 327 | #endif |
328 | 328 | ||
329 | static struct platform_driver puv3_rtcdrv = { | 329 | static struct platform_driver puv3_rtcdrv = { |
330 | .probe = puv3_rtc_probe, | 330 | .probe = puv3_rtc_probe, |
331 | .remove = __devexit_p(puv3_rtc_remove), | 331 | .remove = __devexit_p(puv3_rtc_remove), |
332 | .suspend = puv3_rtc_suspend, | 332 | .suspend = puv3_rtc_suspend, |
333 | .resume = puv3_rtc_resume, | 333 | .resume = puv3_rtc_resume, |
334 | .driver = { | 334 | .driver = { |
335 | .name = "PKUnity-v3-RTC", | 335 | .name = "PKUnity-v3-RTC", |
336 | .owner = THIS_MODULE, | 336 | .owner = THIS_MODULE, |
337 | } | 337 | } |
338 | }; | 338 | }; |
339 | 339 | ||
340 | static char __initdata banner[] = "PKUnity-v3 RTC, (c) 2009 PKUnity Co.\n"; | 340 | module_platform_driver(puv3_rtcdrv); |
341 | |||
342 | static int __init puv3_rtc_init(void) | ||
343 | { | ||
344 | printk(banner); | ||
345 | return platform_driver_register(&puv3_rtcdrv); | ||
346 | } | ||
347 | |||
348 | static void __exit puv3_rtc_exit(void) | ||
349 | { | ||
350 | platform_driver_unregister(&puv3_rtcdrv); | ||
351 | } | ||
352 | |||
353 | module_init(puv3_rtc_init); | ||
354 | module_exit(puv3_rtc_exit); | ||
355 | 341 | ||
356 | MODULE_DESCRIPTION("RTC Driver for the PKUnity v3 chip"); | 342 | MODULE_DESCRIPTION("RTC Driver for the PKUnity v3 chip"); |
357 | MODULE_AUTHOR("Hu Dongliang"); | 343 | MODULE_AUTHOR("Hu Dongliang"); |
358 | MODULE_LICENSE("GPL v2"); | 344 | MODULE_LICENSE("GPL v2"); |
359 | 345 |