From 2fd149645eb46d26130d7070c6de037dddf34880 Mon Sep 17 00:00:00 2001 From: "Govindraj.R" Date: Wed, 9 Nov 2011 17:41:21 +0530 Subject: ARM: OMAP2+: UART: Remove omap_uart_can_sleep and add pm_qos Omap_uart_can_sleep function blocks system wide low power state until uart is active remove this func and add qos requests to prevent MPU from transitioning. Keep qos request to default value which will allow MPU to transition and while uart baud rate is available calculate the latency value from the baudrate and use the same to hold constraint while uart clocks are enabled, and if uart is auto-idled the constraint is updated with default constraint value allowing MPU to transition. Qos requests are blocking notifier calls so put these requests to work queue, also the driver uses irq_safe version of runtime API's and callbacks can be called in interrupt disabled context. So to avoid warn on slow path warning while using qos update API's from runtime callbacks use the qos_work_queue. During bootup the runtime_resume call backs might not be called and runtime callback gets called only after uart is idled by setting the autosuspend timeout. So qos_request from runtime resume callback might not activated during boot if uart baudrate is calculated during bootup for console uart, so schedule the qos_work queue once we calc_latency while configuring the uart port. Flush and complete any pending qos jobs in work queue while suspending. Signed-off-by: Govindraj.R Acked-by: Greg Kroah-Hartman (for drivers/tty changes) Signed-off-by: Kevin Hilman --- drivers/tty/serial/omap-serial.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index e1eaa66c047..f3ff0ca377c 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -51,6 +51,8 @@ static void serial_omap_rxdma_poll(unsigned long uart_no); static int serial_omap_start_rxdma(struct uart_omap_port *up); static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1); +static struct workqueue_struct *serial_omap_uart_wq; + static inline unsigned int serial_in(struct uart_omap_port *up, int offset) { offset <<= up->port.regshift; @@ -671,6 +673,14 @@ serial_omap_configure_xonxoff serial_out(up, UART_LCR, up->lcr); } +static void serial_omap_uart_qos_work(struct work_struct *work) +{ + struct uart_omap_port *up = container_of(work, struct uart_omap_port, + qos_work); + + pm_qos_update_request(&up->pm_qos_request, up->latency); +} + static void serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) @@ -711,6 +721,12 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13); quot = serial_omap_get_divisor(port, baud); + /* calculate wakeup latency constraint */ + up->calc_latency = (1000000 * up->port.fifosize) / + (1000 * baud / 8); + up->latency = up->calc_latency; + schedule_work(&up->qos_work); + up->dll = quot & 0xff; up->dlh = quot >> 8; up->mdr1 = UART_OMAP_MDR1_DISABLE; @@ -1145,8 +1161,11 @@ static int serial_omap_suspend(struct device *dev) { struct uart_omap_port *up = dev_get_drvdata(dev); - if (up) + if (up) { uart_suspend_port(&serial_omap_reg, &up->port); + flush_work_sync(&up->qos_work); + } + return 0; } @@ -1383,6 +1402,13 @@ static int serial_omap_probe(struct platform_device *pdev) up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE; } + up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; + up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; + pm_qos_add_request(&up->pm_qos_request, + PM_QOS_CPU_DMA_LATENCY, up->latency); + serial_omap_uart_wq = create_singlethread_workqueue(up->name); + INIT_WORK(&up->qos_work, serial_omap_uart_qos_work); + pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, omap_up_info->autosuspend_timeout); @@ -1416,6 +1442,8 @@ static int serial_omap_remove(struct platform_device *dev) if (up) { pm_runtime_disable(&up->pdev->dev); uart_remove_one_port(&serial_omap_reg, &up->port); + pm_qos_remove_request(&up->pm_qos_request); + kfree(up); } @@ -1518,6 +1546,9 @@ static int serial_omap_runtime_suspend(struct device *dev) (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE)) pdata->set_forceidle(up->pdev); + up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; + schedule_work(&up->qos_work); + return 0; } @@ -1538,6 +1569,9 @@ static int serial_omap_runtime_resume(struct device *dev) if (up->use_dma && pdata->set_noidle && (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE)) pdata->set_noidle(up->pdev); + + up->latency = up->calc_latency; + schedule_work(&up->qos_work); } return 0; -- cgit v1.2.3