From: Rajendra Nayak Date: Fri, 3 Jul 2020 09:41:31 +0000 (+0530) Subject: spi: spi-qcom-qspi: Use OPP API to set clk/perf state X-Git-Tag: v5.10.7~1991^2~5^2~9 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f79a158d37c26015099f4a7fd7d6592bb2ad3054;p=platform%2Fkernel%2Flinux-rpi.git spi: spi-qcom-qspi: Use OPP API to set clk/perf state 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 Reviewed-by: Matthias Kaehlcke Acked-by: Mark Brown Cc: Alok Chauhan Cc: Akash Asthana Cc: linux-spi@vger.kernel.org Link: https://lore.kernel.org/r/1593769293-6354-2-git-send-email-rnayak@codeaurora.org Signed-off-by: Bjorn Andersson --- diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c index b5b4cf6..18a59aa 100644 --- a/drivers/spi/spi-qcom-qspi.c +++ b/drivers/spi/spi-qcom-qspi.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -141,6 +142,8 @@ struct qcom_qspi { struct clk_bulk_data *clks; struct qspi_xfer xfer; struct icc_path *icc_path_cpu_to_qspi; + struct opp_table *opp_table; + bool has_opp_table; /* Lock to protect data accessed by IRQs */ spinlock_t lock; }; @@ -238,7 +241,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; @@ -519,6 +522,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); @@ -526,6 +543,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); @@ -536,11 +556,15 @@ exit_probe_master_put: 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; } @@ -551,6 +575,8 @@ static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev) struct qcom_qspi *ctrl = spi_master_get_devdata(master); int ret; + /* Drop the performance state vote */ + dev_pm_opp_set_rate(dev, 0); clk_bulk_disable_unprepare(QSPI_NUM_CLKS, ctrl->clks); ret = icc_disable(ctrl->icc_path_cpu_to_qspi);