diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-03 12:31:39 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-03 12:31:39 -0700 |
commit | d25e436c4b68db2895185b24ad1f22499c2f87b0 (patch) | |
tree | dd66245410513f09d2439ef0b34cf1d131696bed /drivers/spi/spi-cadence.c | |
parent | a90f0e9ebb88ba7b0efea4e7d9defc0c2b96f712 (diff) | |
parent | 282ec0ea65dab88fda51b5b9b649958ae42f4ac0 (diff) |
Merge tag 'spi-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi updates from Mark Brown:
"There's quite a lot of small driver specific fixes and enhancements in
this release but the main activity has been around the loopback and
spidev test drivers which is good to see as it should hopefully help
improve the quality of all the drivers as people start to make use of
the new code:
- Additional tests in the loopback test driver for vmalloc()
compatibility and around delays together with fixes for existing
tests.
- Support for testing continuous data transfer for use in soak
testing.
- Device property support for board info platforms.
- Support for registering empty sets of devices via board info
(useful when writing code to enumerate hardware automatically)"
* tag 'spi-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (52 commits)
spi: cadence: Allow for GPIO pins to be used as chipselects
spi-imx: Implements handling of the SPI_READY mode flag.
spi: tegra: fix spelling mistake: "trasfer" -> "transfer"
spi: spi-ti-qspi: Use bounce buffer if read buffer is not DMA'ble
spi: Add can_dma like interface for spi_flash_read
spi: dw: Disable clock after unregistering the host
spi: double time out tolerance
spi: atmel: add deepest PM support to SAMA5D2
spi: atmel: factorize reusable code for SPI controller init
spi: orion: add LSB support
spi: pl022: don't use uninitialized variable
spi: loopback-test: fix spelling mistake: "minimam" -> "minimum"
spi: dynamycally allocated message initialization
spi: spi-ti-qspi: Remove unused dma_dev variable
spi: omap2-mcspi: poll OMAP2_MCSPI_CHSTAT_RXS for PIO transfer
spi: spi-ti-qspi: Use dma_engine wrapper for dma memcpy call
spi: spidev_test: add option to continuously transfer data
spi: loopback-test: fix potential integer overflow on multiple
spi: sun6i: update max transfer size reported
spi: pl022: Document property values
...
Diffstat (limited to 'drivers/spi/spi-cadence.c')
-rw-r--r-- | drivers/spi/spi-cadence.c | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 1c57ce64abba..f0b5c7b91f37 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -13,6 +13,7 @@ #include <linux/clk.h> #include <linux/delay.h> +#include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> @@ -127,6 +128,10 @@ struct cdns_spi { u32 is_decoded_cs; }; +struct cdns_spi_device_data { + bool gpio_requested; +}; + /* Macros for the SPI controller read/write */ static inline u32 cdns_spi_read(struct cdns_spi *xspi, u32 offset) { @@ -456,6 +461,64 @@ static int cdns_unprepare_transfer_hardware(struct spi_master *master) return 0; } +static int cdns_spi_setup(struct spi_device *spi) +{ + + int ret = -EINVAL; + struct cdns_spi_device_data *cdns_spi_data = spi_get_ctldata(spi); + + /* this is a pin managed by the controller, leave it alone */ + if (spi->cs_gpio == -ENOENT) + return 0; + + /* this seems to be the first time we're here */ + if (!cdns_spi_data) { + cdns_spi_data = kzalloc(sizeof(*cdns_spi_data), GFP_KERNEL); + if (!cdns_spi_data) + return -ENOMEM; + cdns_spi_data->gpio_requested = false; + spi_set_ctldata(spi, cdns_spi_data); + } + + /* if we haven't done so, grab the gpio */ + if (!cdns_spi_data->gpio_requested && gpio_is_valid(spi->cs_gpio)) { + 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 + cdns_spi_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 cdns_spi_cleanup(struct spi_device *spi) +{ + struct cdns_spi_device_data *cdns_spi_data = spi_get_ctldata(spi); + + if (cdns_spi_data) { + if (cdns_spi_data->gpio_requested) + gpio_free(spi->cs_gpio); + kfree(cdns_spi_data); + spi_set_ctldata(spi, NULL); + } + +} + /** * cdns_spi_probe - Probe method for the SPI driver * @pdev: Pointer to the platform_device structure @@ -555,6 +618,8 @@ static int cdns_spi_probe(struct platform_device *pdev) master->transfer_one = cdns_transfer_one; master->unprepare_transfer_hardware = cdns_unprepare_transfer_hardware; master->set_cs = cdns_spi_chipselect; + master->setup = cdns_spi_setup; + master->cleanup = cdns_spi_cleanup; master->auto_runtime_pm = true; master->mode_bits = SPI_CPOL | SPI_CPHA; |