mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-07 02:19:54 +00:00
spi: img-spfi: fix multiple calls to request gpio
commitb03ba9e314upstream. 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
3d6cbc37b4
commit
5eddcb34ea
@@ -105,6 +105,10 @@ struct img_spfi {
|
|||||||
bool rx_dma_busy;
|
bool rx_dma_busy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct img_spfi_device_data {
|
||||||
|
bool gpio_requested;
|
||||||
|
};
|
||||||
|
|
||||||
static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg)
|
static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg)
|
||||||
{
|
{
|
||||||
return readl(spfi->regs + reg);
|
return readl(spfi->regs + reg);
|
||||||
@@ -441,20 +445,49 @@ static int img_spfi_unprepare(struct spi_master *master,
|
|||||||
static int img_spfi_setup(struct spi_device *spi)
|
static int img_spfi_setup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
int ret;
|
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,
|
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
|
||||||
dev_name(&spi->dev));
|
dev_name(&spi->dev));
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_err(&spi->dev, "can't request chipselect gpio %d\n",
|
dev_err(&spi->dev, "can't request chipselect gpio %d\n",
|
||||||
spi->cs_gpio);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void img_spfi_cleanup(struct spi_device *spi)
|
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);
|
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,
|
static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
|
||||||
|
|||||||
Reference in New Issue
Block a user