[PATCH v1 2/2] tty: serial: 8250_dw: Keep init pinctrl state until first open
"Michał Kardaś" <[email protected]>
| Newsgroups | org.kernel.vger.linux-serial,org.kernel.vger.linux-gpio,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
When a UART port is connected to an external peripheral whose power domain is kept powered off until first use, transitioning the UART pins from the "init" state to the "default" state prematurely at probe completion can cause parasitic back-powering into the unpowered peripheral. Ensure that on boards specifying an "init" pinctrl state for the port, the "init" state is preserved until the port is first opened: 1. In dw8250_probe(), call pinctrl_keep_init_state(dev) to opt out of the automatic "init" -> "default" transition at probe completion and record this in data->in_init_state. 2. In dw8250_do_pm(), when the port is opened (state == 0), transition pins from "init" to "default" if data->in_init_state is set, and clear the flag. Suggested-by: Douglas Anderson <[email protected]> Co-developed-by: Vic Huang <[email protected]> Signed-off-by: Vic Huang <[email protected]> Signed-off-by: Michał Kardaś <[email protected]> --- drivers/tty/serial/8250/8250_dw.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 5fba913f3301..74e568e2a0d3 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -18,6 +18,7 @@ #include <linux/io.h> #include <linux/lockdep.h> #include <linux/module.h> +#include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/property.h> @@ -77,6 +78,7 @@ struct dw8250_data { unsigned int skip_autocfg:1; unsigned int uart_16550_compatible:1; unsigned int in_idle:1; + unsigned int in_init_state:1; u8 no_int_count; }; @@ -461,8 +463,15 @@ static int dw8250_handle_irq(struct uart_port *p) static void dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) { - if (!state) + struct dw8250_data *d = to_dw8250_data(port->private_data); + + if (!state) { pm_runtime_get_sync(port->dev); + if (d->in_init_state) { + d->in_init_state = false; + pinctrl_pm_select_default_state(port->dev); + } + } serial8250_do_pm(port, state, old); @@ -770,6 +779,8 @@ static int dw8250_probe(struct platform_device *pdev) if (data->data.line < 0) return data->data.line; + data->in_init_state = pinctrl_keep_init_state(dev); + platform_set_drvdata(pdev, data); pm_runtime_enable(dev); -- 2.55.0.654.g21b8a5bc05-goog