Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtc: OMAP: Add support for rtc-only mode

Prepare rtc driver for rtc-only with DDR in self-refresh mode.
omap_rtc_power_off now should cater to two features:

1) RTC plus DDR in self-refresh is power a saving mode where in the
entire system including the different voltage rails from PMIC are
shutdown except the ones feeding on to RTC and DDR. DDR is kept in
self-refresh hence the contents are preserved. RTC ALARM2 is connected
to PMIC_EN line once we the ALARM2 is triggered we enter the mode with
DDR in self-refresh and RTC Ticking. After a predetermined time an RTC
ALARM1 triggers waking up the system[1]. The control goes to bootloader.
The bootloader then checks RTC scratchpad registers to confirm it was an
rtc_only wakeup and follows a different path, configure bare minimal
clocks for ddr and then jumps to the resume address in another RTC
scratchpad registers and transfers the control to Kernel. Kernel then
restores the saved context. omap_rtc_power_off_program does the ALARM2
programming part.

[1] http://www.ti.com/lit/ug/spruhl7h/spruhl7h.pdf Page 2884

2) Power-off: This is usual poweroff mode. omap_rtc_power_off calls the
above omap_rtc_power_off_program function and in addition to that
programs the OMAP_RTC_PMIC_REG for any external wake ups for PMIC like
the pushbutton and shuts off the PMIC.

Hence the split in omap_rtc_power_off.

Signed-off-by: Keerthy <j-keerthy@ti.com>
Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
[tony@atomide.com: folded in a fix for compile warning]
Signed-off-by: Tony Lindgren <tony@atomide.com>

authored by

Keerthy and committed by
Tony Lindgren
6256f7f7 9e98c678

+49 -9
+42 -9
drivers/rtc/rtc-omap.c
··· 415 415 416 416 static struct omap_rtc *omap_rtc_power_off_rtc; 417 417 418 - /* 419 - * omap_rtc_poweroff: RTC-controlled power off 420 - * 421 - * The RTC can be used to control an external PMIC via the pmic_power_en pin, 422 - * which can be configured to transition to OFF on ALARM2 events. 423 - * 424 - * Called with local interrupts disabled. 418 + /** 419 + * omap_rtc_power_off_program: Set the pmic power off sequence. The RTC 420 + * generates pmic_pwr_enable control, which can be used to control an external 421 + * PMIC. 425 422 */ 426 - static void omap_rtc_power_off(void) 423 + int omap_rtc_power_off_program(struct device *dev) 427 424 { 428 425 struct omap_rtc *rtc = omap_rtc_power_off_rtc; 429 426 struct rtc_time tm; ··· 434 437 rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN); 435 438 436 439 again: 440 + /* Clear any existing ALARM2 event */ 441 + rtc_writel(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM2); 442 + 437 443 /* set alarm one second from now */ 438 444 omap_rtc_read_time_raw(rtc, &tm); 439 445 seconds = tm.tm_sec; ··· 447 447 if (tm2bcd(&tm) < 0) { 448 448 dev_err(&rtc->rtc->dev, "power off failed\n"); 449 449 rtc->type->lock(rtc); 450 - return; 450 + return -EINVAL; 451 451 } 452 452 453 453 rtc_wait_not_busy(rtc); ··· 476 476 } 477 477 478 478 rtc->type->lock(rtc); 479 + 480 + return 0; 481 + } 482 + EXPORT_SYMBOL(omap_rtc_power_off_program); 483 + 484 + /* 485 + * omap_rtc_poweroff: RTC-controlled power off 486 + * 487 + * The RTC can be used to control an external PMIC via the pmic_power_en pin, 488 + * which can be configured to transition to OFF on ALARM2 events. 489 + * 490 + * Notes: 491 + * The one-second alarm offset is the shortest offset possible as the alarm 492 + * registers must be set before the next timer update and the offset 493 + * calculation is too heavy for everything to be done within a single access 494 + * period (~15 us). 495 + * 496 + * Called with local interrupts disabled. 497 + */ 498 + static void omap_rtc_power_off(void) 499 + { 500 + struct rtc_device *rtc = omap_rtc_power_off_rtc->rtc; 501 + u32 val; 502 + 503 + omap_rtc_power_off_program(rtc->dev.parent); 504 + 505 + /* Set PMIC power enable and EXT_WAKEUP in case PB power on is used */ 506 + omap_rtc_power_off_rtc->type->unlock(omap_rtc_power_off_rtc); 507 + val = rtc_readl(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG); 508 + val |= OMAP_RTC_PMIC_POWER_EN_EN | OMAP_RTC_PMIC_EXT_WKUP_POL(0) | 509 + OMAP_RTC_PMIC_EXT_WKUP_EN(0); 510 + rtc_writel(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG, val); 511 + omap_rtc_power_off_rtc->type->lock(omap_rtc_power_off_rtc); 479 512 480 513 /* 481 514 * Wait for alarm to trigger (within one second) and external PMIC to
+7
include/linux/rtc/rtc-omap.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef _LINUX_RTCOMAP_H_ 4 + #define _LINUX_RTCOMAP_H_ 5 + 6 + int omap_rtc_power_off_program(struct device *dev); 7 + #endif /* _LINUX_RTCOMAP_H_ */