mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-04-16 04:13:31 +00:00
198 lines
5.8 KiB
Diff
198 lines
5.8 KiB
Diff
From e375f9d76a88bc847d44f38157c2dba1c7e02203 Mon Sep 17 00:00:00 2001
|
|
From: Hector Martin <marcan@marcan.st>
|
|
Date: Mon, 20 Sep 2021 02:23:11 +0900
|
|
Subject: [PATCH 057/171] tty: serial: samsung_tty: Support runtime PM
|
|
|
|
This allows idle UART devices to be suspended using the standard
|
|
runtime-PM framework. The logic is modeled after stm32-usart.
|
|
|
|
Signed-off-by: Hector Martin <marcan@marcan.st>
|
|
---
|
|
drivers/tty/serial/samsung_tty.c | 92 ++++++++++++++++++++------------
|
|
1 file changed, 59 insertions(+), 33 deletions(-)
|
|
|
|
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
|
|
index 1afe47b62ad5..2a4ba4f3d23c 100644
|
|
--- a/drivers/tty/serial/samsung_tty.c
|
|
+++ b/drivers/tty/serial/samsung_tty.c
|
|
@@ -40,6 +40,7 @@
|
|
#include <linux/clk.h>
|
|
#include <linux/cpufreq.h>
|
|
#include <linux/of.h>
|
|
+#include <linux/pm_runtime.h>
|
|
#include <asm/irq.h>
|
|
|
|
/* UART name and device definitions */
|
|
@@ -1354,30 +1355,49 @@ static int apple_s5l_serial_startup(struct uart_port *port)
|
|
|
|
/* power power management control */
|
|
|
|
+static int __maybe_unused s3c24xx_serial_runtime_suspend(struct device *dev)
|
|
+{
|
|
+ struct uart_port *port = dev_get_drvdata(dev);
|
|
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
|
|
+ int timeout = 10000;
|
|
+
|
|
+ while (--timeout && !s3c24xx_serial_txempty_nofifo(port))
|
|
+ udelay(100);
|
|
+
|
|
+ if (!IS_ERR(ourport->baudclk))
|
|
+ clk_disable_unprepare(ourport->baudclk);
|
|
+
|
|
+ clk_disable_unprepare(ourport->clk);
|
|
+ return 0;
|
|
+};
|
|
+
|
|
+static int __maybe_unused s3c24xx_serial_runtime_resume(struct device *dev)
|
|
+{
|
|
+ struct uart_port *port = dev_get_drvdata(dev);
|
|
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
|
|
+
|
|
+ clk_prepare_enable(ourport->clk);
|
|
+
|
|
+ if (!IS_ERR(ourport->baudclk))
|
|
+ clk_prepare_enable(ourport->baudclk);
|
|
+ return 0;
|
|
+};
|
|
+
|
|
static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
|
|
unsigned int old)
|
|
{
|
|
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
|
- int timeout = 10000;
|
|
|
|
ourport->pm_level = level;
|
|
|
|
switch (level) {
|
|
- case 3:
|
|
- while (--timeout && !s3c24xx_serial_txempty_nofifo(port))
|
|
- udelay(100);
|
|
-
|
|
- if (!IS_ERR(ourport->baudclk))
|
|
- clk_disable_unprepare(ourport->baudclk);
|
|
-
|
|
- clk_disable_unprepare(ourport->clk);
|
|
+ case UART_PM_STATE_OFF:
|
|
+ pm_runtime_mark_last_busy(port->dev);
|
|
+ pm_runtime_put_sync(port->dev);
|
|
break;
|
|
|
|
- case 0:
|
|
- clk_prepare_enable(ourport->clk);
|
|
-
|
|
- if (!IS_ERR(ourport->baudclk))
|
|
- clk_prepare_enable(ourport->baudclk);
|
|
+ case UART_PM_STATE_ON:
|
|
+ pm_runtime_get_sync(port->dev);
|
|
break;
|
|
default:
|
|
dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level);
|
|
@@ -2248,18 +2268,15 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
|
|
}
|
|
}
|
|
|
|
+ pm_runtime_get_noresume(&pdev->dev);
|
|
+ pm_runtime_set_active(&pdev->dev);
|
|
+ pm_runtime_enable(&pdev->dev);
|
|
+
|
|
dev_dbg(&pdev->dev, "%s: adding port\n", __func__);
|
|
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
|
|
platform_set_drvdata(pdev, &ourport->port);
|
|
|
|
- /*
|
|
- * Deactivate the clock enabled in s3c24xx_serial_init_port here,
|
|
- * so that a potential re-enablement through the pm-callback overlaps
|
|
- * and keeps the clock enabled in this case.
|
|
- */
|
|
- clk_disable_unprepare(ourport->clk);
|
|
- if (!IS_ERR(ourport->baudclk))
|
|
- clk_disable_unprepare(ourport->baudclk);
|
|
+ pm_runtime_put_sync(&pdev->dev);
|
|
|
|
ret = s3c24xx_serial_cpufreq_register(ourport);
|
|
if (ret < 0)
|
|
@@ -2273,10 +2290,21 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
|
|
static int s3c24xx_serial_remove(struct platform_device *dev)
|
|
{
|
|
struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
|
|
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
|
|
|
|
if (port) {
|
|
+ pm_runtime_get_sync(&dev->dev);
|
|
+
|
|
s3c24xx_serial_cpufreq_deregister(to_ourport(port));
|
|
uart_remove_one_port(&s3c24xx_uart_drv, port);
|
|
+
|
|
+ clk_disable_unprepare(ourport->clk);
|
|
+ if (!IS_ERR(ourport->baudclk))
|
|
+ clk_disable_unprepare(ourport->baudclk);
|
|
+
|
|
+ pm_runtime_disable(&dev->dev);
|
|
+ pm_runtime_set_suspended(&dev->dev);
|
|
+ pm_runtime_put_noidle(&dev->dev);
|
|
}
|
|
|
|
uart_unregister_driver(&s3c24xx_uart_drv);
|
|
@@ -2285,8 +2313,8 @@ static int s3c24xx_serial_remove(struct platform_device *dev)
|
|
}
|
|
|
|
/* UART power management code */
|
|
-#ifdef CONFIG_PM_SLEEP
|
|
-static int s3c24xx_serial_suspend(struct device *dev)
|
|
+
|
|
+static int __maybe_unused s3c24xx_serial_suspend(struct device *dev)
|
|
{
|
|
struct uart_port *port = s3c24xx_dev_to_port(dev);
|
|
|
|
@@ -2296,7 +2324,7 @@ static int s3c24xx_serial_suspend(struct device *dev)
|
|
return 0;
|
|
}
|
|
|
|
-static int s3c24xx_serial_resume(struct device *dev)
|
|
+static int __maybe_unused s3c24xx_serial_resume(struct device *dev)
|
|
{
|
|
struct uart_port *port = s3c24xx_dev_to_port(dev);
|
|
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
|
@@ -2316,7 +2344,7 @@ static int s3c24xx_serial_resume(struct device *dev)
|
|
return 0;
|
|
}
|
|
|
|
-static int s3c24xx_serial_resume_noirq(struct device *dev)
|
|
+static int __maybe_unused s3c24xx_serial_resume_noirq(struct device *dev)
|
|
{
|
|
struct uart_port *port = s3c24xx_dev_to_port(dev);
|
|
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
|
@@ -2386,16 +2414,14 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
|
|
}
|
|
|
|
static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
|
|
+#ifdef CONFIG_PM_SLEEP
|
|
.suspend = s3c24xx_serial_suspend,
|
|
.resume = s3c24xx_serial_resume,
|
|
.resume_noirq = s3c24xx_serial_resume_noirq,
|
|
+#endif
|
|
+ SET_RUNTIME_PM_OPS(s3c24xx_serial_runtime_suspend,
|
|
+ s3c24xx_serial_runtime_resume, NULL)
|
|
};
|
|
-#define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops)
|
|
-
|
|
-#else /* !CONFIG_PM_SLEEP */
|
|
-
|
|
-#define SERIAL_SAMSUNG_PM_OPS NULL
|
|
-#endif /* CONFIG_PM_SLEEP */
|
|
|
|
/* Console code */
|
|
|
|
@@ -2936,7 +2962,7 @@ static struct platform_driver samsung_serial_driver = {
|
|
.id_table = s3c24xx_serial_driver_ids,
|
|
.driver = {
|
|
.name = "samsung-uart",
|
|
- .pm = SERIAL_SAMSUNG_PM_OPS,
|
|
+ .pm = &s3c24xx_serial_pm_ops,
|
|
.of_match_table = of_match_ptr(s3c24xx_uart_dt_match),
|
|
},
|
|
};
|
|
--
|
|
2.34.1
|
|
|