diff options
Diffstat (limited to 'drivers/rtc/rtc-sh.c')
-rw-r--r-- | drivers/rtc/rtc-sh.c | 67 |
1 files changed, 49 insertions, 18 deletions
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 9b1ff12bf947..d7310adb7152 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * SuperH On-Chip RTC Support | 2 | * SuperH On-Chip RTC Support |
3 | * | 3 | * |
4 | * Copyright (C) 2006, 2007, 2008 Paul Mundt | 4 | * Copyright (C) 2006 - 2009 Paul Mundt |
5 | * Copyright (C) 2006 Jamie Lenehan | 5 | * Copyright (C) 2006 Jamie Lenehan |
6 | * Copyright (C) 2008 Angelo Castello | 6 | * Copyright (C) 2008 Angelo Castello |
7 | * | 7 | * |
@@ -25,10 +25,11 @@ | |||
25 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
26 | #include <linux/io.h> | 26 | #include <linux/io.h> |
27 | #include <linux/log2.h> | 27 | #include <linux/log2.h> |
28 | #include <linux/clk.h> | ||
28 | #include <asm/rtc.h> | 29 | #include <asm/rtc.h> |
29 | 30 | ||
30 | #define DRV_NAME "sh-rtc" | 31 | #define DRV_NAME "sh-rtc" |
31 | #define DRV_VERSION "0.2.1" | 32 | #define DRV_VERSION "0.2.2" |
32 | 33 | ||
33 | #define RTC_REG(r) ((r) * rtc_reg_size) | 34 | #define RTC_REG(r) ((r) * rtc_reg_size) |
34 | 35 | ||
@@ -87,16 +88,17 @@ | |||
87 | #define RCR2_START 0x01 /* Start bit */ | 88 | #define RCR2_START 0x01 /* Start bit */ |
88 | 89 | ||
89 | struct sh_rtc { | 90 | struct sh_rtc { |
90 | void __iomem *regbase; | 91 | void __iomem *regbase; |
91 | unsigned long regsize; | 92 | unsigned long regsize; |
92 | struct resource *res; | 93 | struct resource *res; |
93 | int alarm_irq; | 94 | int alarm_irq; |
94 | int periodic_irq; | 95 | int periodic_irq; |
95 | int carry_irq; | 96 | int carry_irq; |
96 | struct rtc_device *rtc_dev; | 97 | struct clk *clk; |
97 | spinlock_t lock; | 98 | struct rtc_device *rtc_dev; |
98 | unsigned long capabilities; /* See asm-sh/rtc.h for cap bits */ | 99 | spinlock_t lock; |
99 | unsigned short periodic_freq; | 100 | unsigned long capabilities; /* See asm/rtc.h for cap bits */ |
101 | unsigned short periodic_freq; | ||
100 | }; | 102 | }; |
101 | 103 | ||
102 | static int __sh_rtc_interrupt(struct sh_rtc *rtc) | 104 | static int __sh_rtc_interrupt(struct sh_rtc *rtc) |
@@ -294,10 +296,10 @@ static inline void sh_rtc_setaie(struct device *dev, unsigned int enable) | |||
294 | 296 | ||
295 | tmp = readb(rtc->regbase + RCR1); | 297 | tmp = readb(rtc->regbase + RCR1); |
296 | 298 | ||
297 | if (!enable) | 299 | if (enable) |
298 | tmp &= ~RCR1_AIE; | ||
299 | else | ||
300 | tmp |= RCR1_AIE; | 300 | tmp |= RCR1_AIE; |
301 | else | ||
302 | tmp &= ~RCR1_AIE; | ||
301 | 303 | ||
302 | writeb(tmp, rtc->regbase + RCR1); | 304 | writeb(tmp, rtc->regbase + RCR1); |
303 | 305 | ||
@@ -618,6 +620,7 @@ static int sh_rtc_irq_set_freq(struct device *dev, int freq) | |||
618 | { | 620 | { |
619 | if (!is_power_of_2(freq)) | 621 | if (!is_power_of_2(freq)) |
620 | return -EINVAL; | 622 | return -EINVAL; |
623 | |||
621 | return sh_rtc_ioctl(dev, RTC_IRQP_SET, freq); | 624 | return sh_rtc_ioctl(dev, RTC_IRQP_SET, freq); |
622 | } | 625 | } |
623 | 626 | ||
@@ -637,7 +640,8 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) | |||
637 | struct sh_rtc *rtc; | 640 | struct sh_rtc *rtc; |
638 | struct resource *res; | 641 | struct resource *res; |
639 | struct rtc_time r; | 642 | struct rtc_time r; |
640 | int ret; | 643 | char clk_name[6]; |
644 | int clk_id, ret; | ||
641 | 645 | ||
642 | rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL); | 646 | rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL); |
643 | if (unlikely(!rtc)) | 647 | if (unlikely(!rtc)) |
@@ -652,6 +656,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) | |||
652 | dev_err(&pdev->dev, "No IRQ resource\n"); | 656 | dev_err(&pdev->dev, "No IRQ resource\n"); |
653 | goto err_badres; | 657 | goto err_badres; |
654 | } | 658 | } |
659 | |||
655 | rtc->periodic_irq = ret; | 660 | rtc->periodic_irq = ret; |
656 | rtc->carry_irq = platform_get_irq(pdev, 1); | 661 | rtc->carry_irq = platform_get_irq(pdev, 1); |
657 | rtc->alarm_irq = platform_get_irq(pdev, 2); | 662 | rtc->alarm_irq = platform_get_irq(pdev, 2); |
@@ -663,7 +668,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) | |||
663 | goto err_badres; | 668 | goto err_badres; |
664 | } | 669 | } |
665 | 670 | ||
666 | rtc->regsize = res->end - res->start + 1; | 671 | rtc->regsize = resource_size(res); |
667 | 672 | ||
668 | rtc->res = request_mem_region(res->start, rtc->regsize, pdev->name); | 673 | rtc->res = request_mem_region(res->start, rtc->regsize, pdev->name); |
669 | if (unlikely(!rtc->res)) { | 674 | if (unlikely(!rtc->res)) { |
@@ -677,6 +682,26 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) | |||
677 | goto err_badmap; | 682 | goto err_badmap; |
678 | } | 683 | } |
679 | 684 | ||
685 | clk_id = pdev->id; | ||
686 | /* With a single device, the clock id is still "rtc0" */ | ||
687 | if (clk_id < 0) | ||
688 | clk_id = 0; | ||
689 | |||
690 | snprintf(clk_name, sizeof(clk_name), "rtc%d", clk_id); | ||
691 | |||
692 | rtc->clk = clk_get(&pdev->dev, clk_name); | ||
693 | if (IS_ERR(rtc->clk)) { | ||
694 | /* | ||
695 | * No error handling for rtc->clk intentionally, not all | ||
696 | * platforms will have a unique clock for the RTC, and | ||
697 | * the clk API can handle the struct clk pointer being | ||
698 | * NULL. | ||
699 | */ | ||
700 | rtc->clk = NULL; | ||
701 | } | ||
702 | |||
703 | clk_enable(rtc->clk); | ||
704 | |||
680 | rtc->rtc_dev = rtc_device_register("sh", &pdev->dev, | 705 | rtc->rtc_dev = rtc_device_register("sh", &pdev->dev, |
681 | &sh_rtc_ops, THIS_MODULE); | 706 | &sh_rtc_ops, THIS_MODULE); |
682 | if (IS_ERR(rtc->rtc_dev)) { | 707 | if (IS_ERR(rtc->rtc_dev)) { |
@@ -759,6 +784,8 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) | |||
759 | return 0; | 784 | return 0; |
760 | 785 | ||
761 | err_unmap: | 786 | err_unmap: |
787 | clk_disable(rtc->clk); | ||
788 | clk_put(rtc->clk); | ||
762 | iounmap(rtc->regbase); | 789 | iounmap(rtc->regbase); |
763 | err_badmap: | 790 | err_badmap: |
764 | release_resource(rtc->res); | 791 | release_resource(rtc->res); |
@@ -780,6 +807,7 @@ static int __devexit sh_rtc_remove(struct platform_device *pdev) | |||
780 | sh_rtc_setcie(&pdev->dev, 0); | 807 | sh_rtc_setcie(&pdev->dev, 0); |
781 | 808 | ||
782 | free_irq(rtc->periodic_irq, rtc); | 809 | free_irq(rtc->periodic_irq, rtc); |
810 | |||
783 | if (rtc->carry_irq > 0) { | 811 | if (rtc->carry_irq > 0) { |
784 | free_irq(rtc->carry_irq, rtc); | 812 | free_irq(rtc->carry_irq, rtc); |
785 | free_irq(rtc->alarm_irq, rtc); | 813 | free_irq(rtc->alarm_irq, rtc); |
@@ -789,6 +817,9 @@ static int __devexit sh_rtc_remove(struct platform_device *pdev) | |||
789 | 817 | ||
790 | iounmap(rtc->regbase); | 818 | iounmap(rtc->regbase); |
791 | 819 | ||
820 | clk_disable(rtc->clk); | ||
821 | clk_put(rtc->clk); | ||
822 | |||
792 | platform_set_drvdata(pdev, NULL); | 823 | platform_set_drvdata(pdev, NULL); |
793 | 824 | ||
794 | kfree(rtc); | 825 | kfree(rtc); |
@@ -802,11 +833,11 @@ static void sh_rtc_set_irq_wake(struct device *dev, int enabled) | |||
802 | struct sh_rtc *rtc = platform_get_drvdata(pdev); | 833 | struct sh_rtc *rtc = platform_get_drvdata(pdev); |
803 | 834 | ||
804 | set_irq_wake(rtc->periodic_irq, enabled); | 835 | set_irq_wake(rtc->periodic_irq, enabled); |
836 | |||
805 | if (rtc->carry_irq > 0) { | 837 | if (rtc->carry_irq > 0) { |
806 | set_irq_wake(rtc->carry_irq, enabled); | 838 | set_irq_wake(rtc->carry_irq, enabled); |
807 | set_irq_wake(rtc->alarm_irq, enabled); | 839 | set_irq_wake(rtc->alarm_irq, enabled); |
808 | } | 840 | } |
809 | |||
810 | } | 841 | } |
811 | 842 | ||
812 | static int sh_rtc_suspend(struct device *dev) | 843 | static int sh_rtc_suspend(struct device *dev) |