diff options
author | Sifan Naeem <sifan.naeem@imgtec.com> | 2015-07-29 06:55:26 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-08-04 13:46:54 -0400 |
commit | b03ba9e314c12b2127243145b5c1f41b2408de62 (patch) | |
tree | e909d33caf1fea825693ef42d3baec7778ea0ae6 /drivers/spi/spi-img-spfi.c | |
parent | 011710e2ab659c7ad6e5e554806414bd7a9508be (diff) |
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: 8c2c8c03cdcb ("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
Diffstat (limited to 'drivers/spi/spi-img-spfi.c')
-rw-r--r-- | drivers/spi/spi-img-spfi.c | 49 |
1 files changed, 41 insertions, 8 deletions
diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index 83b97418fc8d..1ba90562d72a 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c | |||
@@ -104,6 +104,10 @@ struct img_spfi { | |||
104 | bool rx_dma_busy; | 104 | bool rx_dma_busy; |
105 | }; | 105 | }; |
106 | 106 | ||
107 | struct img_spfi_device_data { | ||
108 | bool gpio_requested; | ||
109 | }; | ||
110 | |||
107 | static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg) | 111 | static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg) |
108 | { | 112 | { |
109 | return readl(spfi->regs + reg); | 113 | return readl(spfi->regs + reg); |
@@ -440,20 +444,49 @@ static int img_spfi_unprepare(struct spi_master *master, | |||
440 | static int img_spfi_setup(struct spi_device *spi) | 444 | static int img_spfi_setup(struct spi_device *spi) |
441 | { | 445 | { |
442 | int ret; | 446 | int ret; |
443 | 447 | struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi); | |
444 | ret = gpio_request_one(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ? | 448 | |
445 | GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, | 449 | if (!spfi_data) { |
446 | dev_name(&spi->dev)); | 450 | spfi_data = kzalloc(sizeof(*spfi_data), GFP_KERNEL); |
447 | if (ret) | 451 | if (!spfi_data) |
448 | dev_err(&spi->dev, "can't request chipselect gpio %d\n", | 452 | return -ENOMEM; |
453 | spfi_data->gpio_requested = false; | ||
454 | spi_set_ctldata(spi, spfi_data); | ||
455 | } | ||
456 | if (!spfi_data->gpio_requested) { | ||
457 | ret = gpio_request_one(spi->cs_gpio, | ||
458 | (spi->mode & SPI_CS_HIGH) ? | ||
459 | GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, | ||
460 | dev_name(&spi->dev)); | ||
461 | if (ret) | ||
462 | dev_err(&spi->dev, "can't request chipselect gpio %d\n", | ||
449 | spi->cs_gpio); | 463 | spi->cs_gpio); |
450 | 464 | else | |
465 | spfi_data->gpio_requested = true; | ||
466 | } else { | ||
467 | if (gpio_is_valid(spi->cs_gpio)) { | ||
468 | int mode = ((spi->mode & SPI_CS_HIGH) ? | ||
469 | GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH); | ||
470 | |||
471 | ret = gpio_direction_output(spi->cs_gpio, mode); | ||
472 | if (ret) | ||
473 | dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n", | ||
474 | spi->cs_gpio, ret); | ||
475 | } | ||
476 | } | ||
451 | return ret; | 477 | return ret; |
452 | } | 478 | } |
453 | 479 | ||
454 | static void img_spfi_cleanup(struct spi_device *spi) | 480 | static void img_spfi_cleanup(struct spi_device *spi) |
455 | { | 481 | { |
456 | gpio_free(spi->cs_gpio); | 482 | struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi); |
483 | |||
484 | if (spfi_data) { | ||
485 | if (spfi_data->gpio_requested) | ||
486 | gpio_free(spi->cs_gpio); | ||
487 | kfree(spfi_data); | ||
488 | spi_set_ctldata(spi, NULL); | ||
489 | } | ||
457 | } | 490 | } |
458 | 491 | ||
459 | static void img_spfi_config(struct spi_master *master, struct spi_device *spi, | 492 | static void img_spfi_config(struct spi_master *master, struct spi_device *spi, |