diff options
Diffstat (limited to 'drivers/tty/serial/stm32-usart.c')
-rw-r--r-- | drivers/tty/serial/stm32-usart.c | 83 |
1 files changed, 55 insertions, 28 deletions
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 24a2261f879a..5e93e8d40f59 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -8,10 +8,6 @@ * Inspired by st-asc.c from STMicroelectronics (c) */ -#if defined(CONFIG_SERIAL_STM32_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - #include <linux/clk.h> #include <linux/console.h> #include <linux/delay.h> @@ -24,6 +20,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_platform.h> +#include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/pm_wakeirq.h> @@ -239,8 +236,8 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) * cleared by the sequence [read SR - read DR]. */ if ((sr & USART_SR_ERR_MASK) && ofs->icr != UNDEF_REG) - stm32_clr_bits(port, ofs->icr, USART_ICR_ORECF | - USART_ICR_PECF | USART_ICR_FECF); + writel_relaxed(sr & USART_SR_ERR_MASK, + port->membase + ofs->icr); c = stm32_get_char(port, &sr, &stm32_port->last_res); port->icount.rx++; @@ -434,7 +431,7 @@ static void stm32_transmit_chars(struct uart_port *port) if (ofs->icr == UNDEF_REG) stm32_clr_bits(port, ofs->isr, USART_SR_TC); else - stm32_set_bits(port, ofs->icr, USART_ICR_TCCF); + writel_relaxed(USART_ICR_TCCF, port->membase + ofs->icr); if (stm32_port->tx_ch) stm32_transmit_chars_dma(port); @@ -881,13 +878,13 @@ static void stm32_pm(struct uart_port *port, unsigned int state, switch (state) { case UART_PM_STATE_ON: - clk_prepare_enable(stm32port->clk); + pm_runtime_get_sync(port->dev); break; case UART_PM_STATE_OFF: spin_lock_irqsave(&port->lock, flags); stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); spin_unlock_irqrestore(&port->lock, flags); - clk_disable_unprepare(stm32port->clk); + pm_runtime_put_sync(port->dev); break; } } @@ -925,13 +922,11 @@ static int stm32_init_port(struct stm32_port *stm32port, port->ops = &stm32_uart_ops; port->dev = &pdev->dev; port->fifosize = stm32port->info->cfg.fifosize; + port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE); ret = platform_get_irq(pdev, 0); - if (ret <= 0) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Can't get event IRQ: %d\n", ret); - return ret ? ret : -ENODEV; - } + if (ret <= 0) + return ret ? : -ENODEV; port->irq = ret; port->rs485_config = stm32_config_rs485; @@ -940,14 +935,8 @@ static int stm32_init_port(struct stm32_port *stm32port, if (stm32port->info->cfg.has_wakeup) { stm32port->wakeirq = platform_get_irq(pdev, 1); - if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO) { - if (stm32port->wakeirq != -EPROBE_DEFER) - dev_err(&pdev->dev, - "Can't get event wake IRQ: %d\n", - stm32port->wakeirq); - return stm32port->wakeirq ? stm32port->wakeirq : - -ENODEV; - } + if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO) + return stm32port->wakeirq ? : -ENODEV; } stm32port->fifoen = stm32port->info->cfg.has_fifo; @@ -1185,6 +1174,11 @@ static int stm32_serial_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &stm32port->port); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); + return 0; err_wirq: @@ -1206,6 +1200,9 @@ static int stm32_serial_remove(struct platform_device *pdev) struct uart_port *port = platform_get_drvdata(pdev); struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + int err; + + pm_runtime_get_sync(&pdev->dev); stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); @@ -1234,7 +1231,12 @@ static int stm32_serial_remove(struct platform_device *pdev) clk_disable_unprepare(stm32_port->clk); - return uart_remove_one_port(&stm32_usart_driver, port); + err = uart_remove_one_port(&stm32_usart_driver, port); + + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + + return err; } @@ -1337,8 +1339,8 @@ static struct uart_driver stm32_usart_driver = { .cons = STM32_SERIAL_CONSOLE, }; -#ifdef CONFIG_PM_SLEEP -static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable) +static void __maybe_unused stm32_serial_enable_wakeup(struct uart_port *port, + bool enable) { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; @@ -1362,7 +1364,7 @@ static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable) } } -static int stm32_serial_suspend(struct device *dev) +static int __maybe_unused stm32_serial_suspend(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); @@ -1373,21 +1375,46 @@ static int stm32_serial_suspend(struct device *dev) else stm32_serial_enable_wakeup(port, false); + pinctrl_pm_select_sleep_state(dev); + return 0; } -static int stm32_serial_resume(struct device *dev) +static int __maybe_unused stm32_serial_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + pinctrl_pm_select_default_state(dev); + if (device_may_wakeup(dev)) stm32_serial_enable_wakeup(port, false); return uart_resume_port(&stm32_usart_driver, port); } -#endif /* CONFIG_PM_SLEEP */ + +static int __maybe_unused stm32_serial_runtime_suspend(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct stm32_port *stm32port = container_of(port, + struct stm32_port, port); + + clk_disable_unprepare(stm32port->clk); + + return 0; +} + +static int __maybe_unused stm32_serial_runtime_resume(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct stm32_port *stm32port = container_of(port, + struct stm32_port, port); + + return clk_prepare_enable(stm32port->clk); +} static const struct dev_pm_ops stm32_serial_pm_ops = { + SET_RUNTIME_PM_OPS(stm32_serial_runtime_suspend, + stm32_serial_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(stm32_serial_suspend, stm32_serial_resume) }; |