From: Hector Martin <marcan@marcan.st> To: linux-arm-kernel@lists.infradead.org Cc: Hector Martin <marcan@marcan.st>, Marc Zyngier <maz@kernel.org>, Rob Herring <robh+dt@kernel.org>, Arnd Bergmann <arnd@kernel.org>, Linus Walleij <linus.walleij@linaro.org>, Alyssa Rosenzweig <alyssa@rosenzweig.io>, Krzysztof Kozlowski <krzk@kernel.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Mark Kettenis <mark.kettenis@xs4all.nl>, Philipp Zabel <p.zabel@pengutronix.de>, "Rafael J. Wysocki" <rafael@kernel.org>, Johan Hovold <johan@kernel.org>, devicetree@vger.kernel.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-serial@vger.kernel.org Subject: [PATCH v3 10/11] tty: serial: samsung_tty: Support runtime PM Date: Wed, 24 Nov 2021 16:46:24 +0900 [thread overview] Message-ID: <20211124074625.182815-11-marcan@marcan.st> (raw) In-Reply-To: <20211124073419.181799-1-marcan@marcan.st> 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> --- drivers/tty/serial/samsung_tty.c | 93 ++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 34 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index ca084c10d0bb..75c87d7240d9 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -40,6 +40,7 @@ #include <linux/clk.h> #include <linux/cpufreq.h> #include <linux/of.h> +#include <linux/pm_runtime.h> #include <asm/irq.h> /* UART name and device definitions */ @@ -1381,31 +1382,49 @@ static void exynos_usi_init(struct uart_port *port) /* power power management control */ -static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, - unsigned int old) +static int __maybe_unused s3c24xx_serial_runtime_suspend(struct device *dev) { + struct uart_port *port = dev_get_drvdata(dev); struct s3c24xx_uart_port *ourport = to_ourport(port); int timeout = 10000; - ourport->pm_level = level; + while (--timeout && !s3c24xx_serial_txempty_nofifo(port)) + udelay(100); - switch (level) { - case 3: - while (--timeout && !s3c24xx_serial_txempty_nofifo(port)) - udelay(100); + if (!IS_ERR(ourport->baudclk)) + clk_disable_unprepare(ourport->baudclk); - if (!IS_ERR(ourport->baudclk)) - clk_disable_unprepare(ourport->baudclk); + clk_disable_unprepare(ourport->clk); + return 0; +}; - clk_disable_unprepare(ourport->clk); - break; +static int __maybe_unused s3c24xx_serial_runtime_resume(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct s3c24xx_uart_port *ourport = to_ourport(port); - case 0: - clk_prepare_enable(ourport->clk); + clk_prepare_enable(ourport->clk); - if (!IS_ERR(ourport->baudclk)) - clk_prepare_enable(ourport->baudclk); + if (!IS_ERR(ourport->baudclk)) + clk_prepare_enable(ourport->baudclk); + return 0; +}; +static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, + unsigned int old) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + + ourport->pm_level = level; + + switch (level) { + case UART_PM_STATE_OFF: + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_sync(port->dev); + break; + + case UART_PM_STATE_ON: + pm_runtime_get_sync(port->dev); exynos_usi_init(port); break; default: @@ -2282,18 +2301,15 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) } } + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + dev_dbg(&pdev->dev, "%s: adding port\n", __func__); uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); platform_set_drvdata(pdev, &ourport->port); - /* - * Deactivate the clock enabled in s3c24xx_serial_init_port here, - * so that a potential re-enablement through the pm-callback overlaps - * and keeps the clock enabled in this case. - */ - clk_disable_unprepare(ourport->clk); - if (!IS_ERR(ourport->baudclk)) - clk_disable_unprepare(ourport->baudclk); + pm_runtime_put_sync(&pdev->dev); ret = s3c24xx_serial_cpufreq_register(ourport); if (ret < 0) @@ -2307,10 +2323,21 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) static int s3c24xx_serial_remove(struct platform_device *dev) { struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); + struct s3c24xx_uart_port *ourport = to_ourport(port); if (port) { + pm_runtime_get_sync(&dev->dev); + s3c24xx_serial_cpufreq_deregister(to_ourport(port)); uart_remove_one_port(&s3c24xx_uart_drv, port); + + clk_disable_unprepare(ourport->clk); + if (!IS_ERR(ourport->baudclk)) + clk_disable_unprepare(ourport->baudclk); + + pm_runtime_disable(&dev->dev); + pm_runtime_set_suspended(&dev->dev); + pm_runtime_put_noidle(&dev->dev); } uart_unregister_driver(&s3c24xx_uart_drv); @@ -2319,8 +2346,8 @@ static int s3c24xx_serial_remove(struct platform_device *dev) } /* UART power management code */ -#ifdef CONFIG_PM_SLEEP -static int s3c24xx_serial_suspend(struct device *dev) + +static int __maybe_unused s3c24xx_serial_suspend(struct device *dev) { struct uart_port *port = s3c24xx_dev_to_port(dev); @@ -2330,7 +2357,7 @@ static int s3c24xx_serial_suspend(struct device *dev) return 0; } -static int s3c24xx_serial_resume(struct device *dev) +static int __maybe_unused s3c24xx_serial_resume(struct device *dev) { struct uart_port *port = s3c24xx_dev_to_port(dev); struct s3c24xx_uart_port *ourport = to_ourport(port); @@ -2350,7 +2377,7 @@ static int s3c24xx_serial_resume(struct device *dev) return 0; } -static int s3c24xx_serial_resume_noirq(struct device *dev) +static int __maybe_unused s3c24xx_serial_resume_noirq(struct device *dev) { struct uart_port *port = s3c24xx_dev_to_port(dev); struct s3c24xx_uart_port *ourport = to_ourport(port); @@ -2420,16 +2447,14 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) } static const struct dev_pm_ops s3c24xx_serial_pm_ops = { +#ifdef CONFIG_PM_SLEEP .suspend = s3c24xx_serial_suspend, .resume = s3c24xx_serial_resume, .resume_noirq = s3c24xx_serial_resume_noirq, +#endif + SET_RUNTIME_PM_OPS(s3c24xx_serial_runtime_suspend, + s3c24xx_serial_runtime_resume, NULL) }; -#define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops) - -#else /* !CONFIG_PM_SLEEP */ - -#define SERIAL_SAMSUNG_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ /* Console code */ @@ -2921,7 +2946,7 @@ static struct platform_driver samsung_serial_driver = { .id_table = s3c24xx_serial_driver_ids, .driver = { .name = "samsung-uart", - .pm = SERIAL_SAMSUNG_PM_OPS, + .pm = &s3c24xx_serial_pm_ops, .of_match_table = of_match_ptr(s3c24xx_uart_dt_match), }, }; -- 2.33.0
WARNING: multiple messages have this Message-ID (diff)
From: Hector Martin <marcan@marcan.st> To: linux-arm-kernel@lists.infradead.org Cc: Hector Martin <marcan@marcan.st>, Marc Zyngier <maz@kernel.org>, Rob Herring <robh+dt@kernel.org>, Arnd Bergmann <arnd@kernel.org>, Linus Walleij <linus.walleij@linaro.org>, Alyssa Rosenzweig <alyssa@rosenzweig.io>, Krzysztof Kozlowski <krzk@kernel.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Mark Kettenis <mark.kettenis@xs4all.nl>, Philipp Zabel <p.zabel@pengutronix.de>, "Rafael J. Wysocki" <rafael@kernel.org>, Johan Hovold <johan@kernel.org>, devicetree@vger.kernel.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-serial@vger.kernel.org Subject: [PATCH v3 10/11] tty: serial: samsung_tty: Support runtime PM Date: Wed, 24 Nov 2021 16:46:24 +0900 [thread overview] Message-ID: <20211124074625.182815-11-marcan@marcan.st> (raw) In-Reply-To: <20211124073419.181799-1-marcan@marcan.st> 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> --- drivers/tty/serial/samsung_tty.c | 93 ++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 34 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index ca084c10d0bb..75c87d7240d9 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -40,6 +40,7 @@ #include <linux/clk.h> #include <linux/cpufreq.h> #include <linux/of.h> +#include <linux/pm_runtime.h> #include <asm/irq.h> /* UART name and device definitions */ @@ -1381,31 +1382,49 @@ static void exynos_usi_init(struct uart_port *port) /* power power management control */ -static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, - unsigned int old) +static int __maybe_unused s3c24xx_serial_runtime_suspend(struct device *dev) { + struct uart_port *port = dev_get_drvdata(dev); struct s3c24xx_uart_port *ourport = to_ourport(port); int timeout = 10000; - ourport->pm_level = level; + while (--timeout && !s3c24xx_serial_txempty_nofifo(port)) + udelay(100); - switch (level) { - case 3: - while (--timeout && !s3c24xx_serial_txempty_nofifo(port)) - udelay(100); + if (!IS_ERR(ourport->baudclk)) + clk_disable_unprepare(ourport->baudclk); - if (!IS_ERR(ourport->baudclk)) - clk_disable_unprepare(ourport->baudclk); + clk_disable_unprepare(ourport->clk); + return 0; +}; - clk_disable_unprepare(ourport->clk); - break; +static int __maybe_unused s3c24xx_serial_runtime_resume(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct s3c24xx_uart_port *ourport = to_ourport(port); - case 0: - clk_prepare_enable(ourport->clk); + clk_prepare_enable(ourport->clk); - if (!IS_ERR(ourport->baudclk)) - clk_prepare_enable(ourport->baudclk); + if (!IS_ERR(ourport->baudclk)) + clk_prepare_enable(ourport->baudclk); + return 0; +}; +static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, + unsigned int old) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + + ourport->pm_level = level; + + switch (level) { + case UART_PM_STATE_OFF: + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_sync(port->dev); + break; + + case UART_PM_STATE_ON: + pm_runtime_get_sync(port->dev); exynos_usi_init(port); break; default: @@ -2282,18 +2301,15 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) } } + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + dev_dbg(&pdev->dev, "%s: adding port\n", __func__); uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); platform_set_drvdata(pdev, &ourport->port); - /* - * Deactivate the clock enabled in s3c24xx_serial_init_port here, - * so that a potential re-enablement through the pm-callback overlaps - * and keeps the clock enabled in this case. - */ - clk_disable_unprepare(ourport->clk); - if (!IS_ERR(ourport->baudclk)) - clk_disable_unprepare(ourport->baudclk); + pm_runtime_put_sync(&pdev->dev); ret = s3c24xx_serial_cpufreq_register(ourport); if (ret < 0) @@ -2307,10 +2323,21 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) static int s3c24xx_serial_remove(struct platform_device *dev) { struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); + struct s3c24xx_uart_port *ourport = to_ourport(port); if (port) { + pm_runtime_get_sync(&dev->dev); + s3c24xx_serial_cpufreq_deregister(to_ourport(port)); uart_remove_one_port(&s3c24xx_uart_drv, port); + + clk_disable_unprepare(ourport->clk); + if (!IS_ERR(ourport->baudclk)) + clk_disable_unprepare(ourport->baudclk); + + pm_runtime_disable(&dev->dev); + pm_runtime_set_suspended(&dev->dev); + pm_runtime_put_noidle(&dev->dev); } uart_unregister_driver(&s3c24xx_uart_drv); @@ -2319,8 +2346,8 @@ static int s3c24xx_serial_remove(struct platform_device *dev) } /* UART power management code */ -#ifdef CONFIG_PM_SLEEP -static int s3c24xx_serial_suspend(struct device *dev) + +static int __maybe_unused s3c24xx_serial_suspend(struct device *dev) { struct uart_port *port = s3c24xx_dev_to_port(dev); @@ -2330,7 +2357,7 @@ static int s3c24xx_serial_suspend(struct device *dev) return 0; } -static int s3c24xx_serial_resume(struct device *dev) +static int __maybe_unused s3c24xx_serial_resume(struct device *dev) { struct uart_port *port = s3c24xx_dev_to_port(dev); struct s3c24xx_uart_port *ourport = to_ourport(port); @@ -2350,7 +2377,7 @@ static int s3c24xx_serial_resume(struct device *dev) return 0; } -static int s3c24xx_serial_resume_noirq(struct device *dev) +static int __maybe_unused s3c24xx_serial_resume_noirq(struct device *dev) { struct uart_port *port = s3c24xx_dev_to_port(dev); struct s3c24xx_uart_port *ourport = to_ourport(port); @@ -2420,16 +2447,14 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) } static const struct dev_pm_ops s3c24xx_serial_pm_ops = { +#ifdef CONFIG_PM_SLEEP .suspend = s3c24xx_serial_suspend, .resume = s3c24xx_serial_resume, .resume_noirq = s3c24xx_serial_resume_noirq, +#endif + SET_RUNTIME_PM_OPS(s3c24xx_serial_runtime_suspend, + s3c24xx_serial_runtime_resume, NULL) }; -#define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops) - -#else /* !CONFIG_PM_SLEEP */ - -#define SERIAL_SAMSUNG_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ /* Console code */ @@ -2921,7 +2946,7 @@ static struct platform_driver samsung_serial_driver = { .id_table = s3c24xx_serial_driver_ids, .driver = { .name = "samsung-uart", - .pm = SERIAL_SAMSUNG_PM_OPS, + .pm = &s3c24xx_serial_pm_ops, .of_match_table = of_match_ptr(s3c24xx_uart_dt_match), }, }; -- 2.33.0 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2021-11-24 7:47 UTC|newest] Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-11-24 7:34 [PATCH v3 00/11] Apple SoC PMGR device power states driver Hector Martin 2021-11-24 7:34 ` Hector Martin 2021-11-24 7:34 ` [PATCH v3 01/11] MAINTAINERS: Add PMGR power state files to ARM/APPLE MACHINE Hector Martin 2021-11-24 7:34 ` Hector Martin 2021-11-24 7:34 ` [PATCH v3 02/11] dt-bindings: i2c: apple,i2c: Add power-domains property Hector Martin 2021-11-24 7:34 ` [PATCH v3 02/11] dt-bindings: i2c: apple, i2c: " Hector Martin 2021-11-29 0:54 ` [PATCH v3 02/11] dt-bindings: i2c: apple,i2c: " Rob Herring 2021-11-29 0:54 ` Rob Herring 2021-11-24 7:34 ` [PATCH v3 03/11] dt-bindings: iommu: apple,dart: " Hector Martin 2021-11-24 7:34 ` [PATCH v3 03/11] dt-bindings: iommu: apple, dart: " Hector Martin 2021-11-29 0:54 ` [PATCH v3 03/11] dt-bindings: iommu: apple,dart: " Rob Herring 2021-11-29 0:54 ` Rob Herring 2021-11-24 7:34 ` [PATCH v3 04/11] dt-bindings: pinctrl: apple,pinctrl: " Hector Martin 2021-11-24 7:34 ` [PATCH v3 04/11] dt-bindings: pinctrl: apple, pinctrl: " Hector Martin 2021-11-29 0:58 ` [PATCH v3 04/11] dt-bindings: pinctrl: apple,pinctrl: " Rob Herring 2021-11-29 0:58 ` Rob Herring 2021-11-24 7:34 ` [PATCH v3 05/11] dt-bindings: interrupt-controller: apple,aic: " Hector Martin 2021-11-24 7:34 ` [PATCH v3 05/11] dt-bindings: interrupt-controller: apple, aic: " Hector Martin 2021-11-29 0:58 ` [PATCH v3 05/11] dt-bindings: interrupt-controller: apple,aic: " Rob Herring 2021-11-29 0:58 ` Rob Herring 2021-11-24 7:34 ` [PATCH v3 06/11] dt-bindings: power: Add apple,pmgr-pwrstate binding Hector Martin 2021-11-24 7:34 ` Hector Martin 2021-11-24 7:34 ` [PATCH v3 07/11] dt-bindings: arm: apple: Add apple,pmgr binding Hector Martin 2021-11-24 7:34 ` Hector Martin 2021-11-28 16:24 ` Rob Herring 2021-11-28 16:24 ` Rob Herring 2021-11-24 7:34 ` [PATCH v3 08/11] soc: apple: Add driver for Apple PMGR power state controls Hector Martin 2021-11-24 7:34 ` Hector Martin 2021-11-24 7:34 ` [PATCH v3 09/11] arm64: dts: apple: t8103: Add PMGR nodes Hector Martin 2021-11-24 7:34 ` Hector Martin 2021-12-02 17:59 ` Sven Peter 2021-12-02 17:59 ` Sven Peter 2021-11-24 7:46 ` Hector Martin [this message] 2021-11-24 7:46 ` [PATCH v3 10/11] tty: serial: samsung_tty: Support runtime PM Hector Martin 2021-12-07 9:18 ` Krzysztof Kozlowski 2021-12-07 9:18 ` Krzysztof Kozlowski 2021-12-09 10:48 ` Andy Shevchenko 2021-12-09 10:48 ` Andy Shevchenko 2021-11-24 7:46 ` [PATCH v3 11/11] arm64: dts: apple: t8103: Add UART2 Hector Martin 2021-11-24 7:46 ` Hector Martin 2021-12-07 5:30 ` [PATCH v3 00/11] Apple SoC PMGR device power states driver Hector Martin 2021-12-07 5:30 ` Hector Martin 2021-12-07 7:53 ` Krzysztof Kozlowski 2021-12-07 7:53 ` Krzysztof Kozlowski 2021-12-07 8:06 ` Greg Kroah-Hartman 2021-12-07 8:06 ` Greg Kroah-Hartman
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20211124074625.182815-11-marcan@marcan.st \ --to=marcan@marcan.st \ --cc=alyssa@rosenzweig.io \ --cc=arnd@kernel.org \ --cc=devicetree@vger.kernel.org \ --cc=gregkh@linuxfoundation.org \ --cc=johan@kernel.org \ --cc=krzk@kernel.org \ --cc=linus.walleij@linaro.org \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-pm@vger.kernel.org \ --cc=linux-samsung-soc@vger.kernel.org \ --cc=linux-serial@vger.kernel.org \ --cc=mark.kettenis@xs4all.nl \ --cc=maz@kernel.org \ --cc=p.zabel@pengutronix.de \ --cc=rafael@kernel.org \ --cc=robh+dt@kernel.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.