diff options
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 31 |
1 files changed, 23 insertions, 8 deletions
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 98da861fc8a..07d7081344e 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -53,6 +53,7 @@ #include <linux/scatterlist.h> #include <linux/delay.h> #include <linux/types.h> +#include <linux/pm_runtime.h> #include <asm/io.h> #include <asm/sizes.h> @@ -1231,6 +1232,7 @@ static void pl011_clock_off(struct work_struct *work) struct circ_buf *xmit = &port->state->xmit; unsigned long flags; bool disable_regulator = false; + bool runtime_put = false; unsigned int busy, interrupt_status; spin_lock_irqsave(&port->lock, flags); @@ -1244,6 +1246,7 @@ static void pl011_clock_off(struct work_struct *work) pl011_backup(uap, true); disable_regulator = true; } + runtime_put = true; uap->clk_state = PL011_CLK_OFF; clk_disable(uap->clk); } else @@ -1255,6 +1258,8 @@ static void pl011_clock_off(struct work_struct *work) if (disable_regulator) regulator_disable(uap->regulator); + if (runtime_put) + pm_runtime_put_sync(uap->port.dev); } /* Request to turn off uart clock once pending TX is flushed */ @@ -1285,6 +1290,7 @@ static void pl011_clock_on(struct uart_port *port) switch (uap->clk_state) { case PL011_CLK_OFF: + pm_runtime_get_sync(uap->port.dev); clk_enable(uap->clk); if (!uart_console(&uap->port) && uap->regulator) { spin_unlock_irqrestore(&port->lock, flags); @@ -1319,13 +1325,16 @@ static int pl011_power_startup(struct uart_amba_port *uap) int retval = 0; if (uap->clk_state == PL011_PORT_OFF) { + pm_runtime_get_sync(uap->port.dev); if (!uart_console(&uap->port) && uap->regulator) regulator_enable(uap->regulator); retval = clk_enable(uap->clk); - if (!retval) + if (!retval) { uap->clk_state = PL011_CLK_ON; - else + } else { uap->clk_state = PL011_PORT_OFF; + pm_runtime_put_sync(uap->port.dev); + } } return retval; @@ -1334,6 +1343,7 @@ static int pl011_power_startup(struct uart_amba_port *uap) static void pl011_power_shutdown(struct uart_amba_port *uap) { bool disable_regulator = false; + bool runtime_put = false; cancel_delayed_work_sync(&uap->clk_off_work); @@ -1341,6 +1351,7 @@ static void pl011_power_shutdown(struct uart_amba_port *uap) if (uap->clk_state == PL011_CLK_ON || uap->clk_state == PL011_CLK_REQUEST_OFF) { clk_disable(uap->clk); + runtime_put = true; if (!uart_console(&uap->port) && uap->regulator) disable_regulator = true; } @@ -1349,6 +1360,8 @@ static void pl011_power_shutdown(struct uart_amba_port *uap) if (disable_regulator) regulator_disable(uap->regulator); + if (runtime_put) + pm_runtime_put_sync(uap->port.dev); } static void @@ -1378,12 +1391,14 @@ static inline void pl011_clock_check(struct uart_amba_port *uap) static inline int pl011_power_startup(struct uart_amba_port *uap) { + pm_runtime_get_sync(uap->port.dev); return clk_enable(uap->clk); } static inline void pl011_power_shutdown(struct uart_amba_port *uap) { clk_disable(uap->clk); + pm_runtime_put_sync(uap->port.dev); } static inline void @@ -2288,6 +2303,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) pl011_clock_control_init(uap); ret = uart_add_one_port(&amba_reg, &uap->port); + + if (!ret) + pm_runtime_put(&dev->dev); + if (ret) { amba_set_drvdata(dev, NULL); amba_ports[i] = NULL; @@ -2301,12 +2320,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) kfree(uap); } out: - /* - * Disable the silicon block pclk and any voltage domain and just - * power it up and clock it when it's needed - */ - amba_pclk_disable(dev); - amba_vcore_disable(dev); return ret; } @@ -2318,6 +2331,8 @@ static int pl011_remove(struct amba_device *dev) amba_set_drvdata(dev, NULL); + pm_runtime_get_sync(uap->port.dev); + uart_remove_one_port(&amba_reg, &uap->port); for (i = 0; i < ARRAY_SIZE(amba_ports); i++) |