// 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>
        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;
 };
 
        int ret;
        unsigned long speed_hz;
        unsigned long flags;
+       unsigned int avg_bw_cpu;
 
        speed_hz = slv->max_speed_hz;
        if (xfer->speed_hz)
                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 */
        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;
 {
        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;
 }
 
 {
        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);
 }