From: Mark Brown broonie@linaro.org
Ensure that the FIFOs are fully drained before we deassert /CS or do any delays that have been requested in order to ensure that the behaviour visible on the bus matches that which was requested by the caller.
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-s3c64xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 229c6b9..2e267ce 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -960,6 +960,8 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master, goto out; }
+ flush_fifo(sdd); + if (xfer->delay_usecs) udelay(xfer->delay_usecs);
@@ -972,8 +974,6 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master, }
msg->actual_length += xfer->len; - - flush_fifo(sdd); }
out:
From: Mark Brown broonie@linaro.org
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-s3c64xx.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 2e267ce..dd5ed13 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -1524,9 +1524,17 @@ static int s3c64xx_spi_runtime_resume(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + int ret;
- clk_prepare_enable(sdd->src_clk); - clk_prepare_enable(sdd->clk); + ret = clk_prepare_enable(sdd->src_clk); + if (ret != 0) + return ret; + + ret = clk_prepare_enable(sdd->clk); + if (ret != 0) { + clk_disable_unprepare(sdd->src_clk); + return ret; + }
return 0; }
From: Mark Brown broonie@linaro.org
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-s3c64xx.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index dd5ed13..7f960db 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -205,7 +205,6 @@ struct s3c64xx_spi_driver_data { #endif struct s3c64xx_spi_port_config *port_conf; unsigned int port_id; - unsigned long gpios[4]; bool cs_gpio; };
From: Mark Brown broonie@linaro.org
Rather than using the driver custom platform data to store the chip select GPIO use the cs_gpio field provided by the SPI core, supporting future refectoring.
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-s3c64xx.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 7f960db..43caeee 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -558,22 +558,18 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd, struct spi_device *spi) { - struct s3c64xx_spi_csinfo *cs; - if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */ if (sdd->tgl_spi != spi) { /* if last mssg on diff device */ /* Deselect the last toggled device */ - cs = sdd->tgl_spi->controller_data; - if (sdd->cs_gpio) - gpio_set_value(cs->line, + if (spi->cs_gpio >= 0) + gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); } sdd->tgl_spi = NULL; }
- cs = spi->controller_data; - if (sdd->cs_gpio) - gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0); + if (spi->cs_gpio >= 0) + gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 1 : 0);
/* Start the signals */ writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); @@ -701,13 +697,11 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, struct spi_device *spi) { - struct s3c64xx_spi_csinfo *cs = spi->controller_data; - if (sdd->tgl_spi == spi) sdd->tgl_spi = NULL;
- if (sdd->cs_gpio) - gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1); + if (spi->cs_gpio >= 0) + gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1);
/* Quiese the signals */ writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); @@ -1070,6 +1064,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi) cs->line, err); goto err_gpio_req; } + + spi->cs_gpio = cs->line; }
spi_set_ctldata(spi, cs); @@ -1139,8 +1135,8 @@ static void s3c64xx_spi_cleanup(struct spi_device *spi) struct s3c64xx_spi_driver_data *sdd;
sdd = spi_master_get_devdata(spi->master); - if (cs && sdd->cs_gpio) { - gpio_free(cs->line); + if (spi->cs_gpio) { + gpio_free(spi->cs_gpio); if (spi->dev.of_node) kfree(cs); }
From: Mark Brown broonie@linaro.org
The hardware level /CS handling is tied to the start of the data path so is rolled into the same function as we use to manipulate GPIO /CS. In order to support factoring out the /CS handling into the core separate the two and explicitly start transfers separately to the /CS handling.
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-s3c64xx.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 43caeee..2ab96fb 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -570,9 +570,6 @@ static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
if (spi->cs_gpio >= 0) gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 1 : 0); - - /* Start the signals */ - writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); }
static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd, @@ -702,9 +699,6 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
if (spi->cs_gpio >= 0) gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); - - /* Quiese the signals */ - writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); }
static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) @@ -930,6 +924,9 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master, /* Slave Select */ enable_cs(sdd, spi);
+ /* Start the signals */ + writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); + spin_unlock_irqrestore(&sdd->lock, flags);
status = wait_for_xfer(sdd, xfer, use_dma); @@ -970,10 +967,14 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master, }
out: - if (!cs_toggle || status) + if (!cs_toggle || status) { + /* Quiese the signals */ + writel(S3C64XX_SPI_SLAVE_SIG_INACT, + sdd->regs + S3C64XX_SPI_SLAVE_SEL); disable_cs(sdd, spi); - else + } else { sdd->tgl_spi = spi; + }
s3c64xx_spi_unmap_mssg(sdd, msg);
@@ -1112,11 +1113,13 @@ static int s3c64xx_spi_setup(struct spi_device *spi) }
pm_runtime_put(&sdd->pdev->dev); + writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); disable_cs(sdd, spi); return 0;
setup_exit: /* setup() returns with device de-selected */ + writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); disable_cs(sdd, spi);
gpio_free(cs->line);
From: Mark Brown broonie@linaro.org
To help with bisection of future refactoring to share more of the code for handling a spi_message pull the enabling of GPIO based /CS prior to all the hardware setup for starting a transfer.
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-s3c64xx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 2ab96fb..e631232 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -906,6 +906,9 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master, s3c64xx_spi_config(sdd); }
+ /* Slave Select */ + enable_cs(sdd, spi); + /* Polling method for xfers not bigger than FIFO capacity */ use_dma = 0; if (!is_polling(sdd) && @@ -921,9 +924,6 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
enable_datapath(sdd, spi, xfer, use_dma);
- /* Slave Select */ - enable_cs(sdd, spi); - /* Start the signals */ writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
linaro-kernel@lists.linaro.org