Commit 985f6ab9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull spi fixes from Mark Brown:
 "A few small fixes.

  Mostly driver specific but there's one in the core which fixes a
  deadlock when adding devices on spi-mux that's triggered because
  spi-mux is a SPI device which is itself a SPI controller and so can
  instantiate devices when registered.

  We were using a global lock to protect against reusing chip selects
  but they're a per controller thing so moving the lock per controller
  resolves that"

* tag 'spi-fix-v5.15-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  spi-mux: Fix false-positive lockdep splats
  spi: Fix deadlock when adding SPI controllers on SPI buses
  spi: bcm-qspi: clear MSPI spifie interrupt during probe
  spi: spi-nxp-fspi: don't depend on a specific node name erratum workaround
  spi: mediatek: skip delays if they are 0
  spi: atmel: Fix PDC transfer setup bug
  spi: spidev: Add SPI ID table
  spi: Use 'flash' node name instead of 'spi-flash' in example
parents ccb6a666 16a8e2fb
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -171,7 +171,7 @@ examples:
      cs-gpios = <&gpio0 13 0>,
                 <&gpio0 14 0>;
      rx-sample-delay-ns = <3>;
      spi-flash@1 {
      flash@1 {
        compatible = "spi-nand";
        reg = <1>;
        rx-sample-delay-ns = <7>;
+2 −2
Original line number Diff line number Diff line
@@ -1301,7 +1301,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
	 * DMA map early, for performance (empties dcache ASAP) and
	 * better fault reporting.
	 */
	if ((!master->cur_msg_mapped)
	if ((!master->cur_msg->is_dma_mapped)
		&& as->use_pdc) {
		if (atmel_spi_dma_map_xfer(as, xfer) < 0)
			return -ENOMEM;
@@ -1381,7 +1381,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
		}
	}

	if (!master->cur_msg_mapped
	if (!master->cur_msg->is_dma_mapped
		&& as->use_pdc)
		atmel_spi_dma_unmap_xfer(master, xfer);

+45 −32
Original line number Diff line number Diff line
@@ -1250,10 +1250,14 @@ static void bcm_qspi_hw_init(struct bcm_qspi *qspi)

static void bcm_qspi_hw_uninit(struct bcm_qspi *qspi)
{
	u32 status = bcm_qspi_read(qspi, MSPI, MSPI_MSPI_STATUS);

	bcm_qspi_write(qspi, MSPI, MSPI_SPCR2, 0);
	if (has_bspi(qspi))
		bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);

	/* clear interrupt */
	bcm_qspi_write(qspi, MSPI, MSPI_MSPI_STATUS, status & ~1);
}

static const struct spi_controller_mem_ops bcm_qspi_mem_ops = {
@@ -1397,6 +1401,47 @@ int bcm_qspi_probe(struct platform_device *pdev,
	if (!qspi->dev_ids)
		return -ENOMEM;

	/*
	 * Some SoCs integrate spi controller (e.g., its interrupt bits)
	 * in specific ways
	 */
	if (soc_intc) {
		qspi->soc_intc = soc_intc;
		soc_intc->bcm_qspi_int_set(soc_intc, MSPI_DONE, true);
	} else {
		qspi->soc_intc = NULL;
	}

	if (qspi->clk) {
		ret = clk_prepare_enable(qspi->clk);
		if (ret) {
			dev_err(dev, "failed to prepare clock\n");
			goto qspi_probe_err;
		}
		qspi->base_clk = clk_get_rate(qspi->clk);
	} else {
		qspi->base_clk = MSPI_BASE_FREQ;
	}

	if (data->has_mspi_rev) {
		rev = bcm_qspi_read(qspi, MSPI, MSPI_REV);
		/* some older revs do not have a MSPI_REV register */
		if ((rev & 0xff) == 0xff)
			rev = 0;
	}

	qspi->mspi_maj_rev = (rev >> 4) & 0xf;
	qspi->mspi_min_rev = rev & 0xf;
	qspi->mspi_spcr3_sysclk = data->has_spcr3_sysclk;

	qspi->max_speed_hz = qspi->base_clk / (bcm_qspi_spbr_min(qspi) * 2);

	/*
	 * On SW resets it is possible to have the mask still enabled
	 * Need to disable the mask and clear the status while we init
	 */
	bcm_qspi_hw_uninit(qspi);

	for (val = 0; val < num_irqs; val++) {
		irq = -1;
		name = qspi_irq_tab[val].irq_name;
@@ -1433,38 +1478,6 @@ int bcm_qspi_probe(struct platform_device *pdev,
		goto qspi_probe_err;
	}

	/*
	 * Some SoCs integrate spi controller (e.g., its interrupt bits)
	 * in specific ways
	 */
	if (soc_intc) {
		qspi->soc_intc = soc_intc;
		soc_intc->bcm_qspi_int_set(soc_intc, MSPI_DONE, true);
	} else {
		qspi->soc_intc = NULL;
	}

	ret = clk_prepare_enable(qspi->clk);
	if (ret) {
		dev_err(dev, "failed to prepare clock\n");
		goto qspi_probe_err;
	}

	qspi->base_clk = clk_get_rate(qspi->clk);

	if (data->has_mspi_rev) {
		rev = bcm_qspi_read(qspi, MSPI, MSPI_REV);
		/* some older revs do not have a MSPI_REV register */
		if ((rev & 0xff) == 0xff)
			rev = 0;
	}

	qspi->mspi_maj_rev = (rev >> 4) & 0xf;
	qspi->mspi_min_rev = rev & 0xf;
	qspi->mspi_spcr3_sysclk = data->has_spcr3_sysclk;

	qspi->max_speed_hz = qspi->base_clk / (bcm_qspi_spbr_min(qspi) * 2);

	bcm_qspi_hw_init(qspi);
	init_completion(&qspi->mspi_done);
	init_completion(&qspi->bspi_done);
+36 −28
Original line number Diff line number Diff line
@@ -233,36 +233,44 @@ static int mtk_spi_set_hw_cs_timing(struct spi_device *spi)
		return delay;
	inactive = (delay * DIV_ROUND_UP(mdata->spi_clk_hz, 1000000)) / 1000;

	setup    = setup ? setup : 1;
	hold     = hold ? hold : 1;
	inactive = inactive ? inactive : 1;

	if (hold || setup) {
		reg_val = readl(mdata->base + SPI_CFG0_REG);
		if (mdata->dev_comp->enhance_timing) {
			if (hold) {
				hold = min_t(u32, hold, 0x10000);
		setup = min_t(u32, setup, 0x10000);
				reg_val &= ~(0xffff << SPI_ADJUST_CFG0_CS_HOLD_OFFSET);
				reg_val |= (((hold - 1) & 0xffff)
					<< SPI_ADJUST_CFG0_CS_HOLD_OFFSET);
			}
			if (setup) {
				setup = min_t(u32, setup, 0x10000);
				reg_val &= ~(0xffff << SPI_ADJUST_CFG0_CS_SETUP_OFFSET);
				reg_val |= (((setup - 1) & 0xffff)
					<< SPI_ADJUST_CFG0_CS_SETUP_OFFSET);
			}
		} else {
			if (hold) {
				hold = min_t(u32, hold, 0x100);
		setup = min_t(u32, setup, 0x100);
				reg_val &= ~(0xff << SPI_CFG0_CS_HOLD_OFFSET);
				reg_val |= (((hold - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET);
			}
			if (setup) {
				setup = min_t(u32, setup, 0x100);
				reg_val &= ~(0xff << SPI_CFG0_CS_SETUP_OFFSET);
				reg_val |= (((setup - 1) & 0xff)
					<< SPI_CFG0_CS_SETUP_OFFSET);
			}
		}
		writel(reg_val, mdata->base + SPI_CFG0_REG);
	}

	if (inactive) {
		inactive = min_t(u32, inactive, 0x100);
		reg_val = readl(mdata->base + SPI_CFG1_REG);
		reg_val &= ~SPI_CFG1_CS_IDLE_MASK;
		reg_val |= (((inactive - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET);
		writel(reg_val, mdata->base + SPI_CFG1_REG);
	}

	return 0;
}
+7 −0
Original line number Diff line number Diff line
@@ -137,6 +137,13 @@ static int spi_mux_probe(struct spi_device *spi)
	priv = spi_controller_get_devdata(ctlr);
	priv->spi = spi;

	/*
	 * Increase lockdep class as these lock are taken while the parent bus
	 * already holds their instance's lock.
	 */
	lockdep_set_subclass(&ctlr->io_mutex, 1);
	lockdep_set_subclass(&ctlr->add_lock, 1);

	priv->mux = devm_mux_control_get(&spi->dev, NULL);
	if (IS_ERR(priv->mux)) {
		ret = dev_err_probe(&spi->dev, PTR_ERR(priv->mux),
Loading