From 3f2dad99f6fccfce46aea289ff174485320b69b4 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 21 Aug 2014 18:25:05 +0300 Subject: spi: davinci: fix SPI_NO_CS functionality The driver should not touch CS lines if SPI_NO_CS flag is set. This patch fixes it as this functionality was broken accidentally by commit a88e34ea213e1b ("spi: davinci: add support to configure gpio cs through dt"). Fixes: a88e34ea213e1b ("spi: davinci: add support to configure gpio cs through dt") Signed-off-by: Grygorii Strashko Signed-off-by: Mark Brown --- drivers/spi/spi-davinci.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/spi/spi-davinci.c') diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 276a3884fb3c..48f1d26e6ad9 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -417,16 +417,16 @@ static int davinci_spi_setup(struct spi_device *spi) flags, dev_name(&spi->dev)); internal_cs = false; } - } - if (retval) { - dev_err(&spi->dev, "GPIO %d setup failed (%d)\n", - spi->cs_gpio, retval); - return retval; - } + if (retval) { + dev_err(&spi->dev, "GPIO %d setup failed (%d)\n", + spi->cs_gpio, retval); + return retval; + } - if (internal_cs) - set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select); + if (internal_cs) + set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select); + } if (spi->mode & SPI_READY) set_io_bits(dspi->base + SPIPC0, SPIPC0_SPIENA_MASK); -- cgit v1.2.2 From 8936decdd977ee614234153a1aba85d12329fa7a Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 12 Sep 2014 17:54:00 +0300 Subject: spi: davinci: request cs_gpio's from probe Now CS GPIOs are requested from struct spi_master.setup() callback and that causes failures when Client SPI device is getting accessed through SPIDEV driver. The failure happens, because .setup() callback may be called many times from IOCTL handler and when it's called second time gpio_request() will fail and return -EBUSY. Hence, fix it by moving CS GPIOs requesting code in .probe(). Reported-by: Murali Karicheri Signed-off-by: Grygorii Strashko Signed-off-by: Mark Brown --- drivers/spi/spi-davinci.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'drivers/spi/spi-davinci.c') diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 276a3884fb3c..ff54f73dce4b 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -397,24 +397,21 @@ static int davinci_spi_setup(struct spi_device *spi) struct spi_master *master = spi->master; struct device_node *np = spi->dev.of_node; bool internal_cs = true; - unsigned long flags = GPIOF_DIR_OUT; dspi = spi_master_get_devdata(spi->master); pdata = &dspi->pdata; - flags |= (spi->mode & SPI_CS_HIGH) ? GPIOF_INIT_LOW : GPIOF_INIT_HIGH; - if (!(spi->mode & SPI_NO_CS)) { if (np && (master->cs_gpios != NULL) && (spi->cs_gpio >= 0)) { - retval = gpio_request_one(spi->cs_gpio, - flags, dev_name(&spi->dev)); + retval = gpio_direction_output( + spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); internal_cs = false; } else if (pdata->chip_sel && spi->chip_select < pdata->num_chipselect && pdata->chip_sel[spi->chip_select] != SPI_INTERN_CS) { spi->cs_gpio = pdata->chip_sel[spi->chip_select]; - retval = gpio_request_one(spi->cs_gpio, - flags, dev_name(&spi->dev)); + retval = gpio_direction_output( + spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); internal_cs = false; } } @@ -441,8 +438,6 @@ static int davinci_spi_setup(struct spi_device *spi) static void davinci_spi_cleanup(struct spi_device *spi) { - if (spi->cs_gpio >= 0) - gpio_free(spi->cs_gpio); } static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status) @@ -967,6 +962,27 @@ static int davinci_spi_probe(struct platform_device *pdev) if (dspi->version == SPI_VERSION_2) dspi->bitbang.flags |= SPI_READY; + if (pdev->dev.of_node) { + int i; + + for (i = 0; i < pdata->num_chipselect; i++) { + int cs_gpio = of_get_named_gpio(pdev->dev.of_node, + "cs-gpios", i); + + if (cs_gpio == -EPROBE_DEFER) { + ret = cs_gpio; + goto free_clk; + } + + if (gpio_is_valid(cs_gpio)) { + ret = devm_gpio_request(&pdev->dev, cs_gpio, + dev_name(&pdev->dev)); + if (ret) + goto free_clk; + } + } + } + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (r) dma_rx_chan = r->start; -- cgit v1.2.2 From 6e7488f8f6f68218bd52283f78f571466280ac96 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Tue, 16 Sep 2014 14:14:23 +0300 Subject: spi: davinci: remove empty function davinci_spi_cleanup Remove empty function davinci_spi_cleanup(). Signed-off-by: Grygorii Strashko Signed-off-by: Mark Brown --- drivers/spi/spi-davinci.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/spi/spi-davinci.c') diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index ff54f73dce4b..84a9fb1ab984 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -436,10 +436,6 @@ static int davinci_spi_setup(struct spi_device *spi) return retval; } -static void davinci_spi_cleanup(struct spi_device *spi) -{ -} - static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status) { struct device *sdev = dspi->bitbang.master->dev.parent; @@ -951,7 +947,6 @@ static int davinci_spi_probe(struct platform_device *pdev) master->num_chipselect = pdata->num_chipselect; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16); master->setup = davinci_spi_setup; - master->cleanup = davinci_spi_cleanup; dspi->bitbang.chipselect = davinci_spi_chipselect; dspi->bitbang.setup_transfer = davinci_spi_setup_transfer; -- cgit v1.2.2 From 365a7bb32e097a8501a6a70b9225abcb09924f8c Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Tue, 16 Sep 2014 14:25:05 +0300 Subject: spi: davinci: add support for adding delay between word's transmissions This patch adds ability to configure delay between transmission of words over SPI bus if it's required by SPI slave devices. New optional SPI slave property: - ti,spi-word-delay : delay between transmission of words (SPIFMTn.WDELAY, SPIDAT1.WDEL) Signed-off-by: Murali Karicheri Signed-off-by: Grygorii Strashko Signed-off-by: Mark Brown --- drivers/spi/spi-davinci.c | 55 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 7 deletions(-) (limited to 'drivers/spi/spi-davinci.c') diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 84a9fb1ab984..25886d8a84ba 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -65,6 +65,7 @@ /* SPIDAT1 (upper 16 bit defines) */ #define SPIDAT1_CSHOLD_MASK BIT(12) +#define SPIDAT1_WDEL BIT(10) /* SPIGCR1 */ #define SPIGCR1_CLKMOD_MASK BIT(1) @@ -209,6 +210,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) { struct davinci_spi *dspi; struct davinci_spi_platform_data *pdata; + struct davinci_spi_config *spicfg = spi->controller_data; u8 chip_sel = spi->chip_select; u16 spidat1 = CS_DEFAULT; bool gpio_chipsel = false; @@ -223,6 +225,10 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) gpio = spi->cs_gpio; } + /* program delay transfers if tx_delay is non zero */ + if (spicfg->wdelay) + spidat1 |= SPIDAT1_WDEL; + /* * Board specific chip select logic decides the polarity and cs * line for the controller @@ -237,9 +243,9 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) spidat1 |= SPIDAT1_CSHOLD_MASK; spidat1 &= ~(0x1 << chip_sel); } - - iowrite16(spidat1, dspi->base + SPIDAT1 + 2); } + + iowrite16(spidat1, dspi->base + SPIDAT1 + 2); } /** @@ -285,7 +291,7 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, int prescale; dspi = spi_master_get_devdata(spi->master); - spicfg = (struct davinci_spi_config *)spi->controller_data; + spicfg = spi->controller_data; if (!spicfg) spicfg = &davinci_spi_default_cfg; @@ -332,6 +338,14 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, if (!(spi->mode & SPI_CPHA)) spifmt |= SPIFMT_PHASE_MASK; + /* + * Assume wdelay is used only on SPI peripherals that has this field + * in SPIFMTn register and when it's configured from board file or DT. + */ + if (spicfg->wdelay) + spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT) + & SPIFMT_WDELAY_MASK); + /* * Version 1 hardware supports two basic SPI modes: * - Standard SPI mode uses 4 pins, with chipselect @@ -349,9 +363,6 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, u32 delay = 0; - spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT) - & SPIFMT_WDELAY_MASK); - if (spicfg->odd_parity) spifmt |= SPIFMT_ODD_PARITY_MASK; @@ -383,6 +394,26 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, return 0; } +static int davinci_spi_of_setup(struct spi_device *spi) +{ + struct davinci_spi_config *spicfg = spi->controller_data; + struct device_node *np = spi->dev.of_node; + u32 prop; + + if (spicfg == NULL && np) { + spicfg = kzalloc(sizeof(*spicfg), GFP_KERNEL); + if (!spicfg) + return -ENOMEM; + *spicfg = davinci_spi_default_cfg; + /* override with dt configured values */ + if (!of_property_read_u32(np, "ti,spi-wdelay", &prop)) + spicfg->wdelay = (u8)prop; + spi->controller_data = spicfg; + } + + return 0; +} + /** * davinci_spi_setup - This functions will set default transfer method * @spi: spi device on which data transfer to be done @@ -433,7 +464,16 @@ static int davinci_spi_setup(struct spi_device *spi) else clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK); - return retval; + return davinci_spi_of_setup(spi); +} + +static void davinci_spi_cleanup(struct spi_device *spi) +{ + struct davinci_spi_config *spicfg = spi->controller_data; + + spi->controller_data = NULL; + if (spi->dev.of_node) + kfree(spicfg); } static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status) @@ -947,6 +987,7 @@ static int davinci_spi_probe(struct platform_device *pdev) master->num_chipselect = pdata->num_chipselect; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16); master->setup = davinci_spi_setup; + master->cleanup = davinci_spi_cleanup; dspi->bitbang.chipselect = davinci_spi_chipselect; dspi->bitbang.setup_transfer = davinci_spi_setup_transfer; -- cgit v1.2.2