Message ID | 1589368382-19607-7-git-send-email-rnayak@codeaurora.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | None | expand |
On Wed, May 13, 2020 at 04:43:02PM +0530, Rajendra Nayak wrote: > QSPI needs to vote on a performance state of a power domain depending on > the clock rate. Add support for it by specifying the perf state/clock rate > as an OPP table in device tree. > > Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org> > Cc: Mark Brown <broonie@kernel.org> > Cc: Alok Chauhan <alokc@codeaurora.org> > Cc: Akash Asthana <akashast@codeaurora.org> > Cc: linux-spi@vger.kernel.org > --- > Change in v5: OPP cleanup done as the last thing in qcom_qspi_remove() > > drivers/spi/spi-qcom-qspi.c | 29 ++++++++++++++++++++++++++++- > 1 file changed, 28 insertions(+), 1 deletion(-) > > diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c > index 3c4f83b..c853eba 100644 > --- a/drivers/spi/spi-qcom-qspi.c > +++ b/drivers/spi/spi-qcom-qspi.c > @@ -8,6 +8,7 @@ > #include <linux/of.h> > #include <linux/of_platform.h> > #include <linux/pm_runtime.h> > +#include <linux/pm_opp.h> > #include <linux/spi/spi.h> > #include <linux/spi/spi-mem.h> > > @@ -139,6 +140,8 @@ struct qcom_qspi { > struct device *dev; > struct clk_bulk_data *clks; > struct qspi_xfer xfer; > + struct opp_table *opp_table; > + bool has_opp_table; > /* Lock to protect xfer and IRQ accessed registers */ > spinlock_t lock; > }; > @@ -235,7 +238,7 @@ static int qcom_qspi_transfer_one(struct spi_master *master, > speed_hz = xfer->speed_hz; > > /* In regular operation (SBL_EN=1) core must be 4x transfer clock */ > - ret = clk_set_rate(ctrl->clks[QSPI_CLK_CORE].clk, speed_hz * 4); > + ret = dev_pm_opp_set_rate(ctrl->dev, speed_hz * 4); > if (ret) { > dev_err(ctrl->dev, "Failed to set core clk %d\n", ret); > return ret; > @@ -481,6 +484,20 @@ static int qcom_qspi_probe(struct platform_device *pdev) > master->handle_err = qcom_qspi_handle_err; > master->auto_runtime_pm = true; > > + ctrl->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "core"); > + if (IS_ERR(ctrl->opp_table)) { > + ret = PTR_ERR(ctrl->opp_table); > + goto exit_probe_master_put; > + } > + /* OPP table is optional */ > + ret = dev_pm_opp_of_add_table(&pdev->dev); > + if (!ret) { > + ctrl->has_opp_table = true; > + } else if (ret != -ENODEV) { > + dev_err(&pdev->dev, "invalid OPP table in device tree\n"); > + goto exit_probe_master_put; > + } > + > pm_runtime_enable(dev); > > ret = spi_register_master(master); > @@ -488,6 +505,9 @@ static int qcom_qspi_probe(struct platform_device *pdev) > return 0; > > pm_runtime_disable(dev); > + if (ctrl->has_opp_table) > + dev_pm_opp_of_remove_table(&pdev->dev); > + dev_pm_opp_put_clkname(ctrl->opp_table); > > exit_probe_master_put: > spi_master_put(master); > @@ -498,11 +518,16 @@ static int qcom_qspi_probe(struct platform_device *pdev) > static int qcom_qspi_remove(struct platform_device *pdev) > { > struct spi_master *master = platform_get_drvdata(pdev); > + struct qcom_qspi *ctrl = spi_master_get_devdata(master); > > /* Unregister _before_ disabling pm_runtime() so we stop transfers */ > spi_unregister_master(master); > > pm_runtime_disable(&pdev->dev); > + if (ctrl->has_opp_table) > + dev_pm_opp_of_remove_table(&pdev->dev); > + dev_pm_opp_put_clkname(ctrl->opp_table); > + > remove 2nd empty line. Maybe this can be done when the patch is applied if there are no other reasons to respin the series? Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
On Wed, May 13, 2020 at 04:43:02PM +0530, Rajendra Nayak wrote: > QSPI needs to vote on a performance state of a power domain depending on > the clock rate. Add support for it by specifying the perf state/clock rate > as an OPP table in device Acked-by: Mark Brown <broonie@kernel.org>
diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c index 3c4f83b..c853eba 100644 --- a/drivers/spi/spi-qcom-qspi.c +++ b/drivers/spi/spi-qcom-qspi.c @@ -8,6 +8,7 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <linux/pm_runtime.h> +#include <linux/pm_opp.h> #include <linux/spi/spi.h> #include <linux/spi/spi-mem.h> @@ -139,6 +140,8 @@ struct qcom_qspi { struct device *dev; struct clk_bulk_data *clks; struct qspi_xfer xfer; + struct opp_table *opp_table; + bool has_opp_table; /* Lock to protect xfer and IRQ accessed registers */ spinlock_t lock; }; @@ -235,7 +238,7 @@ static int qcom_qspi_transfer_one(struct spi_master *master, speed_hz = xfer->speed_hz; /* In regular operation (SBL_EN=1) core must be 4x transfer clock */ - ret = clk_set_rate(ctrl->clks[QSPI_CLK_CORE].clk, speed_hz * 4); + ret = dev_pm_opp_set_rate(ctrl->dev, speed_hz * 4); if (ret) { dev_err(ctrl->dev, "Failed to set core clk %d\n", ret); return ret; @@ -481,6 +484,20 @@ static int qcom_qspi_probe(struct platform_device *pdev) master->handle_err = qcom_qspi_handle_err; master->auto_runtime_pm = true; + ctrl->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "core"); + if (IS_ERR(ctrl->opp_table)) { + ret = PTR_ERR(ctrl->opp_table); + goto exit_probe_master_put; + } + /* OPP table is optional */ + ret = dev_pm_opp_of_add_table(&pdev->dev); + if (!ret) { + ctrl->has_opp_table = true; + } else if (ret != -ENODEV) { + dev_err(&pdev->dev, "invalid OPP table in device tree\n"); + goto exit_probe_master_put; + } + pm_runtime_enable(dev); ret = spi_register_master(master); @@ -488,6 +505,9 @@ static int qcom_qspi_probe(struct platform_device *pdev) return 0; pm_runtime_disable(dev); + if (ctrl->has_opp_table) + dev_pm_opp_of_remove_table(&pdev->dev); + dev_pm_opp_put_clkname(ctrl->opp_table); exit_probe_master_put: spi_master_put(master); @@ -498,11 +518,16 @@ static int qcom_qspi_probe(struct platform_device *pdev) static int qcom_qspi_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); + struct qcom_qspi *ctrl = spi_master_get_devdata(master); /* Unregister _before_ disabling pm_runtime() so we stop transfers */ spi_unregister_master(master); pm_runtime_disable(&pdev->dev); + if (ctrl->has_opp_table) + dev_pm_opp_of_remove_table(&pdev->dev); + dev_pm_opp_put_clkname(ctrl->opp_table); + return 0; } @@ -512,6 +537,8 @@ static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev) struct spi_master *master = dev_get_drvdata(dev); struct qcom_qspi *ctrl = spi_master_get_devdata(master); + /* Drop the performance state vote */ + dev_pm_opp_set_rate(dev, 0); clk_bulk_disable_unprepare(QSPI_NUM_CLKS, ctrl->clks); return 0;
QSPI needs to vote on a performance state of a power domain depending on the clock rate. Add support for it by specifying the perf state/clock rate as an OPP table in device tree. Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org> Cc: Mark Brown <broonie@kernel.org> Cc: Alok Chauhan <alokc@codeaurora.org> Cc: Akash Asthana <akashast@codeaurora.org> Cc: linux-spi@vger.kernel.org --- Change in v5: OPP cleanup done as the last thing in qcom_qspi_remove() drivers/spi/spi-qcom-qspi.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-)