Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b03ba9e3 authored by Sifan Naeem's avatar Sifan Naeem Committed by Mark Brown
Browse files

spi: img-spfi: fix multiple calls to request gpio



spfi_setup may be called many times by the spi framework, but
gpio_request_one can only be called once without freeing, repeatedly
calling gpio_request_one will cause an error to be thrown, which
causes the request to spi_setup to be marked as failed.

We can have a per-spi_device flag that indicates whether or not the
gpio has been requested. If the gpio has already been requested use
gpio_direction_output to set the direction of the gpio.

Fixes: 8c2c8c03 ("spi: img-spfi: Control CS lines with GPIO")
Signed-off-by: default avatarSifan Naeem <sifan.naeem@imgtec.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Cc: stable@vger.kernel.org
parent 011710e2
Loading
Loading
Loading
Loading
+41 −8
Original line number Diff line number Diff line
@@ -104,6 +104,10 @@ struct img_spfi {
	bool rx_dma_busy;
};

struct img_spfi_device_data {
	bool gpio_requested;
};

static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg)
{
	return readl(spfi->regs + reg);
@@ -440,20 +444,49 @@ static int img_spfi_unprepare(struct spi_master *master,
static int img_spfi_setup(struct spi_device *spi)
{
	int ret;
	struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi);

	ret = gpio_request_one(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ?
	if (!spfi_data) {
		spfi_data = kzalloc(sizeof(*spfi_data), GFP_KERNEL);
		if (!spfi_data)
			return -ENOMEM;
		spfi_data->gpio_requested = false;
		spi_set_ctldata(spi, spfi_data);
	}
	if (!spfi_data->gpio_requested) {
		ret = gpio_request_one(spi->cs_gpio,
				       (spi->mode & SPI_CS_HIGH) ?
				       GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
				       dev_name(&spi->dev));
		if (ret)
			dev_err(&spi->dev, "can't request chipselect gpio %d\n",
				spi->cs_gpio);
		else
			spfi_data->gpio_requested = true;
	} else {
		if (gpio_is_valid(spi->cs_gpio)) {
			int mode = ((spi->mode & SPI_CS_HIGH) ?
				    GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH);

			ret = gpio_direction_output(spi->cs_gpio, mode);
			if (ret)
				dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n",
					spi->cs_gpio, ret);
		}
	}
	return ret;
}

static void img_spfi_cleanup(struct spi_device *spi)
{
	struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi);

	if (spfi_data) {
		if (spfi_data->gpio_requested)
			gpio_free(spi->cs_gpio);
		kfree(spfi_data);
		spi_set_ctldata(spi, NULL);
	}
}

static void img_spfi_config(struct spi_master *master, struct spi_device *spi,