[PATCH v2 2/7] spi: qcom-qspi: Fix incomplete error handling in runtime PM

From: Viken Dadhaniya

Date: Tue Apr 14 2026 - 13:13:34 EST


The runtime PM functions had incomplete error handling that could leave the
system in an inconsistent state. If any operation failed midway through
suspend or resume, some resources would be left in the wrong state while
others were already changed, leading to potential clock/power imbalances.

Fix by adding proper error checking for all operations and using goto-based
cleanup to ensure all successfully acquired resources are properly released
on any error.

Signed-off-by: Viken Dadhaniya <viken.dadhaniya@xxxxxxxxxxxxxxxx>
---
drivers/spi/spi-qcom-qspi.c | 40 +++++++++++++++++++++++++++++++++-------
1 file changed, 33 insertions(+), 7 deletions(-)

diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c
index 7e39038160e0..38af859713a7 100644
--- a/drivers/spi/spi-qcom-qspi.c
+++ b/drivers/spi/spi-qcom-qspi.c
@@ -819,19 +819,31 @@ static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev)
int ret;

/* Drop the performance state vote */
- dev_pm_opp_set_rate(dev, 0);
+ ret = dev_pm_opp_set_rate(dev, 0);
+ if (ret)
+ return 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;
+ goto err_enable_clk;
}

- pinctrl_pm_select_sleep_state(dev);
+ ret = pinctrl_pm_select_sleep_state(dev);
+ if (ret)
+ goto err_enable_icc;

return 0;
+
+err_enable_icc:
+ icc_enable(ctrl->icc_path_cpu_to_qspi);
+err_enable_clk:
+ clk_bulk_prepare_enable(QSPI_NUM_CLKS, ctrl->clks);
+ dev_pm_opp_set_rate(dev, ctrl->last_speed * 4);
+ return ret;
}

static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev)
@@ -840,20 +852,34 @@ static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev)
struct qcom_qspi *ctrl = spi_controller_get_devdata(host);
int ret;

- pinctrl_pm_select_default_state(dev);
+ ret = pinctrl_pm_select_default_state(dev);
+ if (ret)
+ return 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;
+ goto err_select_sleep_state;
}

ret = clk_bulk_prepare_enable(QSPI_NUM_CLKS, ctrl->clks);
if (ret)
- return ret;
+ goto err_disable_icc;

- return dev_pm_opp_set_rate(dev, ctrl->last_speed * 4);
+ ret = dev_pm_opp_set_rate(dev, ctrl->last_speed * 4);
+ if (ret)
+ goto err_disable_clk;
+
+ return 0;
+
+err_disable_clk:
+ clk_bulk_disable_unprepare(QSPI_NUM_CLKS, ctrl->clks);
+err_disable_icc:
+ icc_disable(ctrl->icc_path_cpu_to_qspi);
+err_select_sleep_state:
+ pinctrl_pm_select_sleep_state(dev);
+ return ret;
}

static int __maybe_unused qcom_qspi_suspend(struct device *dev)

--
2.34.1