spi: spi-qcom-qspi: Add interconnect support
authorAkash Asthana <akashast@codeaurora.org>
Tue, 23 Jun 2020 10:38:56 +0000 (16:08 +0530)
committerBjorn Andersson <bjorn.andersson@linaro.org>
Thu, 25 Jun 2020 04:51:07 +0000 (21:51 -0700)
Get the interconnect paths for QSPI device and vote according to the
current bus speed of the driver.

Acked-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Akash Asthana <akashast@codeaurora.org>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
Link: https://lore.kernel.org/r/1592908737-7068-8-git-send-email-akashast@codeaurora.org
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
drivers/spi/spi-qcom-qspi.c

index 3c4f83b..b5b4cf6 100644 (file)
@@ -2,6 +2,7 @@
 // Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
 
 #include <linux/clk.h>
+#include <linux/interconnect.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -139,7 +140,8 @@ struct qcom_qspi {
        struct device *dev;
        struct clk_bulk_data *clks;
        struct qspi_xfer xfer;
-       /* Lock to protect xfer and IRQ accessed registers */
+       struct icc_path *icc_path_cpu_to_qspi;
+       /* Lock to protect data accessed by IRQs */
        spinlock_t lock;
 };
 
@@ -229,6 +231,7 @@ static int qcom_qspi_transfer_one(struct spi_master *master,
        int ret;
        unsigned long speed_hz;
        unsigned long flags;
+       unsigned int avg_bw_cpu;
 
        speed_hz = slv->max_speed_hz;
        if (xfer->speed_hz)
@@ -241,6 +244,18 @@ static int qcom_qspi_transfer_one(struct spi_master *master,
                return ret;
        }
 
+       /*
+        * Set BW quota for CPU as driver supports FIFO mode only.
+        * We don't have explicit peak requirement so keep it equal to avg_bw.
+        */
+       avg_bw_cpu = Bps_to_icc(speed_hz);
+       ret = icc_set_bw(ctrl->icc_path_cpu_to_qspi, avg_bw_cpu, avg_bw_cpu);
+       if (ret) {
+               dev_err(ctrl->dev, "%s: ICC BW voting failed for cpu: %d\n",
+                       __func__, ret);
+               return ret;
+       }
+
        spin_lock_irqsave(&ctrl->lock, flags);
 
        /* We are half duplex, so either rx or tx will be set */
@@ -458,6 +473,29 @@ static int qcom_qspi_probe(struct platform_device *pdev)
        if (ret)
                goto exit_probe_master_put;
 
+       ctrl->icc_path_cpu_to_qspi = devm_of_icc_get(dev, "qspi-config");
+       if (IS_ERR(ctrl->icc_path_cpu_to_qspi)) {
+               ret = PTR_ERR(ctrl->icc_path_cpu_to_qspi);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to get cpu path: %d\n", ret);
+               goto exit_probe_master_put;
+       }
+       /* Set BW vote for register access */
+       ret = icc_set_bw(ctrl->icc_path_cpu_to_qspi, Bps_to_icc(1000),
+                               Bps_to_icc(1000));
+       if (ret) {
+               dev_err(ctrl->dev, "%s: ICC BW voting failed for cpu: %d\n",
+                               __func__, ret);
+               goto exit_probe_master_put;
+       }
+
+       ret = icc_disable(ctrl->icc_path_cpu_to_qspi);
+       if (ret) {
+               dev_err(ctrl->dev, "%s: ICC disable failed for cpu: %d\n",
+                               __func__, ret);
+               goto exit_probe_master_put;
+       }
+
        ret = platform_get_irq(pdev, 0);
        if (ret < 0)
                goto exit_probe_master_put;
@@ -511,9 +549,17 @@ 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);
+       int ret;
 
        clk_bulk_disable_unprepare(QSPI_NUM_CLKS, ctrl->clks);
 
+       ret = icc_disable(ctrl->icc_path_cpu_to_qspi);
+       if (ret) {
+               dev_err_ratelimited(ctrl->dev, "%s: ICC disable failed for cpu: %d\n",
+                       __func__, ret);
+               return ret;
+       }
+
        return 0;
 }
 
@@ -521,6 +567,14 @@ static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev)
 {
        struct spi_master *master = dev_get_drvdata(dev);
        struct qcom_qspi *ctrl = spi_master_get_devdata(master);
+       int ret;
+
+       ret = icc_enable(ctrl->icc_path_cpu_to_qspi);
+       if (ret) {
+               dev_err_ratelimited(ctrl->dev, "%s: ICC enable failed for cpu: %d\n",
+                       __func__, ret);
+               return ret;
+       }
 
        return clk_bulk_prepare_enable(QSPI_NUM_CLKS, ctrl->clks);
 }