diff options
Diffstat (limited to 'drivers/spi/spi-imx.c')
-rw-r--r-- | drivers/spi/spi-imx.c | 218 |
1 files changed, 196 insertions, 22 deletions
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index f9698b7aeb3b..babb15f07995 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -56,6 +56,7 @@ /* The maximum bytes that a sdma BD can transfer.*/ #define MAX_SDMA_BD_BYTES (1 << 15) +#define MX51_ECSPI_CTRL_MAX_BURST 512 enum spi_imx_devtype { IMX1_CSPI, @@ -63,7 +64,8 @@ enum spi_imx_devtype { IMX27_CSPI, IMX31_CSPI, IMX35_CSPI, /* CSPI on all i.mx except above */ - IMX51_ECSPI, /* ECSPI on i.mx51 and later */ + IMX51_ECSPI, /* ECSPI on i.mx51 */ + IMX53_ECSPI, /* ECSPI on i.mx53 and later */ }; struct spi_imx_data; @@ -74,6 +76,9 @@ struct spi_imx_devtype_data { void (*trigger)(struct spi_imx_data *); int (*rx_available)(struct spi_imx_data *); void (*reset)(struct spi_imx_data *); + bool has_dmamode; + unsigned int fifo_size; + bool dynamic_burst; enum spi_imx_devtype devtype; }; @@ -94,12 +99,14 @@ struct spi_imx_data { unsigned int bits_per_word; unsigned int spi_drctl; - unsigned int count; + unsigned int count, remainder; void (*tx)(struct spi_imx_data *); void (*rx)(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 word_mask; /* DMA */ bool usedma; @@ -125,9 +132,9 @@ static inline int is_imx51_ecspi(struct spi_imx_data *d) return d->devtype_data->devtype == IMX51_ECSPI; } -static inline unsigned spi_imx_get_fifosize(struct spi_imx_data *d) +static inline int is_imx53_ecspi(struct spi_imx_data *d) { - return is_imx51_ecspi(d) ? 64 : 8; + return d->devtype_data->devtype == IMX53_ECSPI; } #define MXC_SPI_BUF_RX(type) \ @@ -219,7 +226,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4) return false; - for (i = spi_imx_get_fifosize(spi_imx) / 2; i > 0; i--) { + for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) { if (!(transfer->len % (i * bytes_per_word))) break; } @@ -228,6 +235,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, return false; spi_imx->wml = i; + spi_imx->dynamic_burst = 0; return true; } @@ -242,6 +250,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, #define MX51_ECSPI_CTRL_PREDIV_OFFSET 12 #define MX51_ECSPI_CTRL_CS(cs) ((cs) << 18) #define MX51_ECSPI_CTRL_BL_OFFSET 20 +#define MX51_ECSPI_CTRL_BL_MASK (0xfff << 20) #define MX51_ECSPI_CONFIG 0x0c #define MX51_ECSPI_CONFIG_SCLKPHA(cs) (1 << ((cs) + 0)) @@ -269,6 +278,106 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, #define MX51_ECSPI_TESTREG 0x20 #define MX51_ECSPI_TESTREG_LBC BIT(31) +static void spi_imx_buf_rx_swap_u32(struct spi_imx_data *spi_imx) +{ + unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA); +#ifdef __LITTLE_ENDIAN + unsigned int bytes_per_word; +#endif + + if (spi_imx->rx_buf) { +#ifdef __LITTLE_ENDIAN + bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word); + if (bytes_per_word == 1) + val = cpu_to_be32(val); + else if (bytes_per_word == 2) + val = (val << 16) | (val >> 16); +#endif + val &= spi_imx->word_mask; + *(u32 *)spi_imx->rx_buf = val; + spi_imx->rx_buf += sizeof(u32); + } +} + +static void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx) +{ + unsigned int bytes_per_word; + + bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word); + if (spi_imx->read_u32) { + 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) + spi_imx_buf_rx_u16(spi_imx); +} + +static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx) +{ + u32 val = 0; +#ifdef __LITTLE_ENDIAN + unsigned int bytes_per_word; +#endif + + if (spi_imx->tx_buf) { + val = *(u32 *)spi_imx->tx_buf; + val &= spi_imx->word_mask; + spi_imx->tx_buf += sizeof(u32); + } + + spi_imx->count -= sizeof(u32); +#ifdef __LITTLE_ENDIAN + bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word); + + if (bytes_per_word == 1) + val = cpu_to_be32(val); + else if (bytes_per_word == 2) + val = (val << 16) | (val >> 16); +#endif + writel(val, spi_imx->base + MXC_CSPITXDATA); +} + +static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx) +{ + u32 ctrl, val; + unsigned int bytes_per_word; + + 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; + } + + ctrl |= (val << MX51_ECSPI_CTRL_BL_OFFSET); + writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); + } + + if (spi_imx->count >= sizeof(u32)) { + 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) + spi_imx_buf_tx_u16(spi_imx); +} + /* MX51 eCSPI */ static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx, unsigned int fspi, unsigned int *fres) @@ -513,8 +622,8 @@ static int mx31_config(struct spi_device *spi) reg |= MX31_CSPICTRL_POL; if (spi->mode & SPI_CS_HIGH) reg |= MX31_CSPICTRL_SSPOL; - if (spi->cs_gpio < 0) - reg |= (spi->cs_gpio + 32) << + if (!gpio_is_valid(spi->cs_gpio)) + reg |= (spi->chip_select) << (is_imx35_cspi(spi_imx) ? MX35_CSPICTRL_CS_SHIFT : MX31_CSPICTRL_CS_SHIFT); @@ -605,8 +714,8 @@ static int mx21_config(struct spi_device *spi) reg |= MX21_CSPICTRL_POL; if (spi->mode & SPI_CS_HIGH) reg |= MX21_CSPICTRL_SSPOL; - if (spi->cs_gpio < 0) - reg |= (spi->cs_gpio + 32) << MX21_CSPICTRL_CS_SHIFT; + if (!gpio_is_valid(spi->cs_gpio)) + reg |= spi->chip_select << MX21_CSPICTRL_CS_SHIFT; writel(reg, spi_imx->base + MXC_CSPICTRL); @@ -693,6 +802,9 @@ static struct spi_imx_devtype_data imx1_cspi_devtype_data = { .trigger = mx1_trigger, .rx_available = mx1_rx_available, .reset = mx1_reset, + .fifo_size = 8, + .has_dmamode = false, + .dynamic_burst = false, .devtype = IMX1_CSPI, }; @@ -702,6 +814,9 @@ static struct spi_imx_devtype_data imx21_cspi_devtype_data = { .trigger = mx21_trigger, .rx_available = mx21_rx_available, .reset = mx21_reset, + .fifo_size = 8, + .has_dmamode = false, + .dynamic_burst = false, .devtype = IMX21_CSPI, }; @@ -712,6 +827,9 @@ static struct spi_imx_devtype_data imx27_cspi_devtype_data = { .trigger = mx21_trigger, .rx_available = mx21_rx_available, .reset = mx21_reset, + .fifo_size = 8, + .has_dmamode = false, + .dynamic_burst = false, .devtype = IMX27_CSPI, }; @@ -721,6 +839,9 @@ static struct spi_imx_devtype_data imx31_cspi_devtype_data = { .trigger = mx31_trigger, .rx_available = mx31_rx_available, .reset = mx31_reset, + .fifo_size = 8, + .has_dmamode = false, + .dynamic_burst = false, .devtype = IMX31_CSPI, }; @@ -731,6 +852,9 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = { .trigger = mx31_trigger, .rx_available = mx31_rx_available, .reset = mx31_reset, + .fifo_size = 8, + .has_dmamode = true, + .dynamic_burst = false, .devtype = IMX35_CSPI, }; @@ -740,9 +864,23 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = { .trigger = mx51_ecspi_trigger, .rx_available = mx51_ecspi_rx_available, .reset = mx51_ecspi_reset, + .fifo_size = 64, + .has_dmamode = true, + .dynamic_burst = true, .devtype = IMX51_ECSPI, }; +static struct spi_imx_devtype_data imx53_ecspi_devtype_data = { + .intctrl = mx51_ecspi_intctrl, + .config = mx51_ecspi_config, + .trigger = mx51_ecspi_trigger, + .rx_available = mx51_ecspi_rx_available, + .reset = mx51_ecspi_reset, + .fifo_size = 64, + .has_dmamode = true, + .devtype = IMX53_ECSPI, +}; + static const struct platform_device_id spi_imx_devtype[] = { { .name = "imx1-cspi", @@ -763,6 +901,9 @@ static const struct platform_device_id spi_imx_devtype[] = { .name = "imx51-ecspi", .driver_data = (kernel_ulong_t) &imx51_ecspi_devtype_data, }, { + .name = "imx53-ecspi", + .driver_data = (kernel_ulong_t) &imx53_ecspi_devtype_data, + }, { /* sentinel */ } }; @@ -774,6 +915,7 @@ static const struct of_device_id spi_imx_dt_ids[] = { { .compatible = "fsl,imx31-cspi", .data = &imx31_cspi_devtype_data, }, { .compatible = "fsl,imx35-cspi", .data = &imx35_cspi_devtype_data, }, { .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, }, + { .compatible = "fsl,imx53-ecspi", .data = &imx53_ecspi_devtype_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, spi_imx_dt_ids); @@ -783,6 +925,9 @@ static void spi_imx_chipselect(struct spi_device *spi, int is_active) int active = is_active != BITBANG_CS_INACTIVE; int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH); + if (spi->mode & SPI_NO_CS) + return; + if (!gpio_is_valid(spi->cs_gpio)) return; @@ -791,9 +936,11 @@ static void spi_imx_chipselect(struct spi_device *spi, int is_active) static void spi_imx_push(struct spi_imx_data *spi_imx) { - while (spi_imx->txfifo < spi_imx_get_fifosize(spi_imx)) { + 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)) + break; spi_imx->tx(spi_imx); spi_imx->txfifo++; } @@ -887,15 +1034,37 @@ static int spi_imx_setupxfer(struct spi_device *spi, spi_imx->speed_hz = t->speed_hz; /* Initialize the functions for transfer */ - if (spi_imx->bits_per_word <= 8) { - spi_imx->rx = spi_imx_buf_rx_u8; - spi_imx->tx = spi_imx_buf_tx_u8; - } else if (spi_imx->bits_per_word <= 16) { - spi_imx->rx = spi_imx_buf_rx_u16; - spi_imx->tx = spi_imx_buf_tx_u16; + if (spi_imx->devtype_data->dynamic_burst) { + u32 mask; + + spi_imx->dynamic_burst = 0; + spi_imx->remainder = 0; + spi_imx->read_u32 = 1; + + mask = (1 << spi_imx->bits_per_word) - 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; + + if (spi_imx->bits_per_word <= 8) + spi_imx->word_mask = mask << 24 | mask << 16 + | mask << 8 | mask; + else if (spi_imx->bits_per_word <= 16) + spi_imx->word_mask = mask << 16 | mask; + else + spi_imx->word_mask = mask; } else { - spi_imx->rx = spi_imx_buf_rx_u32; - spi_imx->tx = spi_imx_buf_tx_u32; + if (spi_imx->bits_per_word <= 8) { + spi_imx->rx = spi_imx_buf_rx_u8; + spi_imx->tx = spi_imx_buf_tx_u8; + } else if (spi_imx->bits_per_word <= 16) { + spi_imx->rx = spi_imx_buf_rx_u16; + spi_imx->tx = spi_imx_buf_tx_u16; + } else { + spi_imx->rx = spi_imx_buf_rx_u32; + spi_imx->tx = spi_imx_buf_tx_u32; + } } if (spi_imx_can_dma(spi_imx->bitbang.master, spi, t)) @@ -938,7 +1107,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx, if (of_machine_is_compatible("fsl,imx6dl")) return 0; - spi_imx->wml = spi_imx_get_fifosize(spi_imx) / 2; + spi_imx->wml = spi_imx->devtype_data->fifo_size / 2; /* Prepare for TX DMA: */ master->dma_tx = dma_request_slave_channel_reason(dev, "tx"); @@ -1109,6 +1278,9 @@ static int spi_imx_setup(struct spi_device *spi) dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__, spi->mode, spi->bits_per_word, spi->max_speed_hz); + if (spi->mode & SPI_NO_CS) + return 0; + if (gpio_is_valid(spi->cs_gpio)) gpio_direction_output(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); @@ -1208,8 +1380,10 @@ static int spi_imx_probe(struct platform_device *pdev) spi_imx->bitbang.master->cleanup = spi_imx_cleanup; spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message; spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message; - spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; - if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx)) + spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ + | SPI_NO_CS; + if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) || + is_imx53_ecspi(spi_imx)) spi_imx->bitbang.master->mode_bits |= SPI_LOOP | SPI_READY; spi_imx->spi_drctl = spi_drctl; @@ -1262,7 +1436,7 @@ static int spi_imx_probe(struct platform_device *pdev) * Only validated on i.mx35 and i.mx6 now, can remove the constraint * if validated on other chips. */ - if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx)) { + if (spi_imx->devtype_data->has_dmamode) { ret = spi_imx_sdma_init(&pdev->dev, spi_imx, master); if (ret == -EPROBE_DEFER) goto out_clk_put; |