[PATCH v4 09/11] OMAP2+: Serial: Use prepare and resume calls to gate uart clocks
From: Kevin Hilman <hidden>
Date: 2011-09-09 18:59:49
Also in:
linux-omap, linux-serial
Possibly related (same subject, not in this thread)
- 2011-09-07 · [PATCH v4 09/11] OMAP2+: Serial: Use prepare and resume calls to gate uart clocks · Govindraj.R <hidden>
"Govindraj.R" [off-list ref] writes:
Currently we are using uart prepare and resume calls to gate uart clocks retaining the same method. More details on reason to retain this design is provided here: http://www.spinics.net/lists/linux-serial/msg04128.html
This type of thing can go after the '---' since it doesn't belong in the permanent git history.
Since prepare and resume hooks are moved to driver itself we can just use a single prepare and resume call. As in driver we traverse on number of uart instance and handle it accordingly.
Some important functionality has been removed (and not documented.) Namely, the current code checks the next power when deciding whether or not to call prepare_idle, and vice versa for resume_idle. It's quite possible that it is no longer needed with the runtime PM
In 34xx uart can wakeup using module level PM_WKEN or IO PAD wakeup use resume_call from prcm irq handler to wakeup uart, based on chk_wakeup_status from io_pad or PM_WKST.
IMO, this patch should just replace the mulitple calls with a single call, but still in the idle path. Using the PRCM IRQ handler should be a separate patch with it's own changelog.
Signed-off-by: Govindraj.R <redacted>
Also, moving these calls to the driver means that the driver cannot be built as a module: arch/arm/mach-omap2/built-in.o: In function `omap2_enter_full_retention': /work/kernel/omap/pm/arch/arm/mach-omap2/pm24xx.c:141: undefined reference to `omap_uart_prepare_idle' /work/kernel/omap/pm/arch/arm/mach-omap2/pm24xx.c:148: undefined reference to `omap_uart_resume_idle' arch/arm/mach-omap2/built-in.o: In function `prcm_clear_mod_irqs': /work/kernel/omap/pm/arch/arm/mach-omap2/pm34xx.c:213: undefined reference to `omap_uart_resume_idle' arch/arm/mach-omap2/built-in.o: In function `omap_sram_idle': /work/kernel/omap/pm/arch/arm/mach-omap2/pm34xx.c:390: undefined reference to `omap_uart_prepare_idle'
quoted hunk
--- arch/arm/mach-omap2/pm24xx.c | 8 +---- arch/arm/mach-omap2/pm34xx.c | 17 +++++------- arch/arm/plat-omap/include/plat/serial.h | 4 +- drivers/tty/serial/omap-serial.c | 40 ++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 18 deletions(-)diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index 39f26af..91eacef 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c@@ -138,18 +138,14 @@ static void omap2_enter_full_retention(void) if (!console_trylock()) goto no_sleep; - omap_uart_prepare_idle(0); - omap_uart_prepare_idle(1); - omap_uart_prepare_idle(2); + omap_uart_prepare_idle(); /* Jump to SRAM suspend code */ omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL), OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL), OMAP_SDRC_REGADDR(SDRC_POWER)); - omap_uart_resume_idle(2); - omap_uart_resume_idle(1); - omap_uart_resume_idle(0); + omap_uart_resume_idle(); if (!is_suspending()) console_unlock();diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 9f3bf2c..26ddd56 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c@@ -210,6 +210,7 @@ static int prcm_clear_mod_irqs(s16 module, u8 regs) wkst = omap2_prm_read_mod_reg(module, wkst_off); wkst &= omap2_prm_read_mod_reg(module, grpsel_off); + c += omap_uart_resume_idle(); if (wkst) { iclk = omap2_cm_read_mod_reg(module, iclk_off); fclk = omap2_cm_read_mod_reg(module, fclk_off);@@ -380,17 +381,19 @@ void omap_sram_idle(void) } /* Block console output in case it is on one of the OMAP UARTs */ - if (!is_suspending()) + if (!is_suspending()) { if (per_next_state < PWRDM_POWER_ON || - core_next_state < PWRDM_POWER_ON) + core_next_state < PWRDM_POWER_ON) { if (!console_trylock()) goto console_still_active; + else + omap_uart_prepare_idle(); + } + } /* PER */ if (per_next_state < PWRDM_POWER_ON) { per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0; - omap_uart_prepare_idle(2); - omap_uart_prepare_idle(3); omap2_gpio_prepare_for_idle(per_going_off); if (per_next_state == PWRDM_POWER_OFF) omap3_per_save_context();@@ -398,8 +401,6 @@ void omap_sram_idle(void) /* CORE */ if (core_next_state < PWRDM_POWER_ON) { - omap_uart_prepare_idle(0); - omap_uart_prepare_idle(1); if (core_next_state == PWRDM_POWER_OFF) { omap3_core_save_context(); omap3_cm_save_context();@@ -446,8 +447,6 @@ void omap_sram_idle(void) omap3_sram_restore_context(); omap2_sms_restore_context(); } - omap_uart_resume_idle(0); - omap_uart_resume_idle(1); if (core_next_state == PWRDM_POWER_OFF) omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK, OMAP3430_GR_MOD,@@ -461,8 +460,6 @@ void omap_sram_idle(void) omap2_gpio_resume_after_idle(); if (per_prev_state == PWRDM_POWER_OFF) omap3_per_restore_context(); - omap_uart_resume_idle(2); - omap_uart_resume_idle(3); } if (!is_suspending())diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h index bfd73b7..5b8c8f2 100644 --- a/arch/arm/plat-omap/include/plat/serial.h +++ b/arch/arm/plat-omap/include/plat/serial.h@@ -109,8 +109,8 @@ struct omap_board_data; extern void omap_serial_init(void); extern void omap_serial_init_port(struct omap_board_data *bdata); -extern void omap_uart_prepare_idle(int num); -extern void omap_uart_resume_idle(int num); +extern void omap_uart_prepare_idle(void); +extern int omap_uart_resume_idle(void); #endif #endifdiff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 96fc860..05c2f52 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c@@ -54,6 +54,46 @@ static void serial_omap_rx_timeout(unsigned long uart_no); static int serial_omap_start_rxdma(struct uart_omap_port *up); static void omap_uart_mdr1_errataset(struct uart_omap_port *up, u8 mdr1); +int omap_uart_resume_idle() +{ + struct uart_omap_port *up; + int i, ret = 0; + + for (i = 0; i < OMAP_MAX_HSUART_PORTS; i++) { + up = ui[i]; + if (!up) + continue; + + if (!up->clocked && up->chk_wakeup(up->pdev)) { + pm_runtime_get_sync(&up->pdev->dev); + up->clocked = 1; + ret++; + } + } + + return ret; +} + +void omap_uart_prepare_idle() +{ + struct uart_omap_port *up; + int i; + + for (i = 0; i < OMAP_MAX_HSUART_PORTS; i++) { + up = ui[i]; + if (!up) + continue; + + if (up->clocked && + jiffies_to_msecs(jiffies - up->port_activity) + > 3000) {
What is this check for?
+ pm_runtime_mark_last_busy(&up->pdev->dev);
+ pm_runtime_put_autosuspend(&up->pdev->dev);
+ up->clocked = 0;
+ }
+ }
+}
+
static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
{
offset <<= up->port.regshift;Kevin