diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index ef6d3648396a..08dd3a31a3e5 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -94,7 +94,7 @@ struct spi_imx_data { void *rx_buf; const void *tx_buf; unsigned int txfifo; /* number of words pushed in tx FIFO */ - unsigned int dynamic_burst, read_u32; + unsigned int dynamic_burst; /* Slave mode */ bool slave_mode; @@ -139,6 +139,8 @@ static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx) \ *(type *)spi_imx->rx_buf = val; \ spi_imx->rx_buf += sizeof(type); \ } \ + \ + spi_imx->remainder -= sizeof(type); \ } #define MXC_SPI_BUF_TX(type) \ @@ -292,22 +294,36 @@ static void spi_imx_buf_rx_swap_u32(struct spi_imx_data *spi_imx) *(u32 *)spi_imx->rx_buf = val; spi_imx->rx_buf += sizeof(u32); } + + spi_imx->remainder -= sizeof(u32); } static void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx) { - unsigned int bytes_per_word; + int unaligned; + u32 val; - bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word); - if (spi_imx->read_u32) { + unaligned = spi_imx->remainder % 4; + + if (!unaligned) { spi_imx_buf_rx_swap_u32(spi_imx); return; } - if (bytes_per_word == 1) - spi_imx_buf_rx_u8(spi_imx); - else if (bytes_per_word == 2) + if (spi_imx_bytes_per_word(spi_imx->bits_per_word) == 2) { spi_imx_buf_rx_u16(spi_imx); + return; + } + + val = readl(spi_imx->base + MXC_CSPIRXDATA); + + while (unaligned--) { + if (spi_imx->rx_buf) { + *(u8 *)spi_imx->rx_buf = (val >> (8 * unaligned)) & 0xff; + spi_imx->rx_buf++; + } + spi_imx->remainder--; + } } static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx) @@ -336,40 +352,30 @@ static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx) static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx) { - u32 ctrl, val; - unsigned int bytes_per_word; + int unaligned; + u32 val = 0; - if (spi_imx->count == spi_imx->remainder) { - ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL); - ctrl &= ~MX51_ECSPI_CTRL_BL_MASK; - if (spi_imx->count > MX51_ECSPI_CTRL_MAX_BURST) { - spi_imx->remainder = spi_imx->count % - MX51_ECSPI_CTRL_MAX_BURST; - val = MX51_ECSPI_CTRL_MAX_BURST * 8 - 1; - } else if (spi_imx->count >= sizeof(u32)) { - spi_imx->remainder = spi_imx->count % sizeof(u32); - val = (spi_imx->count - spi_imx->remainder) * 8 - 1; - } else { - spi_imx->remainder = 0; - val = spi_imx->bits_per_word - 1; - spi_imx->read_u32 = 0; - } + unaligned = spi_imx->count % 4; - ctrl |= (val << MX51_ECSPI_CTRL_BL_OFFSET); - writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); - } - - if (spi_imx->count >= sizeof(u32)) { + if (!unaligned) { spi_imx_buf_tx_swap_u32(spi_imx); return; } - bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word); - - if (bytes_per_word == 1) - spi_imx_buf_tx_u8(spi_imx); - else if (bytes_per_word == 2) + if (spi_imx_bytes_per_word(spi_imx->bits_per_word) == 2) { spi_imx_buf_tx_u16(spi_imx); + return; + } + + while (unaligned--) { + if (spi_imx->tx_buf) { + val |= *(u8 *)spi_imx->tx_buf << (8 * unaligned); + spi_imx->tx_buf++; + } + spi_imx->count--; + } + + writel(val, spi_imx->base + MXC_CSPITXDATA); } static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx) @@ -388,6 +394,8 @@ static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx) spi_imx->rx_buf += n_bytes; spi_imx->slave_burst -= n_bytes; } + + spi_imx->remainder -= sizeof(u32); } static void mx53_ecspi_tx_slave(struct spi_imx_data *spi_imx) @@ -997,12 +1005,52 @@ static void spi_imx_chipselect(struct spi_device *spi, int is_active) gpio_set_value(spi->cs_gpio, dev_is_lowactive ^ active); } +static void spi_imx_set_burst_len(struct spi_imx_data *spi_imx, int n_bits) +{ + u32 ctrl; + + ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL); + ctrl &= ~MX51_ECSPI_CTRL_BL_MASK; + ctrl |= ((n_bits - 1) << MX51_ECSPI_CTRL_BL_OFFSET); + writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); +} + static void spi_imx_push(struct spi_imx_data *spi_imx) { + unsigned int burst_len, fifo_words; + + if (spi_imx->dynamic_burst) + fifo_words = 4; + else + fifo_words = spi_imx_bytes_per_word(spi_imx->bits_per_word); + /* + * Reload the FIFO when the remaining bytes to be transferred in the + * current burst is 0. This only applies when bits_per_word is a + * multiple of 8. + */ + if (!spi_imx->remainder) { + if (spi_imx->dynamic_burst) { + + /* We need to deal unaligned data first */ + burst_len = spi_imx->count % MX51_ECSPI_CTRL_MAX_BURST; + + if (!burst_len) + burst_len = MX51_ECSPI_CTRL_MAX_BURST; + + spi_imx_set_burst_len(spi_imx, burst_len * 8); + + spi_imx->remainder = burst_len; + } else { + spi_imx->remainder = fifo_words; + } + } + while (spi_imx->txfifo < spi_imx->devtype_data->fifo_size) { if (!spi_imx->count) break; - if (spi_imx->txfifo && (spi_imx->count == spi_imx->remainder)) + if (spi_imx->dynamic_burst && + spi_imx->txfifo >= DIV_ROUND_UP(spi_imx->remainder, + fifo_words)) break; spi_imx->tx(spi_imx); spi_imx->txfifo++; @@ -1108,12 +1156,9 @@ static int spi_imx_setupxfer(struct spi_device *spi, spi_imx->bits_per_word == 16 || spi_imx->bits_per_word == 32)) { - spi_imx->read_u32 = 1; - spi_imx->rx = spi_imx_buf_rx_swap; spi_imx->tx = spi_imx_buf_tx_swap; spi_imx->dynamic_burst = 1; - spi_imx->remainder = t->len; } else { if (spi_imx->bits_per_word <= 8) { @@ -1126,6 +1171,7 @@ static int spi_imx_setupxfer(struct spi_device *spi, spi_imx->rx = spi_imx_buf_rx_u32; spi_imx->tx = spi_imx_buf_tx_u32; } + spi_imx->dynamic_burst = 0; } if (spi_imx_can_dma(spi_imx->bitbang.master, spi, t)) @@ -1309,6 +1355,7 @@ static int spi_imx_pio_transfer(struct spi_device *spi, spi_imx->rx_buf = transfer->rx_buf; spi_imx->count = transfer->len; spi_imx->txfifo = 0; + spi_imx->remainder = 0; reinit_completion(&spi_imx->xfer_done); @@ -1346,6 +1393,7 @@ static int spi_imx_pio_transfer_slave(struct spi_device *spi, spi_imx->rx_buf = transfer->rx_buf; spi_imx->count = transfer->len; spi_imx->txfifo = 0; + spi_imx->remainder = 0; reinit_completion(&spi_imx->xfer_done); spi_imx->slave_aborted = false;