Loading drivers/spi/spi-fsl-espi.c +65 −14 Original line number Diff line number Diff line Loading @@ -98,6 +98,11 @@ struct fsl_espi { const void *tx; void *rx; struct list_head *m_transfers; struct spi_transfer *tx_t; unsigned int tx_pos; bool tx_done; bool swab; unsigned int rx_len; unsigned int tx_len; Loading Loading @@ -131,6 +136,12 @@ static inline void fsl_espi_write_reg(struct fsl_espi *espi, int offset, iowrite32be(val, espi->reg_base + offset); } static inline void fsl_espi_write_reg16(struct fsl_espi *espi, int offset, u16 val) { iowrite16(val, espi->reg_base + offset); } static inline void fsl_espi_write_reg8(struct fsl_espi *espi, int offset, u8 val) { Loading Loading @@ -260,24 +271,60 @@ static unsigned int fsl_espi_check_rxskip_mode(struct spi_message *m) static void fsl_espi_fill_tx_fifo(struct fsl_espi *espi, u32 events) { u32 tx_fifo_avail; unsigned int tx_left; const void *tx_buf; /* if events is zero transfer has not started and tx fifo is empty */ tx_fifo_avail = events ? SPIE_TXCNT(events) : FSL_ESPI_FIFO_SIZE; while (tx_fifo_avail >= min(4U, espi->tx_len) && espi->tx_len) if (espi->tx_len >= 4) { fsl_espi_write_reg(espi, ESPI_SPITF, *(u32 *)espi->tx); espi->tx += 4; espi->tx_len -= 4; start: tx_left = espi->tx_t->len - espi->tx_pos; tx_buf = espi->tx_t->tx_buf; while (tx_fifo_avail >= min(4U, tx_left) && tx_left) { if (tx_left >= 4) { if (!tx_buf) fsl_espi_write_reg(espi, ESPI_SPITF, 0); else if (espi->swab) fsl_espi_write_reg(espi, ESPI_SPITF, swahb32p(tx_buf + espi->tx_pos)); else fsl_espi_write_reg(espi, ESPI_SPITF, *(u32 *)(tx_buf + espi->tx_pos)); espi->tx_pos += 4; tx_left -= 4; tx_fifo_avail -= 4; } else if (tx_left >= 2 && tx_buf && espi->swab) { fsl_espi_write_reg16(espi, ESPI_SPITF, swab16p(tx_buf + espi->tx_pos)); espi->tx_pos += 2; tx_left -= 2; tx_fifo_avail -= 2; } else { fsl_espi_write_reg8(espi, ESPI_SPITF, *(u8 *)espi->tx); espi->tx += 1; espi->tx_len -= 1; if (!tx_buf) fsl_espi_write_reg8(espi, ESPI_SPITF, 0); else fsl_espi_write_reg8(espi, ESPI_SPITF, *(u8 *)(tx_buf + espi->tx_pos)); espi->tx_pos += 1; tx_left -= 1; tx_fifo_avail -= 1; } } if (!tx_left) { /* Last transfer finished, in rxskip mode only one is needed */ if (list_is_last(&espi->tx_t->transfer_list, espi->m_transfers) || espi->rxskip) { espi->tx_done = true; return; } espi->tx_t = list_next_entry(espi->tx_t, transfer_list); espi->tx_pos = 0; /* continue with next transfer if tx fifo is not full */ if (tx_fifo_avail) goto start; } } static void fsl_espi_read_rx_fifo(struct fsl_espi *espi, u32 events) { u32 rx_fifo_avail = SPIE_RXCNT(events); Loading Loading @@ -369,9 +416,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) /* Won't hang up forever, SPI bus sometimes got lost interrupts... */ ret = wait_for_completion_timeout(&espi->done, 2 * HZ); if (ret == 0) dev_err(espi->dev, "Transaction hanging up (left %u tx bytes, %u rx bytes)\n", espi->tx_len, espi->rx_len); dev_err(espi->dev, "Transfer timed out!\n"); /* disable rx ints */ fsl_espi_write_reg(espi, ESPI_SPIM, 0); Loading @@ -388,6 +433,12 @@ static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans) /* In case of LSB-first and bits_per_word > 8 byte-swap all words */ espi->swab = spi->mode & SPI_LSB_FIRST && trans->bits_per_word > 8; espi->m_transfers = &m->transfers; espi->tx_t = list_first_entry(&m->transfers, struct spi_transfer, transfer_list); espi->tx_pos = 0; espi->tx_done = false; espi->rxskip = fsl_espi_check_rxskip_mode(m); if (trans->rx_nbits == SPI_NBITS_DUAL && !espi->rxskip) { dev_err(espi->dev, "Dual output mode requires RXSKIP mode!\n"); Loading Loading @@ -508,10 +559,10 @@ static void fsl_espi_cpu_irq(struct fsl_espi *espi, u32 events) if (espi->rx_len) fsl_espi_read_rx_fifo(espi, events); if (espi->tx_len) if (!espi->tx_done) fsl_espi_fill_tx_fifo(espi, events); if (espi->tx_len || espi->rx_len) if (!espi->tx_done || espi->rx_len) return; /* we're done, but check for errors before returning */ Loading Loading
drivers/spi/spi-fsl-espi.c +65 −14 Original line number Diff line number Diff line Loading @@ -98,6 +98,11 @@ struct fsl_espi { const void *tx; void *rx; struct list_head *m_transfers; struct spi_transfer *tx_t; unsigned int tx_pos; bool tx_done; bool swab; unsigned int rx_len; unsigned int tx_len; Loading Loading @@ -131,6 +136,12 @@ static inline void fsl_espi_write_reg(struct fsl_espi *espi, int offset, iowrite32be(val, espi->reg_base + offset); } static inline void fsl_espi_write_reg16(struct fsl_espi *espi, int offset, u16 val) { iowrite16(val, espi->reg_base + offset); } static inline void fsl_espi_write_reg8(struct fsl_espi *espi, int offset, u8 val) { Loading Loading @@ -260,24 +271,60 @@ static unsigned int fsl_espi_check_rxskip_mode(struct spi_message *m) static void fsl_espi_fill_tx_fifo(struct fsl_espi *espi, u32 events) { u32 tx_fifo_avail; unsigned int tx_left; const void *tx_buf; /* if events is zero transfer has not started and tx fifo is empty */ tx_fifo_avail = events ? SPIE_TXCNT(events) : FSL_ESPI_FIFO_SIZE; while (tx_fifo_avail >= min(4U, espi->tx_len) && espi->tx_len) if (espi->tx_len >= 4) { fsl_espi_write_reg(espi, ESPI_SPITF, *(u32 *)espi->tx); espi->tx += 4; espi->tx_len -= 4; start: tx_left = espi->tx_t->len - espi->tx_pos; tx_buf = espi->tx_t->tx_buf; while (tx_fifo_avail >= min(4U, tx_left) && tx_left) { if (tx_left >= 4) { if (!tx_buf) fsl_espi_write_reg(espi, ESPI_SPITF, 0); else if (espi->swab) fsl_espi_write_reg(espi, ESPI_SPITF, swahb32p(tx_buf + espi->tx_pos)); else fsl_espi_write_reg(espi, ESPI_SPITF, *(u32 *)(tx_buf + espi->tx_pos)); espi->tx_pos += 4; tx_left -= 4; tx_fifo_avail -= 4; } else if (tx_left >= 2 && tx_buf && espi->swab) { fsl_espi_write_reg16(espi, ESPI_SPITF, swab16p(tx_buf + espi->tx_pos)); espi->tx_pos += 2; tx_left -= 2; tx_fifo_avail -= 2; } else { fsl_espi_write_reg8(espi, ESPI_SPITF, *(u8 *)espi->tx); espi->tx += 1; espi->tx_len -= 1; if (!tx_buf) fsl_espi_write_reg8(espi, ESPI_SPITF, 0); else fsl_espi_write_reg8(espi, ESPI_SPITF, *(u8 *)(tx_buf + espi->tx_pos)); espi->tx_pos += 1; tx_left -= 1; tx_fifo_avail -= 1; } } if (!tx_left) { /* Last transfer finished, in rxskip mode only one is needed */ if (list_is_last(&espi->tx_t->transfer_list, espi->m_transfers) || espi->rxskip) { espi->tx_done = true; return; } espi->tx_t = list_next_entry(espi->tx_t, transfer_list); espi->tx_pos = 0; /* continue with next transfer if tx fifo is not full */ if (tx_fifo_avail) goto start; } } static void fsl_espi_read_rx_fifo(struct fsl_espi *espi, u32 events) { u32 rx_fifo_avail = SPIE_RXCNT(events); Loading Loading @@ -369,9 +416,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) /* Won't hang up forever, SPI bus sometimes got lost interrupts... */ ret = wait_for_completion_timeout(&espi->done, 2 * HZ); if (ret == 0) dev_err(espi->dev, "Transaction hanging up (left %u tx bytes, %u rx bytes)\n", espi->tx_len, espi->rx_len); dev_err(espi->dev, "Transfer timed out!\n"); /* disable rx ints */ fsl_espi_write_reg(espi, ESPI_SPIM, 0); Loading @@ -388,6 +433,12 @@ static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans) /* In case of LSB-first and bits_per_word > 8 byte-swap all words */ espi->swab = spi->mode & SPI_LSB_FIRST && trans->bits_per_word > 8; espi->m_transfers = &m->transfers; espi->tx_t = list_first_entry(&m->transfers, struct spi_transfer, transfer_list); espi->tx_pos = 0; espi->tx_done = false; espi->rxskip = fsl_espi_check_rxskip_mode(m); if (trans->rx_nbits == SPI_NBITS_DUAL && !espi->rxskip) { dev_err(espi->dev, "Dual output mode requires RXSKIP mode!\n"); Loading Loading @@ -508,10 +559,10 @@ static void fsl_espi_cpu_irq(struct fsl_espi *espi, u32 events) if (espi->rx_len) fsl_espi_read_rx_fifo(espi, events); if (espi->tx_len) if (!espi->tx_done) fsl_espi_fill_tx_fifo(espi, events); if (espi->tx_len || espi->rx_len) if (!espi->tx_done || espi->rx_len) return; /* we're done, but check for errors before returning */ Loading