diff options
Diffstat (limited to 'target/linux/brcm63xx/patches-3.8/106-spi-bcm63xx-reject-transfers-unable-to-transfer.patch')
-rw-r--r-- | target/linux/brcm63xx/patches-3.8/106-spi-bcm63xx-reject-transfers-unable-to-transfer.patch | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/target/linux/brcm63xx/patches-3.8/106-spi-bcm63xx-reject-transfers-unable-to-transfer.patch b/target/linux/brcm63xx/patches-3.8/106-spi-bcm63xx-reject-transfers-unable-to-transfer.patch new file mode 100644 index 0000000000..8726b19e0d --- /dev/null +++ b/target/linux/brcm63xx/patches-3.8/106-spi-bcm63xx-reject-transfers-unable-to-transfer.patch @@ -0,0 +1,162 @@ +From 243970ea035623f70431a80ece802f572cd446be Mon Sep 17 00:00:00 2001 +From: Jonas Gorski <jogo@openwrt.org> +Date: Sun, 9 Dec 2012 00:10:00 +0100 +Subject: [PATCH V2 1/2] spi/bcm63xx: reject transfers unable to transfer + +The hardware does not support keeping CS asserted after sending one +FIFO buffer worth of data, so reject transfers requiring CS being kept +asserted, either between transers or for a certain time after it, +or exceeding the FIFO size. + +Signed-off-by: Jonas Gorski <jogo@openwrt.org> +--- + drivers/spi/spi-bcm63xx.c | 91 +++++++++++++++++++++------------------------ + 1 file changed, 42 insertions(+), 49 deletions(-) + +--- a/drivers/spi/spi-bcm63xx.c ++++ b/drivers/spi/spi-bcm63xx.c +@@ -49,16 +49,10 @@ struct bcm63xx_spi { + unsigned int msg_type_shift; + unsigned int msg_ctl_width; + +- /* Data buffers */ +- const unsigned char *tx_ptr; +- unsigned char *rx_ptr; +- + /* data iomem */ + u8 __iomem *tx_io; + const u8 __iomem *rx_io; + +- int remaining_bytes; +- + struct clk *clk; + struct platform_device *pdev; + }; +@@ -175,24 +169,13 @@ static int bcm63xx_spi_setup(struct spi_ + return 0; + } + +-/* Fill the TX FIFO with as many bytes as possible */ +-static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs) +-{ +- u8 size; +- +- /* Fill the Tx FIFO with as many bytes as possible */ +- size = bs->remaining_bytes < bs->fifo_size ? bs->remaining_bytes : +- bs->fifo_size; +- memcpy_toio(bs->tx_io, bs->tx_ptr, size); +- bs->remaining_bytes -= size; +-} +- +-static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi, +- struct spi_transfer *t) ++static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) + { + struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); + u16 msg_ctl; + u16 cmd; ++ u8 rx_tail; ++ unsigned int timeout = 0; + + /* Disable the CMD_DONE interrupt */ + bcm_spi_writeb(bs, 0, SPI_INT_MASK); +@@ -200,14 +183,8 @@ static unsigned int bcm63xx_txrx_bufs(st + dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n", + t->tx_buf, t->rx_buf, t->len); + +- /* Transmitter is inhibited */ +- bs->tx_ptr = t->tx_buf; +- bs->rx_ptr = t->rx_buf; +- +- if (t->tx_buf) { +- bs->remaining_bytes = t->len; +- bcm63xx_spi_fill_tx_fifo(bs); +- } ++ if (t->tx_buf) ++ memcpy_toio(bs->tx_io, t->tx_buf, t->len); + + init_completion(&bs->done); + +@@ -239,7 +216,18 @@ static unsigned int bcm63xx_txrx_bufs(st + /* Enable the CMD_DONE interrupt */ + bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK); + +- return t->len - bs->remaining_bytes; ++ timeout = wait_for_completion_timeout(&bs->done, HZ); ++ if (!timeout) ++ return -ETIMEDOUT; ++ ++ /* read out all data */ ++ rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL); ++ ++ /* Read out all the data */ ++ if (rx_tail) ++ memcpy_fromio(t->rx_ptr, bs->rx_io, rx_tail); ++ ++ return 0; + } + + static int bcm63xx_spi_prepare_transfer(struct spi_master *master) +@@ -267,36 +255,41 @@ static int bcm63xx_spi_transfer_one(stru + struct spi_transfer *t; + struct spi_device *spi = m->spi; + int status = 0; +- unsigned int timeout = 0; + + list_for_each_entry(t, &m->transfers, transfer_list) { +- unsigned int len = t->len; +- u8 rx_tail; +- + status = bcm63xx_spi_check_transfer(spi, t); + if (status < 0) + goto exit; + ++ /* we can only transfer one fifo worth of data */ ++ if (t->len > bs->fifo_size) { ++ dev_err(&spi->dev, "unable to do transfers larger than FIFO size (%i > %i)\n", ++ t->len, bs->fifo_size); ++ status = -EINVAL; ++ goto exit; ++ } ++ ++ /* CS will be deasserted directly after transfer */ ++ if (t->delay_usecs) { ++ dev_err(&spi->dev, "unable to keep CS asserted after transfer\n"); ++ status = -EINVAL; ++ goto exit; ++ } ++ ++ if (!t->cs_change && ++ !list_is_last(&t->transfer_list, &m->transfers)) { ++ dev_err(&spi->dev, "unable to keep CS asserted between transfers\n"); ++ status = -EINVAL; ++ goto exit; ++ } ++ + /* configure adapter for a new transfer */ + bcm63xx_spi_setup_transfer(spi, t); + +- while (len) { +- /* send the data */ +- len -= bcm63xx_txrx_bufs(spi, t); +- +- timeout = wait_for_completion_timeout(&bs->done, HZ); +- if (!timeout) { +- status = -ETIMEDOUT; +- goto exit; +- } +- +- /* read out all data */ +- rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL); +- +- /* Read out all the data */ +- if (rx_tail) +- memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail); +- } ++ /* send the data */ ++ status = bcm63xx_txrx_bufs(spi, t); ++ if (status) ++ goto exit; + + m->actual_length += t->len; + } |