tty: serial: uartlite: Add runtime pm support
authorShubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
Tue, 13 Jul 2021 06:48:35 +0000 (12:18 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 21 Jul 2021 10:46:52 +0000 (12:46 +0200)
In the commit 07e5d4ff125a ("Revert serial-uartlite: Add runtime
support") the runtime pm support was reverted to aid reverting of
the other patches.

This patch adds the runtime PM support back.
The runtime pm calls are used to gate and enable the clocks.

Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
Link: https://lore.kernel.org/r/20210713064835.27978-3-shubhrajyoti.datta@xilinx.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/uartlite.c

index 0376c8607e898a9924c2666e814ea536bb02de2d..047099b14cee98baeaa985293bce7e41f8734018 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 #include <linux/clk.h>
+#include <linux/pm_runtime.h>
 
 #define ULITE_NAME             "ttyUL"
 #define ULITE_MAJOR            204
@@ -54,6 +55,7 @@
 #define ULITE_CONTROL_RST_TX   0x01
 #define ULITE_CONTROL_RST_RX   0x02
 #define ULITE_CONTROL_IE       0x10
+#define UART_AUTOSUSPEND_TIMEOUT       3000    /* ms */
 
 /* Static pointer to console port */
 #ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
@@ -390,12 +392,16 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
 static void ulite_pm(struct uart_port *port, unsigned int state,
                     unsigned int oldstate)
 {
-       struct uartlite_data *pdata = port->private_data;
+       int ret;
 
-       if (!state)
-               clk_enable(pdata->clk);
-       else
-               clk_disable(pdata->clk);
+       if (!state) {
+               ret = pm_runtime_get_sync(port->dev);
+               if (ret < 0)
+                       dev_err(port->dev, "Failed to enable clocks\n");
+       } else {
+               pm_runtime_mark_last_busy(port->dev);
+               pm_runtime_put_autosuspend(port->dev);
+       }
 }
 
 #ifdef CONFIG_CONSOLE_POLL
@@ -719,11 +725,38 @@ static int __maybe_unused ulite_resume(struct device *dev)
        return 0;
 }
 
+static int __maybe_unused ulite_runtime_suspend(struct device *dev)
+{
+       struct uart_port *port = dev_get_drvdata(dev);
+       struct uartlite_data *pdata = port->private_data;
+
+       clk_disable(pdata->clk);
+       return 0;
+};
+
+static int __maybe_unused ulite_runtime_resume(struct device *dev)
+{
+       struct uart_port *port = dev_get_drvdata(dev);
+       struct uartlite_data *pdata = port->private_data;
+       int ret;
+
+       ret = clk_enable(pdata->clk);
+       if (ret) {
+               dev_err(dev, "Cannot enable clock.\n");
+               return ret;
+       }
+       return 0;
+}
+
 /* ---------------------------------------------------------------------
  * Platform bus binding
  */
 
-static SIMPLE_DEV_PM_OPS(ulite_pm_ops, ulite_suspend, ulite_resume);
+static const struct dev_pm_ops ulite_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(ulite_suspend, ulite_resume)
+       SET_RUNTIME_PM_OPS(ulite_runtime_suspend,
+                          ulite_runtime_resume, NULL)
+};
 
 #if defined(CONFIG_OF)
 /* Match table for of_platform binding */
@@ -779,6 +812,11 @@ static int ulite_probe(struct platform_device *pdev)
                return ret;
        }
 
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
        if (!ulite_uart_driver.state) {
                dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
                ret = uart_register_driver(&ulite_uart_driver);
@@ -791,7 +829,8 @@ static int ulite_probe(struct platform_device *pdev)
 
        ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
 
-       clk_disable(pdata->clk);
+       pm_runtime_mark_last_busy(&pdev->dev);
+       pm_runtime_put_autosuspend(&pdev->dev);
 
        return ret;
 }
@@ -800,9 +839,14 @@ static int ulite_remove(struct platform_device *pdev)
 {
        struct uart_port *port = dev_get_drvdata(&pdev->dev);
        struct uartlite_data *pdata = port->private_data;
+       int rc;
 
        clk_disable_unprepare(pdata->clk);
-       return ulite_release(&pdev->dev);
+       rc = ulite_release(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       pm_runtime_set_suspended(&pdev->dev);
+       pm_runtime_dont_use_autosuspend(&pdev->dev);
+       return rc;
 }
 
 /* work with hotplug and coldplug */