diff options
Diffstat (limited to 'drivers/rtc/rtc-mxc.c')
| -rw-r--r-- | drivers/rtc/rtc-mxc.c | 123 |
1 files changed, 70 insertions, 53 deletions
diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 39e41fbdf08b..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 | |||
| 179 | static 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 | ||
| 245 | static 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 | |||
| 265 | static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) | 252 | static 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); |
| @@ -290,6 +277,17 @@ static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
| 290 | */ | 277 | */ |
| 291 | static int mxc_rtc_set_mmss(struct device *dev, unsigned long time) | 278 | static int mxc_rtc_set_mmss(struct device *dev, unsigned long time) |
| 292 | { | 279 | { |
| 280 | /* | ||
| 281 | * TTC_DAYR register is 9-bit in MX1 SoC, save time and day of year only | ||
| 282 | */ | ||
| 283 | if (cpu_is_mx1()) { | ||
| 284 | struct rtc_time tm; | ||
| 285 | |||
| 286 | rtc_time_to_tm(time, &tm); | ||
| 287 | tm.tm_year = 70; | ||
| 288 | rtc_tm_to_time(&tm, &time); | ||
| 289 | } | ||
| 290 | |||
| 293 | /* Avoid roll-over from reading the different registers */ | 291 | /* Avoid roll-over from reading the different registers */ |
| 294 | do { | 292 | do { |
| 295 | set_alarm_or_time(dev, MXC_RTC_TIME, time); | 293 | set_alarm_or_time(dev, MXC_RTC_TIME, time); |
| @@ -324,21 +322,7 @@ static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
| 324 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 322 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
| 325 | int ret; | 323 | int ret; |
| 326 | 324 | ||
| 327 | if (rtc_valid_tm(&alrm->time)) { | 325 | ret = rtc_update_alarm(dev, &alrm->time); |
| 328 | if (alrm->time.tm_sec > 59 || | ||
| 329 | alrm->time.tm_hour > 23 || | ||
| 330 | alrm->time.tm_min > 59) | ||
| 331 | return -EINVAL; | ||
| 332 | |||
| 333 | ret = rtc_update_alarm(dev, &alrm->time); | ||
| 334 | } else { | ||
| 335 | ret = rtc_valid_tm(&alrm->time); | ||
| 336 | if (ret) | ||
| 337 | return ret; | ||
| 338 | |||
| 339 | ret = rtc_update_alarm(dev, &alrm->time); | ||
| 340 | } | ||
| 341 | |||
| 342 | if (ret) | 326 | if (ret) |
| 343 | return ret; | 327 | return ret; |
| 344 | 328 | ||
| @@ -424,6 +408,9 @@ static int __init mxc_rtc_probe(struct platform_device *pdev) | |||
| 424 | pdata->irq = -1; | 408 | pdata->irq = -1; |
| 425 | } | 409 | } |
| 426 | 410 | ||
| 411 | if (pdata->irq >=0) | ||
| 412 | device_init_wakeup(&pdev->dev, 1); | ||
| 413 | |||
| 427 | rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops, | 414 | rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops, |
| 428 | THIS_MODULE); | 415 | THIS_MODULE); |
| 429 | if (IS_ERR(rtc)) { | 416 | if (IS_ERR(rtc)) { |
| @@ -459,9 +446,39 @@ static int __exit mxc_rtc_remove(struct platform_device *pdev) | |||
| 459 | return 0; | 446 | return 0; |
| 460 | } | 447 | } |
| 461 | 448 | ||
| 449 | #ifdef CONFIG_PM | ||
| 450 | static 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 | |||
| 460 | static 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 | |||
| 470 | static struct dev_pm_ops mxc_rtc_pm_ops = { | ||
| 471 | .suspend = mxc_rtc_suspend, | ||
| 472 | .resume = mxc_rtc_resume, | ||
| 473 | }; | ||
| 474 | #endif | ||
| 475 | |||
| 462 | static struct platform_driver mxc_rtc_driver = { | 476 | static struct platform_driver mxc_rtc_driver = { |
| 463 | .driver = { | 477 | .driver = { |
| 464 | .name = "mxc_rtc", | 478 | .name = "mxc_rtc", |
| 479 | #ifdef CONFIG_PM | ||
| 480 | .pm = &mxc_rtc_pm_ops, | ||
| 481 | #endif | ||
| 465 | .owner = THIS_MODULE, | 482 | .owner = THIS_MODULE, |
| 466 | }, | 483 | }, |
| 467 | .remove = __exit_p(mxc_rtc_remove), | 484 | .remove = __exit_p(mxc_rtc_remove), |
