Skip to content

Commit 532039d

Browse files
committed
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 457391b commit 532039d

1 file changed

Lines changed: 58 additions & 33 deletions

File tree

drivers/tty/serial/samsung_tty.c

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <linux/clk.h>
4141
#include <linux/cpufreq.h>
4242
#include <linux/of.h>
43+
#include <linux/pm_runtime.h>
4344
#include <asm/irq.h>
4445

4546
/* UART name and device definitions */
@@ -1360,30 +1361,49 @@ static int apple_s5l_serial_startup(struct uart_port *port)
13601361

13611362
/* power power management control */
13621363

1364+
static int __maybe_unused s3c24xx_serial_runtime_suspend(struct device *dev)
1365+
{
1366+
struct uart_port *port = dev_get_drvdata(dev);
1367+
struct s3c24xx_uart_port *ourport = to_ourport(port);
1368+
int timeout = 10000;
1369+
1370+
while (--timeout && !s3c24xx_serial_txempty_nofifo(port))
1371+
udelay(100);
1372+
1373+
if (!IS_ERR(ourport->baudclk))
1374+
clk_disable_unprepare(ourport->baudclk);
1375+
1376+
clk_disable_unprepare(ourport->clk);
1377+
return 0;
1378+
};
1379+
1380+
static int __maybe_unused s3c24xx_serial_runtime_resume(struct device *dev)
1381+
{
1382+
struct uart_port *port = dev_get_drvdata(dev);
1383+
struct s3c24xx_uart_port *ourport = to_ourport(port);
1384+
1385+
clk_prepare_enable(ourport->clk);
1386+
1387+
if (!IS_ERR(ourport->baudclk))
1388+
clk_prepare_enable(ourport->baudclk);
1389+
return 0;
1390+
};
1391+
13631392
static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
13641393
unsigned int old)
13651394
{
13661395
struct s3c24xx_uart_port *ourport = to_ourport(port);
1367-
int timeout = 10000;
13681396

13691397
ourport->pm_level = level;
13701398

13711399
switch (level) {
1372-
case 3:
1373-
while (--timeout && !s3c24xx_serial_txempty_nofifo(port))
1374-
udelay(100);
1375-
1376-
if (!IS_ERR(ourport->baudclk))
1377-
clk_disable_unprepare(ourport->baudclk);
1378-
1379-
clk_disable_unprepare(ourport->clk);
1400+
case UART_PM_STATE_OFF:
1401+
pm_runtime_mark_last_busy(port->dev);
1402+
pm_runtime_put_sync(port->dev);
13801403
break;
13811404

1382-
case 0:
1383-
clk_prepare_enable(ourport->clk);
1384-
1385-
if (!IS_ERR(ourport->baudclk))
1386-
clk_prepare_enable(ourport->baudclk);
1405+
case UART_PM_STATE_ON:
1406+
pm_runtime_get_sync(port->dev);
13871407
break;
13881408
default:
13891409
dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level);
@@ -2129,18 +2149,15 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
21292149
}
21302150
}
21312151

2152+
pm_runtime_get_noresume(&pdev->dev);
2153+
pm_runtime_set_active(&pdev->dev);
2154+
pm_runtime_enable(&pdev->dev);
2155+
21322156
dev_dbg(&pdev->dev, "%s: adding port\n", __func__);
21332157
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
21342158
platform_set_drvdata(pdev, &ourport->port);
21352159

2136-
/*
2137-
* Deactivate the clock enabled in s3c24xx_serial_init_port here,
2138-
* so that a potential re-enablement through the pm-callback overlaps
2139-
* and keeps the clock enabled in this case.
2140-
*/
2141-
clk_disable_unprepare(ourport->clk);
2142-
if (!IS_ERR(ourport->baudclk))
2143-
clk_disable_unprepare(ourport->baudclk);
2160+
pm_runtime_put_sync(&pdev->dev);
21442161

21452162
probe_index++;
21462163

@@ -2150,9 +2167,19 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
21502167
static int s3c24xx_serial_remove(struct platform_device *dev)
21512168
{
21522169
struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
2170+
struct s3c24xx_uart_port *ourport = to_ourport(port);
21532171

21542172
if (port) {
2173+
pm_runtime_get_sync(&dev->dev);
21552174
uart_remove_one_port(&s3c24xx_uart_drv, port);
2175+
2176+
clk_disable_unprepare(ourport->clk);
2177+
if (!IS_ERR(ourport->baudclk))
2178+
clk_disable_unprepare(ourport->baudclk);
2179+
2180+
pm_runtime_disable(&dev->dev);
2181+
pm_runtime_set_suspended(&dev->dev);
2182+
pm_runtime_put_noidle(&dev->dev);
21562183
}
21572184

21582185
uart_unregister_driver(&s3c24xx_uart_drv);
@@ -2161,8 +2188,8 @@ static int s3c24xx_serial_remove(struct platform_device *dev)
21612188
}
21622189

21632190
/* UART power management code */
2164-
#ifdef CONFIG_PM_SLEEP
2165-
static int s3c24xx_serial_suspend(struct device *dev)
2191+
2192+
static int __maybe_unused s3c24xx_serial_suspend(struct device *dev)
21662193
{
21672194
struct uart_port *port = s3c24xx_dev_to_port(dev);
21682195

@@ -2172,7 +2199,7 @@ static int s3c24xx_serial_suspend(struct device *dev)
21722199
return 0;
21732200
}
21742201

2175-
static int s3c24xx_serial_resume(struct device *dev)
2202+
static int __maybe_unused s3c24xx_serial_resume(struct device *dev)
21762203
{
21772204
struct uart_port *port = s3c24xx_dev_to_port(dev);
21782205
struct s3c24xx_uart_port *ourport = to_ourport(port);
@@ -2192,7 +2219,7 @@ static int s3c24xx_serial_resume(struct device *dev)
21922219
return 0;
21932220
}
21942221

2195-
static int s3c24xx_serial_resume_noirq(struct device *dev)
2222+
static int __maybe_unused s3c24xx_serial_resume_noirq(struct device *dev)
21962223
{
21972224
struct uart_port *port = s3c24xx_dev_to_port(dev);
21982225
struct s3c24xx_uart_port *ourport = to_ourport(port);
@@ -2262,16 +2289,14 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
22622289
}
22632290

22642291
static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
2292+
#ifdef CONFIG_PM_SLEEP
22652293
.suspend = s3c24xx_serial_suspend,
22662294
.resume = s3c24xx_serial_resume,
22672295
.resume_noirq = s3c24xx_serial_resume_noirq,
2296+
#endif
2297+
SET_RUNTIME_PM_OPS(s3c24xx_serial_runtime_suspend,
2298+
s3c24xx_serial_runtime_resume, NULL)
22682299
};
2269-
#define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops)
2270-
2271-
#else /* !CONFIG_PM_SLEEP */
2272-
2273-
#define SERIAL_SAMSUNG_PM_OPS NULL
2274-
#endif /* CONFIG_PM_SLEEP */
22752300

22762301
/* Console code */
22772302

@@ -2709,7 +2734,7 @@ static struct platform_driver samsung_serial_driver = {
27092734
.id_table = s3c24xx_serial_driver_ids,
27102735
.driver = {
27112736
.name = "samsung-uart",
2712-
.pm = SERIAL_SAMSUNG_PM_OPS,
2737+
.pm = &s3c24xx_serial_pm_ops,
27132738
.of_match_table = of_match_ptr(s3c24xx_uart_dt_match),
27142739
},
27152740
};

0 commit comments

Comments
 (0)