|
@@ -86,6 +86,7 @@
|
|
|
#define SIRFSOC_SPI_TX_DONE BIT(1)
|
|
#define SIRFSOC_SPI_TX_DONE BIT(1)
|
|
|
#define SIRFSOC_SPI_RX_OFLOW BIT(2)
|
|
#define SIRFSOC_SPI_RX_OFLOW BIT(2)
|
|
|
#define SIRFSOC_SPI_TX_UFLOW BIT(3)
|
|
#define SIRFSOC_SPI_TX_UFLOW BIT(3)
|
|
|
|
|
+#define SIRFSOC_SPI_RX_IO_DMA BIT(4)
|
|
|
#define SIRFSOC_SPI_RX_FIFO_FULL BIT(6)
|
|
#define SIRFSOC_SPI_RX_FIFO_FULL BIT(6)
|
|
|
#define SIRFSOC_SPI_TXFIFO_EMPTY BIT(7)
|
|
#define SIRFSOC_SPI_TXFIFO_EMPTY BIT(7)
|
|
|
#define SIRFSOC_SPI_RXFIFO_THD_REACH BIT(8)
|
|
#define SIRFSOC_SPI_RXFIFO_THD_REACH BIT(8)
|
|
@@ -265,41 +266,34 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
|
|
|
{
|
|
{
|
|
|
struct sirfsoc_spi *sspi = dev_id;
|
|
struct sirfsoc_spi *sspi = dev_id;
|
|
|
u32 spi_stat = readl(sspi->base + SIRFSOC_SPI_INT_STATUS);
|
|
u32 spi_stat = readl(sspi->base + SIRFSOC_SPI_INT_STATUS);
|
|
|
-
|
|
|
|
|
- writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS);
|
|
|
|
|
-
|
|
|
|
|
if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) {
|
|
if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) {
|
|
|
complete(&sspi->tx_done);
|
|
complete(&sspi->tx_done);
|
|
|
writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
|
|
writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
|
|
|
|
|
+ writel(SIRFSOC_SPI_INT_MASK_ALL,
|
|
|
|
|
+ sspi->base + SIRFSOC_SPI_INT_STATUS);
|
|
|
return IRQ_HANDLED;
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Error Conditions */
|
|
/* Error Conditions */
|
|
|
if (spi_stat & SIRFSOC_SPI_RX_OFLOW ||
|
|
if (spi_stat & SIRFSOC_SPI_RX_OFLOW ||
|
|
|
spi_stat & SIRFSOC_SPI_TX_UFLOW) {
|
|
spi_stat & SIRFSOC_SPI_TX_UFLOW) {
|
|
|
|
|
+ complete(&sspi->tx_done);
|
|
|
complete(&sspi->rx_done);
|
|
complete(&sspi->rx_done);
|
|
|
writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
|
|
writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
|
|
|
|
|
+ writel(SIRFSOC_SPI_INT_MASK_ALL,
|
|
|
|
|
+ sspi->base + SIRFSOC_SPI_INT_STATUS);
|
|
|
|
|
+ return IRQ_HANDLED;
|
|
|
}
|
|
}
|
|
|
|
|
+ if (spi_stat & SIRFSOC_SPI_TXFIFO_EMPTY)
|
|
|
|
|
+ complete(&sspi->tx_done);
|
|
|
|
|
+ while (!(readl(sspi->base + SIRFSOC_SPI_INT_STATUS) &
|
|
|
|
|
+ SIRFSOC_SPI_RX_IO_DMA))
|
|
|
|
|
+ cpu_relax();
|
|
|
|
|
+ complete(&sspi->rx_done);
|
|
|
|
|
+ writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
|
|
|
|
|
+ writel(SIRFSOC_SPI_INT_MASK_ALL,
|
|
|
|
|
+ sspi->base + SIRFSOC_SPI_INT_STATUS);
|
|
|
|
|
|
|
|
- if (spi_stat & (SIRFSOC_SPI_FRM_END
|
|
|
|
|
- | SIRFSOC_SPI_RXFIFO_THD_REACH))
|
|
|
|
|
- while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS)
|
|
|
|
|
- & SIRFSOC_SPI_FIFO_EMPTY)) &&
|
|
|
|
|
- sspi->left_rx_word)
|
|
|
|
|
- sspi->rx_word(sspi);
|
|
|
|
|
-
|
|
|
|
|
- if (spi_stat & (SIRFSOC_SPI_TXFIFO_EMPTY |
|
|
|
|
|
- SIRFSOC_SPI_TXFIFO_THD_REACH))
|
|
|
|
|
- while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS)
|
|
|
|
|
- & SIRFSOC_SPI_FIFO_FULL)) &&
|
|
|
|
|
- sspi->left_tx_word)
|
|
|
|
|
- sspi->tx_word(sspi);
|
|
|
|
|
-
|
|
|
|
|
- /* Received all words */
|
|
|
|
|
- if ((sspi->left_rx_word == 0) && (sspi->left_tx_word == 0)) {
|
|
|
|
|
- complete(&sspi->rx_done);
|
|
|
|
|
- writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
|
|
|
|
|
- }
|
|
|
|
|
return IRQ_HANDLED;
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -420,32 +414,45 @@ static void spi_sirfsoc_pio_transfer(struct spi_device *spi,
|
|
|
int timeout = t->len * 10;
|
|
int timeout = t->len * 10;
|
|
|
|
|
|
|
|
sspi = spi_master_get_devdata(spi->master);
|
|
sspi = spi_master_get_devdata(spi->master);
|
|
|
- writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
|
|
|
|
|
- writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
|
|
|
|
|
- writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
|
|
|
|
|
- writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
|
|
|
|
|
- writel(0, sspi->base + SIRFSOC_SPI_INT_EN);
|
|
|
|
|
- writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS);
|
|
|
|
|
- writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | SIRFSOC_SPI_MUL_DAT_MODE |
|
|
|
|
|
- SIRFSOC_SPI_ENA_AUTO_CLR, sspi->base + SIRFSOC_SPI_CTRL);
|
|
|
|
|
- writel(sspi->left_tx_word - 1,
|
|
|
|
|
- sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN);
|
|
|
|
|
- writel(sspi->left_rx_word - 1,
|
|
|
|
|
- sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN);
|
|
|
|
|
- sspi->tx_word(sspi);
|
|
|
|
|
- writel(SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN | SIRFSOC_SPI_TX_UFLOW_INT_EN |
|
|
|
|
|
- SIRFSOC_SPI_RX_OFLOW_INT_EN | SIRFSOC_SPI_RXFIFO_THD_INT_EN |
|
|
|
|
|
- SIRFSOC_SPI_TXFIFO_THD_INT_EN | SIRFSOC_SPI_FRM_END_INT_EN|
|
|
|
|
|
- SIRFSOC_SPI_RXFIFO_FULL_INT_EN,
|
|
|
|
|
- sspi->base + SIRFSOC_SPI_INT_EN);
|
|
|
|
|
- writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN,
|
|
|
|
|
|
|
+ do {
|
|
|
|
|
+ writel(SIRFSOC_SPI_FIFO_RESET,
|
|
|
|
|
+ sspi->base + SIRFSOC_SPI_RXFIFO_OP);
|
|
|
|
|
+ writel(SIRFSOC_SPI_FIFO_RESET,
|
|
|
|
|
+ sspi->base + SIRFSOC_SPI_TXFIFO_OP);
|
|
|
|
|
+ writel(SIRFSOC_SPI_FIFO_START,
|
|
|
|
|
+ sspi->base + SIRFSOC_SPI_RXFIFO_OP);
|
|
|
|
|
+ writel(SIRFSOC_SPI_FIFO_START,
|
|
|
|
|
+ sspi->base + SIRFSOC_SPI_TXFIFO_OP);
|
|
|
|
|
+ writel(0, sspi->base + SIRFSOC_SPI_INT_EN);
|
|
|
|
|
+ writel(SIRFSOC_SPI_INT_MASK_ALL,
|
|
|
|
|
+ sspi->base + SIRFSOC_SPI_INT_STATUS);
|
|
|
|
|
+ writel(readl(sspi->base + SIRFSOC_SPI_CTRL) |
|
|
|
|
|
+ SIRFSOC_SPI_MUL_DAT_MODE | SIRFSOC_SPI_ENA_AUTO_CLR,
|
|
|
|
|
+ sspi->base + SIRFSOC_SPI_CTRL);
|
|
|
|
|
+ writel(min(sspi->left_tx_word, (u32)(256 / sspi->word_width))
|
|
|
|
|
+ - 1, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN);
|
|
|
|
|
+ writel(min(sspi->left_rx_word, (u32)(256 / sspi->word_width))
|
|
|
|
|
+ - 1, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN);
|
|
|
|
|
+ while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS)
|
|
|
|
|
+ & SIRFSOC_SPI_FIFO_FULL)) && sspi->left_tx_word)
|
|
|
|
|
+ sspi->tx_word(sspi);
|
|
|
|
|
+ writel(SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN |
|
|
|
|
|
+ SIRFSOC_SPI_TX_UFLOW_INT_EN |
|
|
|
|
|
+ SIRFSOC_SPI_RX_OFLOW_INT_EN,
|
|
|
|
|
+ sspi->base + SIRFSOC_SPI_INT_EN);
|
|
|
|
|
+ writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN,
|
|
|
sspi->base + SIRFSOC_SPI_TX_RX_EN);
|
|
sspi->base + SIRFSOC_SPI_TX_RX_EN);
|
|
|
- if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0)
|
|
|
|
|
- dev_err(&spi->dev, "transfer timeout\n");
|
|
|
|
|
- writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
|
|
|
|
|
- writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
|
|
|
|
|
- writel(0, sspi->base + SIRFSOC_SPI_TX_RX_EN);
|
|
|
|
|
- writel(0, sspi->base + SIRFSOC_SPI_INT_EN);
|
|
|
|
|
|
|
+ if (!wait_for_completion_timeout(&sspi->tx_done, timeout) ||
|
|
|
|
|
+ !wait_for_completion_timeout(&sspi->rx_done, timeout)) {
|
|
|
|
|
+ dev_err(&spi->dev, "transfer timeout\n");
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS)
|
|
|
|
|
+ & SIRFSOC_SPI_FIFO_EMPTY)) && sspi->left_rx_word)
|
|
|
|
|
+ sspi->rx_word(sspi);
|
|
|
|
|
+ writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
|
|
|
|
|
+ writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
|
|
|
|
|
+ } while (sspi->left_tx_word != 0 || sspi->left_rx_word != 0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)
|
|
static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)
|