From: Haibo Chen Date: Tue, 28 Jul 2026 10:18:10 +0000 (+0800) Subject: spi: spi-nxp-fspi: propagate clock reconfig failures in nxp_fspi_select_mem() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b5902b9779796d515b7d65eb9205994b7a8d00cb;p=thirdparty%2Flinux.git spi: spi-nxp-fspi: propagate clock reconfig failures in nxp_fspi_select_mem() nxp_fspi_select_mem() disables the FlexSPI clocks before calling clk_set_rate() and re-enabling them. If clk_set_rate() or the clock re-enable fails, the function returned early (as void) leaving both the serial root clock and the register interface clock disabled. As the function returned void, nxp_fspi_exec_op() had no way to know about the failure and continued to access FlexSPI registers (LUT setup, data transfer, AHB buffer invalidation). Accessing the controller registers while its clock is gated off results in a synchronous external abort. Make nxp_fspi_select_mem() return an error code and have nxp_fspi_exec_op() bail out on failure before any further register access, including nxp_fspi_invalid(). Signed-off-by: Haibo Chen Link: https://patch.msgid.link/20260728-fspi-clock-v2-3-dbe786a4a6eb@nxp.com Signed-off-by: Mark Brown --- diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index 54355295f919..4425132432ec 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -859,8 +859,8 @@ static void nxp_fspi_dll_override(struct nxp_fspi *f) * Value for rest of the CS FLSHxxCR0 register would be zero. * */ -static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi, - const struct spi_mem_op *op) +static int nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi, + const struct spi_mem_op *op) { /* flexspi only support one DTR mode: 8D-8D-8D */ bool op_is_dtr = op->cmd.dtr && op->addr.dtr && op->dummy.dtr && op->data.dtr; @@ -881,7 +881,7 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi, if ((f->selected == spi_get_chipselect(spi, 0)) && (!!(f->flags & FSPI_DTR_MODE) == op_is_dtr) && (f->pre_op_rate == op->max_freq)) - return; + return 0; /* Reset FLSHxxCR0 registers */ fspi_writel(f, 0, f->iobase + FSPI_FLSHA1CR0); @@ -922,12 +922,19 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi, nxp_fspi_clk_disable_unprep(f); ret = clk_set_rate(f->clk, rate); - if (ret) - return; + if (ret) { + /* + * clk_set_rate() failed with the clocks already disabled. + * Re-enable them so the enable count matches what the caller's + * pm_runtime_put() (runtime_suspend) will drop. + */ + nxp_fspi_clk_prep_enable(f); + return ret; + } ret = nxp_fspi_clk_prep_enable(f); if (ret) - return; + return ret; /* * If clock rate > 100MHz, then switch from DLL override mode to @@ -945,6 +952,8 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi, f->pre_op_rate = op->max_freq; f->selected = spi_get_chipselect(spi, 0); + + return 0; } static int nxp_fspi_read_ahb(struct nxp_fspi *f, const struct spi_mem_op *op) @@ -1132,7 +1141,16 @@ static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) FSPI_STS0_ARB_IDLE, 1, POLL_TOUT, true); WARN_ON(err); - nxp_fspi_select_mem(f, mem->spi, op); + err = nxp_fspi_select_mem(f, mem->spi, op); + if (err) { + /* + * On failure the FlexSPI clock may be left disabled, so avoid + * any further register access (which would trigger a synchronous + * external abort) and bail out. + */ + pm_runtime_put_autosuspend(f->dev); + return err; + } nxp_fspi_prepare_lut(f, op); /*