diff options
| -rw-r--r-- | drivers/spi/spi-bcm2835aux.c | 43 |
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 | ||
| 109 | static inline u32 bcm2835aux_rd(struct bcm2835aux_spi *bs, unsigned reg) | 110 | static 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, | |||
| 120 | static inline void bcm2835aux_rd_fifo(struct bcm2835aux_spi *bs) | 121 | static 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 | ||
| 134 | static inline void bcm2835aux_wr_fifo(struct bcm2835aux_spi *bs) | 147 | static 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 | ||
| 246 | static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master, | 262 | static 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); |
