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+
13011330static 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)
20652082static 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)
21782206static 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