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+
12991328static 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)
20632080static 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)
21762204static 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