diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-06-25 10:23:59 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-06-25 10:23:59 -0400 |
| commit | 8abf55883431a91d4877933240c8419b7fc17274 (patch) | |
| tree | c7de035cf068f3edf5053a30d912c2024bac88d8 | |
| parent | 4d362ad280fca0f2e098de607534f72f2c243e12 (diff) | |
| parent | b1eb085c064d0843826d7402db7fc5f3032e01fc (diff) | |
Merge branch 'timer-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'timer-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
rtc: vt8500: Fix build error & cleanup rtc_class_ops->update_irq_enable()
alarmtimers: Return -ENOTSUPP if no RTC device is present
alarmtimers: Handle late rtc module loading
| -rw-r--r-- | drivers/rtc/rtc-vt8500.c | 45 | ||||
| -rw-r--r-- | kernel/time/alarmtimer.c | 158 |
2 files changed, 91 insertions, 112 deletions
diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index b8bc862903ae..efd6066b5cd2 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c | |||
| @@ -78,7 +78,6 @@ struct vt8500_rtc { | |||
| 78 | void __iomem *regbase; | 78 | void __iomem *regbase; |
| 79 | struct resource *res; | 79 | struct resource *res; |
| 80 | int irq_alarm; | 80 | int irq_alarm; |
| 81 | int irq_hz; | ||
| 82 | struct rtc_device *rtc; | 81 | struct rtc_device *rtc; |
| 83 | spinlock_t lock; /* Protects this structure */ | 82 | spinlock_t lock; /* Protects this structure */ |
| 84 | }; | 83 | }; |
| @@ -100,10 +99,6 @@ static irqreturn_t vt8500_rtc_irq(int irq, void *dev_id) | |||
| 100 | if (isr & 1) | 99 | if (isr & 1) |
| 101 | events |= RTC_AF | RTC_IRQF; | 100 | events |= RTC_AF | RTC_IRQF; |
| 102 | 101 | ||
| 103 | /* Only second/minute interrupts are supported */ | ||
| 104 | if (isr & 2) | ||
| 105 | events |= RTC_UF | RTC_IRQF; | ||
| 106 | |||
| 107 | rtc_update_irq(vt8500_rtc->rtc, 1, events); | 102 | rtc_update_irq(vt8500_rtc->rtc, 1, events); |
| 108 | 103 | ||
| 109 | return IRQ_HANDLED; | 104 | return IRQ_HANDLED; |
| @@ -199,27 +194,12 @@ static int vt8500_alarm_irq_enable(struct device *dev, unsigned int enabled) | |||
| 199 | return 0; | 194 | return 0; |
| 200 | } | 195 | } |
| 201 | 196 | ||
| 202 | static int vt8500_update_irq_enable(struct device *dev, unsigned int enabled) | ||
| 203 | { | ||
| 204 | struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); | ||
| 205 | unsigned long tmp = readl(vt8500_rtc->regbase + VT8500_RTC_CR); | ||
| 206 | |||
| 207 | if (enabled) | ||
| 208 | tmp |= VT8500_RTC_CR_SM_SEC | VT8500_RTC_CR_SM_ENABLE; | ||
| 209 | else | ||
| 210 | tmp &= ~VT8500_RTC_CR_SM_ENABLE; | ||
| 211 | |||
| 212 | writel(tmp, vt8500_rtc->regbase + VT8500_RTC_CR); | ||
| 213 | return 0; | ||
| 214 | } | ||
| 215 | |||
| 216 | static const struct rtc_class_ops vt8500_rtc_ops = { | 197 | static const struct rtc_class_ops vt8500_rtc_ops = { |
| 217 | .read_time = vt8500_rtc_read_time, | 198 | .read_time = vt8500_rtc_read_time, |
| 218 | .set_time = vt8500_rtc_set_time, | 199 | .set_time = vt8500_rtc_set_time, |
| 219 | .read_alarm = vt8500_rtc_read_alarm, | 200 | .read_alarm = vt8500_rtc_read_alarm, |
| 220 | .set_alarm = vt8500_rtc_set_alarm, | 201 | .set_alarm = vt8500_rtc_set_alarm, |
| 221 | .alarm_irq_enable = vt8500_alarm_irq_enable, | 202 | .alarm_irq_enable = vt8500_alarm_irq_enable, |
| 222 | .update_irq_enable = vt8500_update_irq_enable, | ||
| 223 | }; | 203 | }; |
| 224 | 204 | ||
| 225 | static int __devinit vt8500_rtc_probe(struct platform_device *pdev) | 205 | static int __devinit vt8500_rtc_probe(struct platform_device *pdev) |
| @@ -248,13 +228,6 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev) | |||
| 248 | goto err_free; | 228 | goto err_free; |
| 249 | } | 229 | } |
| 250 | 230 | ||
| 251 | vt8500_rtc->irq_hz = platform_get_irq(pdev, 1); | ||
| 252 | if (vt8500_rtc->irq_hz < 0) { | ||
| 253 | dev_err(&pdev->dev, "No 1Hz IRQ resource defined\n"); | ||
| 254 | ret = -ENXIO; | ||
| 255 | goto err_free; | ||
| 256 | } | ||
| 257 | |||
| 258 | vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start, | 231 | vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start, |
| 259 | resource_size(vt8500_rtc->res), | 232 | resource_size(vt8500_rtc->res), |
| 260 | "vt8500-rtc"); | 233 | "vt8500-rtc"); |
| @@ -272,9 +245,8 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev) | |||
| 272 | goto err_release; | 245 | goto err_release; |
| 273 | } | 246 | } |
| 274 | 247 | ||
| 275 | /* Enable the second/minute interrupt generation and enable RTC */ | 248 | /* Enable RTC and set it to 24-hour mode */ |
| 276 | writel(VT8500_RTC_CR_ENABLE | VT8500_RTC_CR_24H | 249 | writel(VT8500_RTC_CR_ENABLE | VT8500_RTC_CR_24H, |
| 277 | | VT8500_RTC_CR_SM_ENABLE | VT8500_RTC_CR_SM_SEC, | ||
| 278 | vt8500_rtc->regbase + VT8500_RTC_CR); | 250 | vt8500_rtc->regbase + VT8500_RTC_CR); |
| 279 | 251 | ||
| 280 | vt8500_rtc->rtc = rtc_device_register("vt8500-rtc", &pdev->dev, | 252 | vt8500_rtc->rtc = rtc_device_register("vt8500-rtc", &pdev->dev, |
| @@ -286,26 +258,16 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev) | |||
| 286 | goto err_unmap; | 258 | goto err_unmap; |
| 287 | } | 259 | } |
| 288 | 260 | ||
| 289 | ret = request_irq(vt8500_rtc->irq_hz, vt8500_rtc_irq, 0, | ||
| 290 | "rtc 1Hz", vt8500_rtc); | ||
| 291 | if (ret < 0) { | ||
| 292 | dev_err(&pdev->dev, "can't get irq %i, err %d\n", | ||
| 293 | vt8500_rtc->irq_hz, ret); | ||
| 294 | goto err_unreg; | ||
| 295 | } | ||
| 296 | |||
| 297 | ret = request_irq(vt8500_rtc->irq_alarm, vt8500_rtc_irq, 0, | 261 | ret = request_irq(vt8500_rtc->irq_alarm, vt8500_rtc_irq, 0, |
| 298 | "rtc alarm", vt8500_rtc); | 262 | "rtc alarm", vt8500_rtc); |
| 299 | if (ret < 0) { | 263 | if (ret < 0) { |
| 300 | dev_err(&pdev->dev, "can't get irq %i, err %d\n", | 264 | dev_err(&pdev->dev, "can't get irq %i, err %d\n", |
| 301 | vt8500_rtc->irq_alarm, ret); | 265 | vt8500_rtc->irq_alarm, ret); |
| 302 | goto err_free_hz; | 266 | goto err_unreg; |
| 303 | } | 267 | } |
| 304 | 268 | ||
| 305 | return 0; | 269 | return 0; |
| 306 | 270 | ||
| 307 | err_free_hz: | ||
| 308 | free_irq(vt8500_rtc->irq_hz, vt8500_rtc); | ||
| 309 | err_unreg: | 271 | err_unreg: |
| 310 | rtc_device_unregister(vt8500_rtc->rtc); | 272 | rtc_device_unregister(vt8500_rtc->rtc); |
| 311 | err_unmap: | 273 | err_unmap: |
| @@ -323,7 +285,6 @@ static int __devexit vt8500_rtc_remove(struct platform_device *pdev) | |||
| 323 | struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev); | 285 | struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev); |
| 324 | 286 | ||
| 325 | free_irq(vt8500_rtc->irq_alarm, vt8500_rtc); | 287 | free_irq(vt8500_rtc->irq_alarm, vt8500_rtc); |
| 326 | free_irq(vt8500_rtc->irq_hz, vt8500_rtc); | ||
| 327 | 288 | ||
| 328 | rtc_device_unregister(vt8500_rtc->rtc); | 289 | rtc_device_unregister(vt8500_rtc->rtc); |
| 329 | 290 | ||
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 2d966244ea60..59f369f98a04 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c | |||
| @@ -42,15 +42,75 @@ static struct alarm_base { | |||
| 42 | clockid_t base_clockid; | 42 | clockid_t base_clockid; |
| 43 | } alarm_bases[ALARM_NUMTYPE]; | 43 | } alarm_bases[ALARM_NUMTYPE]; |
| 44 | 44 | ||
| 45 | /* freezer delta & lock used to handle clock_nanosleep triggered wakeups */ | ||
| 46 | static ktime_t freezer_delta; | ||
| 47 | static DEFINE_SPINLOCK(freezer_delta_lock); | ||
| 48 | |||
| 45 | #ifdef CONFIG_RTC_CLASS | 49 | #ifdef CONFIG_RTC_CLASS |
| 46 | /* rtc timer and device for setting alarm wakeups at suspend */ | 50 | /* rtc timer and device for setting alarm wakeups at suspend */ |
| 47 | static struct rtc_timer rtctimer; | 51 | static struct rtc_timer rtctimer; |
| 48 | static struct rtc_device *rtcdev; | 52 | static struct rtc_device *rtcdev; |
| 49 | #endif | 53 | static DEFINE_SPINLOCK(rtcdev_lock); |
| 50 | 54 | ||
| 51 | /* freezer delta & lock used to handle clock_nanosleep triggered wakeups */ | 55 | /** |
| 52 | static ktime_t freezer_delta; | 56 | * has_wakealarm - check rtc device has wakealarm ability |
| 53 | static DEFINE_SPINLOCK(freezer_delta_lock); | 57 | * @dev: current device |
| 58 | * @name_ptr: name to be returned | ||
| 59 | * | ||
| 60 | * This helper function checks to see if the rtc device can wake | ||
| 61 | * from suspend. | ||
| 62 | */ | ||
| 63 | static int has_wakealarm(struct device *dev, void *name_ptr) | ||
| 64 | { | ||
| 65 | struct rtc_device *candidate = to_rtc_device(dev); | ||
| 66 | |||
| 67 | if (!candidate->ops->set_alarm) | ||
| 68 | return 0; | ||
| 69 | if (!device_may_wakeup(candidate->dev.parent)) | ||
| 70 | return 0; | ||
| 71 | |||
| 72 | *(const char **)name_ptr = dev_name(dev); | ||
| 73 | return 1; | ||
| 74 | } | ||
| 75 | |||
| 76 | /** | ||
| 77 | * alarmtimer_get_rtcdev - Return selected rtcdevice | ||
| 78 | * | ||
| 79 | * This function returns the rtc device to use for wakealarms. | ||
| 80 | * If one has not already been chosen, it checks to see if a | ||
| 81 | * functional rtc device is available. | ||
| 82 | */ | ||
| 83 | static struct rtc_device *alarmtimer_get_rtcdev(void) | ||
| 84 | { | ||
| 85 | struct device *dev; | ||
| 86 | char *str; | ||
| 87 | unsigned long flags; | ||
| 88 | struct rtc_device *ret; | ||
| 89 | |||
| 90 | spin_lock_irqsave(&rtcdev_lock, flags); | ||
| 91 | if (!rtcdev) { | ||
| 92 | /* Find an rtc device and init the rtc_timer */ | ||
| 93 | dev = class_find_device(rtc_class, NULL, &str, has_wakealarm); | ||
| 94 | /* If we have a device then str is valid. See has_wakealarm() */ | ||
| 95 | if (dev) { | ||
| 96 | rtcdev = rtc_class_open(str); | ||
| 97 | /* | ||
| 98 | * Drop the reference we got in class_find_device, | ||
| 99 | * rtc_open takes its own. | ||
| 100 | */ | ||
| 101 | put_device(dev); | ||
| 102 | rtc_timer_init(&rtctimer, NULL, NULL); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | ret = rtcdev; | ||
| 106 | spin_unlock_irqrestore(&rtcdev_lock, flags); | ||
| 107 | |||
| 108 | return ret; | ||
| 109 | } | ||
| 110 | #else | ||
| 111 | #define alarmtimer_get_rtcdev() (0) | ||
| 112 | #define rtcdev (0) | ||
| 113 | #endif | ||
| 54 | 114 | ||
| 55 | 115 | ||
| 56 | /** | 116 | /** |
| @@ -166,6 +226,7 @@ static int alarmtimer_suspend(struct device *dev) | |||
| 166 | struct rtc_time tm; | 226 | struct rtc_time tm; |
| 167 | ktime_t min, now; | 227 | ktime_t min, now; |
| 168 | unsigned long flags; | 228 | unsigned long flags; |
| 229 | struct rtc_device *rtc; | ||
| 169 | int i; | 230 | int i; |
| 170 | 231 | ||
| 171 | spin_lock_irqsave(&freezer_delta_lock, flags); | 232 | spin_lock_irqsave(&freezer_delta_lock, flags); |
| @@ -173,8 +234,9 @@ static int alarmtimer_suspend(struct device *dev) | |||
| 173 | freezer_delta = ktime_set(0, 0); | 234 | freezer_delta = ktime_set(0, 0); |
| 174 | spin_unlock_irqrestore(&freezer_delta_lock, flags); | 235 | spin_unlock_irqrestore(&freezer_delta_lock, flags); |
| 175 | 236 | ||
| 237 | rtc = rtcdev; | ||
| 176 | /* If we have no rtcdev, just return */ | 238 | /* If we have no rtcdev, just return */ |
| 177 | if (!rtcdev) | 239 | if (!rtc) |
| 178 | return 0; | 240 | return 0; |
| 179 | 241 | ||
| 180 | /* Find the soonest timer to expire*/ | 242 | /* Find the soonest timer to expire*/ |
| @@ -199,12 +261,12 @@ static int alarmtimer_suspend(struct device *dev) | |||
| 199 | WARN_ON(min.tv64 < NSEC_PER_SEC); | 261 | WARN_ON(min.tv64 < NSEC_PER_SEC); |
| 200 | 262 | ||
| 201 | /* Setup an rtc timer to fire that far in the future */ | 263 | /* Setup an rtc timer to fire that far in the future */ |
| 202 | rtc_timer_cancel(rtcdev, &rtctimer); | 264 | rtc_timer_cancel(rtc, &rtctimer); |
| 203 | rtc_read_time(rtcdev, &tm); | 265 | rtc_read_time(rtc, &tm); |
| 204 | now = rtc_tm_to_ktime(tm); | 266 | now = rtc_tm_to_ktime(tm); |
| 205 | now = ktime_add(now, min); | 267 | now = ktime_add(now, min); |
| 206 | 268 | ||
| 207 | rtc_timer_start(rtcdev, &rtctimer, now, ktime_set(0, 0)); | 269 | rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0)); |
| 208 | 270 | ||
| 209 | return 0; | 271 | return 0; |
| 210 | } | 272 | } |
| @@ -322,6 +384,9 @@ static int alarm_clock_getres(const clockid_t which_clock, struct timespec *tp) | |||
| 322 | { | 384 | { |
| 323 | clockid_t baseid = alarm_bases[clock2alarm(which_clock)].base_clockid; | 385 | clockid_t baseid = alarm_bases[clock2alarm(which_clock)].base_clockid; |
| 324 | 386 | ||
| 387 | if (!alarmtimer_get_rtcdev()) | ||
| 388 | return -ENOTSUPP; | ||
| 389 | |||
| 325 | return hrtimer_get_res(baseid, tp); | 390 | return hrtimer_get_res(baseid, tp); |
| 326 | } | 391 | } |
| 327 | 392 | ||
| @@ -336,6 +401,9 @@ static int alarm_clock_get(clockid_t which_clock, struct timespec *tp) | |||
| 336 | { | 401 | { |
| 337 | struct alarm_base *base = &alarm_bases[clock2alarm(which_clock)]; | 402 | struct alarm_base *base = &alarm_bases[clock2alarm(which_clock)]; |
| 338 | 403 | ||
| 404 | if (!alarmtimer_get_rtcdev()) | ||
| 405 | return -ENOTSUPP; | ||
| 406 | |||
| 339 | *tp = ktime_to_timespec(base->gettime()); | 407 | *tp = ktime_to_timespec(base->gettime()); |
| 340 | return 0; | 408 | return 0; |
| 341 | } | 409 | } |
| @@ -351,6 +419,9 @@ static int alarm_timer_create(struct k_itimer *new_timer) | |||
| 351 | enum alarmtimer_type type; | 419 | enum alarmtimer_type type; |
| 352 | struct alarm_base *base; | 420 | struct alarm_base *base; |
| 353 | 421 | ||
| 422 | if (!alarmtimer_get_rtcdev()) | ||
| 423 | return -ENOTSUPP; | ||
| 424 | |||
| 354 | if (!capable(CAP_WAKE_ALARM)) | 425 | if (!capable(CAP_WAKE_ALARM)) |
| 355 | return -EPERM; | 426 | return -EPERM; |
| 356 | 427 | ||
| @@ -385,6 +456,9 @@ static void alarm_timer_get(struct k_itimer *timr, | |||
| 385 | */ | 456 | */ |
| 386 | static int alarm_timer_del(struct k_itimer *timr) | 457 | static int alarm_timer_del(struct k_itimer *timr) |
| 387 | { | 458 | { |
| 459 | if (!rtcdev) | ||
| 460 | return -ENOTSUPP; | ||
| 461 | |||
| 388 | alarm_cancel(&timr->it.alarmtimer); | 462 | alarm_cancel(&timr->it.alarmtimer); |
| 389 | return 0; | 463 | return 0; |
| 390 | } | 464 | } |
| @@ -402,6 +476,9 @@ static int alarm_timer_set(struct k_itimer *timr, int flags, | |||
| 402 | struct itimerspec *new_setting, | 476 | struct itimerspec *new_setting, |
| 403 | struct itimerspec *old_setting) | 477 | struct itimerspec *old_setting) |
| 404 | { | 478 | { |
| 479 | if (!rtcdev) | ||
| 480 | return -ENOTSUPP; | ||
| 481 | |||
| 405 | /* Save old values */ | 482 | /* Save old values */ |
| 406 | old_setting->it_interval = | 483 | old_setting->it_interval = |
| 407 | ktime_to_timespec(timr->it.alarmtimer.period); | 484 | ktime_to_timespec(timr->it.alarmtimer.period); |
| @@ -541,6 +618,9 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, | |||
| 541 | int ret = 0; | 618 | int ret = 0; |
| 542 | struct restart_block *restart; | 619 | struct restart_block *restart; |
| 543 | 620 | ||
| 621 | if (!alarmtimer_get_rtcdev()) | ||
| 622 | return -ENOTSUPP; | ||
| 623 | |||
| 544 | if (!capable(CAP_WAKE_ALARM)) | 624 | if (!capable(CAP_WAKE_ALARM)) |
| 545 | return -EPERM; | 625 | return -EPERM; |
| 546 | 626 | ||
| @@ -638,65 +718,3 @@ static int __init alarmtimer_init(void) | |||
| 638 | } | 718 | } |
| 639 | device_initcall(alarmtimer_init); | 719 | device_initcall(alarmtimer_init); |
| 640 | 720 | ||
| 641 | #ifdef CONFIG_RTC_CLASS | ||
| 642 | /** | ||
| 643 | * has_wakealarm - check rtc device has wakealarm ability | ||
| 644 | * @dev: current device | ||
| 645 | * @name_ptr: name to be returned | ||
| 646 | * | ||
| 647 | * This helper function checks to see if the rtc device can wake | ||
| 648 | * from suspend. | ||
| 649 | */ | ||
| 650 | static int __init has_wakealarm(struct device *dev, void *name_ptr) | ||
| 651 | { | ||
| 652 | struct rtc_device *candidate = to_rtc_device(dev); | ||
| 653 | |||
| 654 | if (!candidate->ops->set_alarm) | ||
| 655 | return 0; | ||
| 656 | if (!device_may_wakeup(candidate->dev.parent)) | ||
| 657 | return 0; | ||
| 658 | |||
| 659 | *(const char **)name_ptr = dev_name(dev); | ||
| 660 | return 1; | ||
| 661 | } | ||
| 662 | |||
| 663 | /** | ||
| 664 | * alarmtimer_init_late - Late initializing of alarmtimer code | ||
| 665 | * | ||
| 666 | * This function locates a rtc device to use for wakealarms. | ||
| 667 | * Run as late_initcall to make sure rtc devices have been | ||
| 668 | * registered. | ||
| 669 | */ | ||
| 670 | static int __init alarmtimer_init_late(void) | ||
| 671 | { | ||
| 672 | struct device *dev; | ||
| 673 | char *str; | ||
| 674 | |||
| 675 | /* Find an rtc device and init the rtc_timer */ | ||
| 676 | dev = class_find_device(rtc_class, NULL, &str, has_wakealarm); | ||
| 677 | /* If we have a device then str is valid. See has_wakealarm() */ | ||
| 678 | if (dev) { | ||
| 679 | rtcdev = rtc_class_open(str); | ||
| 680 | /* | ||
| 681 | * Drop the reference we got in class_find_device, | ||
| 682 | * rtc_open takes its own. | ||
| 683 | */ | ||
| 684 | put_device(dev); | ||
| 685 | } | ||
| 686 | if (!rtcdev) { | ||
| 687 | printk(KERN_WARNING "No RTC device found, ALARM timers will" | ||
| 688 | " not wake from suspend"); | ||
| 689 | } | ||
| 690 | rtc_timer_init(&rtctimer, NULL, NULL); | ||
| 691 | |||
| 692 | return 0; | ||
| 693 | } | ||
| 694 | #else | ||
| 695 | static int __init alarmtimer_init_late(void) | ||
| 696 | { | ||
| 697 | printk(KERN_WARNING "Kernel not built with RTC support, ALARM timers" | ||
| 698 | " will not wake from suspend"); | ||
| 699 | return 0; | ||
| 700 | } | ||
| 701 | #endif | ||
| 702 | late_initcall(alarmtimer_init_late); | ||
