Commit cff80645 authored by Akash Asthana's avatar Akash Asthana Committed by Bjorn Andersson

spi: spi-qcom-qspi: Add interconnect support

Get the interconnect paths for QSPI device and vote according to the
current bus speed of the driver.
Acked-by: default avatarMark Brown <broonie@kernel.org>
Signed-off-by: default avatarAkash Asthana <akashast@codeaurora.org>
Reviewed-by: default avatarMatthias Kaehlcke <mka@chromium.org>
Link: https://lore.kernel.org/r/1592908737-7068-8-git-send-email-akashast@codeaurora.orgSigned-off-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
parent 0e3b8a81
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Copyright (c) 2017-2018, The Linux foundation. All rights reserved. // Copyright (c) 2017-2018, The Linux foundation. All rights reserved.
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/interconnect.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -139,7 +140,8 @@ struct qcom_qspi { ...@@ -139,7 +140,8 @@ struct qcom_qspi {
struct device *dev; struct device *dev;
struct clk_bulk_data *clks; struct clk_bulk_data *clks;
struct qspi_xfer xfer; 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; spinlock_t lock;
}; };
...@@ -229,6 +231,7 @@ static int qcom_qspi_transfer_one(struct spi_master *master, ...@@ -229,6 +231,7 @@ static int qcom_qspi_transfer_one(struct spi_master *master,
int ret; int ret;
unsigned long speed_hz; unsigned long speed_hz;
unsigned long flags; unsigned long flags;
unsigned int avg_bw_cpu;
speed_hz = slv->max_speed_hz; speed_hz = slv->max_speed_hz;
if (xfer->speed_hz) if (xfer->speed_hz)
...@@ -241,6 +244,18 @@ static int qcom_qspi_transfer_one(struct spi_master *master, ...@@ -241,6 +244,18 @@ static int qcom_qspi_transfer_one(struct spi_master *master,
return ret; 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); spin_lock_irqsave(&ctrl->lock, flags);
/* We are half duplex, so either rx or tx will be set */ /* 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) ...@@ -458,6 +473,29 @@ static int qcom_qspi_probe(struct platform_device *pdev)
if (ret) if (ret)
goto exit_probe_master_put; 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); ret = platform_get_irq(pdev, 0);
if (ret < 0) if (ret < 0)
goto exit_probe_master_put; goto exit_probe_master_put;
...@@ -511,9 +549,17 @@ static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev) ...@@ -511,9 +549,17 @@ static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev)
{ {
struct spi_master *master = dev_get_drvdata(dev); struct spi_master *master = dev_get_drvdata(dev);
struct qcom_qspi *ctrl = spi_master_get_devdata(master); struct qcom_qspi *ctrl = spi_master_get_devdata(master);
int ret;
clk_bulk_disable_unprepare(QSPI_NUM_CLKS, ctrl->clks); 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; return 0;
} }
...@@ -521,6 +567,14 @@ static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev) ...@@ -521,6 +567,14 @@ static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev)
{ {
struct spi_master *master = dev_get_drvdata(dev); struct spi_master *master = dev_get_drvdata(dev);
struct qcom_qspi *ctrl = spi_master_get_devdata(master); 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); return clk_bulk_prepare_enable(QSPI_NUM_CLKS, ctrl->clks);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment