diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/rtc/rtc-stk17ta8.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/rtc/rtc-stk17ta8.c')
-rw-r--r-- | drivers/rtc/rtc-stk17ta8.c | 127 |
1 files changed, 52 insertions, 75 deletions
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c index 7d1547b0070e..875ba099e7a5 100644 --- a/drivers/rtc/rtc-stk17ta8.c +++ b/drivers/rtc/rtc-stk17ta8.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/bcd.h> | 14 | #include <linux/bcd.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/gfp.h> | ||
17 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
18 | #include <linux/jiffies.h> | 19 | #include <linux/jiffies.h> |
19 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
@@ -62,7 +63,6 @@ | |||
62 | struct rtc_plat_data { | 63 | struct rtc_plat_data { |
63 | struct rtc_device *rtc; | 64 | struct rtc_device *rtc; |
64 | void __iomem *ioaddr; | 65 | void __iomem *ioaddr; |
65 | unsigned long baseaddr; | ||
66 | unsigned long last_jiffies; | 66 | unsigned long last_jiffies; |
67 | int irq; | 67 | int irq; |
68 | unsigned int irqen; | 68 | unsigned int irqen; |
@@ -70,6 +70,7 @@ struct rtc_plat_data { | |||
70 | int alrm_min; | 70 | int alrm_min; |
71 | int alrm_hour; | 71 | int alrm_hour; |
72 | int alrm_mday; | 72 | int alrm_mday; |
73 | spinlock_t lock; | ||
73 | }; | 74 | }; |
74 | 75 | ||
75 | static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm) | 76 | static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm) |
@@ -142,7 +143,7 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata) | |||
142 | unsigned long irqflags; | 143 | unsigned long irqflags; |
143 | u8 flags; | 144 | u8 flags; |
144 | 145 | ||
145 | spin_lock_irqsave(&pdata->rtc->irq_lock, irqflags); | 146 | spin_lock_irqsave(&pdata->lock, irqflags); |
146 | 147 | ||
147 | flags = readb(ioaddr + RTC_FLAGS); | 148 | flags = readb(ioaddr + RTC_FLAGS); |
148 | writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS); | 149 | writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS); |
@@ -162,7 +163,7 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata) | |||
162 | writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS); | 163 | writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS); |
163 | readb(ioaddr + RTC_FLAGS); /* clear interrupts */ | 164 | readb(ioaddr + RTC_FLAGS); /* clear interrupts */ |
164 | writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS); | 165 | writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS); |
165 | spin_unlock_irqrestore(&pdata->rtc->irq_lock, irqflags); | 166 | spin_unlock_irqrestore(&pdata->lock, irqflags); |
166 | } | 167 | } |
167 | 168 | ||
168 | static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | 169 | static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
@@ -202,56 +203,53 @@ static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id) | |||
202 | struct platform_device *pdev = dev_id; | 203 | struct platform_device *pdev = dev_id; |
203 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 204 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
204 | void __iomem *ioaddr = pdata->ioaddr; | 205 | void __iomem *ioaddr = pdata->ioaddr; |
205 | unsigned long events = RTC_IRQF; | 206 | unsigned long events = 0; |
206 | 207 | ||
208 | spin_lock(&pdata->lock); | ||
207 | /* read and clear interrupt */ | 209 | /* read and clear interrupt */ |
208 | if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF)) | 210 | if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF) { |
209 | return IRQ_NONE; | 211 | events = RTC_IRQF; |
210 | if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) | 212 | if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) |
211 | events |= RTC_UF; | 213 | events |= RTC_UF; |
212 | else | 214 | else |
213 | events |= RTC_AF; | 215 | events |= RTC_AF; |
214 | rtc_update_irq(pdata->rtc, 1, events); | 216 | if (likely(pdata->rtc)) |
215 | return IRQ_HANDLED; | 217 | rtc_update_irq(pdata->rtc, 1, events); |
218 | } | ||
219 | spin_unlock(&pdata->lock); | ||
220 | return events ? IRQ_HANDLED : IRQ_NONE; | ||
216 | } | 221 | } |
217 | 222 | ||
218 | static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd, | 223 | static int stk17ta8_rtc_alarm_irq_enable(struct device *dev, |
219 | unsigned long arg) | 224 | unsigned int enabled) |
220 | { | 225 | { |
221 | struct platform_device *pdev = to_platform_device(dev); | 226 | struct platform_device *pdev = to_platform_device(dev); |
222 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 227 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
223 | 228 | ||
224 | if (pdata->irq <= 0) | 229 | if (pdata->irq <= 0) |
225 | return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ | 230 | return -EINVAL; |
226 | switch (cmd) { | 231 | if (enabled) |
227 | case RTC_AIE_OFF: | ||
228 | pdata->irqen &= ~RTC_AF; | ||
229 | stk17ta8_rtc_update_alarm(pdata); | ||
230 | break; | ||
231 | case RTC_AIE_ON: | ||
232 | pdata->irqen |= RTC_AF; | 232 | pdata->irqen |= RTC_AF; |
233 | stk17ta8_rtc_update_alarm(pdata); | 233 | else |
234 | break; | 234 | pdata->irqen &= ~RTC_AF; |
235 | default: | 235 | stk17ta8_rtc_update_alarm(pdata); |
236 | return -ENOIOCTLCMD; | ||
237 | } | ||
238 | return 0; | 236 | return 0; |
239 | } | 237 | } |
240 | 238 | ||
241 | static const struct rtc_class_ops stk17ta8_rtc_ops = { | 239 | static const struct rtc_class_ops stk17ta8_rtc_ops = { |
242 | .read_time = stk17ta8_rtc_read_time, | 240 | .read_time = stk17ta8_rtc_read_time, |
243 | .set_time = stk17ta8_rtc_set_time, | 241 | .set_time = stk17ta8_rtc_set_time, |
244 | .read_alarm = stk17ta8_rtc_read_alarm, | 242 | .read_alarm = stk17ta8_rtc_read_alarm, |
245 | .set_alarm = stk17ta8_rtc_set_alarm, | 243 | .set_alarm = stk17ta8_rtc_set_alarm, |
246 | .ioctl = stk17ta8_rtc_ioctl, | 244 | .alarm_irq_enable = stk17ta8_rtc_alarm_irq_enable, |
247 | }; | 245 | }; |
248 | 246 | ||
249 | static ssize_t stk17ta8_nvram_read(struct kobject *kobj, | 247 | static ssize_t stk17ta8_nvram_read(struct kobject *kobj, |
250 | struct bin_attribute *attr, char *buf, | 248 | struct bin_attribute *attr, char *buf, |
251 | loff_t pos, size_t size) | 249 | loff_t pos, size_t size) |
252 | { | 250 | { |
253 | struct platform_device *pdev = | 251 | struct device *dev = container_of(kobj, struct device, kobj); |
254 | to_platform_device(container_of(kobj, struct device, kobj)); | 252 | struct platform_device *pdev = to_platform_device(dev); |
255 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 253 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
256 | void __iomem *ioaddr = pdata->ioaddr; | 254 | void __iomem *ioaddr = pdata->ioaddr; |
257 | ssize_t count; | 255 | ssize_t count; |
@@ -265,8 +263,8 @@ static ssize_t stk17ta8_nvram_write(struct kobject *kobj, | |||
265 | struct bin_attribute *attr, char *buf, | 263 | struct bin_attribute *attr, char *buf, |
266 | loff_t pos, size_t size) | 264 | loff_t pos, size_t size) |
267 | { | 265 | { |
268 | struct platform_device *pdev = | 266 | struct device *dev = container_of(kobj, struct device, kobj); |
269 | to_platform_device(container_of(kobj, struct device, kobj)); | 267 | struct platform_device *pdev = to_platform_device(dev); |
270 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 268 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
271 | void __iomem *ioaddr = pdata->ioaddr; | 269 | void __iomem *ioaddr = pdata->ioaddr; |
272 | ssize_t count; | 270 | ssize_t count; |
@@ -286,33 +284,28 @@ static struct bin_attribute stk17ta8_nvram_attr = { | |||
286 | .write = stk17ta8_nvram_write, | 284 | .write = stk17ta8_nvram_write, |
287 | }; | 285 | }; |
288 | 286 | ||
289 | static int __init stk17ta8_rtc_probe(struct platform_device *pdev) | 287 | static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev) |
290 | { | 288 | { |
291 | struct rtc_device *rtc; | ||
292 | struct resource *res; | 289 | struct resource *res; |
293 | unsigned int cal; | 290 | unsigned int cal; |
294 | unsigned int flags; | 291 | unsigned int flags; |
295 | struct rtc_plat_data *pdata; | 292 | struct rtc_plat_data *pdata; |
296 | void __iomem *ioaddr = NULL; | 293 | void __iomem *ioaddr; |
297 | int ret = 0; | 294 | int ret = 0; |
298 | 295 | ||
299 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 296 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
300 | if (!res) | 297 | if (!res) |
301 | return -ENODEV; | 298 | return -ENODEV; |
302 | 299 | ||
303 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | 300 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
304 | if (!pdata) | 301 | if (!pdata) |
305 | return -ENOMEM; | 302 | return -ENOMEM; |
306 | if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { | 303 | if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE, |
307 | ret = -EBUSY; | 304 | pdev->name)) |
308 | goto out; | 305 | return -EBUSY; |
309 | } | 306 | ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE); |
310 | pdata->baseaddr = res->start; | 307 | if (!ioaddr) |
311 | ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE); | 308 | return -ENOMEM; |
312 | if (!ioaddr) { | ||
313 | ret = -ENOMEM; | ||
314 | goto out; | ||
315 | } | ||
316 | pdata->ioaddr = ioaddr; | 309 | pdata->ioaddr = ioaddr; |
317 | pdata->irq = platform_get_irq(pdev, 0); | 310 | pdata->irq = platform_get_irq(pdev, 0); |
318 | 311 | ||
@@ -328,9 +321,13 @@ static int __init stk17ta8_rtc_probe(struct platform_device *pdev) | |||
328 | if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF) | 321 | if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF) |
329 | dev_warn(&pdev->dev, "voltage-low detected.\n"); | 322 | dev_warn(&pdev->dev, "voltage-low detected.\n"); |
330 | 323 | ||
324 | spin_lock_init(&pdata->lock); | ||
325 | pdata->last_jiffies = jiffies; | ||
326 | platform_set_drvdata(pdev, pdata); | ||
331 | if (pdata->irq > 0) { | 327 | if (pdata->irq > 0) { |
332 | writeb(0, ioaddr + RTC_INTERRUPTS); | 328 | writeb(0, ioaddr + RTC_INTERRUPTS); |
333 | if (request_irq(pdata->irq, stk17ta8_rtc_interrupt, | 329 | if (devm_request_irq(&pdev->dev, pdata->irq, |
330 | stk17ta8_rtc_interrupt, | ||
334 | IRQF_DISABLED | IRQF_SHARED, | 331 | IRQF_DISABLED | IRQF_SHARED, |
335 | pdev->name, pdev) < 0) { | 332 | pdev->name, pdev) < 0) { |
336 | dev_warn(&pdev->dev, "interrupt not available.\n"); | 333 | dev_warn(&pdev->dev, "interrupt not available.\n"); |
@@ -338,29 +335,14 @@ static int __init stk17ta8_rtc_probe(struct platform_device *pdev) | |||
338 | } | 335 | } |
339 | } | 336 | } |
340 | 337 | ||
341 | rtc = rtc_device_register(pdev->name, &pdev->dev, | 338 | pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, |
342 | &stk17ta8_rtc_ops, THIS_MODULE); | 339 | &stk17ta8_rtc_ops, THIS_MODULE); |
343 | if (IS_ERR(rtc)) { | 340 | if (IS_ERR(pdata->rtc)) |
344 | ret = PTR_ERR(rtc); | 341 | return PTR_ERR(pdata->rtc); |
345 | goto out; | 342 | |
346 | } | ||
347 | pdata->rtc = rtc; | ||
348 | pdata->last_jiffies = jiffies; | ||
349 | platform_set_drvdata(pdev, pdata); | ||
350 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); | 343 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); |
351 | if (ret) | 344 | if (ret) |
352 | goto out; | ||
353 | return 0; | ||
354 | out: | ||
355 | if (pdata->rtc) | ||
356 | rtc_device_unregister(pdata->rtc); | 345 | rtc_device_unregister(pdata->rtc); |
357 | if (pdata->irq > 0) | ||
358 | free_irq(pdata->irq, pdev); | ||
359 | if (ioaddr) | ||
360 | iounmap(ioaddr); | ||
361 | if (pdata->baseaddr) | ||
362 | release_mem_region(pdata->baseaddr, RTC_REG_SIZE); | ||
363 | kfree(pdata); | ||
364 | return ret; | 346 | return ret; |
365 | } | 347 | } |
366 | 348 | ||
@@ -370,13 +352,8 @@ static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev) | |||
370 | 352 | ||
371 | sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); | 353 | sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); |
372 | rtc_device_unregister(pdata->rtc); | 354 | rtc_device_unregister(pdata->rtc); |
373 | if (pdata->irq > 0) { | 355 | if (pdata->irq > 0) |
374 | writeb(0, pdata->ioaddr + RTC_INTERRUPTS); | 356 | writeb(0, pdata->ioaddr + RTC_INTERRUPTS); |
375 | free_irq(pdata->irq, pdev); | ||
376 | } | ||
377 | iounmap(pdata->ioaddr); | ||
378 | release_mem_region(pdata->baseaddr, RTC_REG_SIZE); | ||
379 | kfree(pdata); | ||
380 | return 0; | 357 | return 0; |
381 | } | 358 | } |
382 | 359 | ||