aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/rtc/rtc-sh.c190
1 files changed, 117 insertions, 73 deletions
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 1c3fc6b428e9..b37f44b0406e 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -99,56 +99,51 @@ struct sh_rtc {
99 unsigned short periodic_freq; 99 unsigned short periodic_freq;
100}; 100};
101 101
102static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id) 102static int __sh_rtc_interrupt(struct sh_rtc *rtc)
103{ 103{
104 struct sh_rtc *rtc = dev_id; 104 unsigned int tmp, pending;
105 unsigned int tmp;
106
107 spin_lock(&rtc->lock);
108 105
109 tmp = readb(rtc->regbase + RCR1); 106 tmp = readb(rtc->regbase + RCR1);
107 pending = tmp & RCR1_CF;
110 tmp &= ~RCR1_CF; 108 tmp &= ~RCR1_CF;
111 writeb(tmp, rtc->regbase + RCR1); 109 writeb(tmp, rtc->regbase + RCR1);
112 110
113 /* Users have requested One x Second IRQ */ 111 /* Users have requested One x Second IRQ */
114 if (rtc->periodic_freq & PF_OXS) 112 if (pending && rtc->periodic_freq & PF_OXS)
115 rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); 113 rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
116 114
117 spin_unlock(&rtc->lock); 115 return pending;
118
119 return IRQ_HANDLED;
120} 116}
121 117
122static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) 118static int __sh_rtc_alarm(struct sh_rtc *rtc)
123{ 119{
124 struct sh_rtc *rtc = dev_id; 120 unsigned int tmp, pending;
125 unsigned int tmp;
126
127 spin_lock(&rtc->lock);
128 121
129 tmp = readb(rtc->regbase + RCR1); 122 tmp = readb(rtc->regbase + RCR1);
123 pending = tmp & RCR1_AF;
130 tmp &= ~(RCR1_AF | RCR1_AIE); 124 tmp &= ~(RCR1_AF | RCR1_AIE);
131 writeb(tmp, rtc->regbase + RCR1); 125 writeb(tmp, rtc->regbase + RCR1);
132
133 rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
134 126
135 spin_unlock(&rtc->lock); 127 if (pending)
128 rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
136 129
137 return IRQ_HANDLED; 130 return pending;
138} 131}
139 132
140static irqreturn_t sh_rtc_periodic(int irq, void *dev_id) 133static int __sh_rtc_periodic(struct sh_rtc *rtc)
141{ 134{
142 struct sh_rtc *rtc = dev_id;
143 struct rtc_device *rtc_dev = rtc->rtc_dev; 135 struct rtc_device *rtc_dev = rtc->rtc_dev;
144 unsigned int tmp; 136 struct rtc_task *irq_task;
145 137 unsigned int tmp, pending;
146 spin_lock(&rtc->lock);
147 138
148 tmp = readb(rtc->regbase + RCR2); 139 tmp = readb(rtc->regbase + RCR2);
140 pending = tmp & RCR2_PEF;
149 tmp &= ~RCR2_PEF; 141 tmp &= ~RCR2_PEF;
150 writeb(tmp, rtc->regbase + RCR2); 142 writeb(tmp, rtc->regbase + RCR2);
151 143
144 if (!pending)
145 return 0;
146
152 /* Half period enabled than one skipped and the next notified */ 147 /* Half period enabled than one skipped and the next notified */
153 if ((rtc->periodic_freq & PF_HP) && (rtc->periodic_freq & PF_COUNT)) 148 if ((rtc->periodic_freq & PF_HP) && (rtc->periodic_freq & PF_COUNT))
154 rtc->periodic_freq &= ~PF_COUNT; 149 rtc->periodic_freq &= ~PF_COUNT;
@@ -157,16 +152,65 @@ static irqreturn_t sh_rtc_periodic(int irq, void *dev_id)
157 rtc->periodic_freq |= PF_COUNT; 152 rtc->periodic_freq |= PF_COUNT;
158 if (rtc->periodic_freq & PF_KOU) { 153 if (rtc->periodic_freq & PF_KOU) {
159 spin_lock(&rtc_dev->irq_task_lock); 154 spin_lock(&rtc_dev->irq_task_lock);
160 if (rtc_dev->irq_task) 155 irq_task = rtc_dev->irq_task;
161 rtc_dev->irq_task->func(rtc_dev->irq_task->private_data); 156 if (irq_task)
157 irq_task->func(irq_task->private_data);
162 spin_unlock(&rtc_dev->irq_task_lock); 158 spin_unlock(&rtc_dev->irq_task_lock);
163 } else 159 } else
164 rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); 160 rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
165 } 161 }
166 162
163 return pending;
164}
165
166static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
167{
168 struct sh_rtc *rtc = dev_id;
169 int ret;
170
171 spin_lock(&rtc->lock);
172 ret = __sh_rtc_interrupt(rtc);
173 spin_unlock(&rtc->lock);
174
175 return IRQ_RETVAL(ret);
176}
177
178static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
179{
180 struct sh_rtc *rtc = dev_id;
181 int ret;
182
183 spin_lock(&rtc->lock);
184 ret = __sh_rtc_alarm(rtc);
185 spin_unlock(&rtc->lock);
186
187 return IRQ_RETVAL(ret);
188}
189
190static irqreturn_t sh_rtc_periodic(int irq, void *dev_id)
191{
192 struct sh_rtc *rtc = dev_id;
193 int ret;
194
195 spin_lock(&rtc->lock);
196 ret = __sh_rtc_periodic(rtc);
167 spin_unlock(&rtc->lock); 197 spin_unlock(&rtc->lock);
168 198
169 return IRQ_HANDLED; 199 return IRQ_RETVAL(ret);
200}
201
202static irqreturn_t sh_rtc_shared(int irq, void *dev_id)
203{
204 struct sh_rtc *rtc = dev_id;
205 int ret;
206
207 spin_lock(&rtc->lock);
208 ret = __sh_rtc_interrupt(rtc);
209 ret |= __sh_rtc_alarm(rtc);
210 ret |= __sh_rtc_periodic(rtc);
211 spin_unlock(&rtc->lock);
212
213 return IRQ_RETVAL(ret);
170} 214}
171 215
172static inline void sh_rtc_setpie(struct device *dev, unsigned int enable) 216static inline void sh_rtc_setpie(struct device *dev, unsigned int enable)
@@ -585,26 +629,12 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
585 ret = platform_get_irq(pdev, 0); 629 ret = platform_get_irq(pdev, 0);
586 if (unlikely(ret <= 0)) { 630 if (unlikely(ret <= 0)) {
587 ret = -ENOENT; 631 ret = -ENOENT;
588 dev_err(&pdev->dev, "No IRQ for period\n"); 632 dev_err(&pdev->dev, "No IRQ resource\n");
589 goto err_badres; 633 goto err_badres;
590 } 634 }
591 rtc->periodic_irq = ret; 635 rtc->periodic_irq = ret;
592 636 rtc->carry_irq = platform_get_irq(pdev, 1);
593 ret = platform_get_irq(pdev, 1); 637 rtc->alarm_irq = platform_get_irq(pdev, 2);
594 if (unlikely(ret <= 0)) {
595 ret = -ENOENT;
596 dev_err(&pdev->dev, "No IRQ for carry\n");
597 goto err_badres;
598 }
599 rtc->carry_irq = ret;
600
601 ret = platform_get_irq(pdev, 2);
602 if (unlikely(ret <= 0)) {
603 ret = -ENOENT;
604 dev_err(&pdev->dev, "No IRQ for alarm\n");
605 goto err_badres;
606 }
607 rtc->alarm_irq = ret;
608 638
609 res = platform_get_resource(pdev, IORESOURCE_IO, 0); 639 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
610 if (unlikely(res == NULL)) { 640 if (unlikely(res == NULL)) {
@@ -651,35 +681,47 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
651 681
652 platform_set_drvdata(pdev, rtc); 682 platform_set_drvdata(pdev, rtc);
653 683
654 /* register periodic/carry/alarm irqs */ 684 if (rtc->carry_irq <= 0) {
655 ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, IRQF_DISABLED, 685 /* register shared periodic/carry/alarm irq */
656 "sh-rtc period", rtc); 686 ret = request_irq(rtc->periodic_irq, sh_rtc_shared,
657 if (unlikely(ret)) { 687 IRQF_DISABLED, "sh-rtc", rtc);
658 dev_err(&pdev->dev, 688 if (unlikely(ret)) {
659 "request period IRQ failed with %d, IRQ %d\n", ret, 689 dev_err(&pdev->dev,
660 rtc->periodic_irq); 690 "request IRQ failed with %d, IRQ %d\n", ret,
661 goto err_unmap; 691 rtc->periodic_irq);
662 } 692 goto err_unmap;
693 }
694 } else {
695 /* register periodic/carry/alarm irqs */
696 ret = request_irq(rtc->periodic_irq, sh_rtc_periodic,
697 IRQF_DISABLED, "sh-rtc period", rtc);
698 if (unlikely(ret)) {
699 dev_err(&pdev->dev,
700 "request period IRQ failed with %d, IRQ %d\n",
701 ret, rtc->periodic_irq);
702 goto err_unmap;
703 }
663 704
664 ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, IRQF_DISABLED, 705 ret = request_irq(rtc->carry_irq, sh_rtc_interrupt,
665 "sh-rtc carry", rtc); 706 IRQF_DISABLED, "sh-rtc carry", rtc);
666 if (unlikely(ret)) { 707 if (unlikely(ret)) {
667 dev_err(&pdev->dev, 708 dev_err(&pdev->dev,
668 "request carry IRQ failed with %d, IRQ %d\n", ret, 709 "request carry IRQ failed with %d, IRQ %d\n",
669 rtc->carry_irq); 710 ret, rtc->carry_irq);
670 free_irq(rtc->periodic_irq, rtc); 711 free_irq(rtc->periodic_irq, rtc);
671 goto err_unmap; 712 goto err_unmap;
672 } 713 }
673 714
674 ret = request_irq(rtc->alarm_irq, sh_rtc_alarm, IRQF_DISABLED, 715 ret = request_irq(rtc->alarm_irq, sh_rtc_alarm,
675 "sh-rtc alarm", rtc); 716 IRQF_DISABLED, "sh-rtc alarm", rtc);
676 if (unlikely(ret)) { 717 if (unlikely(ret)) {
677 dev_err(&pdev->dev, 718 dev_err(&pdev->dev,
678 "request alarm IRQ failed with %d, IRQ %d\n", ret, 719 "request alarm IRQ failed with %d, IRQ %d\n",
679 rtc->alarm_irq); 720 ret, rtc->alarm_irq);
680 free_irq(rtc->carry_irq, rtc); 721 free_irq(rtc->carry_irq, rtc);
681 free_irq(rtc->periodic_irq, rtc); 722 free_irq(rtc->periodic_irq, rtc);
682 goto err_unmap; 723 goto err_unmap;
724 }
683 } 725 }
684 726
685 tmp = readb(rtc->regbase + RCR1); 727 tmp = readb(rtc->regbase + RCR1);
@@ -709,9 +751,11 @@ static int __devexit sh_rtc_remove(struct platform_device *pdev)
709 sh_rtc_setpie(&pdev->dev, 0); 751 sh_rtc_setpie(&pdev->dev, 0);
710 sh_rtc_setaie(&pdev->dev, 0); 752 sh_rtc_setaie(&pdev->dev, 0);
711 753
712 free_irq(rtc->carry_irq, rtc);
713 free_irq(rtc->periodic_irq, rtc); 754 free_irq(rtc->periodic_irq, rtc);
714 free_irq(rtc->alarm_irq, rtc); 755 if (rtc->carry_irq > 0) {
756 free_irq(rtc->carry_irq, rtc);
757 free_irq(rtc->alarm_irq, rtc);
758 }
715 759
716 release_resource(rtc->res); 760 release_resource(rtc->res);
717 761