Commit 4c8684fe authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull spi fixes from Mark Brown:
 "A small set of SPI fixes that have come up since the merge window, all
  fairly small fixes for rare cases"

* tag 'spi-fix-v5.13-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  spi: stm32-qspi: Always wait BUSY bit to be cleared in stm32_qspi_wait_cmd()
  spi: spi-zynq-qspi: Fix some wrong goto jumps & missing error code
  spi: Cleanup on failure of initial setup
  spi: bcm2835: Fix out-of-bounds access with more than 4 slaves
parents 9b1111fa d38fa9a1
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@
#define BCM2835_SPI_FIFO_SIZE		64
#define BCM2835_SPI_FIFO_SIZE_3_4	48
#define BCM2835_SPI_DMA_MIN_LENGTH	96
#define BCM2835_SPI_NUM_CS		4   /* raise as necessary */
#define BCM2835_SPI_NUM_CS		24  /* raise as necessary */
#define BCM2835_SPI_MODE_BITS	(SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
				| SPI_NO_CS | SPI_3WIRE)

@@ -1195,6 +1195,12 @@ static int bcm2835_spi_setup(struct spi_device *spi)
	struct gpio_chip *chip;
	u32 cs;

	if (spi->chip_select >= BCM2835_SPI_NUM_CS) {
		dev_err(&spi->dev, "only %d chip-selects supported\n",
			BCM2835_SPI_NUM_CS - 1);
		return -EINVAL;
	}

	/*
	 * Precalculate SPI slave's CS register value for ->prepare_message():
	 * The driver always uses software-controlled GPIO chip select, hence
@@ -1288,7 +1294,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
	ctlr->use_gpio_descriptors = true;
	ctlr->mode_bits = BCM2835_SPI_MODE_BITS;
	ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
	ctlr->num_chipselect = BCM2835_SPI_NUM_CS;
	ctlr->num_chipselect = 3;
	ctlr->setup = bcm2835_spi_setup;
	ctlr->transfer_one = bcm2835_spi_transfer_one;
	ctlr->handle_err = bcm2835_spi_handle_err;
+14 −4
Original line number Diff line number Diff line
@@ -184,6 +184,8 @@ int spi_bitbang_setup(struct spi_device *spi)
{
	struct spi_bitbang_cs	*cs = spi->controller_state;
	struct spi_bitbang	*bitbang;
	bool			initial_setup = false;
	int			retval;

	bitbang = spi_master_get_devdata(spi->master);

@@ -192,22 +194,30 @@ int spi_bitbang_setup(struct spi_device *spi)
		if (!cs)
			return -ENOMEM;
		spi->controller_state = cs;
		initial_setup = true;
	}

	/* per-word shift register access, in hardware or bitbanging */
	cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];
	if (!cs->txrx_word)
		return -EINVAL;
	if (!cs->txrx_word) {
		retval = -EINVAL;
		goto err_free;
	}

	if (bitbang->setup_transfer) {
		int retval = bitbang->setup_transfer(spi, NULL);
		retval = bitbang->setup_transfer(spi, NULL);
		if (retval < 0)
			return retval;
			goto err_free;
	}

	dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs);

	return 0;

err_free:
	if (initial_setup)
		kfree(cs);
	return retval;
}
EXPORT_SYMBOL_GPL(spi_bitbang_setup);

+4 −0
Original line number Diff line number Diff line
@@ -440,6 +440,7 @@ static int fsl_spi_setup(struct spi_device *spi)
{
	struct mpc8xxx_spi *mpc8xxx_spi;
	struct fsl_spi_reg __iomem *reg_base;
	bool initial_setup = false;
	int retval;
	u32 hw_mode;
	struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi);
@@ -452,6 +453,7 @@ static int fsl_spi_setup(struct spi_device *spi)
		if (!cs)
			return -ENOMEM;
		spi_set_ctldata(spi, cs);
		initial_setup = true;
	}
	mpc8xxx_spi = spi_master_get_devdata(spi->master);

@@ -475,6 +477,8 @@ static int fsl_spi_setup(struct spi_device *spi)
	retval = fsl_spi_setup_transfer(spi, NULL);
	if (retval < 0) {
		cs->hw_mode = hw_mode; /* Restore settings */
		if (initial_setup)
			kfree(cs);
		return retval;
	}

+8 −1
Original line number Diff line number Diff line
@@ -424,15 +424,22 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
static int uwire_setup(struct spi_device *spi)
{
	struct uwire_state *ust = spi->controller_state;
	bool initial_setup = false;
	int status;

	if (ust == NULL) {
		ust = kzalloc(sizeof(*ust), GFP_KERNEL);
		if (ust == NULL)
			return -ENOMEM;
		spi->controller_state = ust;
		initial_setup = true;
	}

	return uwire_setup_transfer(spi, NULL);
	status = uwire_setup_transfer(spi, NULL);
	if (status && initial_setup)
		kfree(ust);

	return status;
}

static void uwire_cleanup(struct spi_device *spi)
+20 −13
Original line number Diff line number Diff line
@@ -1032,8 +1032,22 @@ static void omap2_mcspi_release_dma(struct spi_master *master)
	}
}

static void omap2_mcspi_cleanup(struct spi_device *spi)
{
	struct omap2_mcspi_cs	*cs;

	if (spi->controller_state) {
		/* Unlink controller state from context save list */
		cs = spi->controller_state;
		list_del(&cs->node);

		kfree(cs);
	}
}

static int omap2_mcspi_setup(struct spi_device *spi)
{
	bool			initial_setup = false;
	int			ret;
	struct omap2_mcspi	*mcspi = spi_master_get_devdata(spi->master);
	struct omap2_mcspi_regs	*ctx = &mcspi->ctx;
@@ -1051,35 +1065,28 @@ static int omap2_mcspi_setup(struct spi_device *spi)
		spi->controller_state = cs;
		/* Link this to context save list */
		list_add_tail(&cs->node, &ctx->cs);
		initial_setup = true;
	}

	ret = pm_runtime_get_sync(mcspi->dev);
	if (ret < 0) {
		pm_runtime_put_noidle(mcspi->dev);
		if (initial_setup)
			omap2_mcspi_cleanup(spi);

		return ret;
	}

	ret = omap2_mcspi_setup_transfer(spi, NULL);
	if (ret && initial_setup)
		omap2_mcspi_cleanup(spi);

	pm_runtime_mark_last_busy(mcspi->dev);
	pm_runtime_put_autosuspend(mcspi->dev);

	return ret;
}

static void omap2_mcspi_cleanup(struct spi_device *spi)
{
	struct omap2_mcspi_cs	*cs;

	if (spi->controller_state) {
		/* Unlink controller state from context save list */
		cs = spi->controller_state;
		list_del(&cs->node);

		kfree(cs);
	}
}

static irqreturn_t omap2_mcspi_irq_handler(int irq, void *data)
{
	struct omap2_mcspi *mcspi = data;
Loading