mirror of
https://github.com/torvalds/linux.git
synced 2024-11-06 03:51:48 +00:00
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:
parent
011710e2ab
commit
b03ba9e314
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user