diff options
Diffstat (limited to 'drivers/rtc/rtc-ds1553.c')
-rw-r--r-- | drivers/rtc/rtc-ds1553.c | 154 |
1 files changed, 71 insertions, 83 deletions
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index 717288527c6b..ff432e2ca275 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/bcd.h> | 11 | #include <linux/bcd.h> |
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/gfp.h> | ||
14 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
15 | #include <linux/jiffies.h> | 16 | #include <linux/jiffies.h> |
16 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
@@ -18,7 +19,7 @@ | |||
18 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
19 | #include <linux/io.h> | 20 | #include <linux/io.h> |
20 | 21 | ||
21 | #define DRV_VERSION "0.2" | 22 | #define DRV_VERSION "0.3" |
22 | 23 | ||
23 | #define RTC_REG_SIZE 0x2000 | 24 | #define RTC_REG_SIZE 0x2000 |
24 | #define RTC_OFFSET 0x1ff0 | 25 | #define RTC_OFFSET 0x1ff0 |
@@ -61,7 +62,6 @@ | |||
61 | struct rtc_plat_data { | 62 | struct rtc_plat_data { |
62 | struct rtc_device *rtc; | 63 | struct rtc_device *rtc; |
63 | void __iomem *ioaddr; | 64 | void __iomem *ioaddr; |
64 | resource_size_t baseaddr; | ||
65 | unsigned long last_jiffies; | 65 | unsigned long last_jiffies; |
66 | int irq; | 66 | int irq; |
67 | unsigned int irqen; | 67 | unsigned int irqen; |
@@ -69,6 +69,7 @@ struct rtc_plat_data { | |||
69 | int alrm_min; | 69 | int alrm_min; |
70 | int alrm_hour; | 70 | int alrm_hour; |
71 | int alrm_mday; | 71 | int alrm_mday; |
72 | spinlock_t lock; | ||
72 | }; | 73 | }; |
73 | 74 | ||
74 | static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm) | 75 | static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm) |
@@ -139,7 +140,7 @@ static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata) | |||
139 | void __iomem *ioaddr = pdata->ioaddr; | 140 | void __iomem *ioaddr = pdata->ioaddr; |
140 | unsigned long flags; | 141 | unsigned long flags; |
141 | 142 | ||
142 | spin_lock_irqsave(&pdata->rtc->irq_lock, flags); | 143 | spin_lock_irqsave(&pdata->lock, flags); |
143 | writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? | 144 | writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? |
144 | 0x80 : bin2bcd(pdata->alrm_mday), | 145 | 0x80 : bin2bcd(pdata->alrm_mday), |
145 | ioaddr + RTC_DATE_ALARM); | 146 | ioaddr + RTC_DATE_ALARM); |
@@ -154,7 +155,7 @@ static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata) | |||
154 | ioaddr + RTC_SECONDS_ALARM); | 155 | ioaddr + RTC_SECONDS_ALARM); |
155 | writeb(pdata->irqen ? RTC_INTS_AE : 0, ioaddr + RTC_INTERRUPTS); | 156 | writeb(pdata->irqen ? RTC_INTS_AE : 0, ioaddr + RTC_INTERRUPTS); |
156 | readb(ioaddr + RTC_FLAGS); /* clear interrupts */ | 157 | readb(ioaddr + RTC_FLAGS); /* clear interrupts */ |
157 | spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags); | 158 | spin_unlock_irqrestore(&pdata->lock, flags); |
158 | } | 159 | } |
159 | 160 | ||
160 | static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | 161 | static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
@@ -194,64 +195,69 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id) | |||
194 | struct platform_device *pdev = dev_id; | 195 | struct platform_device *pdev = dev_id; |
195 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 196 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
196 | void __iomem *ioaddr = pdata->ioaddr; | 197 | void __iomem *ioaddr = pdata->ioaddr; |
197 | unsigned long events = RTC_IRQF; | 198 | unsigned long events = 0; |
198 | 199 | ||
200 | spin_lock(&pdata->lock); | ||
199 | /* read and clear interrupt */ | 201 | /* read and clear interrupt */ |
200 | if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF)) | 202 | if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF) { |
201 | return IRQ_NONE; | 203 | events = RTC_IRQF; |
202 | if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) | 204 | if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) |
203 | events |= RTC_UF; | 205 | events |= RTC_UF; |
204 | else | 206 | else |
205 | events |= RTC_AF; | 207 | events |= RTC_AF; |
206 | rtc_update_irq(pdata->rtc, 1, events); | 208 | if (likely(pdata->rtc)) |
207 | return IRQ_HANDLED; | 209 | rtc_update_irq(pdata->rtc, 1, events); |
210 | } | ||
211 | spin_unlock(&pdata->lock); | ||
212 | return events ? IRQ_HANDLED : IRQ_NONE; | ||
208 | } | 213 | } |
209 | 214 | ||
210 | static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd, | 215 | static int ds1553_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) |
211 | unsigned long arg) | ||
212 | { | 216 | { |
213 | struct platform_device *pdev = to_platform_device(dev); | 217 | struct platform_device *pdev = to_platform_device(dev); |
214 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 218 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
215 | 219 | ||
216 | if (pdata->irq <= 0) | 220 | if (pdata->irq <= 0) |
217 | return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ | 221 | return -EINVAL; |
218 | switch (cmd) { | 222 | 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; | 223 | pdata->irqen |= RTC_AF; |
225 | ds1553_rtc_update_alarm(pdata); | 224 | else |
226 | break; | 225 | pdata->irqen &= ~RTC_AF; |
227 | case RTC_UIE_OFF: | 226 | ds1553_rtc_update_alarm(pdata); |
228 | pdata->irqen &= ~RTC_UF; | 227 | return 0; |
229 | ds1553_rtc_update_alarm(pdata); | 228 | } |
230 | break; | 229 | |
231 | case RTC_UIE_ON: | 230 | static int ds1553_rtc_update_irq_enable(struct device *dev, |
231 | unsigned int enabled) | ||
232 | { | ||
233 | struct platform_device *pdev = to_platform_device(dev); | ||
234 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
235 | |||
236 | if (pdata->irq <= 0) | ||
237 | return -EINVAL; | ||
238 | if (enabled) | ||
232 | pdata->irqen |= RTC_UF; | 239 | pdata->irqen |= RTC_UF; |
233 | ds1553_rtc_update_alarm(pdata); | 240 | else |
234 | break; | 241 | pdata->irqen &= ~RTC_UF; |
235 | default: | 242 | ds1553_rtc_update_alarm(pdata); |
236 | return -ENOIOCTLCMD; | ||
237 | } | ||
238 | return 0; | 243 | return 0; |
239 | } | 244 | } |
240 | 245 | ||
241 | static const struct rtc_class_ops ds1553_rtc_ops = { | 246 | static const struct rtc_class_ops ds1553_rtc_ops = { |
242 | .read_time = ds1553_rtc_read_time, | 247 | .read_time = ds1553_rtc_read_time, |
243 | .set_time = ds1553_rtc_set_time, | 248 | .set_time = ds1553_rtc_set_time, |
244 | .read_alarm = ds1553_rtc_read_alarm, | 249 | .read_alarm = ds1553_rtc_read_alarm, |
245 | .set_alarm = ds1553_rtc_set_alarm, | 250 | .set_alarm = ds1553_rtc_set_alarm, |
246 | .ioctl = ds1553_rtc_ioctl, | 251 | .alarm_irq_enable = ds1553_rtc_alarm_irq_enable, |
252 | .update_irq_enable = ds1553_rtc_update_irq_enable, | ||
247 | }; | 253 | }; |
248 | 254 | ||
249 | static ssize_t ds1553_nvram_read(struct kobject *kobj, | 255 | static ssize_t ds1553_nvram_read(struct file *filp, struct kobject *kobj, |
250 | struct bin_attribute *bin_attr, | 256 | struct bin_attribute *bin_attr, |
251 | char *buf, loff_t pos, size_t size) | 257 | char *buf, loff_t pos, size_t size) |
252 | { | 258 | { |
253 | struct platform_device *pdev = | 259 | struct device *dev = container_of(kobj, struct device, kobj); |
254 | to_platform_device(container_of(kobj, struct device, kobj)); | 260 | struct platform_device *pdev = to_platform_device(dev); |
255 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 261 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
256 | void __iomem *ioaddr = pdata->ioaddr; | 262 | void __iomem *ioaddr = pdata->ioaddr; |
257 | ssize_t count; | 263 | ssize_t count; |
@@ -261,12 +267,12 @@ static ssize_t ds1553_nvram_read(struct kobject *kobj, | |||
261 | return count; | 267 | return count; |
262 | } | 268 | } |
263 | 269 | ||
264 | static ssize_t ds1553_nvram_write(struct kobject *kobj, | 270 | static ssize_t ds1553_nvram_write(struct file *filp, struct kobject *kobj, |
265 | struct bin_attribute *bin_attr, | 271 | struct bin_attribute *bin_attr, |
266 | char *buf, loff_t pos, size_t size) | 272 | char *buf, loff_t pos, size_t size) |
267 | { | 273 | { |
268 | struct platform_device *pdev = | 274 | struct device *dev = container_of(kobj, struct device, kobj); |
269 | to_platform_device(container_of(kobj, struct device, kobj)); | 275 | struct platform_device *pdev = to_platform_device(dev); |
270 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 276 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
271 | void __iomem *ioaddr = pdata->ioaddr; | 277 | void __iomem *ioaddr = pdata->ioaddr; |
272 | ssize_t count; | 278 | ssize_t count; |
@@ -291,26 +297,23 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) | |||
291 | struct rtc_device *rtc; | 297 | struct rtc_device *rtc; |
292 | struct resource *res; | 298 | struct resource *res; |
293 | unsigned int cen, sec; | 299 | unsigned int cen, sec; |
294 | struct rtc_plat_data *pdata = NULL; | 300 | struct rtc_plat_data *pdata; |
295 | void __iomem *ioaddr = NULL; | 301 | void __iomem *ioaddr; |
296 | int ret = 0; | 302 | int ret = 0; |
297 | 303 | ||
298 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 304 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
299 | if (!res) | 305 | if (!res) |
300 | return -ENODEV; | 306 | return -ENODEV; |
301 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | 307 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
302 | if (!pdata) | 308 | if (!pdata) |
303 | return -ENOMEM; | 309 | return -ENOMEM; |
304 | if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { | 310 | if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE, |
305 | ret = -EBUSY; | 311 | pdev->name)) |
306 | goto out; | 312 | return -EBUSY; |
307 | } | 313 | |
308 | pdata->baseaddr = res->start; | 314 | ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE); |
309 | ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE); | 315 | if (!ioaddr) |
310 | if (!ioaddr) { | 316 | return -ENOMEM; |
311 | ret = -ENOMEM; | ||
312 | goto out; | ||
313 | } | ||
314 | pdata->ioaddr = ioaddr; | 317 | pdata->ioaddr = ioaddr; |
315 | pdata->irq = platform_get_irq(pdev, 0); | 318 | pdata->irq = platform_get_irq(pdev, 0); |
316 | 319 | ||
@@ -326,9 +329,13 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) | |||
326 | if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_BLF) | 329 | if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_BLF) |
327 | dev_warn(&pdev->dev, "voltage-low detected.\n"); | 330 | dev_warn(&pdev->dev, "voltage-low detected.\n"); |
328 | 331 | ||
332 | spin_lock_init(&pdata->lock); | ||
333 | pdata->last_jiffies = jiffies; | ||
334 | platform_set_drvdata(pdev, pdata); | ||
329 | if (pdata->irq > 0) { | 335 | if (pdata->irq > 0) { |
330 | writeb(0, ioaddr + RTC_INTERRUPTS); | 336 | writeb(0, ioaddr + RTC_INTERRUPTS); |
331 | if (request_irq(pdata->irq, ds1553_rtc_interrupt, | 337 | if (devm_request_irq(&pdev->dev, pdata->irq, |
338 | ds1553_rtc_interrupt, | ||
332 | IRQF_DISABLED, pdev->name, pdev) < 0) { | 339 | IRQF_DISABLED, pdev->name, pdev) < 0) { |
333 | dev_warn(&pdev->dev, "interrupt not available.\n"); | 340 | dev_warn(&pdev->dev, "interrupt not available.\n"); |
334 | pdata->irq = 0; | 341 | pdata->irq = 0; |
@@ -337,27 +344,13 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) | |||
337 | 344 | ||
338 | rtc = rtc_device_register(pdev->name, &pdev->dev, | 345 | rtc = rtc_device_register(pdev->name, &pdev->dev, |
339 | &ds1553_rtc_ops, THIS_MODULE); | 346 | &ds1553_rtc_ops, THIS_MODULE); |
340 | if (IS_ERR(rtc)) { | 347 | if (IS_ERR(rtc)) |
341 | ret = PTR_ERR(rtc); | 348 | return PTR_ERR(rtc); |
342 | goto out; | ||
343 | } | ||
344 | pdata->rtc = rtc; | 349 | pdata->rtc = rtc; |
345 | pdata->last_jiffies = jiffies; | 350 | |
346 | platform_set_drvdata(pdev, pdata); | ||
347 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); | 351 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); |
348 | if (ret) | 352 | if (ret) |
349 | goto out; | 353 | 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; | 354 | return ret; |
362 | } | 355 | } |
363 | 356 | ||
@@ -367,13 +360,8 @@ static int __devexit ds1553_rtc_remove(struct platform_device *pdev) | |||
367 | 360 | ||
368 | sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); | 361 | sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); |
369 | rtc_device_unregister(pdata->rtc); | 362 | rtc_device_unregister(pdata->rtc); |
370 | if (pdata->irq > 0) { | 363 | if (pdata->irq > 0) |
371 | writeb(0, pdata->ioaddr + RTC_INTERRUPTS); | 364 | 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; | 365 | return 0; |
378 | } | 366 | } |
379 | 367 | ||