Skip to content

Commit 5e2b50a

Browse files
marcanjannau
authored andcommitted
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>
1 parent 0c0dd58 commit 5e2b50a

1 file changed

Lines changed: 58 additions & 34 deletions

File tree

drivers/tty/serial/samsung_tty.c

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <linux/module.h>
3535
#include <linux/of.h>
3636
#include <linux/platform_device.h>
37+
#include <linux/pm_runtime.h>
3738
#include <linux/serial.h>
3839
#include <linux/serial_core.h>
3940
#include <linux/serial_s3c.h>
@@ -1296,30 +1297,49 @@ static int apple_s5l_serial_startup(struct uart_port *port)
12961297
return ret;
12971298
}
12981299

1300+
static int __maybe_unused s3c24xx_serial_runtime_suspend(struct device *dev)
1301+
{
1302+
struct uart_port *port = dev_get_drvdata(dev);
1303+
struct s3c24xx_uart_port *ourport = to_ourport(port);
1304+
int timeout = 10000;
1305+
1306+
while (--timeout && !s3c24xx_serial_txempty_nofifo(port))
1307+
udelay(100);
1308+
1309+
if (!IS_ERR(ourport->baudclk))
1310+
clk_disable_unprepare(ourport->baudclk);
1311+
1312+
clk_disable_unprepare(ourport->clk);
1313+
return 0;
1314+
};
1315+
1316+
static int __maybe_unused s3c24xx_serial_runtime_resume(struct device *dev)
1317+
{
1318+
struct uart_port *port = dev_get_drvdata(dev);
1319+
struct s3c24xx_uart_port *ourport = to_ourport(port);
1320+
1321+
clk_prepare_enable(ourport->clk);
1322+
1323+
if (!IS_ERR(ourport->baudclk))
1324+
clk_prepare_enable(ourport->baudclk);
1325+
return 0;
1326+
};
1327+
12991328
static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
13001329
unsigned int old)
13011330
{
13021331
struct s3c24xx_uart_port *ourport = to_ourport(port);
1303-
int timeout = 10000;
13041332

13051333
ourport->pm_level = level;
13061334

13071335
switch (level) {
1308-
case 3:
1309-
while (--timeout && !s3c24xx_serial_txempty_nofifo(port))
1310-
udelay(100);
1311-
1312-
if (!IS_ERR(ourport->baudclk))
1313-
clk_disable_unprepare(ourport->baudclk);
1314-
1315-
clk_disable_unprepare(ourport->clk);
1336+
case UART_PM_STATE_OFF:
1337+
pm_runtime_mark_last_busy(port->dev);
1338+
pm_runtime_put_sync(port->dev);
13161339
break;
13171340

1318-
case 0:
1319-
clk_prepare_enable(ourport->clk);
1320-
1321-
if (!IS_ERR(ourport->baudclk))
1322-
clk_prepare_enable(ourport->baudclk);
1341+
case UART_PM_STATE_ON:
1342+
pm_runtime_get_sync(port->dev);
13231343
break;
13241344
default:
13251345
dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level);
@@ -2042,18 +2062,15 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
20422062
}
20432063
}
20442064

2065+
pm_runtime_get_noresume(&pdev->dev);
2066+
pm_runtime_set_active(&pdev->dev);
2067+
pm_runtime_enable(&pdev->dev);
2068+
20452069
dev_dbg(&pdev->dev, "%s: adding port\n", __func__);
20462070
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
20472071
platform_set_drvdata(pdev, &ourport->port);
20482072

2049-
/*
2050-
* Deactivate the clock enabled in s3c24xx_serial_init_port here,
2051-
* so that a potential re-enablement through the pm-callback overlaps
2052-
* and keeps the clock enabled in this case.
2053-
*/
2054-
clk_disable_unprepare(ourport->clk);
2055-
if (!IS_ERR(ourport->baudclk))
2056-
clk_disable_unprepare(ourport->baudclk);
2073+
pm_runtime_put_sync(&pdev->dev);
20572074

20582075
probe_index++;
20592076

@@ -2063,16 +2080,27 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
20632080
static void s3c24xx_serial_remove(struct platform_device *dev)
20642081
{
20652082
struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
2083+
struct s3c24xx_uart_port *ourport = to_ourport(port);
20662084

2067-
if (port)
2085+
if (port) {
2086+
pm_runtime_get_sync(&dev->dev);
20682087
uart_remove_one_port(&s3c24xx_uart_drv, port);
20692088

2089+
clk_disable_unprepare(ourport->clk);
2090+
if (!IS_ERR(ourport->baudclk))
2091+
clk_disable_unprepare(ourport->baudclk);
2092+
2093+
pm_runtime_disable(&dev->dev);
2094+
pm_runtime_set_suspended(&dev->dev);
2095+
pm_runtime_put_noidle(&dev->dev);
2096+
}
2097+
20702098
uart_unregister_driver(&s3c24xx_uart_drv);
20712099
}
20722100

20732101
/* UART power management code */
2074-
#ifdef CONFIG_PM_SLEEP
2075-
static int s3c24xx_serial_suspend(struct device *dev)
2102+
2103+
static int __maybe_unused s3c24xx_serial_suspend(struct device *dev)
20762104
{
20772105
struct uart_port *port = s3c24xx_dev_to_port(dev);
20782106

@@ -2082,7 +2110,7 @@ static int s3c24xx_serial_suspend(struct device *dev)
20822110
return 0;
20832111
}
20842112

2085-
static int s3c24xx_serial_resume(struct device *dev)
2113+
static int __maybe_unused s3c24xx_serial_resume(struct device *dev)
20862114
{
20872115
struct uart_port *port = s3c24xx_dev_to_port(dev);
20882116
struct s3c24xx_uart_port *ourport = to_ourport(port);
@@ -2102,7 +2130,7 @@ static int s3c24xx_serial_resume(struct device *dev)
21022130
return 0;
21032131
}
21042132

2105-
static int s3c24xx_serial_resume_noirq(struct device *dev)
2133+
static int __maybe_unused s3c24xx_serial_resume_noirq(struct device *dev)
21062134
{
21072135
struct uart_port *port = s3c24xx_dev_to_port(dev);
21082136
struct s3c24xx_uart_port *ourport = to_ourport(port);
@@ -2176,13 +2204,9 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
21762204
static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
21772205
SET_SYSTEM_SLEEP_PM_OPS(s3c24xx_serial_suspend, s3c24xx_serial_resume)
21782206
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, s3c24xx_serial_resume_noirq)
2207+
SET_RUNTIME_PM_OPS(s3c24xx_serial_runtime_suspend,
2208+
s3c24xx_serial_runtime_resume, NULL)
21792209
};
2180-
#define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops)
2181-
2182-
#else /* !CONFIG_PM_SLEEP */
2183-
2184-
#define SERIAL_SAMSUNG_PM_OPS NULL
2185-
#endif /* CONFIG_PM_SLEEP */
21862210

21872211
/* Console code */
21882212

@@ -2670,7 +2694,7 @@ static struct platform_driver samsung_serial_driver = {
26702694
.id_table = s3c24xx_serial_driver_ids,
26712695
.driver = {
26722696
.name = "samsung-uart",
2673-
.pm = SERIAL_SAMSUNG_PM_OPS,
2697+
.pm = &s3c24xx_serial_pm_ops,
26742698
.of_match_table = of_match_ptr(s3c24xx_uart_dt_match),
26752699
},
26762700
};

0 commit comments

Comments
 (0)