1 From 0f2ae1e1282ff64f74a5e36f7da874f94911225e Mon Sep 17 00:00:00 2001
2 From: Jonas Gorski <jonas.gorski@gmail.com>
3 Date: Wed, 14 Nov 2012 22:22:33 +0100
4 Subject: [PATCH] spi/bcm63xx: fix multi transfer messages
6 The BCM63XX SPI controller does not support keeping CS asserted after
7 sending its buffer. This breaks common usages like spi_write_then_read,
8 where it is expected to be kept active during the whole transfers.
10 Work around this by combining the transfers into one if the buffer
11 allows. For spi_write_then_read, use the prepend byte feature to write
12 to "prepend" the write if it is less than 15 bytes, allowing the whole
13 fifo size for the read.
15 Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
17 Tested on a SPI conntected switch which required keeping CS active between
18 the register read command and reading the register contents.
20 Based on Mark's spi/next.
22 Not sure if this is stable material, as it's quite invasive.
24 drivers/spi/spi-bcm63xx.c | 172 ++++++++++++++++++++++++++++++---------------
25 1 file changed, 117 insertions(+), 55 deletions(-)
27 --- a/drivers/spi/spi-bcm63xx.c
28 +++ b/drivers/spi/spi-bcm63xx.c
30 #define PFX KBUILD_MODNAME
31 #define DRV_VER "0.1.2"
33 +#define BCM63XX_SPI_MAX_PREPEND 15
36 struct completion done;
38 @@ -50,16 +52,10 @@ struct bcm63xx_spi {
39 unsigned int msg_type_shift;
40 unsigned int msg_ctl_width;
43 - const unsigned char *tx_ptr;
44 - unsigned char *rx_ptr;
48 const u8 __iomem *rx_io;
50 - int remaining_bytes;
53 struct platform_device *pdev;
55 @@ -184,50 +180,60 @@ static int bcm63xx_spi_setup(struct spi_
59 -/* Fill the TX FIFO with as many bytes as possible */
60 -static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs)
64 - /* Fill the Tx FIFO with as many bytes as possible */
65 - size = bs->remaining_bytes < bs->fifo_size ? bs->remaining_bytes :
67 - memcpy_toio(bs->tx_io, bs->tx_ptr, size);
68 - bs->remaining_bytes -= size;
71 static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi,
72 - struct spi_transfer *t)
73 + struct spi_transfer *first,
74 + unsigned int n_transfers)
76 struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
79 + unsigned int i, timeout, total_len = 0, prepend_len = 0, len = 0;
80 + struct spi_transfer *t = first;
85 /* Disable the CMD_DONE interrupt */
86 bcm_spi_writeb(bs, 0, SPI_INT_MASK);
88 - dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
89 - t->tx_buf, t->rx_buf, t->len);
90 + if (n_transfers > 1 && t->tx_buf && t->len <= BCM63XX_SPI_MAX_PREPEND)
91 + prepend_len = t->len;
93 + /* prepare the buffer */
94 + for (i = 0; i < n_transfers; i++) {
97 + memcpy_toio(bs->tx_io + total_len, t->tx_buf, t->len);
99 + /* don't prepend more than one tx */
110 - /* Transmitter is inhibited */
111 - bs->tx_ptr = t->tx_buf;
112 - bs->rx_ptr = t->rx_buf;
115 - bs->remaining_bytes = t->len;
116 - bcm63xx_spi_fill_tx_fifo(bs);
117 + total_len += t->len;
119 + t = list_entry(t->transfer_list.next, struct spi_transfer,
123 + len = total_len - prepend_len;
125 init_completion(&bs->done);
127 /* Fill in the Message control register */
128 - msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT);
129 + msg_ctl = (len << SPI_BYTE_CNT_SHIFT);
131 - if (t->rx_buf && t->tx_buf)
132 + if (do_rx && do_tx && prepend_len == 0)
133 msg_ctl |= (SPI_FD_RW << bs->msg_type_shift);
134 - else if (t->rx_buf)
136 msg_ctl |= (SPI_HD_R << bs->msg_type_shift);
137 - else if (t->tx_buf)
139 msg_ctl |= (SPI_HD_W << bs->msg_type_shift);
141 switch (bs->msg_ctl_width) {
142 @@ -245,14 +251,41 @@ static unsigned int bcm63xx_txrx_bufs(st
144 /* Issue the transfer */
145 cmd = SPI_CMD_START_IMMEDIATE;
146 - cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
147 + cmd |= (prepend_len << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
148 cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT);
149 bcm_spi_writew(bs, cmd, SPI_CMD);
151 /* Enable the CMD_DONE interrupt */
152 bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
154 - return t->len - bs->remaining_bytes;
155 + timeout = wait_for_completion_timeout(&bs->done, HZ);
159 + /* read out all data */
160 + rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
162 + if (do_rx && rx_tail != len)
170 + /* Read out all the data */
171 + for (i = 0; i < n_transfers; i++) {
173 + memcpy_fromio(t->rx_buf, bs->rx_io + len, t->len);
175 + if (t != first || prepend_len == 0)
178 + t = list_entry(t->transfer_list.next, struct spi_transfer,
185 static int bcm63xx_spi_prepare_transfer(struct spi_master *master)
186 @@ -277,42 +310,71 @@ static int bcm63xx_spi_transfer_one(stru
187 struct spi_message *m)
189 struct bcm63xx_spi *bs = spi_master_get_devdata(master);
190 - struct spi_transfer *t;
191 + struct spi_transfer *t, *first = NULL;
192 struct spi_device *spi = m->spi;
194 - unsigned int timeout = 0;
195 + unsigned int n_transfers = 0, total_len = 0;
196 + bool can_use_prepend = false;
199 + * This SPI controller does not support keeping CS active after a
200 + * transfer, so we need to combine the transfers into one until we may
203 list_for_each_entry(t, &m->transfers, transfer_list) {
204 - unsigned int len = t->len;
207 status = bcm63xx_spi_check_transfer(spi, t);
211 - /* configure adapter for a new transfer */
212 - bcm63xx_spi_setup_transfer(spi, t);
217 - /* send the data */
218 - len -= bcm63xx_txrx_bufs(spi, t);
220 - timeout = wait_for_completion_timeout(&bs->done, HZ);
222 - status = -ETIMEDOUT;
226 + total_len += t->len;
228 + if (n_transfers == 2 && !first->rx_buf && !t->tx_buf &&
229 + first->len <= BCM63XX_SPI_MAX_PREPEND)
230 + can_use_prepend = true;
231 + else if (can_use_prepend && t->tx_buf)
232 + can_use_prepend = false;
234 + if ((can_use_prepend &&
235 + total_len > (bs->fifo_size + BCM63XX_SPI_MAX_PREPEND)) ||
236 + (!can_use_prepend && total_len > bs->fifo_size)) {
241 - /* read out all data */
242 - rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
243 + /* all transfers have to be made at the same speed */
244 + if (t->speed_hz != first->speed_hz) {
249 - /* Read out all the data */
251 - memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail);
252 + /* CS will be deasserted directly after the transfer */
253 + if (t->delay_usecs) {
258 - m->actual_length += t->len;
259 + if (t->cs_change ||
260 + list_is_last(&t->transfer_list, &m->transfers)) {
261 + /* configure adapter for a new transfer */
262 + bcm63xx_spi_setup_transfer(spi, first);
264 + status = bcm63xx_txrx_bufs(spi, first, n_transfers);
268 + m->actual_length += status;
273 + can_use_prepend = false;
279 spi_finalize_current_message(master);