diff options
Diffstat (limited to 'drivers/rtc/rtc-omap.c')
-rw-r--r-- | drivers/rtc/rtc-omap.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index c508e45ca3ce..e83f51ae7f63 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c | |||
@@ -68,6 +68,15 @@ | |||
68 | 68 | ||
69 | #define OMAP_RTC_IRQWAKEEN 0x7c | 69 | #define OMAP_RTC_IRQWAKEEN 0x7c |
70 | 70 | ||
71 | #define OMAP_RTC_ALARM2_SECONDS_REG 0x80 | ||
72 | #define OMAP_RTC_ALARM2_MINUTES_REG 0x84 | ||
73 | #define OMAP_RTC_ALARM2_HOURS_REG 0x88 | ||
74 | #define OMAP_RTC_ALARM2_DAYS_REG 0x8c | ||
75 | #define OMAP_RTC_ALARM2_MONTHS_REG 0x90 | ||
76 | #define OMAP_RTC_ALARM2_YEARS_REG 0x94 | ||
77 | |||
78 | #define OMAP_RTC_PMIC_REG 0x98 | ||
79 | |||
71 | /* OMAP_RTC_CTRL_REG bit fields: */ | 80 | /* OMAP_RTC_CTRL_REG bit fields: */ |
72 | #define OMAP_RTC_CTRL_SPLIT BIT(7) | 81 | #define OMAP_RTC_CTRL_SPLIT BIT(7) |
73 | #define OMAP_RTC_CTRL_DISABLE BIT(6) | 82 | #define OMAP_RTC_CTRL_DISABLE BIT(6) |
@@ -80,6 +89,7 @@ | |||
80 | 89 | ||
81 | /* OMAP_RTC_STATUS_REG bit fields: */ | 90 | /* OMAP_RTC_STATUS_REG bit fields: */ |
82 | #define OMAP_RTC_STATUS_POWER_UP BIT(7) | 91 | #define OMAP_RTC_STATUS_POWER_UP BIT(7) |
92 | #define OMAP_RTC_STATUS_ALARM2 BIT(7) | ||
83 | #define OMAP_RTC_STATUS_ALARM BIT(6) | 93 | #define OMAP_RTC_STATUS_ALARM BIT(6) |
84 | #define OMAP_RTC_STATUS_1D_EVENT BIT(5) | 94 | #define OMAP_RTC_STATUS_1D_EVENT BIT(5) |
85 | #define OMAP_RTC_STATUS_1H_EVENT BIT(4) | 95 | #define OMAP_RTC_STATUS_1H_EVENT BIT(4) |
@@ -89,6 +99,7 @@ | |||
89 | #define OMAP_RTC_STATUS_BUSY BIT(0) | 99 | #define OMAP_RTC_STATUS_BUSY BIT(0) |
90 | 100 | ||
91 | /* OMAP_RTC_INTERRUPTS_REG bit fields: */ | 101 | /* OMAP_RTC_INTERRUPTS_REG bit fields: */ |
102 | #define OMAP_RTC_INTERRUPTS_IT_ALARM2 BIT(4) | ||
92 | #define OMAP_RTC_INTERRUPTS_IT_ALARM BIT(3) | 103 | #define OMAP_RTC_INTERRUPTS_IT_ALARM BIT(3) |
93 | #define OMAP_RTC_INTERRUPTS_IT_TIMER BIT(2) | 104 | #define OMAP_RTC_INTERRUPTS_IT_TIMER BIT(2) |
94 | 105 | ||
@@ -98,6 +109,9 @@ | |||
98 | /* OMAP_RTC_IRQWAKEEN bit fields: */ | 109 | /* OMAP_RTC_IRQWAKEEN bit fields: */ |
99 | #define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN BIT(1) | 110 | #define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN BIT(1) |
100 | 111 | ||
112 | /* OMAP_RTC_PMIC bit fields: */ | ||
113 | #define OMAP_RTC_PMIC_POWER_EN_EN BIT(16) | ||
114 | |||
101 | /* OMAP_RTC_KICKER values */ | 115 | /* OMAP_RTC_KICKER values */ |
102 | #define KICK0_VALUE 0x83e70b13 | 116 | #define KICK0_VALUE 0x83e70b13 |
103 | #define KICK1_VALUE 0x95a4f1e0 | 117 | #define KICK1_VALUE 0x95a4f1e0 |
@@ -106,6 +120,7 @@ struct omap_rtc_device_type { | |||
106 | bool has_32kclk_en; | 120 | bool has_32kclk_en; |
107 | bool has_kicker; | 121 | bool has_kicker; |
108 | bool has_irqwakeen; | 122 | bool has_irqwakeen; |
123 | bool has_pmic_mode; | ||
109 | bool has_power_up_reset; | 124 | bool has_power_up_reset; |
110 | }; | 125 | }; |
111 | 126 | ||
@@ -115,6 +130,7 @@ struct omap_rtc { | |||
115 | int irq_alarm; | 130 | int irq_alarm; |
116 | int irq_timer; | 131 | int irq_timer; |
117 | u8 interrupts_reg; | 132 | u8 interrupts_reg; |
133 | bool is_pmic_controller; | ||
118 | const struct omap_rtc_device_type *type; | 134 | const struct omap_rtc_device_type *type; |
119 | }; | 135 | }; |
120 | 136 | ||
@@ -345,6 +361,70 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) | |||
345 | return 0; | 361 | return 0; |
346 | } | 362 | } |
347 | 363 | ||
364 | static struct omap_rtc *omap_rtc_power_off_rtc; | ||
365 | |||
366 | /* | ||
367 | * omap_rtc_poweroff: RTC-controlled power off | ||
368 | * | ||
369 | * The RTC can be used to control an external PMIC via the pmic_power_en pin, | ||
370 | * which can be configured to transition to OFF on ALARM2 events. | ||
371 | * | ||
372 | * Notes: | ||
373 | * The two-second alarm offset is the shortest offset possible as the alarm | ||
374 | * registers must be set before the next timer update and the offset | ||
375 | * calculation is too heavy for everything to be done within a single access | ||
376 | * period (~15 us). | ||
377 | * | ||
378 | * Called with local interrupts disabled. | ||
379 | */ | ||
380 | static void omap_rtc_power_off(void) | ||
381 | { | ||
382 | struct omap_rtc *rtc = omap_rtc_power_off_rtc; | ||
383 | struct rtc_time tm; | ||
384 | unsigned long now; | ||
385 | u32 val; | ||
386 | |||
387 | /* enable pmic_power_en control */ | ||
388 | val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); | ||
389 | rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN); | ||
390 | |||
391 | /* set alarm two seconds from now */ | ||
392 | omap_rtc_read_time_raw(rtc, &tm); | ||
393 | bcd2tm(&tm); | ||
394 | rtc_tm_to_time(&tm, &now); | ||
395 | rtc_time_to_tm(now + 2, &tm); | ||
396 | |||
397 | if (tm2bcd(&tm) < 0) { | ||
398 | dev_err(&rtc->rtc->dev, "power off failed\n"); | ||
399 | return; | ||
400 | } | ||
401 | |||
402 | rtc_wait_not_busy(rtc); | ||
403 | |||
404 | rtc_write(rtc, OMAP_RTC_ALARM2_SECONDS_REG, tm.tm_sec); | ||
405 | rtc_write(rtc, OMAP_RTC_ALARM2_MINUTES_REG, tm.tm_min); | ||
406 | rtc_write(rtc, OMAP_RTC_ALARM2_HOURS_REG, tm.tm_hour); | ||
407 | rtc_write(rtc, OMAP_RTC_ALARM2_DAYS_REG, tm.tm_mday); | ||
408 | rtc_write(rtc, OMAP_RTC_ALARM2_MONTHS_REG, tm.tm_mon); | ||
409 | rtc_write(rtc, OMAP_RTC_ALARM2_YEARS_REG, tm.tm_year); | ||
410 | |||
411 | /* | ||
412 | * enable ALARM2 interrupt | ||
413 | * | ||
414 | * NOTE: this fails on AM3352 if rtc_write (writeb) is used | ||
415 | */ | ||
416 | val = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); | ||
417 | rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG, | ||
418 | val | OMAP_RTC_INTERRUPTS_IT_ALARM2); | ||
419 | |||
420 | /* | ||
421 | * Wait for alarm to trigger (within two seconds) and external PMIC to | ||
422 | * power off the system. Add a 500 ms margin for external latencies | ||
423 | * (e.g. debounce circuits). | ||
424 | */ | ||
425 | mdelay(2500); | ||
426 | } | ||
427 | |||
348 | static struct rtc_class_ops omap_rtc_ops = { | 428 | static struct rtc_class_ops omap_rtc_ops = { |
349 | .read_time = omap_rtc_read_time, | 429 | .read_time = omap_rtc_read_time, |
350 | .set_time = omap_rtc_set_time, | 430 | .set_time = omap_rtc_set_time, |
@@ -361,6 +441,7 @@ static const struct omap_rtc_device_type omap_rtc_am3352_type = { | |||
361 | .has_32kclk_en = true, | 441 | .has_32kclk_en = true, |
362 | .has_kicker = true, | 442 | .has_kicker = true, |
363 | .has_irqwakeen = true, | 443 | .has_irqwakeen = true, |
444 | .has_pmic_mode = true, | ||
364 | }; | 445 | }; |
365 | 446 | ||
366 | static const struct omap_rtc_device_type omap_rtc_da830_type = { | 447 | static const struct omap_rtc_device_type omap_rtc_da830_type = { |
@@ -412,6 +493,9 @@ static int __init omap_rtc_probe(struct platform_device *pdev) | |||
412 | of_id = of_match_device(omap_rtc_of_match, &pdev->dev); | 493 | of_id = of_match_device(omap_rtc_of_match, &pdev->dev); |
413 | if (of_id) { | 494 | if (of_id) { |
414 | rtc->type = of_id->data; | 495 | rtc->type = of_id->data; |
496 | rtc->is_pmic_controller = rtc->type->has_pmic_mode && | ||
497 | of_property_read_bool(pdev->dev.of_node, | ||
498 | "ti,system-power-controller"); | ||
415 | } else { | 499 | } else { |
416 | id_entry = platform_get_device_id(pdev); | 500 | id_entry = platform_get_device_id(pdev); |
417 | rtc->type = (void *)id_entry->driver_data; | 501 | rtc->type = (void *)id_entry->driver_data; |
@@ -460,6 +544,9 @@ static int __init omap_rtc_probe(struct platform_device *pdev) | |||
460 | 544 | ||
461 | mask = OMAP_RTC_STATUS_ALARM; | 545 | mask = OMAP_RTC_STATUS_ALARM; |
462 | 546 | ||
547 | if (rtc->type->has_pmic_mode) | ||
548 | mask |= OMAP_RTC_STATUS_ALARM2; | ||
549 | |||
463 | if (rtc->type->has_power_up_reset) { | 550 | if (rtc->type->has_power_up_reset) { |
464 | mask |= OMAP_RTC_STATUS_POWER_UP; | 551 | mask |= OMAP_RTC_STATUS_POWER_UP; |
465 | if (reg & OMAP_RTC_STATUS_POWER_UP) | 552 | if (reg & OMAP_RTC_STATUS_POWER_UP) |
@@ -520,6 +607,13 @@ static int __init omap_rtc_probe(struct platform_device *pdev) | |||
520 | goto err; | 607 | goto err; |
521 | } | 608 | } |
522 | 609 | ||
610 | if (rtc->is_pmic_controller) { | ||
611 | if (!pm_power_off) { | ||
612 | omap_rtc_power_off_rtc = rtc; | ||
613 | pm_power_off = omap_rtc_power_off; | ||
614 | } | ||
615 | } | ||
616 | |||
523 | return 0; | 617 | return 0; |
524 | 618 | ||
525 | err: | 619 | err: |
@@ -536,6 +630,12 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) | |||
536 | { | 630 | { |
537 | struct omap_rtc *rtc = platform_get_drvdata(pdev); | 631 | struct omap_rtc *rtc = platform_get_drvdata(pdev); |
538 | 632 | ||
633 | if (pm_power_off == omap_rtc_power_off && | ||
634 | omap_rtc_power_off_rtc == rtc) { | ||
635 | pm_power_off = NULL; | ||
636 | omap_rtc_power_off_rtc = NULL; | ||
637 | } | ||
638 | |||
539 | device_init_wakeup(&pdev->dev, 0); | 639 | device_init_wakeup(&pdev->dev, 0); |
540 | 640 | ||
541 | /* leave rtc running, but disable irqs */ | 641 | /* leave rtc running, but disable irqs */ |