diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2017-05-17 12:01:25 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2017-05-17 12:01:25 +1000 |
commit | 802dd094490db30ffc8ac399a5f758975946a82a (patch) | |
tree | 870eb39176f6270f155abf64d24faf8e4e820b49 | |
parent | da401eef36de0e4ce12f013946410d0fb8008322 (diff) | |
parent | a645312f10e87fa1d692b4153fb4bc8de51d54f6 (diff) |
Merge remote-tracking branch 'spi/for-next'
-rw-r--r-- | drivers/spi/Kconfig | 1 | ||||
-rw-r--r-- | drivers/spi/spi-bcm63xx-hsspi.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-imx.c | 157 | ||||
-rw-r--r-- | drivers/spi/spi.c | 6 | ||||
-rw-r--r-- | drivers/spi/spidev.c | 11 |
5 files changed, 155 insertions, 21 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 1761c9004fc1..097883362036 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -457,6 +457,7 @@ config SPI_OMAP24XX config SPI_TI_QSPI tristate "DRA7xxx QSPI controller support" + depends on HAS_DMA depends on ARCH_OMAP2PLUS || COMPILE_TEST help QSPI master controller for DRA7xxx used for flash devices. diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index 5514cd02e93a..4da2d4a524ca 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -484,6 +484,7 @@ static const struct of_device_id bcm63xx_hsspi_of_match[] = { { .compatible = "brcm,bcm6328-hsspi", }, { }, }; +MODULE_DEVICE_TABLE(of, bcm63xx_hsspi_of_match); static struct platform_driver bcm63xx_hsspi_driver = { .driver = { diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index b402530a7a9a..782045f0d79e 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -56,9 +56,11 @@ /* The maximum bytes that a sdma BD can transfer.*/ #define MAX_SDMA_BD_BYTES (1 << 15) +#define MX51_ECSPI_CTRL_MAX_BURST 512 struct spi_imx_config { unsigned int speed_hz; unsigned int bpw; + unsigned int len; }; enum spi_imx_devtype { @@ -97,12 +99,14 @@ struct spi_imx_data { unsigned int bytes_per_word; unsigned int spi_drctl; - unsigned int count; + unsigned int count, count_index; 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, bpw_rx; + unsigned int bpw_w; /* DMA */ bool usedma; @@ -252,6 +256,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)) @@ -279,6 +284,71 @@ 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_u32_swap_u8(struct spi_transfer *transfer, u32 *buf) +{ + int i; + + for (i = 0; i < transfer->len / 4; i++) + *(buf + i) = cpu_to_be32(*(buf + i)); +} + +static void spi_imx_u32_swap_u16(struct spi_transfer *transfer, u32 *buf) +{ + int i; + + for (i = 0; i < transfer->len / 4; i++) { + u16 *temp = (u16 *)buf; + + *(temp + i * 2) = cpu_to_be16(*(temp + i * 2)); + *(temp + i * 2 + 1) = cpu_to_be16(*(temp + i * 2 + 1)); + + *(buf + i) = cpu_to_be32(*(buf + i)); + } +} + +static void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx) +{ + if (!spi_imx->bpw_rx) { + spi_imx_buf_rx_u32(spi_imx); + return; + } + + if (spi_imx->bpw_w == 1) + spi_imx_buf_rx_u8(spi_imx); + else if (spi_imx->bpw_w == 2) + spi_imx_buf_rx_u16(spi_imx); +} + +static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx) +{ + u32 ctrl, val; + + if (spi_imx->count == spi_imx->count_index) { + spi_imx->count_index = spi_imx->count > sizeof(u32) ? + spi_imx->count % sizeof(u32) : 0; + ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL); + ctrl &= ~MX51_ECSPI_CTRL_BL_MASK; + if (spi_imx->count >= sizeof(u32)) { + val = spi_imx->count - spi_imx->count_index; + } else { + val = spi_imx->bpw_w; + spi_imx->bpw_rx = 1; + } + ctrl |= ((val * 8 - 1) << MX51_ECSPI_CTRL_BL_OFFSET); + writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); + } + + if (spi_imx->count >= sizeof(u32)) { + spi_imx_buf_tx_u32(spi_imx); + return; + } + + if (spi_imx->bpw_w == 1) + spi_imx_buf_tx_u8(spi_imx); + else if (spi_imx->bpw_w == 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) @@ -370,7 +440,15 @@ static int mx51_ecspi_config(struct spi_device *spi, /* set chip select to use */ ctrl |= MX51_ECSPI_CTRL_CS(spi->chip_select); - ctrl |= (config->bpw - 1) << MX51_ECSPI_CTRL_BL_OFFSET; + if (spi_imx->dynamic_burst) { + if (config->len > MX51_ECSPI_CTRL_MAX_BURST) + ctrl |= MX51_ECSPI_CTRL_BL_MASK; + else + ctrl |= (((config->len - config->len % 4) * 8 - 1) << + MX51_ECSPI_CTRL_BL_OFFSET); + } else { + ctrl |= (config->bpw - 1) << MX51_ECSPI_CTRL_BL_OFFSET; + } cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select); @@ -805,6 +883,8 @@ static void spi_imx_push(struct spi_imx_data *spi_imx) while (spi_imx->txfifo < spi_imx_get_fifosize(spi_imx)) { if (!spi_imx->count) break; + if (spi_imx->txfifo && (spi_imx->count == spi_imx->count_index)) + break; spi_imx->tx(spi_imx); spi_imx->txfifo++; } @@ -895,8 +975,12 @@ static int spi_imx_setupxfer(struct spi_device *spi, struct spi_imx_config config; int ret; + spi_imx->dynamic_burst = 0; + spi_imx->bpw_rx = 0; + config.bpw = t ? t->bits_per_word : spi->bits_per_word; config.speed_hz = t ? t->speed_hz : spi->max_speed_hz; + config.len = t->len; if (!config.speed_hz) config.speed_hz = spi->max_speed_hz; @@ -905,14 +989,32 @@ static int spi_imx_setupxfer(struct spi_device *spi, /* Initialize the functions for transfer */ if (config.bpw <= 8) { - spi_imx->rx = spi_imx_buf_rx_u8; - spi_imx->tx = spi_imx_buf_tx_u8; + if (t->len >= sizeof(u32) && is_imx51_ecspi(spi_imx)) { + spi_imx->dynamic_burst = 1; + spi_imx->rx = spi_imx_buf_rx_swap; + spi_imx->tx = spi_imx_buf_tx_swap; + } else { + spi_imx->rx = spi_imx_buf_rx_u8; + spi_imx->tx = spi_imx_buf_tx_u8; + } } else if (config.bpw <= 16) { - spi_imx->rx = spi_imx_buf_rx_u16; - spi_imx->tx = spi_imx_buf_tx_u16; + if (t->len >= sizeof(u32) && is_imx51_ecspi(spi_imx)) { + spi_imx->dynamic_burst = 1; + spi_imx->rx = spi_imx_buf_rx_swap; + spi_imx->tx = spi_imx_buf_tx_swap; + } else { + 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 (is_imx51_ecspi(spi_imx)) { + spi_imx->dynamic_burst = 1; + spi_imx->rx = spi_imx_buf_rx_swap; + spi_imx->tx = spi_imx_buf_tx_swap; + } 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)) @@ -920,6 +1022,8 @@ static int spi_imx_setupxfer(struct spi_device *spi, else spi_imx->usedma = 0; + spi_imx->bpw_w = DIV_ROUND_UP(config.bpw, 8); + if (spi_imx->usedma) { ret = spi_imx_dma_configure(spi->master, spi_imx_bytes_per_word(config.bpw)); @@ -1094,6 +1198,27 @@ static int spi_imx_pio_transfer(struct spi_device *spi, spi_imx->count = transfer->len; spi_imx->txfifo = 0; + if (spi_imx->dynamic_burst) { + if (spi_imx->count > MX51_ECSPI_CTRL_MAX_BURST) + spi_imx->count_index = spi_imx->count % + MX51_ECSPI_CTRL_MAX_BURST; + else + spi_imx->count_index = spi_imx->count % sizeof(u32); + + switch (spi_imx->bpw_w) { + case 1: + spi_imx_u32_swap_u8(transfer, + (u32 *)transfer->tx_buf); + break; + case 2: + spi_imx_u32_swap_u16(transfer, + (u32 *)transfer->tx_buf); + break; + default: + break; + } + } + reinit_completion(&spi_imx->xfer_done); spi_imx_push(spi_imx); @@ -1110,6 +1235,22 @@ static int spi_imx_pio_transfer(struct spi_device *spi, return -ETIMEDOUT; } + if (spi_imx->dynamic_burst) { + switch (spi_imx->bpw_w) { + case 1: + spi_imx_u32_swap_u8(transfer, + (u32 *)transfer->rx_buf); + break; + case 2: + spi_imx_u32_swap_u16(transfer, + (u32 *)transfer->rx_buf); + break; + default: + break; + } + spi_imx->dynamic_burst = 0; + } + return transfer->len; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 89254a55eb2e..6f87fec409b5 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -80,7 +80,7 @@ static ssize_t spi_master_##field##_show(struct device *dev, \ return spi_statistics_##field##_show(&master->statistics, buf); \ } \ static struct device_attribute dev_attr_spi_master_##field = { \ - .attr = { .name = file, .mode = S_IRUGO }, \ + .attr = { .name = file, .mode = 0444 }, \ .show = spi_master_##field##_show, \ }; \ static ssize_t spi_device_##field##_show(struct device *dev, \ @@ -91,7 +91,7 @@ static ssize_t spi_device_##field##_show(struct device *dev, \ return spi_statistics_##field##_show(&spi->statistics, buf); \ } \ static struct device_attribute dev_attr_spi_device_##field = { \ - .attr = { .name = file, .mode = S_IRUGO }, \ + .attr = { .name = file, .mode = 0444 }, \ .show = spi_device_##field##_show, \ } @@ -2021,7 +2021,7 @@ static void devm_spi_unregister(struct device *dev, void *res) } /** - * dev_spi_register_master - register managed SPI master controller + * devm_spi_register_master - register managed SPI master controller * @dev: device managing SPI master * @master: initialized master, originally from spi_alloc_master() * Context: can sleep diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 9a2a79a871ba..d4d2d8d9f3e7 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -99,7 +99,6 @@ MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message"); static ssize_t spidev_sync(struct spidev_data *spidev, struct spi_message *message) { - DECLARE_COMPLETION_ONSTACK(done); int status; struct spi_device *spi; @@ -325,7 +324,6 @@ static struct spi_ioc_transfer * spidev_get_ioc_message(unsigned int cmd, struct spi_ioc_transfer __user *u_ioc, unsigned *n_ioc) { - struct spi_ioc_transfer *ioc; u32 tmp; /* Check type, command number and direction */ @@ -342,14 +340,7 @@ spidev_get_ioc_message(unsigned int cmd, struct spi_ioc_transfer __user *u_ioc, return NULL; /* copy into scratch area */ - ioc = kmalloc(tmp, GFP_KERNEL); - if (!ioc) - return ERR_PTR(-ENOMEM); - if (__copy_from_user(ioc, u_ioc, tmp)) { - kfree(ioc); - return ERR_PTR(-EFAULT); - } - return ioc; + return memdup_user(u_ioc, tmp); } static long |