Root/target/linux/brcm63xx/patches-3.3/110-spi-bcm63xx-fix-multi-transfer-messages.patch

1From 0f2ae1e1282ff64f74a5e36f7da874f94911225e Mon Sep 17 00:00:00 2001
2From: Jonas Gorski <jonas.gorski@gmail.com>
3Date: Wed, 14 Nov 2012 22:22:33 +0100
4Subject: [PATCH] spi/bcm63xx: fix multi transfer messages
5
6The BCM63XX SPI controller does not support keeping CS asserted after
7sending its buffer. This breaks common usages like spi_write_then_read,
8where it is expected to be kept active during the whole transfers.
9
10Work around this by combining the transfers into one if the buffer
11allows. For spi_write_then_read, use the prepend byte feature to write
12to "prepend" the write if it is less than 15 bytes, allowing the whole
13fifo size for the read.
14
15Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
16---
17Tested on a SPI conntected switch which required keeping CS active between
18the register read command and reading the register contents.
19
20Based on Mark's spi/next.
21
22Not sure if this is stable material, as it's quite invasive.
23
24 drivers/spi/spi-bcm63xx.c | 172 ++++++++++++++++++++++++++++++---------------
25 1 file changed, 117 insertions(+), 55 deletions(-)
26
27--- a/drivers/spi/spi-bcm63xx.c
28+++ b/drivers/spi/spi-bcm63xx.c
29@@ -38,6 +38,8 @@
30 #define PFX KBUILD_MODNAME
31 #define DRV_VER "0.1.2"
32 
33+#define BCM63XX_SPI_MAX_PREPEND 15
34+
35 struct bcm63xx_spi {
36     struct completion done;
37 
38@@ -50,16 +52,10 @@ struct bcm63xx_spi {
39     unsigned int msg_type_shift;
40     unsigned int msg_ctl_width;
41 
42- /* Data buffers */
43- const unsigned char *tx_ptr;
44- unsigned char *rx_ptr;
45-
46     /* data iomem */
47     u8 __iomem *tx_io;
48     const u8 __iomem *rx_io;
49 
50- int remaining_bytes;
51-
52     struct clk *clk;
53     struct platform_device *pdev;
54 };
55@@ -184,50 +180,60 @@ static int bcm63xx_spi_setup(struct spi_
56     return 0;
57 }
58 
59-/* Fill the TX FIFO with as many bytes as possible */
60-static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs)
61-{
62- u8 size;
63-
64- /* Fill the Tx FIFO with as many bytes as possible */
65- size = bs->remaining_bytes < bs->fifo_size ? bs->remaining_bytes :
66- bs->fifo_size;
67- memcpy_toio(bs->tx_io, bs->tx_ptr, size);
68- bs->remaining_bytes -= size;
69-}
70-
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)
75 {
76     struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
77     u16 msg_ctl;
78     u16 cmd;
79+ unsigned int i, timeout, total_len = 0, prepend_len = 0, len = 0;
80+ struct spi_transfer *t = first;
81+ u8 rx_tail;
82+ bool do_rx = false;
83+ bool do_tx = false;
84 
85     /* Disable the CMD_DONE interrupt */
86     bcm_spi_writeb(bs, 0, SPI_INT_MASK);
87 
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;
92+
93+ /* prepare the buffer */
94+ for (i = 0; i < n_transfers; i++) {
95+ if (t->tx_buf) {
96+ do_tx = true;
97+ memcpy_toio(bs->tx_io + total_len, t->tx_buf, t->len);
98+
99+ /* don't prepend more than one tx */
100+ if (t != first)
101+ prepend_len = 0;
102+ }
103+
104+ if (t->rx_buf) {
105+ do_rx = true;
106+ if (t == first)
107+ prepend_len = 0;
108+ }
109 
110- /* Transmitter is inhibited */
111- bs->tx_ptr = t->tx_buf;
112- bs->rx_ptr = t->rx_buf;
113-
114- if (t->tx_buf) {
115- bs->remaining_bytes = t->len;
116- bcm63xx_spi_fill_tx_fifo(bs);
117+ total_len += t->len;
118+
119+ t = list_entry(t->transfer_list.next, struct spi_transfer,
120+ transfer_list);
121     }
122 
123+ len = total_len - prepend_len;
124+
125     init_completion(&bs->done);
126 
127     /* Fill in the Message control register */
128- msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT);
129+ msg_ctl = (len << SPI_BYTE_CNT_SHIFT);
130 
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)
135+ else if (do_rx)
136         msg_ctl |= (SPI_HD_R << bs->msg_type_shift);
137- else if (t->tx_buf)
138+ else if (do_tx)
139         msg_ctl |= (SPI_HD_W << bs->msg_type_shift);
140 
141     switch (bs->msg_ctl_width) {
142@@ -245,14 +251,41 @@ static unsigned int bcm63xx_txrx_bufs(st
143 
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);
150 
151     /* Enable the CMD_DONE interrupt */
152     bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
153 
154- return t->len - bs->remaining_bytes;
155+ timeout = wait_for_completion_timeout(&bs->done, HZ);
156+ if (!timeout)
157+ return -ETIMEDOUT;
158+
159+ /* read out all data */
160+ rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
161+
162+ if (do_rx && rx_tail != len)
163+ return -EINVAL;
164+
165+ if (!rx_tail)
166+ return total_len;
167+
168+ len = 0;
169+ t = first;
170+ /* Read out all the data */
171+ for (i = 0; i < n_transfers; i++) {
172+ if (t->rx_buf)
173+ memcpy_fromio(t->rx_buf, bs->rx_io + len, t->len);
174+
175+ if (t != first || prepend_len == 0)
176+ len += t->len;
177+
178+ t = list_entry(t->transfer_list.next, struct spi_transfer,
179+ transfer_list);
180+ }
181+
182+ return total_len;
183 }
184 
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)
188 {
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;
193     int status = 0;
194- unsigned int timeout = 0;
195+ unsigned int n_transfers = 0, total_len = 0;
196+ bool can_use_prepend = false;
197 
198+ /*
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
201+ * deassert CS.
202+ */
203     list_for_each_entry(t, &m->transfers, transfer_list) {
204- unsigned int len = t->len;
205- u8 rx_tail;
206-
207         status = bcm63xx_spi_check_transfer(spi, t);
208         if (status < 0)
209             goto exit;
210 
211- /* configure adapter for a new transfer */
212- bcm63xx_spi_setup_transfer(spi, t);
213+ if (!first)
214+ first = t;
215 
216- while (len) {
217- /* send the data */
218- len -= bcm63xx_txrx_bufs(spi, t);
219-
220- timeout = wait_for_completion_timeout(&bs->done, HZ);
221- if (!timeout) {
222- status = -ETIMEDOUT;
223- goto exit;
224- }
225+ n_transfers++;
226+ total_len += t->len;
227+
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;
233+
234+ if ((can_use_prepend &&
235+ total_len > (bs->fifo_size + BCM63XX_SPI_MAX_PREPEND)) ||
236+ (!can_use_prepend && total_len > bs->fifo_size)) {
237+ status = -EINVAL;
238+ goto exit;
239+ }
240 
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) {
245+ status = -EINVAL;
246+ goto exit;
247+ }
248 
249- /* Read out all the data */
250- if (rx_tail)
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) {
254+ status = -EINVAL;
255+ goto exit;
256         }
257 
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);
263+
264+ status = bcm63xx_txrx_bufs(spi, first, n_transfers);
265+ if (status < 0)
266+ goto exit;
267+
268+ m->actual_length += status;
269+ first = NULL;
270+ status = 0;
271+ n_transfers = 0;
272+ total_len = 0;
273+ can_use_prepend = false;
274+ }
275     }
276+
277 exit:
278     m->status = status;
279     spi_finalize_current_message(master);
280

Archive Download this file



interactive