Skip to content

Commit 7dac434

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 ffc2532 commit 7dac434

1 file changed

Lines changed: 56 additions & 33 deletions

File tree

drivers/tty/serial/samsung_tty.c

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <linux/clk.h>
4242
#include <linux/cpufreq.h>
4343
#include <linux/of.h>
44+
#include <linux/pm_runtime.h>
4445
#include <asm/irq.h>
4546

4647
/* UART name and device definitions */
@@ -1362,30 +1363,49 @@ static int apple_s5l_serial_startup(struct uart_port *port)
13621363

13631364
/* power power management control */
13641365

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

13711399
ourport->pm_level = level;
13721400

13731401
switch (level) {
1374-
case 3:
1375-
while (--timeout && !s3c24xx_serial_txempty_nofifo(port))
1376-
udelay(100);
1377-
1378-
if (!IS_ERR(ourport->baudclk))
1379-
clk_disable_unprepare(ourport->baudclk);
1380-
1381-
clk_disable_unprepare(ourport->clk);
1402+
case UART_PM_STATE_OFF:
1403+
pm_runtime_mark_last_busy(port->dev);
1404+
pm_runtime_put_sync(port->dev);
13821405
break;
13831406

1384-
case 0:
1385-
clk_prepare_enable(ourport->clk);
1386-
1387-
if (!IS_ERR(ourport->baudclk))
1388-
clk_prepare_enable(ourport->baudclk);
1407+
case UART_PM_STATE_ON:
1408+
pm_runtime_get_sync(port->dev);
13891409
break;
13901410
default:
13911411
dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level);
@@ -2141,18 +2161,15 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
21412161
}
21422162
}
21432163

2164+
pm_runtime_get_noresume(&pdev->dev);
2165+
pm_runtime_set_active(&pdev->dev);
2166+
pm_runtime_enable(&pdev->dev);
2167+
21442168
dev_dbg(&pdev->dev, "%s: adding port\n", __func__);
21452169
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
21462170
platform_set_drvdata(pdev, &ourport->port);
21472171

2148-
/*
2149-
* Deactivate the clock enabled in s3c24xx_serial_init_port here,
2150-
* so that a potential re-enablement through the pm-callback overlaps
2151-
* and keeps the clock enabled in this case.
2152-
*/
2153-
clk_disable_unprepare(ourport->clk);
2154-
if (!IS_ERR(ourport->baudclk))
2155-
clk_disable_unprepare(ourport->baudclk);
2172+
pm_runtime_put_sync(&pdev->dev);
21562173

21572174
probe_index++;
21582175

@@ -2162,9 +2179,19 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
21622179
static int s3c24xx_serial_remove(struct platform_device *dev)
21632180
{
21642181
struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
2182+
struct s3c24xx_uart_port *ourport = to_ourport(port);
21652183

21662184
if (port) {
2185+
pm_runtime_get_sync(&dev->dev);
21672186
uart_remove_one_port(&s3c24xx_uart_drv, port);
2187+
2188+
clk_disable_unprepare(ourport->clk);
2189+
if (!IS_ERR(ourport->baudclk))
2190+
clk_disable_unprepare(ourport->baudclk);
2191+
2192+
pm_runtime_disable(&dev->dev);
2193+
pm_runtime_set_suspended(&dev->dev);
2194+
pm_runtime_put_noidle(&dev->dev);
21682195
}
21692196

21702197
uart_unregister_driver(&s3c24xx_uart_drv);
@@ -2173,8 +2200,8 @@ static int s3c24xx_serial_remove(struct platform_device *dev)
21732200
}
21742201

21752202
/* UART power management code */
2176-
#ifdef CONFIG_PM_SLEEP
2177-
static int s3c24xx_serial_suspend(struct device *dev)
2203+
2204+
static int __maybe_unused s3c24xx_serial_suspend(struct device *dev)
21782205
{
21792206
struct uart_port *port = s3c24xx_dev_to_port(dev);
21802207

@@ -2184,7 +2211,7 @@ static int s3c24xx_serial_suspend(struct device *dev)
21842211
return 0;
21852212
}
21862213

2187-
static int s3c24xx_serial_resume(struct device *dev)
2214+
static int __maybe_unused s3c24xx_serial_resume(struct device *dev)
21882215
{
21892216
struct uart_port *port = s3c24xx_dev_to_port(dev);
21902217
struct s3c24xx_uart_port *ourport = to_ourport(port);
@@ -2204,7 +2231,7 @@ static int s3c24xx_serial_resume(struct device *dev)
22042231
return 0;
22052232
}
22062233

2207-
static int s3c24xx_serial_resume_noirq(struct device *dev)
2234+
static int __maybe_unused s3c24xx_serial_resume_noirq(struct device *dev)
22082235
{
22092236
struct uart_port *port = s3c24xx_dev_to_port(dev);
22102237
struct s3c24xx_uart_port *ourport = to_ourport(port);
@@ -2276,13 +2303,9 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
22762303
static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
22772304
SET_SYSTEM_SLEEP_PM_OPS(s3c24xx_serial_suspend, s3c24xx_serial_resume)
22782305
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, s3c24xx_serial_resume_noirq)
2306+
SET_RUNTIME_PM_OPS(s3c24xx_serial_runtime_suspend,
2307+
s3c24xx_serial_runtime_resume, NULL)
22792308
};
2280-
#define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops)
2281-
2282-
#else /* !CONFIG_PM_SLEEP */
2283-
2284-
#define SERIAL_SAMSUNG_PM_OPS NULL
2285-
#endif /* CONFIG_PM_SLEEP */
22862309

22872310
/* Console code */
22882311

@@ -2720,7 +2743,7 @@ static struct platform_driver samsung_serial_driver = {
27202743
.id_table = s3c24xx_serial_driver_ids,
27212744
.driver = {
27222745
.name = "samsung-uart",
2723-
.pm = SERIAL_SAMSUNG_PM_OPS,
2746+
.pm = &s3c24xx_serial_pm_ops,
27242747
.of_match_table = of_match_ptr(s3c24xx_uart_dt_match),
27252748
},
27262749
};

0 commit comments

Comments
 (0)