summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2017-05-17 12:01:25 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2017-05-17 12:01:25 +1000
commit802dd094490db30ffc8ac399a5f758975946a82a (patch)
tree870eb39176f6270f155abf64d24faf8e4e820b49
parentda401eef36de0e4ce12f013946410d0fb8008322 (diff)
parenta645312f10e87fa1d692b4153fb4bc8de51d54f6 (diff)
Merge remote-tracking branch 'spi/for-next'
-rw-r--r--drivers/spi/Kconfig1
-rw-r--r--drivers/spi/spi-bcm63xx-hsspi.c1
-rw-r--r--drivers/spi/spi-imx.c157
-rw-r--r--drivers/spi/spi.c6
-rw-r--r--drivers/spi/spidev.c11
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