aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-ds1511.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc/rtc-ds1511.c')
-rw-r--r--drivers/rtc/rtc-ds1511.c163
1 files changed, 69 insertions, 94 deletions
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index 0b6b7730c716..37268e97de49 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -2,7 +2,7 @@
2 * An rtc driver for the Dallas DS1511 2 * An rtc driver for the Dallas DS1511
3 * 3 *
4 * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> 4 * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
5 * Copyright (C) 2007 Andrew Sharp <andy.sharp@onstor.com> 5 * Copyright (C) 2007 Andrew Sharp <andy.sharp@lsi.com>
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
@@ -17,6 +17,7 @@
17#include <linux/bcd.h> 17#include <linux/bcd.h>
18#include <linux/init.h> 18#include <linux/init.h>
19#include <linux/kernel.h> 19#include <linux/kernel.h>
20#include <linux/gfp.h>
20#include <linux/delay.h> 21#include <linux/delay.h>
21#include <linux/interrupt.h> 22#include <linux/interrupt.h>
22#include <linux/rtc.h> 23#include <linux/rtc.h>
@@ -87,7 +88,6 @@ enum ds1511reg {
87struct rtc_plat_data { 88struct rtc_plat_data {
88 struct rtc_device *rtc; 89 struct rtc_device *rtc;
89 void __iomem *ioaddr; /* virtual base address */ 90 void __iomem *ioaddr; /* virtual base address */
90 unsigned long baseaddr; /* physical base address */
91 int size; /* amount of memory mapped */ 91 int size; /* amount of memory mapped */
92 int irq; 92 int irq;
93 unsigned int irqen; 93 unsigned int irqen;
@@ -95,6 +95,7 @@ struct rtc_plat_data {
95 int alrm_min; 95 int alrm_min;
96 int alrm_hour; 96 int alrm_hour;
97 int alrm_mday; 97 int alrm_mday;
98 spinlock_t lock;
98}; 99};
99 100
100static DEFINE_SPINLOCK(ds1511_lock); 101static DEFINE_SPINLOCK(ds1511_lock);
@@ -302,7 +303,7 @@ ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
302{ 303{
303 unsigned long flags; 304 unsigned long flags;
304 305
305 spin_lock_irqsave(&pdata->rtc->irq_lock, flags); 306 spin_lock_irqsave(&pdata->lock, flags);
306 rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? 307 rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
307 0x80 : bin2bcd(pdata->alrm_mday) & 0x3f, 308 0x80 : bin2bcd(pdata->alrm_mday) & 0x3f,
308 RTC_ALARM_DATE); 309 RTC_ALARM_DATE);
@@ -317,7 +318,7 @@ ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
317 RTC_ALARM_SEC); 318 RTC_ALARM_SEC);
318 rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD); 319 rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD);
319 rtc_read(RTC_CMD1); /* clear interrupts */ 320 rtc_read(RTC_CMD1); /* clear interrupts */
320 spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags); 321 spin_unlock_irqrestore(&pdata->lock, flags);
321} 322}
322 323
323 static int 324 static int
@@ -362,66 +363,69 @@ ds1511_interrupt(int irq, void *dev_id)
362{ 363{
363 struct platform_device *pdev = dev_id; 364 struct platform_device *pdev = dev_id;
364 struct rtc_plat_data *pdata = platform_get_drvdata(pdev); 365 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
365 unsigned long events = RTC_IRQF; 366 unsigned long events = 0;
366 367
368 spin_lock(&pdata->lock);
367 /* 369 /*
368 * read and clear interrupt 370 * read and clear interrupt
369 */ 371 */
370 if (!(rtc_read(RTC_CMD1) & DS1511_IRQF)) { 372 if (rtc_read(RTC_CMD1) & DS1511_IRQF) {
371 return IRQ_NONE; 373 events = RTC_IRQF;
372 } 374 if (rtc_read(RTC_ALARM_SEC) & 0x80)
373 if (rtc_read(RTC_ALARM_SEC) & 0x80) { 375 events |= RTC_UF;
374 events |= RTC_UF; 376 else
375 } else { 377 events |= RTC_AF;
376 events |= RTC_AF; 378 if (likely(pdata->rtc))
377 } 379 rtc_update_irq(pdata->rtc, 1, events);
378 rtc_update_irq(pdata->rtc, 1, events); 380 }
379 return IRQ_HANDLED; 381 spin_unlock(&pdata->lock);
382 return events ? IRQ_HANDLED : IRQ_NONE;
380} 383}
381 384
382 static int 385static int ds1511_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
383ds1511_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
384{ 386{
385 struct platform_device *pdev = to_platform_device(dev); 387 struct platform_device *pdev = to_platform_device(dev);
386 struct rtc_plat_data *pdata = platform_get_drvdata(pdev); 388 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
387 389
388 if (pdata->irq <= 0) { 390 if (pdata->irq <= 0)
389 return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ 391 return -EINVAL;
390 } 392 if (enabled)
391 switch (cmd) {
392 case RTC_AIE_OFF:
393 pdata->irqen &= ~RTC_AF;
394 ds1511_rtc_update_alarm(pdata);
395 break;
396 case RTC_AIE_ON:
397 pdata->irqen |= RTC_AF; 393 pdata->irqen |= RTC_AF;
398 ds1511_rtc_update_alarm(pdata); 394 else
399 break; 395 pdata->irqen &= ~RTC_AF;
400 case RTC_UIE_OFF: 396 ds1511_rtc_update_alarm(pdata);
401 pdata->irqen &= ~RTC_UF; 397 return 0;
402 ds1511_rtc_update_alarm(pdata); 398}
403 break; 399
404 case RTC_UIE_ON: 400static int ds1511_rtc_update_irq_enable(struct device *dev,
401 unsigned int enabled)
402{
403 struct platform_device *pdev = to_platform_device(dev);
404 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
405
406 if (pdata->irq <= 0)
407 return -EINVAL;
408 if (enabled)
405 pdata->irqen |= RTC_UF; 409 pdata->irqen |= RTC_UF;
406 ds1511_rtc_update_alarm(pdata); 410 else
407 break; 411 pdata->irqen &= ~RTC_UF;
408 default: 412 ds1511_rtc_update_alarm(pdata);
409 return -ENOIOCTLCMD;
410 }
411 return 0; 413 return 0;
412} 414}
413 415
414static const struct rtc_class_ops ds1511_rtc_ops = { 416static const struct rtc_class_ops ds1511_rtc_ops = {
415 .read_time = ds1511_rtc_read_time, 417 .read_time = ds1511_rtc_read_time,
416 .set_time = ds1511_rtc_set_time, 418 .set_time = ds1511_rtc_set_time,
417 .read_alarm = ds1511_rtc_read_alarm, 419 .read_alarm = ds1511_rtc_read_alarm,
418 .set_alarm = ds1511_rtc_set_alarm, 420 .set_alarm = ds1511_rtc_set_alarm,
419 .ioctl = ds1511_rtc_ioctl, 421 .alarm_irq_enable = ds1511_rtc_alarm_irq_enable,
422 .update_irq_enable = ds1511_rtc_update_irq_enable,
420}; 423};
421 424
422 static ssize_t 425 static ssize_t
423ds1511_nvram_read(struct kobject *kobj, struct bin_attribute *ba, 426ds1511_nvram_read(struct file *filp, struct kobject *kobj,
424 char *buf, loff_t pos, size_t size) 427 struct bin_attribute *ba,
428 char *buf, loff_t pos, size_t size)
425{ 429{
426 ssize_t count; 430 ssize_t count;
427 431
@@ -449,8 +453,9 @@ ds1511_nvram_read(struct kobject *kobj, struct bin_attribute *ba,
449} 453}
450 454
451 static ssize_t 455 static ssize_t
452ds1511_nvram_write(struct kobject *kobj, struct bin_attribute *bin_attr, 456ds1511_nvram_write(struct file *filp, struct kobject *kobj,
453 char *buf, loff_t pos, size_t size) 457 struct bin_attribute *bin_attr,
458 char *buf, loff_t pos, size_t size)
454{ 459{
455 ssize_t count; 460 ssize_t count;
456 461
@@ -492,29 +497,23 @@ ds1511_rtc_probe(struct platform_device *pdev)
492{ 497{
493 struct rtc_device *rtc; 498 struct rtc_device *rtc;
494 struct resource *res; 499 struct resource *res;
495 struct rtc_plat_data *pdata = NULL; 500 struct rtc_plat_data *pdata;
496 int ret = 0; 501 int ret = 0;
497 502
498 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 503 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
499 if (!res) { 504 if (!res) {
500 return -ENODEV; 505 return -ENODEV;
501 } 506 }
502 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); 507 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
503 if (!pdata) { 508 if (!pdata)
504 return -ENOMEM; 509 return -ENOMEM;
505 }
506 pdata->size = res->end - res->start + 1; 510 pdata->size = res->end - res->start + 1;
507 if (!request_mem_region(res->start, pdata->size, pdev->name)) { 511 if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size,
508 ret = -EBUSY; 512 pdev->name))
509 goto out; 513 return -EBUSY;
510 } 514 ds1511_base = devm_ioremap(&pdev->dev, res->start, pdata->size);
511 pdata->baseaddr = res->start; 515 if (!ds1511_base)
512 pdata->size = pdata->size; 516 return -ENOMEM;
513 ds1511_base = ioremap(pdata->baseaddr, pdata->size);
514 if (!ds1511_base) {
515 ret = -ENOMEM;
516 goto out;
517 }
518 pdata->ioaddr = ds1511_base; 517 pdata->ioaddr = ds1511_base;
519 pdata->irq = platform_get_irq(pdev, 0); 518 pdata->irq = platform_get_irq(pdev, 0);
520 519
@@ -540,13 +539,15 @@ ds1511_rtc_probe(struct platform_device *pdev)
540 dev_warn(&pdev->dev, "voltage-low detected.\n"); 539 dev_warn(&pdev->dev, "voltage-low detected.\n");
541 } 540 }
542 541
542 spin_lock_init(&pdata->lock);
543 platform_set_drvdata(pdev, pdata);
543 /* 544 /*
544 * if the platform has an interrupt in mind for this device, 545 * if the platform has an interrupt in mind for this device,
545 * then by all means, set it 546 * then by all means, set it
546 */ 547 */
547 if (pdata->irq > 0) { 548 if (pdata->irq > 0) {
548 rtc_read(RTC_CMD1); 549 rtc_read(RTC_CMD1);
549 if (request_irq(pdata->irq, ds1511_interrupt, 550 if (devm_request_irq(&pdev->dev, pdata->irq, ds1511_interrupt,
550 IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) { 551 IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) {
551 552
552 dev_warn(&pdev->dev, "interrupt not available.\n"); 553 dev_warn(&pdev->dev, "interrupt not available.\n");
@@ -556,33 +557,13 @@ ds1511_rtc_probe(struct platform_device *pdev)
556 557
557 rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1511_rtc_ops, 558 rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1511_rtc_ops,
558 THIS_MODULE); 559 THIS_MODULE);
559 if (IS_ERR(rtc)) { 560 if (IS_ERR(rtc))
560 ret = PTR_ERR(rtc); 561 return PTR_ERR(rtc);
561 goto out;
562 }
563 pdata->rtc = rtc; 562 pdata->rtc = rtc;
564 platform_set_drvdata(pdev, pdata); 563
565 ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); 564 ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
566 if (ret) { 565 if (ret)
567 goto out;
568 }
569 return 0;
570 out:
571 if (pdata->rtc) {
572 rtc_device_unregister(pdata->rtc); 566 rtc_device_unregister(pdata->rtc);
573 }
574 if (pdata->irq > 0) {
575 free_irq(pdata->irq, pdev);
576 }
577 if (ds1511_base) {
578 iounmap(ds1511_base);
579 ds1511_base = NULL;
580 }
581 if (pdata->baseaddr) {
582 release_mem_region(pdata->baseaddr, pdata->size);
583 }
584
585 kfree(pdata);
586 return ret; 567 return ret;
587} 568}
588 569
@@ -593,19 +574,13 @@ ds1511_rtc_remove(struct platform_device *pdev)
593 574
594 sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); 575 sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
595 rtc_device_unregister(pdata->rtc); 576 rtc_device_unregister(pdata->rtc);
596 pdata->rtc = NULL;
597 if (pdata->irq > 0) { 577 if (pdata->irq > 0) {
598 /* 578 /*
599 * disable the alarm interrupt 579 * disable the alarm interrupt
600 */ 580 */
601 rtc_write(rtc_read(RTC_CMD) & ~RTC_TIE, RTC_CMD); 581 rtc_write(rtc_read(RTC_CMD) & ~RTC_TIE, RTC_CMD);
602 rtc_read(RTC_CMD1); 582 rtc_read(RTC_CMD1);
603 free_irq(pdata->irq, pdev);
604 } 583 }
605 iounmap(pdata->ioaddr);
606 ds1511_base = NULL;
607 release_mem_region(pdata->baseaddr, pdata->size);
608 kfree(pdata);
609 return 0; 584 return 0;
610} 585}
611 586
@@ -636,7 +611,7 @@ ds1511_rtc_exit(void)
636module_init(ds1511_rtc_init); 611module_init(ds1511_rtc_init);
637module_exit(ds1511_rtc_exit); 612module_exit(ds1511_rtc_exit);
638 613
639MODULE_AUTHOR("Andrew Sharp <andy.sharp@onstor.com>"); 614MODULE_AUTHOR("Andrew Sharp <andy.sharp@lsi.com>");
640MODULE_DESCRIPTION("Dallas DS1511 RTC driver"); 615MODULE_DESCRIPTION("Dallas DS1511 RTC driver");
641MODULE_LICENSE("GPL"); 616MODULE_LICENSE("GPL");
642MODULE_VERSION(DRV_VERSION); 617MODULE_VERSION(DRV_VERSION);