diff mbox series

[4/7,v2] spi: cadence: Convert to use CS GPIO descriptors

Message ID 20190107155156.3738-5-linus.walleij@linaro.org (mailing list archive)
State Accepted
Commit cfeefa79dc37d378216e2ced1600e297dd04e591
Headers show
Series SPI CS using GPIO descriptors | expand

Commit Message

Linus Walleij Jan. 7, 2019, 3:51 p.m. UTC
This converts the Cadence SPI master driver to use GPIO
descriptors for chip select handling.

The Cadence driver was allocating a state container just
to hold the requested GPIO line and contained lots of
polarity inversion code. As this is all handled by gpiolib
and a simple devm_* request in the core, and as the driver
is fully device tree only, most of this code chunk goes
away in favour of central handling. The setup/cleanup
callbacks goes away.

This driver does NOT drive the CS line by setting the
value of the GPIO so it relies on the SPI core to do
this, which should work just fine with the descriptors.

Cc: Wei Yongjun <weiyongjun1@huawei.com>
Cc: Janek Kotas <jank@cadence.com>
Cc: Linuxarm <linuxarm@huawei.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v1->v2:
- Rebase on v5.0-rc1
---
 drivers/spi/spi-cadence.c | 67 ++-------------------------------------
 1 file changed, 2 insertions(+), 65 deletions(-)

Comments

Jan Kotas Jan. 10, 2019, 8:56 a.m. UTC | #1
> On 7 Jan 2019, at 16:51, Linus Walleij <linus.walleij@linaro.org> wrote:
> 
> +	master->use_gpio_descriptors = true;
> 	master->prepare_transfer_hardware = cdns_prepare_transfer_hardware;
> 	master->prepare_message = cdns_prepare_message;
> 	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;
> 

Hi,

It seems this patch breaks the Cadence SPI driver:

spi spi0.0: setup: unsupported mode bits 4
cdns-spi fd0b0000.spi: can't setup spi0.0, status -22


It looks like the reason is that, the driver only sets:
master->mode_bits = SPI_CPOL | SPI_CPHA;

The of_spi_parse_dt function adds an SPI_CS_HIGH:
if (ctlr->use_gpio_descriptors)
	spi->mode |= SPI_CS_HIGH;

However the spi_setup function checks if a driver supports 
selected SPI modes:
bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD);

Because the of_spi_parse_dt added an SPI_CS_HIGH, 
which is not set in the controller the setup fails:

if (bad_bits) {
	dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
		bad_bits);
	return -EINVAL;
}

Sorry for not picking it up earlier, I was busy with some other stuff.
I noticed it, when our Jenkins job for SPI Kernel CI failed.

I think it’s not an uncommon case, maybe if use_gpio_descriptors
is set, we should ignore an SPI_CS_HIGH in the setup?

Regards,
Jan
diff mbox series

Patch

diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c
index 7c88f74f7f47..e332d173dbf9 100644
--- a/drivers/spi/spi-cadence.c
+++ b/drivers/spi/spi-cadence.c
@@ -13,7 +13,7 @@ 
 
 #include <linux/clk.h>
 #include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -128,10 +128,6 @@  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)
 {
@@ -469,64 +465,6 @@  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
@@ -621,13 +559,12 @@  static int cdns_spi_probe(struct platform_device *pdev)
 		goto clk_dis_all;
 	}
 
+	master->use_gpio_descriptors = true;
 	master->prepare_transfer_hardware = cdns_prepare_transfer_hardware;
 	master->prepare_message = cdns_prepare_message;
 	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;