Skip to content

Commit 621d319

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 05f7e89 commit 621d319

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>
@@ -1298,30 +1299,49 @@ static int apple_s5l_serial_startup(struct uart_port *port)
12981299
return ret;
12991300
}
13001301

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

13071335
ourport->pm_level = level;
13081336

13091337
switch (level) {
1310-
case 3:
1311-
while (--timeout && !s3c24xx_serial_txempty_nofifo(port))
1312-
udelay(100);
1313-
1314-
if (!IS_ERR(ourport->baudclk))
1315-
clk_disable_unprepare(ourport->baudclk);
1316-
1317-
clk_disable_unprepare(ourport->clk);
1338+
case UART_PM_STATE_OFF:
1339+
pm_runtime_mark_last_busy(port->dev);
1340+
pm_runtime_put_sync(port->dev);
13181341
break;
13191342

1320-
case 0:
1321-
clk_prepare_enable(ourport->clk);
1322-
1323-
if (!IS_ERR(ourport->baudclk))
1324-
clk_prepare_enable(ourport->baudclk);
1343+
case UART_PM_STATE_ON:
1344+
pm_runtime_get_sync(port->dev);
13251345
break;
13261346
default:
13271347
dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level);
@@ -2044,18 +2064,15 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
20442064
}
20452065
}
20462066

2067+
pm_runtime_get_noresume(&pdev->dev);
2068+
pm_runtime_set_active(&pdev->dev);
2069+
pm_runtime_enable(&pdev->dev);
2070+
20472071
dev_dbg(&pdev->dev, "%s: adding port\n", __func__);
20482072
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
20492073
platform_set_drvdata(pdev, &ourport->port);
20502074

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

20602077
probe_index++;
20612078

@@ -2065,16 +2082,27 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
20652082
static void s3c24xx_serial_remove(struct platform_device *dev)
20662083
{
20672084
struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
2085+
struct s3c24xx_uart_port *ourport = to_ourport(port);
20682086

2069-
if (port)
2087+
if (port) {
2088+
pm_runtime_get_sync(&dev->dev);
20702089
uart_remove_one_port(&s3c24xx_uart_drv, port);
20712090

2091+
clk_disable_unprepare(ourport->clk);
2092+
if (!IS_ERR(ourport->baudclk))
2093+
clk_disable_unprepare(ourport->baudclk);
2094+
2095+
pm_runtime_disable(&dev->dev);
2096+
pm_runtime_set_suspended(&dev->dev);
2097+
pm_runtime_put_noidle(&dev->dev);
2098+
}
2099+
20722100
uart_unregister_driver(&s3c24xx_uart_drv);
20732101
}
20742102

20752103
/* UART power management code */
2076-
#ifdef CONFIG_PM_SLEEP
2077-
static int s3c24xx_serial_suspend(struct device *dev)
2104+
2105+
static int __maybe_unused s3c24xx_serial_suspend(struct device *dev)
20782106
{
20792107
struct uart_port *port = s3c24xx_dev_to_port(dev);
20802108

@@ -2084,7 +2112,7 @@ static int s3c24xx_serial_suspend(struct device *dev)
20842112
return 0;
20852113
}
20862114

2087-
static int s3c24xx_serial_resume(struct device *dev)
2115+
static int __maybe_unused s3c24xx_serial_resume(struct device *dev)
20882116
{
20892117
struct uart_port *port = s3c24xx_dev_to_port(dev);
20902118
struct s3c24xx_uart_port *ourport = to_ourport(port);
@@ -2104,7 +2132,7 @@ static int s3c24xx_serial_resume(struct device *dev)
21042132
return 0;
21052133
}
21062134

2107-
static int s3c24xx_serial_resume_noirq(struct device *dev)
2135+
static int __maybe_unused s3c24xx_serial_resume_noirq(struct device *dev)
21082136
{
21092137
struct uart_port *port = s3c24xx_dev_to_port(dev);
21102138
struct s3c24xx_uart_port *ourport = to_ourport(port);
@@ -2178,13 +2206,9 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
21782206
static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
21792207
SET_SYSTEM_SLEEP_PM_OPS(s3c24xx_serial_suspend, s3c24xx_serial_resume)
21802208
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, s3c24xx_serial_resume_noirq)
2209+
SET_RUNTIME_PM_OPS(s3c24xx_serial_runtime_suspend,
2210+
s3c24xx_serial_runtime_resume, NULL)
21812211
};
2182-
#define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops)
2183-
2184-
#else /* !CONFIG_PM_SLEEP */
2185-
2186-
#define SERIAL_SAMSUNG_PM_OPS NULL
2187-
#endif /* CONFIG_PM_SLEEP */
21882212

21892213
/* Console code */
21902214

@@ -2672,7 +2696,7 @@ static struct platform_driver samsung_serial_driver = {
26722696
.id_table = s3c24xx_serial_driver_ids,
26732697
.driver = {
26742698
.name = "samsung-uart",
2675-
.pm = SERIAL_SAMSUNG_PM_OPS,
2699+
.pm = &s3c24xx_serial_pm_ops,
26762700
.of_match_table = of_match_ptr(s3c24xx_uart_dt_match),
26772701
},
26782702
};

0 commit comments

Comments
 (0)