diff --git a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt index 31b5b21598ff..5bf13960f7f4 100644 --- a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt +++ b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt @@ -9,6 +9,7 @@ Required properties: - "fsl,imx31-cspi" for SPI compatible with the one integrated on i.MX31 - "fsl,imx35-cspi" for SPI compatible with the one integrated on i.MX35 - "fsl,imx51-ecspi" for SPI compatible with the one integrated on i.MX51 + - "fsl,imx53-ecspi" for SPI compatible with the one integrated on i.MX53 and later Soc - reg : Offset and length of the register set for the device - interrupts : Should contain CSPI/eCSPI interrupt - cs-gpios : Specifies the gpio pins to be used for chipselects. 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", @@ -762,6 +900,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; diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index 3459965004f8..bed7403bb6b3 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -32,39 +32,50 @@ #include "spi-test.h" /* flag to only simulate transfers */ -int simulate_only; +static int simulate_only; module_param(simulate_only, int, 0); MODULE_PARM_DESC(simulate_only, "if not 0 do not execute the spi message"); /* dump spi messages */ -int dump_messages; +static int dump_messages; module_param(dump_messages, int, 0); MODULE_PARM_DESC(dump_messages, "=1 dump the basic spi_message_structure, " \ "=2 dump the spi_message_structure including data, " \ "=3 dump the spi_message structure before and after execution"); /* the device is jumpered for loopback - enabling some rx_buf tests */ -int loopback; +static int loopback; module_param(loopback, int, 0); MODULE_PARM_DESC(loopback, "if set enable loopback mode, where the rx_buf " \ "is checked to match tx_buf after the spi_message " \ "is executed"); +static int loop_req; +module_param(loop_req, int, 0); +MODULE_PARM_DESC(loop_req, + "if set controller will be asked to enable test loop mode. " \ + "If controller supported it, MISO and MOSI will be connected"); + +static int no_cs; +module_param(no_cs, int, 0); +MODULE_PARM_DESC(no_cs, + "if set Chip Select (CS) will not be used"); + /* run only a specific test */ -int run_only_test = -1; +static int run_only_test = -1; module_param(run_only_test, int, 0); MODULE_PARM_DESC(run_only_test, "only run the test with this number (0-based !)"); /* use vmalloc'ed buffers */ -int use_vmalloc; +static int use_vmalloc; module_param(use_vmalloc, int, 0644); MODULE_PARM_DESC(use_vmalloc, "use vmalloc'ed buffers instead of kmalloc'ed"); /* check rx ranges */ -int check_ranges = 1; +static int check_ranges = 1; module_param(check_ranges, int, 0644); MODULE_PARM_DESC(check_ranges, "checks rx_buffer pattern are valid"); @@ -313,6 +324,17 @@ static int spi_loopback_test_probe(struct spi_device *spi) { int ret; + if (loop_req || no_cs) { + spi->mode |= loop_req ? SPI_LOOP : 0; + spi->mode |= no_cs ? SPI_NO_CS : 0; + ret = spi_setup(spi); + if (ret) { + dev_err(&spi->dev, "SPI setup with SPI_LOOP or SPI_NO_CS failed (%d)\n", + ret); + return ret; + } + } + dev_info(&spi->dev, "Executing spi-loopback-tests\n"); ret = spi_test_run_tests(spi, spi_tests); diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index e048268d8ba2..9bf64e6eca9b 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1338,7 +1338,6 @@ static int omap2_mcspi_probe(struct platform_device *pdev) struct resource *r; int status = 0, i; u32 regs_offset = 0; - static int bus_num = 1; struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; @@ -1374,14 +1373,11 @@ static int omap2_mcspi_probe(struct platform_device *pdev) of_property_read_u32(node, "ti,spi-num-cs", &num_cs); master->num_chipselect = num_cs; - master->bus_num = bus_num++; if (of_get_property(node, "ti,pindir-d0-out-d1-in", NULL)) mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; } else { pdata = dev_get_platdata(&pdev->dev); master->num_chipselect = pdata->num_cs; - if (pdev->id != -1) - master->bus_num = pdev->id; mcspi->pin_dir = pdata->pin_dir; } regs_offset = pdata->regs_offset; diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c index fefb688a3432..f8a45af1fa9f 100644 --- a/drivers/spi/spi-pic32.c +++ b/drivers/spi/spi-pic32.c @@ -52,14 +52,14 @@ struct pic32_spi_regs { /* Bit fields of SPI Control Register */ #define CTRL_RX_INT_SHIFT 0 /* Rx interrupt generation */ -#define RX_FIFO_EMTPY 0 +#define RX_FIFO_EMPTY 0 #define RX_FIFO_NOT_EMPTY 1 /* not empty */ #define RX_FIFO_HALF_FULL 2 /* full by half or more */ #define RX_FIFO_FULL 3 /* completely full */ #define CTRL_TX_INT_SHIFT 2 /* TX interrupt generation */ #define TX_FIFO_ALL_EMPTY 0 /* completely empty */ -#define TX_FIFO_EMTPY 1 /* empty */ +#define TX_FIFO_EMPTY 1 /* empty */ #define TX_FIFO_HALF_EMPTY 2 /* empty by half or more */ #define TX_FIFO_NOT_FULL 3 /* atleast one empty */ diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 2f76e022cc59..4797c57f4263 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2429,7 +2429,7 @@ static struct vendor_data vendor_lsi = { .internal_cs_ctrl = true, }; -static struct amba_id pl022_ids[] = { +static const struct amba_id pl022_ids[] = { { /* * ARM PL022 variant, this has a 16bit wide