aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Sperl <kernel@martin.sperl.org>2015-10-16 10:17:19 -0400
committerMark Brown <broonie@kernel.org>2015-10-16 10:35:33 -0400
commit72aac02b3730fa0e2e1ccab57712a94400344f8a (patch)
tree1da5d79bb78a92b2d557e9b386a22f1cb61ad450
parent1ea29b39f4c812ece2f936065a0a3d6fe44a263e (diff)
spi: bcm2835aux: fixed bad data on longer transfers
There are strange issues with the auxiliary spi device that result in "lost" data in the RX path if the fifo is filled by too much (even though the status register is checked if new data can get filled in). This has been observed primarily for the interrupt case. Polling works fine, probably because the RX fifo is pulled immediately when in the tight polling loop. For that reason we have to limit the pending bytes to less than 15 when filling the fifo in interrupt mode. There also was an issue returning the "wrong" last 1/2 bytes of a transfer when the transfer is not a multiple of 3 bytes. (this impacted polling and interrupt modes) Also fixed an overflow in the estimation of the transfer time used to decide if we run in interrupt or polling mode (found with the spi-bcm2835.c driver originally). Reported-by: Georgii Staroselskii <georgii.staroselskii@emlid.com> Signed-off-by: Martin Sperl <kernel@martin.sperl.org> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/spi/spi-bcm2835aux.c43
1 files changed, 31 insertions, 12 deletions
diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
index f92b4a69fffa..05d2d6eb7bfa 100644
--- a/drivers/spi/spi-bcm2835aux.c
+++ b/drivers/spi/spi-bcm2835aux.c
@@ -104,6 +104,7 @@ struct bcm2835aux_spi {
104 u8 *rx_buf; 104 u8 *rx_buf;
105 int tx_len; 105 int tx_len;
106 int rx_len; 106 int rx_len;
107 int pending;
107}; 108};
108 109
109static inline u32 bcm2835aux_rd(struct bcm2835aux_spi *bs, unsigned reg) 110static inline u32 bcm2835aux_rd(struct bcm2835aux_spi *bs, unsigned reg)
@@ -120,15 +121,27 @@ static inline void bcm2835aux_wr(struct bcm2835aux_spi *bs, unsigned reg,
120static inline void bcm2835aux_rd_fifo(struct bcm2835aux_spi *bs) 121static inline void bcm2835aux_rd_fifo(struct bcm2835aux_spi *bs)
121{ 122{
122 u32 data; 123 u32 data;
123 int i;
124 int count = min(bs->rx_len, 3); 124 int count = min(bs->rx_len, 3);
125 125
126 data = bcm2835aux_rd(bs, BCM2835_AUX_SPI_IO); 126 data = bcm2835aux_rd(bs, BCM2835_AUX_SPI_IO);
127 if (bs->rx_buf) { 127 if (bs->rx_buf) {
128 for (i = 0; i < count; i++) 128 switch (count) {
129 *bs->rx_buf++ = (data >> (8 * (2 - i))) & 0xff; 129 case 4:
130 *bs->rx_buf++ = (data >> 24) & 0xff;
131 /* fallthrough */
132 case 3:
133 *bs->rx_buf++ = (data >> 16) & 0xff;
134 /* fallthrough */
135 case 2:
136 *bs->rx_buf++ = (data >> 8) & 0xff;
137 /* fallthrough */
138 case 1:
139 *bs->rx_buf++ = (data >> 0) & 0xff;
140 /* fallthrough - no default */
141 }
130 } 142 }
131 bs->rx_len -= count; 143 bs->rx_len -= count;
144 bs->pending -= count;
132} 145}
133 146
134static inline void bcm2835aux_wr_fifo(struct bcm2835aux_spi *bs) 147static inline void bcm2835aux_wr_fifo(struct bcm2835aux_spi *bs)
@@ -151,6 +164,7 @@ static inline void bcm2835aux_wr_fifo(struct bcm2835aux_spi *bs)
151 164
152 /* and decrement length */ 165 /* and decrement length */
153 bs->tx_len -= count; 166 bs->tx_len -= count;
167 bs->pending += count;
154 168
155 /* write to the correct TX-register */ 169 /* write to the correct TX-register */
156 if (bs->tx_len) 170 if (bs->tx_len)
@@ -183,6 +197,7 @@ static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id)
183 197
184 /* check if we have data to write */ 198 /* check if we have data to write */
185 while (bs->tx_len && 199 while (bs->tx_len &&
200 (bs->pending < 12) &&
186 (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & 201 (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) &
187 BCM2835_AUX_SPI_STAT_TX_FULL))) { 202 BCM2835_AUX_SPI_STAT_TX_FULL))) {
188 bcm2835aux_wr_fifo(bs); 203 bcm2835aux_wr_fifo(bs);
@@ -234,6 +249,7 @@ static int bcm2835aux_spi_transfer_one_irq(struct spi_master *master,
234 249
235 /* fill in tx fifo with data before enabling interrupts */ 250 /* fill in tx fifo with data before enabling interrupts */
236 while ((bs->tx_len) && 251 while ((bs->tx_len) &&
252 (bs->pending < 12) &&
237 (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) & 253 (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) &
238 BCM2835_AUX_SPI_STAT_TX_FULL))) { 254 BCM2835_AUX_SPI_STAT_TX_FULL))) {
239 bcm2835aux_wr_fifo(bs); 255 bcm2835aux_wr_fifo(bs);
@@ -245,8 +261,7 @@ static int bcm2835aux_spi_transfer_one_irq(struct spi_master *master,
245 261
246static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master, 262static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master,
247 struct spi_device *spi, 263 struct spi_device *spi,
248 struct spi_transfer *tfr, 264 struct spi_transfer *tfr)
249 unsigned long xfer_time_us)
250{ 265{
251 struct bcm2835aux_spi *bs = spi_master_get_devdata(master); 266 struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
252 unsigned long timeout; 267 unsigned long timeout;
@@ -305,7 +320,8 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
305{ 320{
306 struct bcm2835aux_spi *bs = spi_master_get_devdata(master); 321 struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
307 unsigned long spi_hz, clk_hz, speed; 322 unsigned long spi_hz, clk_hz, speed;
308 unsigned long spi_used_hz, xfer_time_us; 323 unsigned long spi_used_hz;
324 unsigned long long xfer_time_us;
309 325
310 /* calculate the registers to handle 326 /* calculate the registers to handle
311 * 327 *
@@ -348,16 +364,19 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
348 bs->rx_buf = tfr->rx_buf; 364 bs->rx_buf = tfr->rx_buf;
349 bs->tx_len = tfr->len; 365 bs->tx_len = tfr->len;
350 bs->rx_len = tfr->len; 366 bs->rx_len = tfr->len;
367 bs->pending = 0;
351 368
352 /* calculate the estimated time in us the transfer runs */ 369 /* calculate the estimated time in us the transfer runs
353 xfer_time_us = tfr->len 370 * note that there are are 2 idle clocks after each
354 * 9 /* clocks/byte - SPI-HW waits 1 clock after each byte */ 371 * chunk getting transferred - in our case the chunk size
355 * 1000000 / spi_used_hz; 372 * is 3 bytes, so we approximate this by 9 bits/byte
373 */
374 xfer_time_us = tfr->len * 9 * 1000000;
375 do_div(xfer_time_us, spi_used_hz);
356 376
357 /* run in polling mode for short transfers */ 377 /* run in polling mode for short transfers */
358 if (xfer_time_us < BCM2835_AUX_SPI_POLLING_LIMIT_US) 378 if (xfer_time_us < BCM2835_AUX_SPI_POLLING_LIMIT_US)
359 return bcm2835aux_spi_transfer_one_poll(master, spi, tfr, 379 return bcm2835aux_spi_transfer_one_poll(master, spi, tfr);
360 xfer_time_us);
361 380
362 /* run in interrupt mode for all others */ 381 /* run in interrupt mode for all others */
363 return bcm2835aux_spi_transfer_one_irq(master, spi, tfr); 382 return bcm2835aux_spi_transfer_one_irq(master, spi, tfr);