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: 8c2c8c03cd ("spi: img-spfi: Control CS lines with GPIO")
Signed-off-by: Sifan Naeem <sifan.naeem@imgtec.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Cc: stable@vger.kernel.org
This commit is contained in:
Sifan Naeem 2015-07-29 11:55:26 +01:00 committed by Mark Brown
parent 011710e2ab
commit b03ba9e314
1 changed files with 39 additions and 6 deletions

View File

@ -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) ?
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",
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)
{
gpio_free(spi->cs_gpio);
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,