From bca690db90b832a58756b30d5ff41e65881216f9 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Fri, 23 Jan 2015 17:08:33 +0100 Subject: spi/xilinx: Support for spi mode LSB_FIRST Hardware supports LSB_FIRST mode. Support it also in the driver. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 79bd84f43430..d4edeeeabbc3 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -34,7 +34,8 @@ #define XSPI_CR_MASTER_MODE 0x04 #define XSPI_CR_CPOL 0x08 #define XSPI_CR_CPHA 0x10 -#define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL) +#define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL | \ + XSPI_CR_LSB_FIRST) #define XSPI_CR_TXFIFO_RESET 0x20 #define XSPI_CR_RXFIFO_RESET 0x40 #define XSPI_CR_MANUAL_SSELECT 0x80 @@ -194,6 +195,8 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on) cr |= XSPI_CR_CPHA; if (spi->mode & SPI_CPOL) cr |= XSPI_CR_CPOL; + if (spi->mode & SPI_LSB_FIRST) + cr |= XSPI_CR_LSB_FIRST; xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); /* We do not check spi->max_speed_hz here as the SPI clock @@ -353,7 +356,7 @@ static int xilinx_spi_probe(struct platform_device *pdev) return -ENODEV; /* the spi->mode bits understood by this driver: */ - master->mode_bits = SPI_CPOL | SPI_CPHA; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; xspi = spi_master_get_devdata(master); xspi->bitbang.master = master; -- cgit v1.2.3 From 0240f94516964db00d0fc1d1e676f3c273710e17 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Fri, 23 Jan 2015 17:08:34 +0100 Subject: spi/xilinx: Support for spi mode LOOP Hardware supports LOOP mode. Support it also in the driver. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index d4edeeeabbc3..e1d9a2003ae6 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -35,7 +35,7 @@ #define XSPI_CR_CPOL 0x08 #define XSPI_CR_CPHA 0x10 #define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL | \ - XSPI_CR_LSB_FIRST) + XSPI_CR_LSB_FIRST | XSPI_CR_LOOP) #define XSPI_CR_TXFIFO_RESET 0x20 #define XSPI_CR_RXFIFO_RESET 0x40 #define XSPI_CR_MANUAL_SSELECT 0x80 @@ -197,6 +197,8 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on) cr |= XSPI_CR_CPOL; if (spi->mode & SPI_LSB_FIRST) cr |= XSPI_CR_LSB_FIRST; + if (spi->mode & SPI_LOOP) + cr |= XSPI_CR_LOOP; xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); /* We do not check spi->max_speed_hz here as the SPI clock @@ -356,7 +358,7 @@ static int xilinx_spi_probe(struct platform_device *pdev) return -ENODEV; /* the spi->mode bits understood by this driver: */ - master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP; xspi = spi_master_get_devdata(master); xspi->bitbang.master = master; -- cgit v1.2.3 From c5d348dffa7ca1f072ff5526171a2b88bbffc24b Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Fri, 23 Jan 2015 17:08:35 +0100 Subject: spi/xilinx: Simplify data read from the Rx FIFO The number of words in the read buffer will be exactly the same as the number of words written on write buffer, once the transaction has finished. Instead of cheking the rx_empty flags for every word simply save the number of words written by fill_tx_fifo. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index e1d9a2003ae6..416b227eb302 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -221,9 +221,10 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi, return 0; } -static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi) +static int xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi) { u8 sr; + int n_words = 0; /* Fill the Tx FIFO with as many bytes as possible */ sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); @@ -234,7 +235,10 @@ static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi) xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); xspi->remaining_bytes -= xspi->bits_per_word / 8; sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); + n_words++; } + + return n_words; } static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) @@ -259,9 +263,9 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) for (;;) { u16 cr; - u8 sr; + int n_words; - xilinx_spi_fill_tx_fifo(xspi); + n_words = xilinx_spi_fill_tx_fifo(xspi); /* Start the transfer by not inhibiting the transmitter any * longer @@ -282,11 +286,8 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) xspi->regs + XSPI_CR_OFFSET); /* Read out all the data from the Rx FIFO */ - sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); - while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) { + while (n_words--) xspi->rx_fn(xspi); - sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); - } /* See if there is more data to send */ if (xspi->remaining_bytes <= 0) -- cgit v1.2.3 From 4c9a761402d780b86b9b068aba4ef8e29ed15e99 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 28 Jan 2015 13:23:40 +0100 Subject: spi/xilinx: Simplify spi_fill_tx_fifo Instead of checking the TX_FULL flag for every transaction, find out the size of the buffer at probe time and use it. To avoid situations where the core had some data on the buffer before initialization, the core is reseted before the buffer size is detected Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 416b227eb302..1890af8f8636 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -88,6 +88,7 @@ struct xilinx_spi { const u8 *tx_ptr; /* pointer in the Rx buffer */ int remaining_bytes; /* the number of bytes left to transfer */ u8 bits_per_word; + int buffer_size; /* buffer size in words */ unsigned int (*read_fn)(void __iomem *); void (*write_fn)(u32, void __iomem *); void (*tx_fn)(struct xilinx_spi *); @@ -221,24 +222,16 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi, return 0; } -static int xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi) +static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi, int n_words) { - u8 sr; - int n_words = 0; + xspi->remaining_bytes -= n_words * xspi->bits_per_word / 8; - /* Fill the Tx FIFO with as many bytes as possible */ - sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); - while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) { + while (n_words--) if (xspi->tx_ptr) xspi->tx_fn(xspi); else xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); - xspi->remaining_bytes -= xspi->bits_per_word / 8; - sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); - n_words++; - } - - return n_words; + return; } static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) @@ -265,7 +258,10 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) u16 cr; int n_words; - n_words = xilinx_spi_fill_tx_fifo(xspi); + n_words = (xspi->remaining_bytes * 8) / xspi->bits_per_word; + n_words = min(n_words, xspi->buffer_size); + + xilinx_spi_fill_tx_fifo(xspi, n_words); /* Start the transfer by not inhibiting the transmitter any * longer @@ -322,6 +318,28 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static int xilinx_spi_find_buffer_size(struct xilinx_spi *xspi) +{ + u8 sr; + int n_words = 0; + + /* + * Before the buffer_size detection we reset the core + * to make sure we start with a clean state. + */ + xspi->write_fn(XIPIF_V123B_RESET_MASK, + xspi->regs + XIPIF_V123B_RESETR_OFFSET); + + /* Fill the Tx FIFO with as many words as possible */ + do { + xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); + sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); + n_words++; + } while (!(sr & XSPI_SR_TX_FULL_MASK)); + + return n_words; +} + static const struct of_device_id xilinx_spi_of_match[] = { { .compatible = "xlnx,xps-spi-2.00.a", }, { .compatible = "xlnx,xps-spi-2.00.b", }, @@ -413,6 +431,8 @@ static int xilinx_spi_probe(struct platform_device *pdev) goto put_master; } + xspi->buffer_size = xilinx_spi_find_buffer_size(xspi); + /* SPI controller initializations */ xspi_init_hw(xspi); -- cgit v1.2.3 From 899929babac9d85ddd3f86b813a8b8654ab93523 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 28 Jan 2015 13:23:41 +0100 Subject: spi/xilinx: Leave the IRQ always enabled. Instead of enabling the IRQ and disabling it for every transaction. Specially the small transactions (1,2 words) benefit from removing 3 bus accesses. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 1890af8f8636..d933207c212c 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -167,8 +167,11 @@ static void xspi_init_hw(struct xilinx_spi *xspi) /* Reset the SPI device */ xspi->write_fn(XIPIF_V123B_RESET_MASK, regs_base + XIPIF_V123B_RESETR_OFFSET); - /* Disable all the interrupts just in case */ - xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET); + /* Enable the transmit empty interrupt, which we use to determine + * progress on the transmission. + */ + xspi->write_fn(XSPI_INTR_TX_EMPTY, + regs_base + XIPIF_V123B_IIER_OFFSET); /* Enable the global IPIF interrupt */ xspi->write_fn(XIPIF_V123B_GINTR_ENABLE, regs_base + XIPIF_V123B_DGIER_OFFSET); @@ -237,7 +240,6 @@ static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi, int n_words) static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) { struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); - u32 ipif_ier; /* We get here with transmitter inhibited */ @@ -246,14 +248,6 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) xspi->remaining_bytes = t->len; reinit_completion(&xspi->done); - - /* Enable the transmit empty interrupt, which we use to determine - * progress on the transmission. - */ - ipif_ier = xspi->read_fn(xspi->regs + XIPIF_V123B_IIER_OFFSET); - xspi->write_fn(ipif_ier | XSPI_INTR_TX_EMPTY, - xspi->regs + XIPIF_V123B_IIER_OFFSET); - for (;;) { u16 cr; int n_words; @@ -290,9 +284,6 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) break; } - /* Disable the transmit empty interrupt */ - xspi->write_fn(ipif_ier, xspi->regs + XIPIF_V123B_IIER_OFFSET); - return t->len - xspi->remaining_bytes; } -- cgit v1.2.3 From a87cbca0acef0b1f57e4b216f1965468ee521cd3 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 28 Jan 2015 13:23:42 +0100 Subject: spi/xilinx: Code cleanup On the transmission loop, check for remaining bytes at the loop condition. This way we can handle transmissions of 0 bytes and clean the code. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index d933207c212c..a0f7c9d4a349 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -248,7 +248,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) xspi->remaining_bytes = t->len; reinit_completion(&xspi->done); - for (;;) { + while (xspi->remaining_bytes) { u16 cr; int n_words; @@ -278,10 +278,6 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) /* Read out all the data from the Rx FIFO */ while (n_words--) xspi->rx_fn(xspi); - - /* See if there is more data to send */ - if (xspi->remaining_bytes <= 0) - break; } return t->len - xspi->remaining_bytes; -- cgit v1.2.3 From 5b74d7a3b888fd3db6dce77eb11b3d55b64f6833 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 28 Jan 2015 13:23:43 +0100 Subject: spi/xilinx: Use cached value of register The control register has not changed since the previous access. Therefore we can use the cached value and safe one bus access. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index a0f7c9d4a349..12b311ed9bfa 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -271,7 +271,6 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) * transmitter while the Isr refills the transmit register/FIFO, * or make sure it is stopped if we're done. */ - cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, xspi->regs + XSPI_CR_OFFSET); -- cgit v1.2.3 From 5fe11cc09ce81b000b1deadcdec3813fcb423c8c Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 28 Jan 2015 13:23:44 +0100 Subject: spi/xilinx: Support cores with no interrupt The core can run in polling mode. In fact, the performance of the core is similar (or even better), due to the fact most of the spi transactions are just a couple of bytes and there is one irq per transactions. When an mtd device is connected via spi, reading 8MB of data produces more than 80K interrupts (with irq disabling, context swith....) Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 12b311ed9bfa..f21e857d54b1 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -173,8 +173,11 @@ static void xspi_init_hw(struct xilinx_spi *xspi) xspi->write_fn(XSPI_INTR_TX_EMPTY, regs_base + XIPIF_V123B_IIER_OFFSET); /* Enable the global IPIF interrupt */ - xspi->write_fn(XIPIF_V123B_GINTR_ENABLE, - regs_base + XIPIF_V123B_DGIER_OFFSET); + if (xspi->irq >= 0) + xspi->write_fn(XIPIF_V123B_GINTR_ENABLE, + regs_base + XIPIF_V123B_DGIER_OFFSET); + else + xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET); /* Deselect the slave on the SPI bus */ xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET); /* Disable the transmitter, enable Manual Slave Select Assertion, @@ -264,7 +267,12 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) ~XSPI_CR_TRANS_INHIBIT; xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); - wait_for_completion(&xspi->done); + if (xspi->irq >= 0) + wait_for_completion(&xspi->done); + else + while (!(xspi->read_fn(xspi->regs + XSPI_SR_OFFSET) & + XSPI_SR_TX_EMPTY_MASK)) + ; /* A transmit has just completed. Process received data and * check for more data to transmit. Always inhibit the @@ -419,20 +427,17 @@ static int xilinx_spi_probe(struct platform_device *pdev) xspi->buffer_size = xilinx_spi_find_buffer_size(xspi); - /* SPI controller initializations */ - xspi_init_hw(xspi); - xspi->irq = platform_get_irq(pdev, 0); - if (xspi->irq < 0) { - ret = xspi->irq; - goto put_master; + if (xspi->irq >= 0) { + /* Register for SPI Interrupt */ + ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0, + dev_name(&pdev->dev), xspi); + if (ret) + goto put_master; } - /* Register for SPI Interrupt */ - ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0, - dev_name(&pdev->dev), xspi); - if (ret) - goto put_master; + /* SPI controller initializations */ + xspi_init_hw(xspi); ret = spi_bitbang_start(&xspi->bitbang); if (ret) { -- cgit v1.2.3 From d9f5881242db8f9dc8a262c4bc613ba6fcb66bfc Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 28 Jan 2015 13:23:45 +0100 Subject: spi/xilinx: Do not inhibit transmission in polling mode When no irq is used, there is no need to inhibit the transmission for every transaction. This inhibition was implemented to avoid a race condition with the irq handler. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index f21e857d54b1..6656b2c82693 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -163,6 +163,7 @@ static void xspi_rx32(struct xilinx_spi *xspi) static void xspi_init_hw(struct xilinx_spi *xspi) { void __iomem *regs_base = xspi->regs; + u32 inhibit; /* Reset the SPI device */ xspi->write_fn(XIPIF_V123B_RESET_MASK, @@ -173,16 +174,19 @@ static void xspi_init_hw(struct xilinx_spi *xspi) xspi->write_fn(XSPI_INTR_TX_EMPTY, regs_base + XIPIF_V123B_IIER_OFFSET); /* Enable the global IPIF interrupt */ - if (xspi->irq >= 0) + if (xspi->irq >= 0) { xspi->write_fn(XIPIF_V123B_GINTR_ENABLE, regs_base + XIPIF_V123B_DGIER_OFFSET); - else + inhibit = XSPI_CR_TRANS_INHIBIT; + } else { xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET); + inhibit = 0; + } /* Deselect the slave on the SPI bus */ xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET); /* Disable the transmitter, enable Manual Slave Select Assertion, * put SPI controller into master mode, and enable it */ - xspi->write_fn(XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT | + xspi->write_fn(inhibit | XSPI_CR_MANUAL_SSELECT | XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET | XSPI_CR_RXFIFO_RESET, regs_base + XSPI_CR_OFFSET); } @@ -252,7 +256,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) reinit_completion(&xspi->done); while (xspi->remaining_bytes) { - u16 cr; + u16 cr = 0; int n_words; n_words = (xspi->remaining_bytes * 8) / xspi->bits_per_word; @@ -263,13 +267,13 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) /* Start the transfer by not inhibiting the transmitter any * longer */ - cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) & - ~XSPI_CR_TRANS_INHIBIT; - xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); - if (xspi->irq >= 0) + if (xspi->irq >= 0) { + cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) & + ~XSPI_CR_TRANS_INHIBIT; + xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); wait_for_completion(&xspi->done); - else + } else while (!(xspi->read_fn(xspi->regs + XSPI_SR_OFFSET) & XSPI_SR_TX_EMPTY_MASK)) ; @@ -279,7 +283,8 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) * transmitter while the Isr refills the transmit register/FIFO, * or make sure it is stopped if we're done. */ - xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, + if (xspi->irq >= 0) + xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, xspi->regs + XSPI_CR_OFFSET); /* Read out all the data from the Rx FIFO */ -- cgit v1.2.3 From f9c6ef6cfe9c16b6681607afd7e4f8379e615c4f Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 28 Jan 2015 13:23:46 +0100 Subject: spi/xilinx: Support for spi mode CS_HIGH The core controls the chip select lines individually. By default, all the lines are consider active_low. After spi_setup_transfer, it has its real value. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 62 +++++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 24 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 6656b2c82693..523da738805f 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -89,6 +89,7 @@ struct xilinx_spi { int remaining_bytes; /* the number of bytes left to transfer */ u8 bits_per_word; int buffer_size; /* buffer size in words */ + u32 cs_inactive; /* Level of the CS pins when inactive*/ unsigned int (*read_fn)(void __iomem *); void (*write_fn)(u32, void __iomem *); void (*tx_fn)(struct xilinx_spi *); @@ -194,33 +195,37 @@ static void xspi_init_hw(struct xilinx_spi *xspi) static void xilinx_spi_chipselect(struct spi_device *spi, int is_on) { struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); + u16 cr; + u32 cs; if (is_on == BITBANG_CS_INACTIVE) { /* Deselect the slave on the SPI bus */ - xspi->write_fn(0xffff, xspi->regs + XSPI_SSR_OFFSET); - } else if (is_on == BITBANG_CS_ACTIVE) { - /* Set the SPI clock phase and polarity */ - u16 cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) - & ~XSPI_CR_MODE_MASK; - if (spi->mode & SPI_CPHA) - cr |= XSPI_CR_CPHA; - if (spi->mode & SPI_CPOL) - cr |= XSPI_CR_CPOL; - if (spi->mode & SPI_LSB_FIRST) - cr |= XSPI_CR_LSB_FIRST; - if (spi->mode & SPI_LOOP) - cr |= XSPI_CR_LOOP; - xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); - - /* We do not check spi->max_speed_hz here as the SPI clock - * frequency is not software programmable (the IP block design - * parameter) - */ - - /* Activate the chip select */ - xspi->write_fn(~(0x0001 << spi->chip_select), - xspi->regs + XSPI_SSR_OFFSET); + xspi->write_fn(xspi->cs_inactive, xspi->regs + XSPI_SSR_OFFSET); + return; } + + /* Set the SPI clock phase and polarity */ + cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_MODE_MASK; + if (spi->mode & SPI_CPHA) + cr |= XSPI_CR_CPHA; + if (spi->mode & SPI_CPOL) + cr |= XSPI_CR_CPOL; + if (spi->mode & SPI_LSB_FIRST) + cr |= XSPI_CR_LSB_FIRST; + if (spi->mode & SPI_LOOP) + cr |= XSPI_CR_LOOP; + xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); + + /* We do not check spi->max_speed_hz here as the SPI clock + * frequency is not software programmable (the IP block design + * parameter) + */ + + cs = xspi->cs_inactive; + cs ^= BIT(spi->chip_select); + + /* Activate the chip select */ + xspi->write_fn(cs, xspi->regs + XSPI_SSR_OFFSET); } /* spi_bitbang requires custom setup_transfer() to be defined if there is a @@ -229,6 +234,13 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on) static int xilinx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { + struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); + + if (spi->mode & SPI_CS_HIGH) + xspi->cs_inactive &= ~BIT(spi->chip_select); + else + xspi->cs_inactive |= BIT(spi->chip_select); + return 0; } @@ -376,9 +388,11 @@ static int xilinx_spi_probe(struct platform_device *pdev) return -ENODEV; /* the spi->mode bits understood by this driver: */ - master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP | + SPI_CS_HIGH; xspi = spi_master_get_devdata(master); + xspi->cs_inactive = 0xffffffff; xspi->bitbang.master = master; xspi->bitbang.chipselect = xilinx_spi_chipselect; xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer; -- cgit v1.2.3 From 24ba5e593f391507c614f5b62065194e6593a658 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 28 Jan 2015 13:23:47 +0100 Subject: spi/xilinx: Remove rx_fn and tx_fn pointer Simplify the code by removing the tx and and rx function pointers and substitute them by a single function. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 69 +++++++++++++----------------------------------- 1 file changed, 18 insertions(+), 51 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 523da738805f..ac94e546a555 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -92,8 +92,6 @@ struct xilinx_spi { u32 cs_inactive; /* Level of the CS pins when inactive*/ unsigned int (*read_fn)(void __iomem *); void (*write_fn)(u32, void __iomem *); - void (*tx_fn)(struct xilinx_spi *); - void (*rx_fn)(struct xilinx_spi *); }; static void xspi_write32(u32 val, void __iomem *addr) @@ -116,49 +114,32 @@ static unsigned int xspi_read32_be(void __iomem *addr) return ioread32be(addr); } -static void xspi_tx8(struct xilinx_spi *xspi) -{ - xspi->write_fn(*xspi->tx_ptr, xspi->regs + XSPI_TXD_OFFSET); - xspi->tx_ptr++; -} - -static void xspi_tx16(struct xilinx_spi *xspi) -{ - xspi->write_fn(*(u16 *)(xspi->tx_ptr), xspi->regs + XSPI_TXD_OFFSET); - xspi->tx_ptr += 2; -} - -static void xspi_tx32(struct xilinx_spi *xspi) +static void xilinx_spi_tx(struct xilinx_spi *xspi) { xspi->write_fn(*(u32 *)(xspi->tx_ptr), xspi->regs + XSPI_TXD_OFFSET); - xspi->tx_ptr += 4; + xspi->tx_ptr += xspi->bits_per_word / 8; } -static void xspi_rx8(struct xilinx_spi *xspi) +static void xilinx_spi_rx(struct xilinx_spi *xspi) { u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET); - if (xspi->rx_ptr) { - *xspi->rx_ptr = data & 0xff; - xspi->rx_ptr++; - } -} -static void xspi_rx16(struct xilinx_spi *xspi) -{ - u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET); - if (xspi->rx_ptr) { - *(u16 *)(xspi->rx_ptr) = data & 0xffff; - xspi->rx_ptr += 2; - } -} + if (!xspi->rx_ptr) + return; -static void xspi_rx32(struct xilinx_spi *xspi) -{ - u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET); - if (xspi->rx_ptr) { + switch (xspi->bits_per_word) { + case 8: + *(u8 *)(xspi->rx_ptr) = data; + break; + case 16: + *(u16 *)(xspi->rx_ptr) = data; + break; + case 32: *(u32 *)(xspi->rx_ptr) = data; - xspi->rx_ptr += 4; + break; } + + xspi->rx_ptr += xspi->bits_per_word / 8; } static void xspi_init_hw(struct xilinx_spi *xspi) @@ -250,7 +231,7 @@ static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi, int n_words) while (n_words--) if (xspi->tx_ptr) - xspi->tx_fn(xspi); + xilinx_spi_tx(xspi); else xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); return; @@ -301,7 +282,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) /* Read out all the data from the Rx FIFO */ while (n_words--) - xspi->rx_fn(xspi); + xilinx_spi_rx(xspi); } return t->len - xspi->remaining_bytes; @@ -430,20 +411,6 @@ static int xilinx_spi_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word); xspi->bits_per_word = bits_per_word; - if (xspi->bits_per_word == 8) { - xspi->tx_fn = xspi_tx8; - xspi->rx_fn = xspi_rx8; - } else if (xspi->bits_per_word == 16) { - xspi->tx_fn = xspi_tx16; - xspi->rx_fn = xspi_rx16; - } else if (xspi->bits_per_word == 32) { - xspi->tx_fn = xspi_tx32; - xspi->rx_fn = xspi_rx32; - } else { - ret = -EINVAL; - goto put_master; - } - xspi->buffer_size = xilinx_spi_find_buffer_size(xspi); xspi->irq = platform_get_irq(pdev, 0); -- cgit v1.2.3 From c30929415a3d7f186da888d322f93150af308287 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 28 Jan 2015 13:23:48 +0100 Subject: spi/xilinx: Make spi_tx and spi_rx simmetric spi_rx handles the case where the buffer is null. Nevertheless spi_tx did not handle it, and was handled by the caller function. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index ac94e546a555..6ce1066be98b 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -116,6 +116,10 @@ static unsigned int xspi_read32_be(void __iomem *addr) static void xilinx_spi_tx(struct xilinx_spi *xspi) { + if (!xspi->tx_ptr) { + xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); + return; + } xspi->write_fn(*(u32 *)(xspi->tx_ptr), xspi->regs + XSPI_TXD_OFFSET); xspi->tx_ptr += xspi->bits_per_word / 8; } @@ -230,10 +234,7 @@ static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi, int n_words) xspi->remaining_bytes -= n_words * xspi->bits_per_word / 8; while (n_words--) - if (xspi->tx_ptr) - xilinx_spi_tx(xspi); - else - xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); + xilinx_spi_tx(xspi); return; } -- cgit v1.2.3 From d79b2d073ae4eeb79ce1aa27c96fe9e3f7582e97 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 28 Jan 2015 13:23:49 +0100 Subject: spi/xilinx: Convert remainding_bytes in remaining words Simplify the code by using the unit used on most of the code logic. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 6ce1066be98b..8ed306e44df7 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -86,7 +86,7 @@ struct xilinx_spi { u8 *rx_ptr; /* pointer in the Tx buffer */ const u8 *tx_ptr; /* pointer in the Rx buffer */ - int remaining_bytes; /* the number of bytes left to transfer */ + int remaining_words; /* the number of words left to transfer */ u8 bits_per_word; int buffer_size; /* buffer size in words */ u32 cs_inactive; /* Level of the CS pins when inactive*/ @@ -231,7 +231,7 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi, static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi, int n_words) { - xspi->remaining_bytes -= n_words * xspi->bits_per_word / 8; + xspi->remaining_words -= n_words; while (n_words--) xilinx_spi_tx(xspi); @@ -246,15 +246,14 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) xspi->tx_ptr = t->tx_buf; xspi->rx_ptr = t->rx_buf; - xspi->remaining_bytes = t->len; + xspi->remaining_words = (t->len * 8) / xspi->bits_per_word; reinit_completion(&xspi->done); - while (xspi->remaining_bytes) { + while (xspi->remaining_words) { u16 cr = 0; int n_words; - n_words = (xspi->remaining_bytes * 8) / xspi->bits_per_word; - n_words = min(n_words, xspi->buffer_size); + n_words = min(xspi->remaining_words, xspi->buffer_size); xilinx_spi_fill_tx_fifo(xspi, n_words); @@ -286,7 +285,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) xilinx_spi_rx(xspi); } - return t->len - xspi->remaining_bytes; + return t->len; } -- cgit v1.2.3 From 17aaaa80327107843f8ea6d2629ab5f733fc01aa Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 28 Jan 2015 13:23:50 +0100 Subject: spi/xilinx: Convert bits_per_word in bytes_per_word Simplify the code by using the unit used on most of the code logic. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 8ed306e44df7..b16fccfe69bf 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -87,7 +87,7 @@ struct xilinx_spi { u8 *rx_ptr; /* pointer in the Tx buffer */ const u8 *tx_ptr; /* pointer in the Rx buffer */ int remaining_words; /* the number of words left to transfer */ - u8 bits_per_word; + u8 bytes_per_word; int buffer_size; /* buffer size in words */ u32 cs_inactive; /* Level of the CS pins when inactive*/ unsigned int (*read_fn)(void __iomem *); @@ -121,7 +121,7 @@ static void xilinx_spi_tx(struct xilinx_spi *xspi) return; } xspi->write_fn(*(u32 *)(xspi->tx_ptr), xspi->regs + XSPI_TXD_OFFSET); - xspi->tx_ptr += xspi->bits_per_word / 8; + xspi->tx_ptr += xspi->bytes_per_word; } static void xilinx_spi_rx(struct xilinx_spi *xspi) @@ -131,19 +131,19 @@ static void xilinx_spi_rx(struct xilinx_spi *xspi) if (!xspi->rx_ptr) return; - switch (xspi->bits_per_word) { - case 8: + switch (xspi->bytes_per_word) { + case 1: *(u8 *)(xspi->rx_ptr) = data; break; - case 16: + case 2: *(u16 *)(xspi->rx_ptr) = data; break; - case 32: + case 4: *(u32 *)(xspi->rx_ptr) = data; break; } - xspi->rx_ptr += xspi->bits_per_word / 8; + xspi->rx_ptr += xspi->bytes_per_word; } static void xspi_init_hw(struct xilinx_spi *xspi) @@ -246,7 +246,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) xspi->tx_ptr = t->tx_buf; xspi->rx_ptr = t->rx_buf; - xspi->remaining_words = (t->len * 8) / xspi->bits_per_word; + xspi->remaining_words = t->len / xspi->bytes_per_word; reinit_completion(&xspi->done); while (xspi->remaining_words) { @@ -410,7 +410,7 @@ static int xilinx_spi_probe(struct platform_device *pdev) } master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word); - xspi->bits_per_word = bits_per_word; + xspi->bytes_per_word = bits_per_word / 8; xspi->buffer_size = xilinx_spi_find_buffer_size(xspi); xspi->irq = platform_get_irq(pdev, 0); -- cgit v1.2.3 From 99082eab63449f9dfa83d5157fa6d78bfc1b04d7 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 28 Jan 2015 13:23:51 +0100 Subject: spi/xilinx: Remove iowrite/ioread wrappers Save a stack level and cleanup code. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index b16fccfe69bf..8c25c59df7b0 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -94,26 +94,6 @@ struct xilinx_spi { void (*write_fn)(u32, void __iomem *); }; -static void xspi_write32(u32 val, void __iomem *addr) -{ - iowrite32(val, addr); -} - -static unsigned int xspi_read32(void __iomem *addr) -{ - return ioread32(addr); -} - -static void xspi_write32_be(u32 val, void __iomem *addr) -{ - iowrite32be(val, addr); -} - -static unsigned int xspi_read32_be(void __iomem *addr) -{ - return ioread32be(addr); -} - static void xilinx_spi_tx(struct xilinx_spi *xspi) { if (!xspi->tx_ptr) { @@ -398,15 +378,15 @@ static int xilinx_spi_probe(struct platform_device *pdev) * Setup little endian helper functions first and try to use them * and check if bit was correctly setup or not. */ - xspi->read_fn = xspi_read32; - xspi->write_fn = xspi_write32; + xspi->read_fn = ioread32; + xspi->write_fn = iowrite32; xspi->write_fn(XSPI_CR_LOOP, xspi->regs + XSPI_CR_OFFSET); tmp = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); tmp &= XSPI_CR_LOOP; if (tmp != XSPI_CR_LOOP) { - xspi->read_fn = xspi_read32_be; - xspi->write_fn = xspi_write32_be; + xspi->read_fn = ioread32be; + xspi->write_fn = iowrite32be; } master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word); -- cgit v1.2.3 From b563bfb8d76762fe5a4db1e4f983f3647d60e456 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 28 Jan 2015 13:23:52 +0100 Subject: spi/xilinx: Remove remaining_words driver data variable The variable never leaves the scope of txrx_bufs. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 8c25c59df7b0..026f4c59a941 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -86,7 +86,6 @@ struct xilinx_spi { u8 *rx_ptr; /* pointer in the Tx buffer */ const u8 *tx_ptr; /* pointer in the Rx buffer */ - int remaining_words; /* the number of words left to transfer */ u8 bytes_per_word; int buffer_size; /* buffer size in words */ u32 cs_inactive; /* Level of the CS pins when inactive*/ @@ -209,33 +208,27 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi, return 0; } -static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi, int n_words) -{ - xspi->remaining_words -= n_words; - - while (n_words--) - xilinx_spi_tx(xspi); - return; -} - static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) { struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); + int remaining_words; /* the number of words left to transfer */ /* We get here with transmitter inhibited */ xspi->tx_ptr = t->tx_buf; xspi->rx_ptr = t->rx_buf; - xspi->remaining_words = t->len / xspi->bytes_per_word; + remaining_words = t->len / xspi->bytes_per_word; reinit_completion(&xspi->done); - while (xspi->remaining_words) { + while (remaining_words) { u16 cr = 0; - int n_words; + int n_words, tx_words, rx_words; - n_words = min(xspi->remaining_words, xspi->buffer_size); + n_words = min(remaining_words, xspi->buffer_size); - xilinx_spi_fill_tx_fifo(xspi, n_words); + tx_words = n_words; + while (tx_words--) + xilinx_spi_tx(xspi); /* Start the transfer by not inhibiting the transmitter any * longer @@ -261,8 +254,11 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) xspi->regs + XSPI_CR_OFFSET); /* Read out all the data from the Rx FIFO */ - while (n_words--) + rx_words = n_words; + while (rx_words--) xilinx_spi_rx(xspi); + + remaining_words -= n_words; } return t->len; -- cgit v1.2.3 From 22417352f6b7f623495cc426680de75d725197df Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Wed, 28 Jan 2015 13:23:54 +0100 Subject: spi/xilinx: Use polling mode on small transfers Small transfers generally can be accomplished faster in polling mode. This patch select the transfer which size is bellow the buffer size to be done on polling mode Suggested-by: Mark Brown Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 026f4c59a941..337fda4e78a6 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -128,7 +128,6 @@ static void xilinx_spi_rx(struct xilinx_spi *xspi) static void xspi_init_hw(struct xilinx_spi *xspi) { void __iomem *regs_base = xspi->regs; - u32 inhibit; /* Reset the SPI device */ xspi->write_fn(XIPIF_V123B_RESET_MASK, @@ -138,22 +137,15 @@ static void xspi_init_hw(struct xilinx_spi *xspi) */ xspi->write_fn(XSPI_INTR_TX_EMPTY, regs_base + XIPIF_V123B_IIER_OFFSET); - /* Enable the global IPIF interrupt */ - if (xspi->irq >= 0) { - xspi->write_fn(XIPIF_V123B_GINTR_ENABLE, - regs_base + XIPIF_V123B_DGIER_OFFSET); - inhibit = XSPI_CR_TRANS_INHIBIT; - } else { - xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET); - inhibit = 0; - } + /* Disable the global IPIF interrupt */ + xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET); /* Deselect the slave on the SPI bus */ xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET); /* Disable the transmitter, enable Manual Slave Select Assertion, * put SPI controller into master mode, and enable it */ - xspi->write_fn(inhibit | XSPI_CR_MANUAL_SSELECT | - XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET | - XSPI_CR_RXFIFO_RESET, regs_base + XSPI_CR_OFFSET); + xspi->write_fn(XSPI_CR_MANUAL_SSELECT | XSPI_CR_MASTER_MODE | + XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET | XSPI_CR_RXFIFO_RESET, + regs_base + XSPI_CR_OFFSET); } static void xilinx_spi_chipselect(struct spi_device *spi, int is_on) @@ -212,6 +204,8 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) { struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); int remaining_words; /* the number of words left to transfer */ + bool use_irq = false; + u16 cr = 0; /* We get here with transmitter inhibited */ @@ -220,8 +214,20 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) remaining_words = t->len / xspi->bytes_per_word; reinit_completion(&xspi->done); + if (xspi->irq >= 0 && remaining_words > xspi->buffer_size) { + use_irq = true; + xspi->write_fn(XSPI_INTR_TX_EMPTY, + xspi->regs + XIPIF_V123B_IISR_OFFSET); + /* Enable the global IPIF interrupt */ + xspi->write_fn(XIPIF_V123B_GINTR_ENABLE, + xspi->regs + XIPIF_V123B_DGIER_OFFSET); + /* Inhibit irq to avoid spurious irqs on tx_empty*/ + cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); + xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, + xspi->regs + XSPI_CR_OFFSET); + } + while (remaining_words) { - u16 cr = 0; int n_words, tx_words, rx_words; n_words = min(remaining_words, xspi->buffer_size); @@ -234,9 +240,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) * longer */ - if (xspi->irq >= 0) { - cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) & - ~XSPI_CR_TRANS_INHIBIT; + if (use_irq) { xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); wait_for_completion(&xspi->done); } else @@ -249,7 +253,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) * transmitter while the Isr refills the transmit register/FIFO, * or make sure it is stopped if we're done. */ - if (xspi->irq >= 0) + if (use_irq) xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, xspi->regs + XSPI_CR_OFFSET); @@ -261,6 +265,9 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) remaining_words -= n_words; } + if (use_irq) + xspi->write_fn(0, xspi->regs + XIPIF_V123B_DGIER_OFFSET); + return t->len; } -- cgit v1.2.3 From eb25f16c6f446936932f41f3ff811fbdc285bbc4 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Wed, 28 Jan 2015 20:53:39 +0100 Subject: spi/xilinx: Check number of slaves range The core only supports up to 32 slaves, and the chipselect function expects the same. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 337fda4e78a6..2ca55f6b5158 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -22,6 +22,8 @@ #include #include +#define XILINX_SPI_MAX_CS 32 + #define XILINX_SPI_NAME "xilinx_spi" /* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e) @@ -347,6 +349,11 @@ static int xilinx_spi_probe(struct platform_device *pdev) return -EINVAL; } + if (num_cs > XILINX_SPI_MAX_CS) { + dev_err(&pdev->dev, "Invalid number of spi slaves\n"); + return -EINVAL; + } + master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi)); if (!master) return -ENODEV; -- cgit v1.2.3 From 0635287a308d38bad334fe91ea5a69b597e0a583 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 30 Jan 2015 13:42:00 +0100 Subject: spi: Revert "spi/xilinx: Remove iowrite/ioread wrappers" This reverts commit 99082eab63449f9dfa83d5157fa6d78bfc1b04d7 since it breaks the build due to differing implementations of iowrite() and ioread(). Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 2ca55f6b5158..d1901d578823 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -95,6 +95,26 @@ struct xilinx_spi { void (*write_fn)(u32, void __iomem *); }; +static void xspi_write32(u32 val, void __iomem *addr) +{ + iowrite32(val, addr); +} + +static unsigned int xspi_read32(void __iomem *addr) +{ + return ioread32(addr); +} + +static void xspi_write32_be(u32 val, void __iomem *addr) +{ + iowrite32be(val, addr); +} + +static unsigned int xspi_read32_be(void __iomem *addr) +{ + return ioread32be(addr); +} + static void xilinx_spi_tx(struct xilinx_spi *xspi) { if (!xspi->tx_ptr) { @@ -388,15 +408,15 @@ static int xilinx_spi_probe(struct platform_device *pdev) * Setup little endian helper functions first and try to use them * and check if bit was correctly setup or not. */ - xspi->read_fn = ioread32; - xspi->write_fn = iowrite32; + xspi->read_fn = xspi_read32; + xspi->write_fn = xspi_write32; xspi->write_fn(XSPI_CR_LOOP, xspi->regs + XSPI_CR_OFFSET); tmp = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); tmp &= XSPI_CR_LOOP; if (tmp != XSPI_CR_LOOP) { - xspi->read_fn = ioread32be; - xspi->write_fn = iowrite32be; + xspi->read_fn = xspi_read32_be; + xspi->write_fn = xspi_write32_be; } master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word); -- cgit v1.2.3 From 34093cb97abe9298a19a96b1b2f1714e28f8e67f Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Mon, 2 Feb 2015 11:06:56 +0100 Subject: spi/xilinx: Fix access invalid memory on xilinx_spi_tx On 1 and 2 bytes per word, the transfer of the 3 last bytes will access memory outside tx_ptr. Although this has not trigger any error on real hardware, we should better fix this. Fixes: 24ba5e593f391507 (Remove rx_fn and tx_fn pointer) Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index d1901d578823..133f53a9c1d4 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -117,11 +117,26 @@ static unsigned int xspi_read32_be(void __iomem *addr) static void xilinx_spi_tx(struct xilinx_spi *xspi) { + u32 data = 0; + if (!xspi->tx_ptr) { xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); return; } - xspi->write_fn(*(u32 *)(xspi->tx_ptr), xspi->regs + XSPI_TXD_OFFSET); + + switch (xspi->bytes_per_word) { + case 1: + data = *(u8 *)(xspi->tx_ptr); + break; + case 2: + data = *(u16 *)(xspi->tx_ptr); + break; + case 4: + data = *(u32 *)(xspi->tx_ptr); + break; + } + + xspi->write_fn(data, xspi->regs + XSPI_TXD_OFFSET); xspi->tx_ptr += xspi->bytes_per_word; } -- cgit v1.2.3