Hi, On Wed, Sep 21, 2011 at 8:13 PM, Govindraj.R <govindraj.raja@xxxxxx> wrote: > Adapts omap-serial driver to use pm_runtime API's. > console_unlock(); > > - if ((cpu_is_omap34xx() && bdata->pads) || > - (pdata->wk_en && pdata->wk_mask)) > + if ((cpu_is_omap34xx() && bdata->pads)) > device_init_wakeup(&pdev->dev, true); Just a bit curious, why doesn't the code enable wakeup at default on omap4, which will disable runtime pm of serial port on omap4. I have tested your patches on omap4 panda(enable wakeup at default manually), runtime pm of serial port 2 can work well and remote wakeup too. > > kfree(pdata); > diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h > index 74822b3..8ef81ce 100644 > --- a/arch/arm/plat-omap/include/plat/omap-serial.h > +++ b/arch/arm/plat-omap/include/plat/omap-serial.h > @@ -62,6 +62,9 @@ struct omap_uart_port_info { > upf_t flags; /* UPF_* flags */ > > u32 errata; > + > + void (*enable_wakeup)(struct platform_device *, bool); > + u32 (*get_context_loss_count)(struct device *); > }; > > struct uart_omap_dma { > @@ -113,6 +116,8 @@ struct uart_omap_port { > unsigned char msr_saved_flags; > char name[20]; > unsigned long port_activity; > + u32 context_loss_cnt; > + u8 wakeups_enabled; > }; > > #endif /* __OMAP_SERIAL_H__ */ > diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c > index 9a0eac2..43c33da 100644 > --- a/drivers/tty/serial/omap-serial.c > +++ b/drivers/tty/serial/omap-serial.c > @@ -37,11 +37,14 @@ > #include <linux/clk.h> > #include <linux/serial_core.h> > #include <linux/irq.h> > +#include <linux/pm_runtime.h> > > #include <plat/dma.h> > #include <plat/dmtimer.h> > #include <plat/omap-serial.h> > > +#define OMAP_UART_AUTOSUSPEND_DELAY -1 > + > static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; > > /* Forward declaration of functions */ > @@ -102,6 +105,8 @@ static void serial_omap_stop_rxdma(struct uart_omap_port *up) > omap_free_dma(up->uart_dma.rx_dma_channel); > up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE; > up->uart_dma.rx_dma_used = false; > + pm_runtime_mark_last_busy(&up->pdev->dev); > + pm_runtime_put_autosuspend(&up->pdev->dev); > } > } > > @@ -110,8 +115,11 @@ static void serial_omap_enable_ms(struct uart_port *port) > struct uart_omap_port *up = (struct uart_omap_port *)port; > > dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->pdev->id); > + > + pm_runtime_get_sync(&up->pdev->dev); > up->ier |= UART_IER_MSI; > serial_out(up, UART_IER, up->ier); > + pm_runtime_put(&up->pdev->dev); > } > > static void serial_omap_stop_tx(struct uart_port *port) > @@ -129,23 +137,32 @@ static void serial_omap_stop_tx(struct uart_port *port) > omap_stop_dma(up->uart_dma.tx_dma_channel); > omap_free_dma(up->uart_dma.tx_dma_channel); > up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE; > + pm_runtime_mark_last_busy(&up->pdev->dev); > + pm_runtime_put_autosuspend(&up->pdev->dev); > } > > + pm_runtime_get_sync(&up->pdev->dev); > if (up->ier & UART_IER_THRI) { > up->ier &= ~UART_IER_THRI; > serial_out(up, UART_IER, up->ier); > } > + > + pm_runtime_mark_last_busy(&up->pdev->dev); > + pm_runtime_put_autosuspend(&up->pdev->dev); > } > > static void serial_omap_stop_rx(struct uart_port *port) > { > struct uart_omap_port *up = (struct uart_omap_port *)port; > > + pm_runtime_get_sync(&up->pdev->dev); > if (up->use_dma) > serial_omap_stop_rxdma(up); > up->ier &= ~UART_IER_RLSI; > up->port.read_status_mask &= ~UART_LSR_DR; > serial_out(up, UART_IER, up->ier); > + pm_runtime_mark_last_busy(&up->pdev->dev); > + pm_runtime_put_autosuspend(&up->pdev->dev); > } > > static inline void receive_chars(struct uart_omap_port *up, int *status) > @@ -262,7 +279,10 @@ static void serial_omap_start_tx(struct uart_port *port) > int ret = 0; > > if (!up->use_dma) { > + pm_runtime_get_sync(&up->pdev->dev); > serial_omap_enable_ier_thri(up); > + pm_runtime_mark_last_busy(&up->pdev->dev); > + pm_runtime_put_autosuspend(&up->pdev->dev); > return; > } > > @@ -272,6 +292,7 @@ static void serial_omap_start_tx(struct uart_port *port) > xmit = &up->port.state->xmit; > > if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) { > + pm_runtime_get_sync(&up->pdev->dev); > ret = omap_request_dma(up->uart_dma.uart_dma_tx, > "UART Tx DMA", > (void *)uart_tx_dma_callback, up, > @@ -354,9 +375,13 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) > unsigned int iir, lsr; > unsigned long flags; > > + pm_runtime_get_sync(&up->pdev->dev); > iir = serial_in(up, UART_IIR); > - if (iir & UART_IIR_NO_INT) > + if (iir & UART_IIR_NO_INT) { > + pm_runtime_mark_last_busy(&up->pdev->dev); > + pm_runtime_put_autosuspend(&up->pdev->dev); > return IRQ_NONE; > + } > > spin_lock_irqsave(&up->port.lock, flags); > lsr = serial_in(up, UART_LSR); > @@ -378,6 +403,9 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) > transmit_chars(up); > > spin_unlock_irqrestore(&up->port.lock, flags); > + pm_runtime_mark_last_busy(&up->pdev->dev); > + pm_runtime_put_autosuspend(&up->pdev->dev); > + > up->port_activity = jiffies; > return IRQ_HANDLED; > } > @@ -388,11 +416,12 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port) > unsigned long flags = 0; > unsigned int ret = 0; > > + pm_runtime_get_sync(&up->pdev->dev); > dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id); > spin_lock_irqsave(&up->port.lock, flags); > ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; > spin_unlock_irqrestore(&up->port.lock, flags); > - > + pm_runtime_put(&up->pdev->dev); > return ret; > } > > @@ -402,7 +431,10 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port) > unsigned char status; > unsigned int ret = 0; > > + pm_runtime_get_sync(&up->pdev->dev); > status = check_modem_status(up); > + pm_runtime_put(&up->pdev->dev); > + > dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id); > > if (status & UART_MSR_DCD) > @@ -433,9 +465,11 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) > if (mctrl & TIOCM_LOOP) > mcr |= UART_MCR_LOOP; > > + pm_runtime_get_sync(&up->pdev->dev); > up->mcr = serial_in(up, UART_MCR); > up->mcr |= mcr; > serial_out(up, UART_MCR, up->mcr); > + pm_runtime_put(&up->pdev->dev); > } > > static void serial_omap_break_ctl(struct uart_port *port, int break_state) > @@ -444,6 +478,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state) > unsigned long flags = 0; > > dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id); > + pm_runtime_get_sync(&up->pdev->dev); > spin_lock_irqsave(&up->port.lock, flags); > if (break_state == -1) > up->lcr |= UART_LCR_SBC; > @@ -451,6 +486,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state) > up->lcr &= ~UART_LCR_SBC; > serial_out(up, UART_LCR, up->lcr); > spin_unlock_irqrestore(&up->port.lock, flags); > + pm_runtime_put(&up->pdev->dev); > } > > static int serial_omap_startup(struct uart_port *port) > @@ -469,6 +505,7 @@ static int serial_omap_startup(struct uart_port *port) > > dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id); > > + pm_runtime_get_sync(&up->pdev->dev); > /* > * Clear the FIFO buffers and disable them. > * (they will be reenabled in set_termios()) > @@ -524,6 +561,8 @@ static int serial_omap_startup(struct uart_port *port) > /* Enable module level wake up */ > serial_out(up, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP); > > + pm_runtime_mark_last_busy(&up->pdev->dev); > + pm_runtime_put_autosuspend(&up->pdev->dev); > up->port_activity = jiffies; > return 0; > } > @@ -534,6 +573,8 @@ static void serial_omap_shutdown(struct uart_port *port) > unsigned long flags = 0; > > dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id); > + > + pm_runtime_get_sync(&up->pdev->dev); > /* > * Disable interrupts from this port > */ > @@ -567,6 +608,7 @@ static void serial_omap_shutdown(struct uart_port *port) > up->uart_dma.rx_buf_dma_phys); > up->uart_dma.rx_buf = NULL; > } > + pm_runtime_put(&up->pdev->dev); > free_irq(up->port.irq, up); > } > > @@ -682,6 +724,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, > * Ok, we're now changing the port state. Do it with > * interrupts disabled. > */ > + pm_runtime_get_sync(&up->pdev->dev); > spin_lock_irqsave(&up->port.lock, flags); > > /* > @@ -814,6 +857,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, > serial_omap_configure_xonxoff(up, termios); > > spin_unlock_irqrestore(&up->port.lock, flags); > + pm_runtime_put(&up->pdev->dev); > dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id); > } > > @@ -825,6 +869,8 @@ serial_omap_pm(struct uart_port *port, unsigned int state, > unsigned char efr; > > dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id); > + > + pm_runtime_get_sync(&up->pdev->dev); > serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); > efr = serial_in(up, UART_EFR); > serial_out(up, UART_EFR, efr | UART_EFR_ECB); > @@ -834,6 +880,7 @@ serial_omap_pm(struct uart_port *port, unsigned int state, > serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); > serial_out(up, UART_EFR, efr); > serial_out(up, UART_LCR, 0); > + pm_runtime_put(&up->pdev->dev); > } > > static void serial_omap_release_port(struct uart_port *port) > @@ -911,19 +958,26 @@ static inline void wait_for_xmitr(struct uart_omap_port *up) > static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch) > { > struct uart_omap_port *up = (struct uart_omap_port *)port; > + > + pm_runtime_get_sync(&up->pdev->dev); > wait_for_xmitr(up); > serial_out(up, UART_TX, ch); > + pm_runtime_put(&up->pdev->dev); > } > > static int serial_omap_poll_get_char(struct uart_port *port) > { > struct uart_omap_port *up = (struct uart_omap_port *)port; > - unsigned int status = serial_in(up, UART_LSR); > + unsigned int status; > > + pm_runtime_get_sync(&up->pdev->dev); > + status = serial_in(up, UART_LSR); > if (!(status & UART_LSR_DR)) > return NO_POLL_CHAR; > > - return serial_in(up, UART_RX); > + status = serial_in(up, UART_RX); > + pm_runtime_put(&up->pdev->dev); > + return status; > } > > #endif /* CONFIG_CONSOLE_POLL */ > @@ -951,6 +1005,8 @@ serial_omap_console_write(struct console *co, const char *s, > unsigned int ier; > int locked = 1; > > + pm_runtime_get_sync(&up->pdev->dev); > + > local_irq_save(flags); > if (up->port.sysrq) > locked = 0; > @@ -983,6 +1039,8 @@ serial_omap_console_write(struct console *co, const char *s, > if (up->msr_saved_flags) > check_modem_status(up); > > + pm_runtime_mark_last_busy(&up->pdev->dev); > + pm_runtime_put_autosuspend(&up->pdev->dev); > if (locked) > spin_unlock(&up->port.lock); > local_irq_restore(flags); > @@ -1065,19 +1123,18 @@ static struct uart_driver serial_omap_reg = { > .cons = OMAP_CONSOLE, > }; > > -static int > -serial_omap_suspend(struct platform_device *pdev, pm_message_t state) > +static int serial_omap_suspend(struct device *dev) > { > - struct uart_omap_port *up = platform_get_drvdata(pdev); > + struct uart_omap_port *up = dev_get_drvdata(dev); > > if (up) > uart_suspend_port(&serial_omap_reg, &up->port); > return 0; > } > > -static int serial_omap_resume(struct platform_device *dev) > +static int serial_omap_resume(struct device *dev) > { > - struct uart_omap_port *up = platform_get_drvdata(dev); > + struct uart_omap_port *up = dev_get_drvdata(dev); > > if (up) > uart_resume_port(&serial_omap_reg, &up->port); > @@ -1140,6 +1197,7 @@ static int serial_omap_start_rxdma(struct uart_omap_port *up) > int ret = 0; > > if (up->uart_dma.rx_dma_channel == -1) { > + pm_runtime_get_sync(&up->pdev->dev); > ret = omap_request_dma(up->uart_dma.uart_dma_rx, > "UART Rx DMA", > (void *)uart_rx_dma_callback, up, > @@ -1305,6 +1363,16 @@ static int serial_omap_probe(struct platform_device *pdev) > up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE; > } > > + pm_runtime_use_autosuspend(&pdev->dev); > + pm_runtime_set_autosuspend_delay(&pdev->dev, > + OMAP_UART_AUTOSUSPEND_DELAY); > + > + pm_runtime_irq_safe(&pdev->dev); > + if (device_may_wakeup(&pdev->dev)) { > + pm_runtime_enable(&pdev->dev); > + pm_runtime_get_sync(&pdev->dev); > + } > + > ui[pdev->id] = up; > serial_omap_add_console_port(up); > > @@ -1312,6 +1380,7 @@ static int serial_omap_probe(struct platform_device *pdev) > if (ret != 0) > goto do_release_region; > > + pm_runtime_put(&pdev->dev); > platform_set_drvdata(pdev, up); > return 0; > err: > @@ -1326,22 +1395,96 @@ static int serial_omap_remove(struct platform_device *dev) > { > struct uart_omap_port *up = platform_get_drvdata(dev); > > - platform_set_drvdata(dev, NULL); > if (up) { > + pm_runtime_disable(&up->pdev->dev); > uart_remove_one_port(&serial_omap_reg, &up->port); > kfree(up); > } > + > + platform_set_drvdata(dev, NULL); > + return 0; > +} > + > +static void serial_omap_restore_context(struct uart_omap_port *up) > +{ > + serial_out(up, UART_OMAP_MDR1, up->mdr1); > + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */ > + serial_out(up, UART_EFR, UART_EFR_ECB); > + serial_out(up, UART_LCR, 0x0); /* Operational mode */ > + serial_out(up, UART_IER, 0x0); > + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */ > + serial_out(up, UART_DLL, up->dll); > + serial_out(up, UART_DLM, up->dlh); > + serial_out(up, UART_LCR, 0x0); /* Operational mode */ > + serial_out(up, UART_IER, up->ier); > + serial_out(up, UART_FCR, up->fcr); > + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); > + serial_out(up, UART_MCR, up->mcr); > + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */ > + serial_out(up, UART_EFR, up->efr); > + serial_out(up, UART_LCR, up->lcr); > + /* UART 16x mode */ > + serial_out(up, UART_OMAP_MDR1, up->mdr1); > +} > + > +static int serial_omap_runtime_suspend(struct device *dev) > +{ > + struct uart_omap_port *up = dev_get_drvdata(dev); > + struct omap_uart_port_info *pdata = dev->platform_data; > + > + if (!up) > + return -EINVAL; > + > + if (!pdata->enable_wakeup || !pdata->get_context_loss_count) > + return 0; > + > + if (pdata->get_context_loss_count) > + up->context_loss_cnt = pdata->get_context_loss_count(dev); > + > + if (device_may_wakeup(dev)) { > + if (!up->wakeups_enabled) { > + pdata->enable_wakeup(up->pdev, true); > + up->wakeups_enabled = true; > + } > + } else { > + if (up->wakeups_enabled) { > + pdata->enable_wakeup(up->pdev, false); > + up->wakeups_enabled = false; > + } > + } > + > + return 0; > +} > + > +static int serial_omap_runtime_resume(struct device *dev) > +{ > + struct uart_omap_port *up = dev_get_drvdata(dev); > + struct omap_uart_port_info *pdata = dev->platform_data; > + > + if (up) { > + if (pdata->get_context_loss_count) { > + u32 loss_cnt = pdata->get_context_loss_count(dev); > + > + if (up->context_loss_cnt != loss_cnt) > + serial_omap_restore_context(up); > + } > + } > + > return 0; > } > > +static const struct dev_pm_ops serial_omap_dev_pm_ops = { > + SET_SYSTEM_SLEEP_PM_OPS(serial_omap_suspend, serial_omap_resume) > + SET_RUNTIME_PM_OPS(serial_omap_runtime_suspend, > + serial_omap_runtime_resume, NULL) > +}; > + > static struct platform_driver serial_omap_driver = { > .probe = serial_omap_probe, > .remove = serial_omap_remove, > - > - .suspend = serial_omap_suspend, > - .resume = serial_omap_resume, > .driver = { > .name = DRIVER_NAME, > + .pm = &serial_omap_dev_pm_ops, > }, > }; > > -- > 1.7.4.1 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-omap" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > thanks, -- Ming Lei -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html