aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorJohan Hovold <johan@kernel.org>2014-12-10 18:53:13 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-10 20:41:14 -0500
commit222a12fca6048249d9007f2a4c5fbcea532e8522 (patch)
tree6b0ce1d345dae13406bd81dbdbfa363cc389a4ce /drivers/rtc
parentc253a8965cdf54806f74c4f46cb2f50b95a65b83 (diff)
rtc: omap: add support for pmic_power_en
Add new property "ti,system-power-controller" to register the RTC as a power-off handler. Some RTC IP revisions can control an external PMIC via the pmic_power_en pin, which can be configured to transition to OFF on ALARM2 events and back to ON on subsequent ALARM (wakealarm) events. This is based on earlier work by Colin Foe-Parker and AnilKumar Ch. [1] [1] https://www.mail-archive.com/linux-omap@vger.kernel.org/msg82127.html [akpm@linux-foundation.org: add comment] Signed-off-by: Johan Hovold <johan@kernel.org> Cc: Colin Foe-Parker <colin.foeparker@logicpd.com> Cc: AnilKumar Ch <anilkumar@ti.com> Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: Tony Lindgren <tony@atomide.com> Cc: Benot Cousson <bcousson@baylibre.com> Cc: Lokesh Vutla <lokeshvutla@ti.com> Cc: Guenter Roeck <linux@roeck-us.net> Cc: Sekhar Nori <nsekhar@ti.com> Cc: Tero Kristo <t-kristo@ti.com> Cc: Keerthy J <j-keerthy@ti.com> Tested-by: Felipe Balbi <balbi@ti.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/rtc-omap.c100
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
364static 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 */
380static 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
348static struct rtc_class_ops omap_rtc_ops = { 428static 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
366static const struct omap_rtc_device_type omap_rtc_da830_type = { 447static 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
525err: 619err:
@@ -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 */