aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-ds1553.c
diff options
context:
space:
mode:
authorAtsushi Nemoto <anemo@mba.ocn.ne.jp>2009-12-15 19:46:01 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-16 10:19:59 -0500
commit618161f71cb10ff9bfe74c9bd766faf339f98274 (patch)
treea5c9c77aa4359d023f3c4cd3ebdc2c7b5cc3bf8b /drivers/rtc/rtc-ds1553.c
parentaf69a180e0675ce95842adb519079204ee5647ea (diff)
rtc-ds1553: fix races around device registration
* Call dev_set_drvdata before rtc device creation * Use its own spinlock instead of rtc->irq_lock * Check pdata->rtc before calling rtc_update_irq * Use {alarm,update}_irq_enable and remove ioctl routine * Use devres APIs and simplify error/remove path Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Acked-by: Alessandro Zummo <a.zummo@towertech.it> Cc: David Brownell <david-b@pacbell.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc/rtc-ds1553.c')
-rw-r--r--drivers/rtc/rtc-ds1553.c141
1 files changed, 64 insertions, 77 deletions
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index 717288527c6b..dadd0f517d5a 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -18,7 +18,7 @@
18#include <linux/platform_device.h> 18#include <linux/platform_device.h>
19#include <linux/io.h> 19#include <linux/io.h>
20 20
21#define DRV_VERSION "0.2" 21#define DRV_VERSION "0.3"
22 22
23#define RTC_REG_SIZE 0x2000 23#define RTC_REG_SIZE 0x2000
24#define RTC_OFFSET 0x1ff0 24#define RTC_OFFSET 0x1ff0
@@ -61,7 +61,6 @@
61struct rtc_plat_data { 61struct rtc_plat_data {
62 struct rtc_device *rtc; 62 struct rtc_device *rtc;
63 void __iomem *ioaddr; 63 void __iomem *ioaddr;
64 resource_size_t baseaddr;
65 unsigned long last_jiffies; 64 unsigned long last_jiffies;
66 int irq; 65 int irq;
67 unsigned int irqen; 66 unsigned int irqen;
@@ -69,6 +68,7 @@ struct rtc_plat_data {
69 int alrm_min; 68 int alrm_min;
70 int alrm_hour; 69 int alrm_hour;
71 int alrm_mday; 70 int alrm_mday;
71 spinlock_t lock;
72}; 72};
73 73
74static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm) 74static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm)
@@ -139,7 +139,7 @@ static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata)
139 void __iomem *ioaddr = pdata->ioaddr; 139 void __iomem *ioaddr = pdata->ioaddr;
140 unsigned long flags; 140 unsigned long flags;
141 141
142 spin_lock_irqsave(&pdata->rtc->irq_lock, flags); 142 spin_lock_irqsave(&pdata->lock, flags);
143 writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? 143 writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
144 0x80 : bin2bcd(pdata->alrm_mday), 144 0x80 : bin2bcd(pdata->alrm_mday),
145 ioaddr + RTC_DATE_ALARM); 145 ioaddr + RTC_DATE_ALARM);
@@ -154,7 +154,7 @@ static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata)
154 ioaddr + RTC_SECONDS_ALARM); 154 ioaddr + RTC_SECONDS_ALARM);
155 writeb(pdata->irqen ? RTC_INTS_AE : 0, ioaddr + RTC_INTERRUPTS); 155 writeb(pdata->irqen ? RTC_INTS_AE : 0, ioaddr + RTC_INTERRUPTS);
156 readb(ioaddr + RTC_FLAGS); /* clear interrupts */ 156 readb(ioaddr + RTC_FLAGS); /* clear interrupts */
157 spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags); 157 spin_unlock_irqrestore(&pdata->lock, flags);
158} 158}
159 159
160static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 160static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -194,56 +194,61 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id)
194 struct platform_device *pdev = dev_id; 194 struct platform_device *pdev = dev_id;
195 struct rtc_plat_data *pdata = platform_get_drvdata(pdev); 195 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
196 void __iomem *ioaddr = pdata->ioaddr; 196 void __iomem *ioaddr = pdata->ioaddr;
197 unsigned long events = RTC_IRQF; 197 unsigned long events = 0;
198 198
199 spin_lock(&pdata->lock);
199 /* read and clear interrupt */ 200 /* read and clear interrupt */
200 if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF)) 201 if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF) {
201 return IRQ_NONE; 202 events = RTC_IRQF;
202 if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) 203 if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80)
203 events |= RTC_UF; 204 events |= RTC_UF;
204 else 205 else
205 events |= RTC_AF; 206 events |= RTC_AF;
206 rtc_update_irq(pdata->rtc, 1, events); 207 if (likely(pdata->rtc))
207 return IRQ_HANDLED; 208 rtc_update_irq(pdata->rtc, 1, events);
209 }
210 spin_unlock(&pdata->lock);
211 return events ? IRQ_HANDLED : IRQ_NONE;
208} 212}
209 213
210static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd, 214static int ds1553_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
211 unsigned long arg)
212{ 215{
213 struct platform_device *pdev = to_platform_device(dev); 216 struct platform_device *pdev = to_platform_device(dev);
214 struct rtc_plat_data *pdata = platform_get_drvdata(pdev); 217 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
215 218
216 if (pdata->irq <= 0) 219 if (pdata->irq <= 0)
217 return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ 220 return -EINVAL;
218 switch (cmd) { 221 if (enabled)
219 case RTC_AIE_OFF:
220 pdata->irqen &= ~RTC_AF;
221 ds1553_rtc_update_alarm(pdata);
222 break;
223 case RTC_AIE_ON:
224 pdata->irqen |= RTC_AF; 222 pdata->irqen |= RTC_AF;
225 ds1553_rtc_update_alarm(pdata); 223 else
226 break; 224 pdata->irqen &= ~RTC_AF;
227 case RTC_UIE_OFF: 225 ds1553_rtc_update_alarm(pdata);
228 pdata->irqen &= ~RTC_UF; 226 return 0;
229 ds1553_rtc_update_alarm(pdata); 227}
230 break; 228
231 case RTC_UIE_ON: 229static int ds1553_rtc_update_irq_enable(struct device *dev,
230 unsigned int enabled)
231{
232 struct platform_device *pdev = to_platform_device(dev);
233 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
234
235 if (pdata->irq <= 0)
236 return -EINVAL;
237 if (enabled)
232 pdata->irqen |= RTC_UF; 238 pdata->irqen |= RTC_UF;
233 ds1553_rtc_update_alarm(pdata); 239 else
234 break; 240 pdata->irqen &= ~RTC_UF;
235 default: 241 ds1553_rtc_update_alarm(pdata);
236 return -ENOIOCTLCMD;
237 }
238 return 0; 242 return 0;
239} 243}
240 244
241static const struct rtc_class_ops ds1553_rtc_ops = { 245static const struct rtc_class_ops ds1553_rtc_ops = {
242 .read_time = ds1553_rtc_read_time, 246 .read_time = ds1553_rtc_read_time,
243 .set_time = ds1553_rtc_set_time, 247 .set_time = ds1553_rtc_set_time,
244 .read_alarm = ds1553_rtc_read_alarm, 248 .read_alarm = ds1553_rtc_read_alarm,
245 .set_alarm = ds1553_rtc_set_alarm, 249 .set_alarm = ds1553_rtc_set_alarm,
246 .ioctl = ds1553_rtc_ioctl, 250 .alarm_irq_enable = ds1553_rtc_alarm_irq_enable,
251 .update_irq_enable = ds1553_rtc_update_irq_enable,
247}; 252};
248 253
249static ssize_t ds1553_nvram_read(struct kobject *kobj, 254static ssize_t ds1553_nvram_read(struct kobject *kobj,
@@ -291,26 +296,23 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev)
291 struct rtc_device *rtc; 296 struct rtc_device *rtc;
292 struct resource *res; 297 struct resource *res;
293 unsigned int cen, sec; 298 unsigned int cen, sec;
294 struct rtc_plat_data *pdata = NULL; 299 struct rtc_plat_data *pdata;
295 void __iomem *ioaddr = NULL; 300 void __iomem *ioaddr;
296 int ret = 0; 301 int ret = 0;
297 302
298 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 303 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
299 if (!res) 304 if (!res)
300 return -ENODEV; 305 return -ENODEV;
301 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); 306 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
302 if (!pdata) 307 if (!pdata)
303 return -ENOMEM; 308 return -ENOMEM;
304 if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { 309 if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE,
305 ret = -EBUSY; 310 pdev->name))
306 goto out; 311 return -EBUSY;
307 } 312
308 pdata->baseaddr = res->start; 313 ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE);
309 ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE); 314 if (!ioaddr)
310 if (!ioaddr) { 315 return -ENOMEM;
311 ret = -ENOMEM;
312 goto out;
313 }
314 pdata->ioaddr = ioaddr; 316 pdata->ioaddr = ioaddr;
315 pdata->irq = platform_get_irq(pdev, 0); 317 pdata->irq = platform_get_irq(pdev, 0);
316 318
@@ -326,9 +328,13 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev)
326 if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_BLF) 328 if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_BLF)
327 dev_warn(&pdev->dev, "voltage-low detected.\n"); 329 dev_warn(&pdev->dev, "voltage-low detected.\n");
328 330
331 spin_lock_init(&pdata->lock);
332 pdata->last_jiffies = jiffies;
333 platform_set_drvdata(pdev, pdata);
329 if (pdata->irq > 0) { 334 if (pdata->irq > 0) {
330 writeb(0, ioaddr + RTC_INTERRUPTS); 335 writeb(0, ioaddr + RTC_INTERRUPTS);
331 if (request_irq(pdata->irq, ds1553_rtc_interrupt, 336 if (devm_request_irq(&pdev->dev, pdata->irq,
337 ds1553_rtc_interrupt,
332 IRQF_DISABLED, pdev->name, pdev) < 0) { 338 IRQF_DISABLED, pdev->name, pdev) < 0) {
333 dev_warn(&pdev->dev, "interrupt not available.\n"); 339 dev_warn(&pdev->dev, "interrupt not available.\n");
334 pdata->irq = 0; 340 pdata->irq = 0;
@@ -337,27 +343,13 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev)
337 343
338 rtc = rtc_device_register(pdev->name, &pdev->dev, 344 rtc = rtc_device_register(pdev->name, &pdev->dev,
339 &ds1553_rtc_ops, THIS_MODULE); 345 &ds1553_rtc_ops, THIS_MODULE);
340 if (IS_ERR(rtc)) { 346 if (IS_ERR(rtc))
341 ret = PTR_ERR(rtc); 347 return PTR_ERR(rtc);
342 goto out;
343 }
344 pdata->rtc = rtc; 348 pdata->rtc = rtc;
345 pdata->last_jiffies = jiffies; 349
346 platform_set_drvdata(pdev, pdata);
347 ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); 350 ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
348 if (ret) 351 if (ret)
349 goto out; 352 rtc_device_unregister(rtc);
350 return 0;
351 out:
352 if (pdata->rtc)
353 rtc_device_unregister(pdata->rtc);
354 if (pdata->irq > 0)
355 free_irq(pdata->irq, pdev);
356 if (ioaddr)
357 iounmap(ioaddr);
358 if (pdata->baseaddr)
359 release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
360 kfree(pdata);
361 return ret; 353 return ret;
362} 354}
363 355
@@ -367,13 +359,8 @@ static int __devexit ds1553_rtc_remove(struct platform_device *pdev)
367 359
368 sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); 360 sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
369 rtc_device_unregister(pdata->rtc); 361 rtc_device_unregister(pdata->rtc);
370 if (pdata->irq > 0) { 362 if (pdata->irq > 0)
371 writeb(0, pdata->ioaddr + RTC_INTERRUPTS); 363 writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
372 free_irq(pdata->irq, pdev);
373 }
374 iounmap(pdata->ioaddr);
375 release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
376 kfree(pdata);
377 return 0; 364 return 0;
378} 365}
379 366