aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-mxc.c
diff options
context:
space:
mode:
authorYauhen Kharuzhy <jekhor@gmail.com>2012-01-10 18:10:34 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-01-10 19:30:52 -0500
commitc92182ee0b5a33c74e4b6c0ded36166e4ef3bc3e (patch)
tree4583c06816318f4e4b4216239f83d91aa11b5fbe /drivers/rtc/rtc-mxc.c
parent7287be1d0ac8c82999b67c2a33517c6ec9cfdbe7 (diff)
drivers/rtc/rtc-mxc.c: make alarm work
Fix alarm IRQ handling, make the alarm one-shot. Cleanup black magick with a validation of already validated time data. Add ability to wake the system with alarm. [akpm@linux-foundation.org: fix CONFIG_PM=n build] Signed-off-by: Yauhen Kharuzhy <jekhor@gmail.com> Cc: Daniel Mack <daniel@caiaq.de> Cc: Alessandro Zummo <a.zummo@towertech.it> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc/rtc-mxc.c')
-rw-r--r--drivers/rtc/rtc-mxc.c112
1 files changed, 59 insertions, 53 deletions
diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c
index 11b7b614fc8d..5e1d64ee5228 100644
--- a/drivers/rtc/rtc-mxc.c
+++ b/drivers/rtc/rtc-mxc.c
@@ -155,7 +155,6 @@ static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
155{ 155{
156 struct rtc_time alarm_tm, now_tm; 156 struct rtc_time alarm_tm, now_tm;
157 unsigned long now, time; 157 unsigned long now, time;
158 int ret;
159 struct platform_device *pdev = to_platform_device(dev); 158 struct platform_device *pdev = to_platform_device(dev);
160 struct rtc_plat_data *pdata = platform_get_drvdata(pdev); 159 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
161 void __iomem *ioaddr = pdata->ioaddr; 160 void __iomem *ioaddr = pdata->ioaddr;
@@ -168,21 +167,33 @@ static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
168 alarm_tm.tm_hour = alrm->tm_hour; 167 alarm_tm.tm_hour = alrm->tm_hour;
169 alarm_tm.tm_min = alrm->tm_min; 168 alarm_tm.tm_min = alrm->tm_min;
170 alarm_tm.tm_sec = alrm->tm_sec; 169 alarm_tm.tm_sec = alrm->tm_sec;
171 rtc_tm_to_time(&now_tm, &now);
172 rtc_tm_to_time(&alarm_tm, &time); 170 rtc_tm_to_time(&alarm_tm, &time);
173 171
174 if (time < now) {
175 time += 60 * 60 * 24;
176 rtc_time_to_tm(time, &alarm_tm);
177 }
178
179 ret = rtc_tm_to_time(&alarm_tm, &time);
180
181 /* clear all the interrupt status bits */ 172 /* clear all the interrupt status bits */
182 writew(readw(ioaddr + RTC_RTCISR), ioaddr + RTC_RTCISR); 173 writew(readw(ioaddr + RTC_RTCISR), ioaddr + RTC_RTCISR);
183 set_alarm_or_time(dev, MXC_RTC_ALARM, time); 174 set_alarm_or_time(dev, MXC_RTC_ALARM, time);
184 175
185 return ret; 176 return 0;
177}
178
179static void mxc_rtc_irq_enable(struct device *dev, unsigned int bit,
180 unsigned int enabled)
181{
182 struct platform_device *pdev = to_platform_device(dev);
183 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
184 void __iomem *ioaddr = pdata->ioaddr;
185 u32 reg;
186
187 spin_lock_irq(&pdata->rtc->irq_lock);
188 reg = readw(ioaddr + RTC_RTCIENR);
189
190 if (enabled)
191 reg |= bit;
192 else
193 reg &= ~bit;
194
195 writew(reg, ioaddr + RTC_RTCIENR);
196 spin_unlock_irq(&pdata->rtc->irq_lock);
186} 197}
187 198
188/* This function is the RTC interrupt service routine. */ 199/* This function is the RTC interrupt service routine. */
@@ -199,13 +210,12 @@ static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
199 /* clear interrupt sources */ 210 /* clear interrupt sources */
200 writew(status, ioaddr + RTC_RTCISR); 211 writew(status, ioaddr + RTC_RTCISR);
201 212
202 /* clear alarm interrupt if it has occurred */
203 if (status & RTC_ALM_BIT)
204 status &= ~RTC_ALM_BIT;
205
206 /* update irq data & counter */ 213 /* update irq data & counter */
207 if (status & RTC_ALM_BIT) 214 if (status & RTC_ALM_BIT) {
208 events |= (RTC_AF | RTC_IRQF); 215 events |= (RTC_AF | RTC_IRQF);
216 /* RTC alarm should be one-shot */
217 mxc_rtc_irq_enable(&pdev->dev, RTC_ALM_BIT, 0);
218 }
209 219
210 if (status & RTC_1HZ_BIT) 220 if (status & RTC_1HZ_BIT)
211 events |= (RTC_UF | RTC_IRQF); 221 events |= (RTC_UF | RTC_IRQF);
@@ -213,9 +223,6 @@ static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
213 if (status & PIT_ALL_ON) 223 if (status & PIT_ALL_ON)
214 events |= (RTC_PF | RTC_IRQF); 224 events |= (RTC_PF | RTC_IRQF);
215 225
216 if ((status & RTC_ALM_BIT) && rtc_valid_tm(&pdata->g_rtc_alarm))
217 rtc_update_alarm(&pdev->dev, &pdata->g_rtc_alarm);
218
219 rtc_update_irq(pdata->rtc, 1, events); 226 rtc_update_irq(pdata->rtc, 1, events);
220 spin_unlock_irq(&pdata->rtc->irq_lock); 227 spin_unlock_irq(&pdata->rtc->irq_lock);
221 228
@@ -242,26 +249,6 @@ static void mxc_rtc_release(struct device *dev)
242 spin_unlock_irq(&pdata->rtc->irq_lock); 249 spin_unlock_irq(&pdata->rtc->irq_lock);
243} 250}
244 251
245static void mxc_rtc_irq_enable(struct device *dev, unsigned int bit,
246 unsigned int enabled)
247{
248 struct platform_device *pdev = to_platform_device(dev);
249 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
250 void __iomem *ioaddr = pdata->ioaddr;
251 u32 reg;
252
253 spin_lock_irq(&pdata->rtc->irq_lock);
254 reg = readw(ioaddr + RTC_RTCIENR);
255
256 if (enabled)
257 reg |= bit;
258 else
259 reg &= ~bit;
260
261 writew(reg, ioaddr + RTC_RTCIENR);
262 spin_unlock_irq(&pdata->rtc->irq_lock);
263}
264
265static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) 252static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
266{ 253{
267 mxc_rtc_irq_enable(dev, RTC_ALM_BIT, enabled); 254 mxc_rtc_irq_enable(dev, RTC_ALM_BIT, enabled);
@@ -335,21 +322,7 @@ static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
335 struct rtc_plat_data *pdata = platform_get_drvdata(pdev); 322 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
336 int ret; 323 int ret;
337 324
338 if (rtc_valid_tm(&alrm->time)) { 325 ret = rtc_update_alarm(dev, &alrm->time);
339 if (alrm->time.tm_sec > 59 ||
340 alrm->time.tm_hour > 23 ||
341 alrm->time.tm_min > 59)
342 return -EINVAL;
343
344 ret = rtc_update_alarm(dev, &alrm->time);
345 } else {
346 ret = rtc_valid_tm(&alrm->time);
347 if (ret)
348 return ret;
349
350 ret = rtc_update_alarm(dev, &alrm->time);
351 }
352
353 if (ret) 326 if (ret)
354 return ret; 327 return ret;
355 328
@@ -435,6 +408,9 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
435 pdata->irq = -1; 408 pdata->irq = -1;
436 } 409 }
437 410
411 if (pdata->irq >=0)
412 device_init_wakeup(&pdev->dev, 1);
413
438 rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops, 414 rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops,
439 THIS_MODULE); 415 THIS_MODULE);
440 if (IS_ERR(rtc)) { 416 if (IS_ERR(rtc)) {
@@ -470,9 +446,39 @@ static int __exit mxc_rtc_remove(struct platform_device *pdev)
470 return 0; 446 return 0;
471} 447}
472 448
449#ifdef CONFIG_PM
450static int mxc_rtc_suspend(struct device *dev)
451{
452 struct rtc_plat_data *pdata = dev_get_drvdata(dev);
453
454 if (device_may_wakeup(dev))
455 enable_irq_wake(pdata->irq);
456
457 return 0;
458}
459
460static int mxc_rtc_resume(struct device *dev)
461{
462 struct rtc_plat_data *pdata = dev_get_drvdata(dev);
463
464 if (device_may_wakeup(dev))
465 disable_irq_wake(pdata->irq);
466
467 return 0;
468}
469
470static struct dev_pm_ops mxc_rtc_pm_ops = {
471 .suspend = mxc_rtc_suspend,
472 .resume = mxc_rtc_resume,
473};
474#endif
475
473static struct platform_driver mxc_rtc_driver = { 476static struct platform_driver mxc_rtc_driver = {
474 .driver = { 477 .driver = {
475 .name = "mxc_rtc", 478 .name = "mxc_rtc",
479#ifdef CONFIG_PM
480 .pm = &mxc_rtc_pm_ops,
481#endif
476 .owner = THIS_MODULE, 482 .owner = THIS_MODULE,
477 }, 483 },
478 .remove = __exit_p(mxc_rtc_remove), 484 .remove = __exit_p(mxc_rtc_remove),