summaryrefslogtreecommitdiff
path: root/drivers/spi/spi-bcm63xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-bcm63xx.c')
-rw-r--r--drivers/spi/spi-bcm63xx.c91
1 files changed, 42 insertions, 49 deletions
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index f44ab55..27667c1 100644
--- 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_device *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(struct spi_device *spi,
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(struct spi_device *spi,
/* 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(struct spi_master *master,
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;
- /* configure adapter for a new transfer */
- bcm63xx_spi_setup_transfer(spi, t);
+ /* 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;
+ }
- while (len) {
- /* send the data */
- len -= bcm63xx_txrx_bufs(spi, t);
+ /* 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;
+ }
- timeout = wait_for_completion_timeout(&bs->done, HZ);
- if (!timeout) {
- status = -ETIMEDOUT;
- 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;
+ }
- /* read out all data */
- rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
+ /* configure adapter for a new transfer */
+ bcm63xx_spi_setup_transfer(spi, t);
- /* 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;
}