|
@@ -104,6 +104,7 @@ struct bcm2835aux_spi {
|
|
u8 *rx_buf;
|
|
u8 *rx_buf;
|
|
int tx_len;
|
|
int tx_len;
|
|
int rx_len;
|
|
int rx_len;
|
|
|
|
+ int pending;
|
|
};
|
|
};
|
|
|
|
|
|
static inline u32 bcm2835aux_rd(struct bcm2835aux_spi *bs, unsigned reg)
|
|
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,
|
|
static inline void bcm2835aux_rd_fifo(struct bcm2835aux_spi *bs)
|
|
static inline void bcm2835aux_rd_fifo(struct bcm2835aux_spi *bs)
|
|
{
|
|
{
|
|
u32 data;
|
|
u32 data;
|
|
- int i;
|
|
|
|
int count = min(bs->rx_len, 3);
|
|
int count = min(bs->rx_len, 3);
|
|
|
|
|
|
data = bcm2835aux_rd(bs, BCM2835_AUX_SPI_IO);
|
|
data = bcm2835aux_rd(bs, BCM2835_AUX_SPI_IO);
|
|
if (bs->rx_buf) {
|
|
if (bs->rx_buf) {
|
|
- for (i = 0; i < count; i++)
|
|
|
|
- *bs->rx_buf++ = (data >> (8 * (2 - i))) & 0xff;
|
|
|
|
|
|
+ switch (count) {
|
|
|
|
+ case 4:
|
|
|
|
+ *bs->rx_buf++ = (data >> 24) & 0xff;
|
|
|
|
+ /* fallthrough */
|
|
|
|
+ case 3:
|
|
|
|
+ *bs->rx_buf++ = (data >> 16) & 0xff;
|
|
|
|
+ /* fallthrough */
|
|
|
|
+ case 2:
|
|
|
|
+ *bs->rx_buf++ = (data >> 8) & 0xff;
|
|
|
|
+ /* fallthrough */
|
|
|
|
+ case 1:
|
|
|
|
+ *bs->rx_buf++ = (data >> 0) & 0xff;
|
|
|
|
+ /* fallthrough - no default */
|
|
|
|
+ }
|
|
}
|
|
}
|
|
bs->rx_len -= count;
|
|
bs->rx_len -= count;
|
|
|
|
+ bs->pending -= count;
|
|
}
|
|
}
|
|
|
|
|
|
static inline void bcm2835aux_wr_fifo(struct bcm2835aux_spi *bs)
|
|
static inline void bcm2835aux_wr_fifo(struct bcm2835aux_spi *bs)
|
|
@@ -151,6 +164,7 @@ static inline void bcm2835aux_wr_fifo(struct bcm2835aux_spi *bs)
|
|
|
|
|
|
/* and decrement length */
|
|
/* and decrement length */
|
|
bs->tx_len -= count;
|
|
bs->tx_len -= count;
|
|
|
|
+ bs->pending += count;
|
|
|
|
|
|
/* write to the correct TX-register */
|
|
/* write to the correct TX-register */
|
|
if (bs->tx_len)
|
|
if (bs->tx_len)
|
|
@@ -183,6 +197,7 @@ static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id)
|
|
|
|
|
|
/* check if we have data to write */
|
|
/* check if we have data to write */
|
|
while (bs->tx_len &&
|
|
while (bs->tx_len &&
|
|
|
|
+ (bs->pending < 12) &&
|
|
(!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) &
|
|
(!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) &
|
|
BCM2835_AUX_SPI_STAT_TX_FULL))) {
|
|
BCM2835_AUX_SPI_STAT_TX_FULL))) {
|
|
bcm2835aux_wr_fifo(bs);
|
|
bcm2835aux_wr_fifo(bs);
|
|
@@ -234,6 +249,7 @@ static int bcm2835aux_spi_transfer_one_irq(struct spi_master *master,
|
|
|
|
|
|
/* fill in tx fifo with data before enabling interrupts */
|
|
/* fill in tx fifo with data before enabling interrupts */
|
|
while ((bs->tx_len) &&
|
|
while ((bs->tx_len) &&
|
|
|
|
+ (bs->pending < 12) &&
|
|
(!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) &
|
|
(!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_STAT) &
|
|
BCM2835_AUX_SPI_STAT_TX_FULL))) {
|
|
BCM2835_AUX_SPI_STAT_TX_FULL))) {
|
|
bcm2835aux_wr_fifo(bs);
|
|
bcm2835aux_wr_fifo(bs);
|
|
@@ -245,8 +261,7 @@ static int bcm2835aux_spi_transfer_one_irq(struct spi_master *master,
|
|
|
|
|
|
static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master,
|
|
static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master,
|
|
struct spi_device *spi,
|
|
struct spi_device *spi,
|
|
- struct spi_transfer *tfr,
|
|
|
|
- unsigned long xfer_time_us)
|
|
|
|
|
|
+ struct spi_transfer *tfr)
|
|
{
|
|
{
|
|
struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
|
|
struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
|
|
unsigned long timeout;
|
|
unsigned long timeout;
|
|
@@ -305,7 +320,8 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
|
|
{
|
|
{
|
|
struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
|
|
struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
|
|
unsigned long spi_hz, clk_hz, speed;
|
|
unsigned long spi_hz, clk_hz, speed;
|
|
- unsigned long spi_used_hz, xfer_time_us;
|
|
|
|
|
|
+ unsigned long spi_used_hz;
|
|
|
|
+ unsigned long long xfer_time_us;
|
|
|
|
|
|
/* calculate the registers to handle
|
|
/* calculate the registers to handle
|
|
*
|
|
*
|
|
@@ -348,16 +364,19 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
|
|
bs->rx_buf = tfr->rx_buf;
|
|
bs->rx_buf = tfr->rx_buf;
|
|
bs->tx_len = tfr->len;
|
|
bs->tx_len = tfr->len;
|
|
bs->rx_len = tfr->len;
|
|
bs->rx_len = tfr->len;
|
|
|
|
+ bs->pending = 0;
|
|
|
|
|
|
- /* calculate the estimated time in us the transfer runs */
|
|
|
|
- xfer_time_us = tfr->len
|
|
|
|
- * 9 /* clocks/byte - SPI-HW waits 1 clock after each byte */
|
|
|
|
- * 1000000 / spi_used_hz;
|
|
|
|
|
|
+ /* calculate the estimated time in us the transfer runs
|
|
|
|
+ * note that there are are 2 idle clocks after each
|
|
|
|
+ * chunk getting transferred - in our case the chunk size
|
|
|
|
+ * is 3 bytes, so we approximate this by 9 bits/byte
|
|
|
|
+ */
|
|
|
|
+ xfer_time_us = tfr->len * 9 * 1000000;
|
|
|
|
+ do_div(xfer_time_us, spi_used_hz);
|
|
|
|
|
|
/* run in polling mode for short transfers */
|
|
/* run in polling mode for short transfers */
|
|
if (xfer_time_us < BCM2835_AUX_SPI_POLLING_LIMIT_US)
|
|
if (xfer_time_us < BCM2835_AUX_SPI_POLLING_LIMIT_US)
|
|
- return bcm2835aux_spi_transfer_one_poll(master, spi, tfr,
|
|
|
|
- xfer_time_us);
|
|
|
|
|
|
+ return bcm2835aux_spi_transfer_one_poll(master, spi, tfr);
|
|
|
|
|
|
/* run in interrupt mode for all others */
|
|
/* run in interrupt mode for all others */
|
|
return bcm2835aux_spi_transfer_one_irq(master, spi, tfr);
|
|
return bcm2835aux_spi_transfer_one_irq(master, spi, tfr);
|