From 589f6a90e6c5cda51ecb89799c5bff4074e9ef77 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 20 Jan 2014 23:18:45 +0800 Subject: [PATCH 01/39] spi: sc18is602: Remove sc18is602_setup() because it is done by spi core The checking for spi->mode is done in the implementation of spi_setup(). Calling sc18is602_check_transfer(spi, NULL, 0) is pointless because the code is equivent to checking if spi->max_speed_hz is 0. Note, sc18is602_check_transfer actually allows spi->max_speed_hz is 0 if t->speed_hz is set. So return error in sc18is602_setup() when spi->max_speed_hz is 0 does not make sense. Signed-off-by: Axel Lin Acked-by: Guenter Roeck Signed-off-by: Mark Brown --- drivers/spi/spi-sc18is602.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c index 121c2e1dea36..b3ac776def9b 100644 --- a/drivers/spi/spi-sc18is602.c +++ b/drivers/spi/spi-sc18is602.c @@ -245,14 +245,6 @@ error: return status; } -static int sc18is602_setup(struct spi_device *spi) -{ - if (spi->mode & ~(SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST)) - return -EINVAL; - - return sc18is602_check_transfer(spi, NULL, 0); -} - static int sc18is602_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -306,7 +298,6 @@ static int sc18is602_probe(struct i2c_client *client, master->bus_num = client->adapter->nr; master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST; master->bits_per_word_mask = SPI_BPW_MASK(8); - master->setup = sc18is602_setup; master->transfer_one_message = sc18is602_transfer_one; master->dev.of_node = np; From 8c328a262f513c042f97fcd2f2797a6d69fc0773 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 15 Jan 2014 17:07:43 +0800 Subject: [PATCH 02/39] spi: sirf: Avoid duplicate code in various bits_per_word cases Trivial cleanup to avoid duplicate code in various bits_per_word cases. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index e430689c3837..632d2b5b821f 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -459,11 +459,6 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_8; sspi->rx_word = spi_sirfsoc_rx_word_u8; sspi->tx_word = spi_sirfsoc_tx_word_u8; - txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_BYTE; - rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_BYTE; - sspi->word_width = 1; break; case 12: case 16: @@ -471,26 +466,22 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) SIRFSOC_SPI_TRAN_DAT_FORMAT_16; sspi->rx_word = spi_sirfsoc_rx_word_u16; sspi->tx_word = spi_sirfsoc_tx_word_u16; - txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_WORD; - rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_WORD; - sspi->word_width = 2; break; case 32: regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_32; sspi->rx_word = spi_sirfsoc_rx_word_u32; sspi->tx_word = spi_sirfsoc_tx_word_u32; - txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_DWORD; - rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_DWORD; - sspi->word_width = 4; break; default: BUG(); } + sspi->word_width = DIV_ROUND_UP(bits_per_word, 8); + txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | + sspi->word_width; + rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | + sspi->word_width; + if (!(spi->mode & SPI_CS_HIGH)) regval |= SIRFSOC_SPI_CS_IDLE_STAT; if (!(spi->mode & SPI_LSB_FIRST)) From 3f29588795bdd0d48f0ecc94e3ee06c128ca3300 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 16 Jan 2014 12:25:46 +0000 Subject: [PATCH 03/39] spi/s3c64xx: Use core DMA mapping code with dmaengine When using dmaengine allow the core to do the DMA mapping. We still need local mapping code for the non-dmaengine case so this doesn't save us anything for now. Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 178 ++++++++++++++++++++++---------------- 1 file changed, 103 insertions(+), 75 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 25c9bd409a87..4490e8c499c0 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -291,6 +291,81 @@ static struct s3c2410_dma_client s3c64xx_spi_dma_client = { .name = "samsung-spi-dma", }; +static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, + struct spi_message *msg) +{ + struct device *dev = &sdd->pdev->dev; + struct spi_transfer *xfer; + + if (is_polling(sdd) || msg->is_dma_mapped) + return 0; + + /* First mark all xfer unmapped */ + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + xfer->rx_dma = XFER_DMAADDR_INVALID; + xfer->tx_dma = XFER_DMAADDR_INVALID; + } + + /* Map until end or first fail */ + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + + if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1)) + continue; + + if (xfer->tx_buf != NULL) { + xfer->tx_dma = dma_map_single(dev, + (void *)xfer->tx_buf, xfer->len, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, xfer->tx_dma)) { + dev_err(dev, "dma_map_single Tx failed\n"); + xfer->tx_dma = XFER_DMAADDR_INVALID; + return -ENOMEM; + } + } + + if (xfer->rx_buf != NULL) { + xfer->rx_dma = dma_map_single(dev, xfer->rx_buf, + xfer->len, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, xfer->rx_dma)) { + dev_err(dev, "dma_map_single Rx failed\n"); + dma_unmap_single(dev, xfer->tx_dma, + xfer->len, DMA_TO_DEVICE); + xfer->tx_dma = XFER_DMAADDR_INVALID; + xfer->rx_dma = XFER_DMAADDR_INVALID; + return -ENOMEM; + } + } + } + + return 0; +} + +static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, + struct spi_message *msg) +{ + struct device *dev = &sdd->pdev->dev; + struct spi_transfer *xfer; + + if (is_polling(sdd) || msg->is_dma_mapped) + return; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + + if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1)) + continue; + + if (xfer->rx_buf != NULL + && xfer->rx_dma != XFER_DMAADDR_INVALID) + dma_unmap_single(dev, xfer->rx_dma, + xfer->len, DMA_FROM_DEVICE); + + if (xfer->tx_buf != NULL + && xfer->tx_dma != XFER_DMAADDR_INVALID) + dma_unmap_single(dev, xfer->tx_dma, + xfer->len, DMA_TO_DEVICE); + } +} + static void prepare_dma(struct s3c64xx_spi_dma_data *dma, unsigned len, dma_addr_t buf) { @@ -378,8 +453,22 @@ static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd, { sdd->ops->stop((enum dma_ch)dma->ch); } + +#define s3c64xx_spi_can_dma NULL + #else +static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, + struct spi_message *msg) +{ + return 0; +} + +static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, + struct spi_message *msg) +{ +} + static void prepare_dma(struct s3c64xx_spi_dma_data *dma, struct sg_table *sgt) { @@ -437,6 +526,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) ret = -EBUSY; goto out; } + spi->dma_rx = sdd->rx_dma.ch; sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter, (void *)sdd->tx_dma.dmach, dev, "tx"); @@ -445,6 +535,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) ret = -EBUSY; goto out_rx; } + spi->dma_tx = sdd->tx_dma.ch; } ret = pm_runtime_get_sync(&sdd->pdev->dev); @@ -482,6 +573,16 @@ static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd, { dmaengine_terminate_all(dma->ch); } + +static bool s3c64xx_spi_can_dma(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + + return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1; +} + #endif static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, @@ -764,81 +865,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32) -static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, - struct spi_message *msg) -{ - struct device *dev = &sdd->pdev->dev; - struct spi_transfer *xfer; - - if (is_polling(sdd) || msg->is_dma_mapped) - return 0; - - /* First mark all xfer unmapped */ - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - xfer->rx_dma = XFER_DMAADDR_INVALID; - xfer->tx_dma = XFER_DMAADDR_INVALID; - } - - /* Map until end or first fail */ - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - - if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1)) - continue; - - if (xfer->tx_buf != NULL) { - xfer->tx_dma = dma_map_single(dev, - (void *)xfer->tx_buf, xfer->len, - DMA_TO_DEVICE); - if (dma_mapping_error(dev, xfer->tx_dma)) { - dev_err(dev, "dma_map_single Tx failed\n"); - xfer->tx_dma = XFER_DMAADDR_INVALID; - return -ENOMEM; - } - } - - if (xfer->rx_buf != NULL) { - xfer->rx_dma = dma_map_single(dev, xfer->rx_buf, - xfer->len, DMA_FROM_DEVICE); - if (dma_mapping_error(dev, xfer->rx_dma)) { - dev_err(dev, "dma_map_single Rx failed\n"); - dma_unmap_single(dev, xfer->tx_dma, - xfer->len, DMA_TO_DEVICE); - xfer->tx_dma = XFER_DMAADDR_INVALID; - xfer->rx_dma = XFER_DMAADDR_INVALID; - return -ENOMEM; - } - } - } - - return 0; -} - -static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, - struct spi_message *msg) -{ - struct device *dev = &sdd->pdev->dev; - struct spi_transfer *xfer; - - if (is_polling(sdd) || msg->is_dma_mapped) - return; - - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - - if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1)) - continue; - - if (xfer->rx_buf != NULL - && xfer->rx_dma != XFER_DMAADDR_INVALID) - dma_unmap_single(dev, xfer->rx_dma, - xfer->len, DMA_FROM_DEVICE); - - if (xfer->tx_buf != NULL - && xfer->tx_dma != XFER_DMAADDR_INVALID) - dma_unmap_single(dev, xfer->tx_dma, - xfer->len, DMA_TO_DEVICE); - } -} - static int s3c64xx_spi_prepare_message(struct spi_master *master, struct spi_message *msg) { @@ -1338,6 +1364,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->auto_runtime_pm = true; + if (!is_polling(sdd)) + master->can_dma = s3c64xx_spi_can_dma; sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res); if (IS_ERR(sdd->regs)) { From 90e73973d3e48b3f6b37ea944fdef8e1543d36fc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 7 Feb 2014 12:34:36 +0000 Subject: [PATCH 04/39] spi/s3c64xx: Remove S3C_DMA support All the platforms which use the old S3C_DMA API have now been converted to dmaengine so we can remove the legacy code from the driver, simplifying maintenance. Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 191 -------------------------------------- 1 file changed, 191 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 4490e8c499c0..18ec7e65a319 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -34,10 +34,6 @@ #include -#ifdef CONFIG_S3C_DMA -#include -#endif - #define MAX_SPI_PORTS 3 #define S3C64XX_SPI_QUIRK_POLL (1 << 0) @@ -200,9 +196,6 @@ struct s3c64xx_spi_driver_data { unsigned cur_speed; struct s3c64xx_spi_dma_data rx_dma; struct s3c64xx_spi_dma_data tx_dma; -#ifdef CONFIG_S3C_DMA - struct samsung_dma_ops *ops; -#endif struct s3c64xx_spi_port_config *port_conf; unsigned int port_id; bool cs_gpio; @@ -284,180 +277,6 @@ static void s3c64xx_spi_dmacb(void *data) spin_unlock_irqrestore(&sdd->lock, flags); } -#ifdef CONFIG_S3C_DMA -/* FIXME: remove this section once arch/arm/mach-s3c64xx uses dmaengine */ - -static struct s3c2410_dma_client s3c64xx_spi_dma_client = { - .name = "samsung-spi-dma", -}; - -static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, - struct spi_message *msg) -{ - struct device *dev = &sdd->pdev->dev; - struct spi_transfer *xfer; - - if (is_polling(sdd) || msg->is_dma_mapped) - return 0; - - /* First mark all xfer unmapped */ - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - xfer->rx_dma = XFER_DMAADDR_INVALID; - xfer->tx_dma = XFER_DMAADDR_INVALID; - } - - /* Map until end or first fail */ - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - - if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1)) - continue; - - if (xfer->tx_buf != NULL) { - xfer->tx_dma = dma_map_single(dev, - (void *)xfer->tx_buf, xfer->len, - DMA_TO_DEVICE); - if (dma_mapping_error(dev, xfer->tx_dma)) { - dev_err(dev, "dma_map_single Tx failed\n"); - xfer->tx_dma = XFER_DMAADDR_INVALID; - return -ENOMEM; - } - } - - if (xfer->rx_buf != NULL) { - xfer->rx_dma = dma_map_single(dev, xfer->rx_buf, - xfer->len, DMA_FROM_DEVICE); - if (dma_mapping_error(dev, xfer->rx_dma)) { - dev_err(dev, "dma_map_single Rx failed\n"); - dma_unmap_single(dev, xfer->tx_dma, - xfer->len, DMA_TO_DEVICE); - xfer->tx_dma = XFER_DMAADDR_INVALID; - xfer->rx_dma = XFER_DMAADDR_INVALID; - return -ENOMEM; - } - } - } - - return 0; -} - -static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, - struct spi_message *msg) -{ - struct device *dev = &sdd->pdev->dev; - struct spi_transfer *xfer; - - if (is_polling(sdd) || msg->is_dma_mapped) - return; - - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - - if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1)) - continue; - - if (xfer->rx_buf != NULL - && xfer->rx_dma != XFER_DMAADDR_INVALID) - dma_unmap_single(dev, xfer->rx_dma, - xfer->len, DMA_FROM_DEVICE); - - if (xfer->tx_buf != NULL - && xfer->tx_dma != XFER_DMAADDR_INVALID) - dma_unmap_single(dev, xfer->tx_dma, - xfer->len, DMA_TO_DEVICE); - } -} - -static void prepare_dma(struct s3c64xx_spi_dma_data *dma, - unsigned len, dma_addr_t buf) -{ - struct s3c64xx_spi_driver_data *sdd; - struct samsung_dma_prep info; - struct samsung_dma_config config; - - if (dma->direction == DMA_DEV_TO_MEM) { - sdd = container_of((void *)dma, - struct s3c64xx_spi_driver_data, rx_dma); - config.direction = sdd->rx_dma.direction; - config.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA; - config.width = sdd->cur_bpw / 8; - sdd->ops->config((enum dma_ch)sdd->rx_dma.ch, &config); - } else { - sdd = container_of((void *)dma, - struct s3c64xx_spi_driver_data, tx_dma); - config.direction = sdd->tx_dma.direction; - config.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA; - config.width = sdd->cur_bpw / 8; - sdd->ops->config((enum dma_ch)sdd->tx_dma.ch, &config); - } - - info.cap = DMA_SLAVE; - info.len = len; - info.fp = s3c64xx_spi_dmacb; - info.fp_param = dma; - info.direction = dma->direction; - info.buf = buf; - - sdd->ops->prepare((enum dma_ch)dma->ch, &info); - sdd->ops->trigger((enum dma_ch)dma->ch); -} - -static int acquire_dma(struct s3c64xx_spi_driver_data *sdd) -{ - struct samsung_dma_req req; - struct device *dev = &sdd->pdev->dev; - - sdd->ops = samsung_dma_get_ops(); - - req.cap = DMA_SLAVE; - req.client = &s3c64xx_spi_dma_client; - - sdd->rx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request( - sdd->rx_dma.dmach, &req, dev, "rx"); - sdd->tx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request( - sdd->tx_dma.dmach, &req, dev, "tx"); - - return 1; -} - -static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) -{ - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); - - /* - * If DMA resource was not available during - * probe, no need to continue with dma requests - * else Acquire DMA channels - */ - while (!is_polling(sdd) && !acquire_dma(sdd)) - usleep_range(10000, 11000); - - return 0; -} - -static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) -{ - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); - - /* Free DMA channels */ - if (!is_polling(sdd)) { - sdd->ops->release((enum dma_ch)sdd->rx_dma.ch, - &s3c64xx_spi_dma_client); - sdd->ops->release((enum dma_ch)sdd->tx_dma.ch, - &s3c64xx_spi_dma_client); - } - - return 0; -} - -static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd, - struct s3c64xx_spi_dma_data *dma) -{ - sdd->ops->stop((enum dma_ch)dma->ch); -} - -#define s3c64xx_spi_can_dma NULL - -#else - static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, struct spi_message *msg) { @@ -583,8 +402,6 @@ static bool s3c64xx_spi_can_dma(struct spi_master *master, return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1; } -#endif - static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, struct spi_device *spi, struct spi_transfer *xfer, int dma_mode) @@ -616,11 +433,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, chcfg |= S3C64XX_SPI_CH_TXCH_ON; if (dma_mode) { modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; -#ifndef CONFIG_S3C_DMA prepare_dma(&sdd->tx_dma, &xfer->tx_sg); -#else - prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma); -#endif } else { switch (sdd->cur_bpw) { case 32: @@ -652,11 +465,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) | S3C64XX_SPI_PACKET_CNT_EN, regs + S3C64XX_SPI_PACKET_CNT); -#ifndef CONFIG_S3C_DMA prepare_dma(&sdd->rx_dma, &xfer->rx_sg); -#else - prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma); -#endif } } From 1b5e1b694919ee13b9ae6e5c6727363103e6f7f2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 7 Feb 2014 12:39:22 +0000 Subject: [PATCH 05/39] spi/s3c64xx: Remove code no longer needed as a result of S3C_DMA removal Remove functions that only had an effect when using S3C_DMA and inline dmaengine_terminate_all() since it's pointless to have a function which expands to a single function call. Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 39 ++------------------------------------- 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 18ec7e65a319..9ad5e3e76b96 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -277,17 +277,6 @@ static void s3c64xx_spi_dmacb(void *data) spin_unlock_irqrestore(&sdd->lock, flags); } -static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, - struct spi_message *msg) -{ - return 0; -} - -static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, - struct spi_message *msg) -{ -} - static void prepare_dma(struct s3c64xx_spi_dma_data *dma, struct sg_table *sgt) { @@ -387,12 +376,6 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) return 0; } -static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd, - struct s3c64xx_spi_dma_data *dma) -{ - dmaengine_terminate_all(dma->ch); -} - static bool s3c64xx_spi_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) @@ -691,13 +674,6 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master, s3c64xx_spi_config(sdd); } - /* Map all the transfers if needed */ - if (s3c64xx_spi_map_mssg(sdd, msg)) { - dev_err(&spi->dev, - "Xfer: Unable to map message buffers!\n"); - return -ENOMEM; - } - /* Configure feedback delay */ writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK); @@ -769,10 +745,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, if (use_dma) { if (xfer->tx_buf != NULL && (sdd->state & TXBUSY)) - s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma); + dmaengine_terminate_all(sdd->tx_dma.ch); if (xfer->rx_buf != NULL && (sdd->state & RXBUSY)) - s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma); + dmaengine_terminate_all(sdd->rx_dma.ch); } } else { flush_fifo(sdd); @@ -781,16 +757,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, return status; } -static int s3c64xx_spi_unprepare_message(struct spi_master *master, - struct spi_message *msg) -{ - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - - s3c64xx_spi_unmap_mssg(sdd, msg); - - return 0; -} - static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( struct spi_device *spi) { @@ -1164,7 +1130,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer; master->prepare_message = s3c64xx_spi_prepare_message; master->transfer_one = s3c64xx_spi_transfer_one; - master->unprepare_message = s3c64xx_spi_unprepare_message; master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer; master->num_chipselect = sci->num_cs; master->dma_alignment = 8; From c5c67e31bc1b96658169b5b553b9be42e2ca6368 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 11 Feb 2014 20:54:17 +0800 Subject: [PATCH 06/39] spi: sc18is602: Move checking chip_select for SC18IS602 to sc18is602_setup So it will be checked when spi device is added onto the spi bus. spi_add_device() calls spi_setup() which then calls spi->master->setup(). No need to check it every time sc18is602_transfer_one() is called. Signed-off-by: Axel Lin Acked-by: Guenter Roeck Signed-off-by: Mark Brown --- drivers/spi/spi-sc18is602.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c index b3ac776def9b..7fba10bba3b0 100644 --- a/drivers/spi/spi-sc18is602.c +++ b/drivers/spi/spi-sc18is602.c @@ -205,12 +205,6 @@ static int sc18is602_transfer_one(struct spi_master *master, struct spi_transfer *t; int status = 0; - /* SC18IS602 does not support CS2 */ - if (hw->id == sc18is602 && spi->chip_select == 2) { - status = -ENXIO; - goto error; - } - hw->tlen = 0; list_for_each_entry(t, &m->transfers, transfer_list) { u32 hz = t->speed_hz ? : spi->max_speed_hz; @@ -238,13 +232,23 @@ static int sc18is602_transfer_one(struct spi_master *master, if (t->delay_usecs) udelay(t->delay_usecs); } -error: m->status = status; spi_finalize_current_message(master); return status; } +static int sc18is602_setup(struct spi_device *spi) +{ + struct sc18is602 *hw = spi_master_get_devdata(spi->master); + + /* SC18IS602 does not support CS2 */ + if (hw->id == sc18is602 && spi->chip_select == 2) + return -ENXIO; + + return 0; +} + static int sc18is602_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -298,6 +302,7 @@ static int sc18is602_probe(struct i2c_client *client, master->bus_num = client->adapter->nr; master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST; master->bits_per_word_mask = SPI_BPW_MASK(8); + master->setup = sc18is602_setup; master->transfer_one_message = sc18is602_transfer_one; master->dev.of_node = np; From 963eb4b87dcfc0f9a1ac0ea85ca92832e61544ad Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 14 Feb 2014 12:26:17 +0530 Subject: [PATCH 07/39] spi/s3c64xx: Trivial cleanup in header file Commit 436d42c61c3e ("ARM: samsung: move platform_data definitions") moved the files to the current location but forgot to remove the pointer to its previous location. Clean it up. While at it also change the header file protection macros appropriately. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- include/linux/platform_data/spi-s3c64xx.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/linux/platform_data/spi-s3c64xx.h b/include/linux/platform_data/spi-s3c64xx.h index 8447f634c7f5..d3889b98a1a1 100644 --- a/include/linux/platform_data/spi-s3c64xx.h +++ b/include/linux/platform_data/spi-s3c64xx.h @@ -1,5 +1,4 @@ -/* linux/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h - * +/* * Copyright (C) 2009 Samsung Electronics Ltd. * Jaswinder Singh * @@ -8,8 +7,8 @@ * published by the Free Software Foundation. */ -#ifndef __S3C64XX_PLAT_SPI_H -#define __S3C64XX_PLAT_SPI_H +#ifndef __SPI_S3C64XX_H +#define __SPI_S3C64XX_H #include @@ -68,4 +67,4 @@ extern int s3c64xx_spi2_cfg_gpio(void); extern struct s3c64xx_spi_info s3c64xx_spi0_pdata; extern struct s3c64xx_spi_info s3c64xx_spi1_pdata; extern struct s3c64xx_spi_info s3c64xx_spi2_pdata; -#endif /* __S3C64XX_PLAT_SPI_H */ +#endif /*__SPI_S3C64XX_H */ From 925d16a209b40a3e7202a4f867991fb608834d36 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 20 Feb 2014 16:01:43 +0100 Subject: [PATCH 08/39] spi/spidev_test: Document -N/--no-cs and -R/--ready commit b55f627feeb9d48fdbde3835e18afbc76712e49b ("spi: new spi->mode bits") added two new command line options without adding the respective help texts. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- Documentation/spi/spidev_test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/spi/spidev_test.c b/Documentation/spi/spidev_test.c index 16feda901469..efd7385e907f 100644 --- a/Documentation/spi/spidev_test.c +++ b/Documentation/spi/spidev_test.c @@ -81,7 +81,9 @@ static void print_usage(const char *prog) " -O --cpol clock polarity\n" " -L --lsb least significant bit first\n" " -C --cs-high chip select active high\n" - " -3 --3wire SI/SO signals shared\n"); + " -3 --3wire SI/SO signals shared\n" + " -N --no-cs no chip select\n" + " -R --ready slave pulls low to pause\n"); exit(1); } From f7c05e837df794d2aaf19174269a270c93a52eca Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 20 Feb 2014 15:43:00 +0100 Subject: [PATCH 09/39] spi: sh-msiof: Fix SPI bus population from DT DT doesn't instantiate SPI children if spi_master.dev.of_node is not set up properly. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 81cc02f5f9b0..21ac8f668682 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -711,6 +711,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE; master->flags = 0; master->bus_num = pdev->id; + master->dev.of_node = pdev->dev.of_node; master->num_chipselect = p->info->num_chipselect; master->setup = spi_bitbang_setup; master->cleanup = spi_bitbang_cleanup; From a669c11a0df07477afbfeb53bc9d8fc989d1ed59 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 20 Feb 2014 15:43:01 +0100 Subject: [PATCH 10/39] spi: sh-msiof: Typo in comment s/tx/rx/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 21ac8f668682..5eded247fce4 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -487,7 +487,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, /* clear status bits */ sh_msiof_reset_str(p); - /* shut down frame, tx/tx and clock signals */ + /* shut down frame, rx/tx and clock signals */ ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0); ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TXE, 0); if (rx_buf) From 6a85fc5af1f09982e50abe56efc70eda9ad24632 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 20 Feb 2014 15:43:02 +0100 Subject: [PATCH 11/39] spi: sh-msiof: Change hz from unsigned long to u32 Both spi_transfer.speed_hz and spi_master.max_speed_hz are u32 Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 5eded247fce4..d0af05e96a2d 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -145,8 +145,7 @@ static struct { }; static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, - unsigned long parent_rate, - unsigned long spi_hz) + unsigned long parent_rate, u32 spi_hz) { unsigned long div = 1024; size_t k; @@ -373,10 +372,9 @@ static int sh_msiof_spi_bits(struct spi_device *spi, struct spi_transfer *t) return bits; } -static unsigned long sh_msiof_spi_hz(struct spi_device *spi, - struct spi_transfer *t) +static u32 sh_msiof_spi_hz(struct spi_device *spi, struct spi_transfer *t) { - unsigned long hz; + u32 hz; hz = t ? t->speed_hz : 0; if (!hz) From 01cfef57efe9c8ef445d4a5ad3bf26770fd5942a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 20 Feb 2014 15:43:03 +0100 Subject: [PATCH 12/39] spi: sh-msiof: Add more register documentation Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 148 ++++++++++++++++++++++++------------- 1 file changed, 98 insertions(+), 50 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index d0af05e96a2d..7acbc4052757 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -42,32 +42,80 @@ struct sh_msiof_spi_priv { int rx_fifo_size; }; -#define TMDR1 0x00 -#define TMDR2 0x04 -#define TMDR3 0x08 -#define RMDR1 0x10 -#define RMDR2 0x14 -#define RMDR3 0x18 -#define TSCR 0x20 -#define RSCR 0x22 -#define CTR 0x28 -#define FCTR 0x30 -#define STR 0x40 -#define IER 0x44 -#define TDR1 0x48 -#define TDR2 0x4c -#define TFDR 0x50 -#define RDR1 0x58 -#define RDR2 0x5c -#define RFDR 0x60 +#define TMDR1 0x00 /* Transmit Mode Register 1 */ +#define TMDR2 0x04 /* Transmit Mode Register 2 */ +#define TMDR3 0x08 /* Transmit Mode Register 3 */ +#define RMDR1 0x10 /* Receive Mode Register 1 */ +#define RMDR2 0x14 /* Receive Mode Register 2 */ +#define RMDR3 0x18 /* Receive Mode Register 3 */ +#define TSCR 0x20 /* Transmit Clock Select Register */ +#define RSCR 0x22 /* Receive Clock Select Register (SH, A1, APE6) */ +#define CTR 0x28 /* Control Register */ +#define FCTR 0x30 /* FIFO Control Register */ +#define STR 0x40 /* Status Register */ +#define IER 0x44 /* Interrupt Enable Register */ +#define TDR1 0x48 /* Transmit Control Data Register 1 (SH, A1) */ +#define TDR2 0x4c /* Transmit Control Data Register 2 (SH, A1) */ +#define TFDR 0x50 /* Transmit FIFO Data Register */ +#define RDR1 0x58 /* Receive Control Data Register 1 (SH, A1) */ +#define RDR2 0x5c /* Receive Control Data Register 2 (SH, A1) */ +#define RFDR 0x60 /* Receive FIFO Data Register */ -#define CTR_TSCKE (1 << 15) -#define CTR_TFSE (1 << 14) -#define CTR_TXE (1 << 9) -#define CTR_RXE (1 << 8) +/* TMDR1 and RMDR1 */ +#define MDR1_TRMD 0x80000000 /* Transfer Mode (1 = Master mode) */ +#define MDR1_SYNCMD_MASK 0x30000000 /* SYNC Mode */ +#define MDR1_SYNCMD_SPI 0x20000000 /* Level mode/SPI */ +#define MDR1_SYNCMD_LR 0x30000000 /* L/R mode */ +#define MDR1_SYNCAC_SHIFT 25 /* Sync Polarity (1 = Active-low) */ +#define MDR1_BITLSB_SHIFT 24 /* MSB/LSB First (1 = LSB first) */ +#define MDR1_FLD_MASK 0x000000c0 /* Frame Sync Signal Interval (0-3) */ +#define MDR1_FLD_SHIFT 2 +#define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */ +/* TMDR1 */ +#define TMDR1_PCON 0x40000000 /* Transfer Signal Connection */ + +/* TMDR2 and RMDR2 */ +#define MDR2_BITLEN1(i) (((i) - 1) << 24) /* Data Size (8-32 bits) */ +#define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */ +#define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */ + +/* TSCR and RSCR */ +#define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */ +#define SCR_BRPS(i) (((i) - 1) << 8) +#define SCR_BRDV_MASK 0x0007 /* Baud Rate Generator's Division Ratio */ +#define SCR_BRDV_DIV_2 0x0000 +#define SCR_BRDV_DIV_4 0x0001 +#define SCR_BRDV_DIV_8 0x0002 +#define SCR_BRDV_DIV_16 0x0003 +#define SCR_BRDV_DIV_32 0x0004 +#define SCR_BRDV_DIV_1 0x0007 + +/* CTR */ +#define CTR_TSCKIZ_MASK 0xc0000000 /* Transmit Clock I/O Polarity Select */ +#define CTR_TSCKIZ_SCK 0x80000000 /* Disable SCK when TX disabled */ +#define CTR_TSCKIZ_POL_SHIFT 30 /* Transmit Clock Polarity */ +#define CTR_RSCKIZ_MASK 0x30000000 /* Receive Clock Polarity Select */ +#define CTR_RSCKIZ_SCK 0x20000000 /* Must match CTR_TSCKIZ_SCK */ +#define CTR_RSCKIZ_POL_SHIFT 28 /* Receive Clock Polarity */ +#define CTR_TEDG_SHIFT 27 /* Transmit Timing (1 = falling edge) */ +#define CTR_REDG_SHIFT 26 /* Receive Timing (1 = falling edge) */ +#define CTR_TXDIZ_MASK 0x00c00000 /* Pin Output When TX is Disabled */ +#define CTR_TXDIZ_LOW 0x00000000 /* 0 */ +#define CTR_TXDIZ_HIGH 0x00400000 /* 1 */ +#define CTR_TXDIZ_HIZ 0x00800000 /* High-impedance */ +#define CTR_TSCKE 0x00008000 /* Transmit Serial Clock Output Enable */ +#define CTR_TFSE 0x00004000 /* Transmit Frame Sync Signal Output Enable */ +#define CTR_TXE 0x00000200 /* Transmit Enable */ +#define CTR_RXE 0x00000100 /* Receive Enable */ + +/* STR and IER */ +#define STR_TEOF 0x00800000 /* Frame Transmission End */ +#define STR_REOF 0x00000080 /* Frame Reception End */ + + +#define DEFAULT_TX_FIFO_SIZE 64 +#define DEFAULT_RX_FIFO_SIZE 64 -#define STR_TEOF (1 << 23) -#define STR_REOF (1 << 7) static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs) { @@ -131,17 +179,17 @@ static struct { unsigned short div; unsigned short scr; } const sh_msiof_spi_clk_table[] = { - { 1, 0x0007 }, - { 2, 0x0000 }, - { 4, 0x0001 }, - { 8, 0x0002 }, - { 16, 0x0003 }, - { 32, 0x0004 }, - { 64, 0x1f00 }, - { 128, 0x1f01 }, - { 256, 0x1f02 }, - { 512, 0x1f03 }, - { 1024, 0x1f04 }, + { 1, SCR_BRPS( 1) | SCR_BRDV_DIV_1 }, + { 2, SCR_BRPS( 1) | SCR_BRDV_DIV_2 }, + { 4, SCR_BRPS( 1) | SCR_BRDV_DIV_4 }, + { 8, SCR_BRPS( 1) | SCR_BRDV_DIV_8 }, + { 16, SCR_BRPS( 1) | SCR_BRDV_DIV_16 }, + { 32, SCR_BRPS( 1) | SCR_BRDV_DIV_32 }, + { 64, SCR_BRPS(32) | SCR_BRDV_DIV_2 }, + { 128, SCR_BRPS(32) | SCR_BRDV_DIV_4 }, + { 256, SCR_BRPS(32) | SCR_BRDV_DIV_8 }, + { 512, SCR_BRPS(32) | SCR_BRDV_DIV_16 }, + { 1024, SCR_BRPS(32) | SCR_BRDV_DIV_32 }, }; static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, @@ -182,21 +230,21 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, */ sh_msiof_write(p, FCTR, 0); - tmp = 0; - tmp |= !cs_high << 25; - tmp |= lsb_first << 24; - sh_msiof_write(p, TMDR1, 0xe0000005 | tmp); - sh_msiof_write(p, RMDR1, 0x20000005 | tmp); + tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP; + tmp |= !cs_high << MDR1_SYNCAC_SHIFT; + tmp |= lsb_first << MDR1_BITLSB_SHIFT; + sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON); + sh_msiof_write(p, RMDR1, tmp); - tmp = 0xa0000000; - tmp |= cpol << 30; /* TSCKIZ */ - tmp |= cpol << 28; /* RSCKIZ */ + tmp = 0; + tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT; + tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT; edge = cpol ^ !cpha; - tmp |= edge << 27; /* TEDG */ - tmp |= edge << 26; /* REDG */ - tmp |= (tx_hi_z ? 2 : 0) << 22; /* TXDIZ */ + tmp |= edge << CTR_TEDG_SHIFT; + tmp |= edge << CTR_REDG_SHIFT; + tmp |= tx_hi_z ? CTR_TXDIZ_HIZ : CTR_TXDIZ_LOW; sh_msiof_write(p, CTR, tmp); } @@ -204,12 +252,12 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p, const void *tx_buf, void *rx_buf, u32 bits, u32 words) { - u32 dr2 = ((bits - 1) << 24) | ((words - 1) << 16); + u32 dr2 = MDR2_BITLEN1(bits) | MDR2_WDLEN1(words); if (tx_buf) sh_msiof_write(p, TMDR2, dr2); else - sh_msiof_write(p, TMDR2, dr2 | 1); + sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1); if (rx_buf) sh_msiof_write(p, RMDR2, dr2); @@ -695,8 +743,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); /* The standard version of MSIOF use 64 word FIFOs */ - p->tx_fifo_size = 64; - p->rx_fifo_size = 64; + p->tx_fifo_size = DEFAULT_TX_FIFO_SIZE; + p->rx_fifo_size = DEFAULT_RX_FIFO_SIZE; /* Platform data may override FIFO sizes */ if (p->info->tx_fifo_override) From 8d19534a8d539bb2e598e56e017a423f205e909e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 20 Feb 2014 15:43:04 +0100 Subject: [PATCH 13/39] spi: sh-msiof: Use the core cs_gpio field, and make it optional In current implementation, CS is controlled by GPIO, which is passed through spi->controller_data. However, the MSIOF HW module has a function to output CS by itself, which is already enabled and actual switch will be done by pinmux. Store the GPIO number in the core cs_gpio field, and ignore it if it is an invalid (negative) GPIO number. Loosely based on a patch from Takashi Yoshii . Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 7acbc4052757..6e2ba62ceb63 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -446,6 +446,21 @@ static int sh_msiof_spi_setup_transfer(struct spi_device *spi, return spi_bitbang_setup_transfer(spi, t); } +static int sh_msiof_spi_setup(struct spi_device *spi) +{ + struct device_node *np = spi->master->dev.of_node; + + if (!np) { + /* + * Use spi->controller_data for CS (same strategy as spi_gpio), + * if any. otherwise let HW control CS + */ + spi->cs_gpio = (uintptr_t)spi->controller_data; + } + + return spi_bitbang_setup(spi); +} + static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on) { struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); @@ -471,8 +486,8 @@ static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on) !!(spi->mode & SPI_CS_HIGH)); } - /* use spi->controller data for CS (same strategy as spi_gpio) */ - gpio_set_value((uintptr_t)spi->controller_data, value); + if (spi->cs_gpio >= 0) + gpio_set_value(spi->cs_gpio, value); if (is_on == BITBANG_CS_INACTIVE) { if (test_and_clear_bit(0, &p->flags)) { @@ -759,7 +774,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->dev.of_node = pdev->dev.of_node; master->num_chipselect = p->info->num_chipselect; - master->setup = spi_bitbang_setup; + master->setup = sh_msiof_spi_setup; master->cleanup = spi_bitbang_cleanup; p->bitbang.master = master; From 4522193698d115761f9e4f340697f86975ac8e69 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 12 Feb 2014 22:09:52 +0800 Subject: [PATCH 14/39] spi: sh-hspi: Convert to let spi core validate bits_per_word Set bits_per_word_mask so spi core will reject transfers that attempt to use an unsupported bits_per_word value. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-sh-hspi.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 82d2f922ffa0..dbd2c44f95e9 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -230,21 +230,6 @@ static int hspi_transfer_one_message(struct spi_master *master, return ret; } -static int hspi_setup(struct spi_device *spi) -{ - struct hspi_priv *hspi = spi_master_get_devdata(spi->master); - struct device *dev = hspi->dev; - - if (8 != spi->bits_per_word) { - dev_err(dev, "bits_per_word should be 8\n"); - return -EIO; - } - - dev_dbg(dev, "%s setup\n", spi->modalias); - - return 0; -} - static void hspi_cleanup(struct spi_device *spi) { struct hspi_priv *hspi = spi_master_get_devdata(spi->master); @@ -300,12 +285,13 @@ static int hspi_probe(struct platform_device *pdev) master->num_chipselect = 1; master->bus_num = pdev->id; - master->setup = hspi_setup; master->cleanup = hspi_cleanup; master->mode_bits = SPI_CPOL | SPI_CPHA; master->dev.of_node = pdev->dev.of_node; master->auto_runtime_pm = true; master->transfer_one_message = hspi_transfer_one_message; + master->bits_per_word_mask = SPI_BPW_MASK(8); + ret = devm_spi_register_master(&pdev->dev, master); if (ret < 0) { dev_err(&pdev->dev, "spi_register_master error.\n"); From dd7243d6a5de6faaef30cebc554ce8b39d5a3de5 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 13 Feb 2014 00:30:19 +0800 Subject: [PATCH 15/39] spi: sirf: move to use generic dma dt-binding sirf-dma driver enabled generic dt binding for dma channels. see here we remove self-defined dma channel prop and move to use generic dma_request_slave_channel. related changes in dts is something like: dmas = <&dmac1 9>, <&dmac1 4>; dma-names = "rx", "tx"; Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 632d2b5b821f..61e5eafac92c 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -22,7 +22,6 @@ #include #include #include -#include #define DRIVER_NAME "sirfsoc_spi" @@ -539,8 +538,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) struct spi_master *master; struct resource *mem_res; int num_cs, cs_gpio, irq; - u32 rx_dma_ch, tx_dma_ch; - dma_cap_mask_t dma_cap_mask; int i; int ret; @@ -551,20 +548,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) goto err_cs; } - ret = of_property_read_u32(pdev->dev.of_node, - "sirf,spi-dma-rx-channel", &rx_dma_ch); - if (ret < 0) { - dev_err(&pdev->dev, "Unable to get rx dma channel\n"); - goto err_cs; - } - - ret = of_property_read_u32(pdev->dev.of_node, - "sirf,spi-dma-tx-channel", &tx_dma_ch); - if (ret < 0) { - dev_err(&pdev->dev, "Unable to get tx dma channel\n"); - goto err_cs; - } - master = spi_alloc_master(&pdev->dev, sizeof(*sspi) + sizeof(int) * num_cs); if (!master) { dev_err(&pdev->dev, "Unable to allocate SPI master\n"); @@ -628,18 +611,13 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) sspi->bitbang.master->dev.of_node = pdev->dev.of_node; /* request DMA channels */ - dma_cap_zero(dma_cap_mask); - dma_cap_set(DMA_INTERLEAVE, dma_cap_mask); - - sspi->rx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id, - (void *)rx_dma_ch); + sspi->rx_chan = dma_request_slave_channel(&pdev->dev, "rx"); if (!sspi->rx_chan) { dev_err(&pdev->dev, "can not allocate rx dma channel\n"); ret = -ENODEV; goto free_master; } - sspi->tx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id, - (void *)tx_dma_ch); + sspi->tx_chan = dma_request_slave_channel(&pdev->dev, "tx"); if (!sspi->tx_chan) { dev_err(&pdev->dev, "can not allocate tx dma channel\n"); ret = -ENODEV; From facffed29709313593e6feab3a08d9664874e977 Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Thu, 13 Feb 2014 00:30:20 +0800 Subject: [PATCH 16/39] spi: sirf: use SET_SYSTEM_SLEEP_PM_OPS to initialize PM entries use SET_SYSTEM_SLEEP_PM_OPS to initialize PM entries, this makes the codes clean and also enable the ability of hibernation support for sirf SPI. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 61e5eafac92c..5210b94729aa 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -693,7 +693,7 @@ static int spi_sirfsoc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int spi_sirfsoc_suspend(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); @@ -716,12 +716,11 @@ static int spi_sirfsoc_resume(struct device *dev) return 0; } +#endif static const struct dev_pm_ops spi_sirfsoc_pm_ops = { - .suspend = spi_sirfsoc_suspend, - .resume = spi_sirfsoc_resume, + SET_SYSTEM_SLEEP_PM_OPS(spi_sirfsoc_suspend, spi_sirfsoc_resume) }; -#endif static const struct of_device_id spi_sirfsoc_of_match[] = { { .compatible = "sirf,prima2-spi", }, @@ -734,9 +733,7 @@ static struct platform_driver spi_sirfsoc_driver = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, -#ifdef CONFIG_PM .pm = &spi_sirfsoc_pm_ops, -#endif .of_match_table = spi_sirfsoc_of_match, }, .probe = spi_sirfsoc_probe, From 382ab20e8138083966b7bde141d3c6a79dda68bf Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 25 Feb 2014 19:18:29 +0800 Subject: [PATCH 17/39] spi: s3c64xx: Let spi core handle validating transfer length spi core will handle validating transfer length since commit 4d94bd21b333 "spi: core: Validate length of the transfers in message". So remove the same checking in this driver. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 9ad5e3e76b96..f19cd97855e8 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -697,13 +697,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, bpw = xfer->bits_per_word; speed = xfer->speed_hz ? : spi->max_speed_hz; - if (xfer->len % (bpw / 8)) { - dev_err(&spi->dev, - "Xfer length(%u) not a multiple of word size(%u)\n", - xfer->len, bpw / 8); - return -EIO; - } - if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) { sdd->cur_bpw = bpw; sdd->cur_speed = speed; From 71aa2e3207ad3249b4a7ceff7ca775a08341fdcb Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 26 Feb 2014 10:32:48 +0900 Subject: [PATCH 18/39] spi: sirf: Use SIMPLE_DEV_PM_OPS macro Use SIMPLE_DEV_PM_OPS macro in order to make the code simpler. Signed-off-by: Jingoo Han Acked-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 5210b94729aa..dc962a17f373 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -718,9 +718,8 @@ static int spi_sirfsoc_resume(struct device *dev) } #endif -static const struct dev_pm_ops spi_sirfsoc_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(spi_sirfsoc_suspend, spi_sirfsoc_resume) -}; +static SIMPLE_DEV_PM_OPS(spi_sirfsoc_pm_ops, spi_sirfsoc_suspend, + spi_sirfsoc_resume); static const struct of_device_id spi_sirfsoc_of_match[] = { { .compatible = "sirf,prima2-spi", }, From e6456186cae76f80446ba911f77eb2f85d3d927e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:40:16 +0100 Subject: [PATCH 19/39] spi: spidev: Restore all SPI mode flags on ioctl failure In commit f477b7fb13df2b843997559ff34e87d054ba6538 ("spi: DUAL and QUAD support"), spi_device.mode was enlarged from 8 to 16 bits. However, the spidev code still only saved 8 bits of data. If a spidev SPI_IOC_WR_MODE or SPI_IOC_WR_LSB_FIRST request failed, only the lower 8 bits of the SPI mode were restored, inadvertently clearing the upper 8 bits, possibly disabling Quad or Dual SPI transfers for the device. Save up to 32 bits to fix this. For SPI_IOC_WR_MODE this is probably not so important, as it doesn't allow setting Quad or Dual mode anyway, but SPI_IOC_WR_LSB_FIRST is used to just set or clear a single bit. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spidev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index d7c6e36021e8..2abc0f5a82be 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -374,7 +374,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case SPI_IOC_WR_MODE: retval = __get_user(tmp, (u8 __user *)arg); if (retval == 0) { - u8 save = spi->mode; + u32 save = spi->mode; if (tmp & ~SPI_MODE_MASK) { retval = -EINVAL; @@ -393,7 +393,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case SPI_IOC_WR_LSB_FIRST: retval = __get_user(tmp, (__u8 __user *)arg); if (retval == 0) { - u8 save = spi->mode; + u32 save = spi->mode; if (tmp) spi->mode |= SPI_LSB_FIRST; From dc64d39b54c1e9db97a6fb1ca52598c981728157 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:40:17 +0100 Subject: [PATCH 20/39] spi: spidev: Add support for Dual/Quad SPI Transfers Add support for Dual/Quad SPI Transfers to the spidev API. As this uses SPI mode bits that don't fit in a single byte, two new ioctls (SPI_IOC_RD_MODE32 and SPI_IOC_WR_MODE32) are introduced. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- Documentation/spi/spidev | 6 ++++++ drivers/spi/spidev.c | 19 +++++++++++++++---- include/uapi/linux/spi/spidev.h | 14 ++++++++++++-- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/Documentation/spi/spidev b/Documentation/spi/spidev index ed2da5e5b28a..3d14035b1766 100644 --- a/Documentation/spi/spidev +++ b/Documentation/spi/spidev @@ -85,6 +85,12 @@ settings for data transfer parameters: SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL (clock polarity, idle high iff this is set) or SPI_CPHA (clock phase, sample on trailing edge iff this is set) flags. + Note that this request is limited to SPI mode flags that fit in a + single byte. + + SPI_IOC_RD_MODE32, SPI_IOC_WR_MODE32 ... pass a pointer to a uin32_t + which will return (RD) or assign (WR) the full SPI transfer mode, + not limited to the bits that fit in one byte. SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte which will return (RD) or assign (WR) the bit justification used to diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 2abc0f5a82be..e3bc23bb5883 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -73,7 +73,8 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS); */ #define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \ | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \ - | SPI_NO_CS | SPI_READY) + | SPI_NO_CS | SPI_READY | SPI_TX_DUAL \ + | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD) struct spidev_data { dev_t devt; @@ -265,6 +266,8 @@ static int spidev_message(struct spidev_data *spidev, buf += k_tmp->len; k_tmp->cs_change = !!u_tmp->cs_change; + k_tmp->tx_nbits = u_tmp->tx_nbits; + k_tmp->rx_nbits = u_tmp->rx_nbits; k_tmp->bits_per_word = u_tmp->bits_per_word; k_tmp->delay_usecs = u_tmp->delay_usecs; k_tmp->speed_hz = u_tmp->speed_hz; @@ -359,6 +362,10 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = __put_user(spi->mode & SPI_MODE_MASK, (__u8 __user *)arg); break; + case SPI_IOC_RD_MODE32: + retval = __put_user(spi->mode & SPI_MODE_MASK, + (__u32 __user *)arg); + break; case SPI_IOC_RD_LSB_FIRST: retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0, (__u8 __user *)arg); @@ -372,7 +379,11 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* write requests */ case SPI_IOC_WR_MODE: - retval = __get_user(tmp, (u8 __user *)arg); + case SPI_IOC_WR_MODE32: + if (cmd == SPI_IOC_WR_MODE) + retval = __get_user(tmp, (u8 __user *)arg); + else + retval = __get_user(tmp, (u32 __user *)arg); if (retval == 0) { u32 save = spi->mode; @@ -382,12 +393,12 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } tmp |= spi->mode & ~SPI_MODE_MASK; - spi->mode = (u8)tmp; + spi->mode = (u16)tmp; retval = spi_setup(spi); if (retval < 0) spi->mode = save; else - dev_dbg(&spi->dev, "spi mode %02x\n", tmp); + dev_dbg(&spi->dev, "spi mode %x\n", tmp); } break; case SPI_IOC_WR_LSB_FIRST: diff --git a/include/uapi/linux/spi/spidev.h b/include/uapi/linux/spi/spidev.h index 52d9ed01855f..dd5f21e75805 100644 --- a/include/uapi/linux/spi/spidev.h +++ b/include/uapi/linux/spi/spidev.h @@ -42,6 +42,10 @@ #define SPI_LOOP 0x20 #define SPI_NO_CS 0x40 #define SPI_READY 0x80 +#define SPI_TX_DUAL 0x100 +#define SPI_TX_QUAD 0x200 +#define SPI_RX_DUAL 0x400 +#define SPI_RX_QUAD 0x800 /*---------------------------------------------------------------------------*/ @@ -92,7 +96,9 @@ struct spi_ioc_transfer { __u16 delay_usecs; __u8 bits_per_word; __u8 cs_change; - __u32 pad; + __u8 tx_nbits; + __u8 rx_nbits; + __u16 pad; /* If the contents of 'struct spi_ioc_transfer' ever change * incompatibly, then the ioctl number (currently 0) must change; @@ -110,7 +116,7 @@ struct spi_ioc_transfer { #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) -/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */ +/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) (limited to 8 bits) */ #define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8) #define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, __u8) @@ -126,6 +132,10 @@ struct spi_ioc_transfer { #define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32) #define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32) +/* Read / Write of the SPI mode field */ +#define SPI_IOC_RD_MODE32 _IOR(SPI_IOC_MAGIC, 5, __u32) +#define SPI_IOC_WR_MODE32 _IOW(SPI_IOC_MAGIC, 5, __u32) + #endif /* SPIDEV_H */ From c2e78c34ef0bf4fa860b5fffc99c769d6ddaf52d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:40:18 +0100 Subject: [PATCH 21/39] spi: spidev_test: Add support for Dual/Quad SPI Transfers Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- Documentation/spi/spidev_test.c | 43 ++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/Documentation/spi/spidev_test.c b/Documentation/spi/spidev_test.c index efd7385e907f..3a2f9d59edab 100644 --- a/Documentation/spi/spidev_test.c +++ b/Documentation/spi/spidev_test.c @@ -30,7 +30,7 @@ static void pabort(const char *s) } static const char *device = "/dev/spidev1.1"; -static uint8_t mode; +static uint32_t mode; static uint8_t bits = 8; static uint32_t speed = 500000; static uint16_t delay; @@ -57,6 +57,21 @@ static void transfer(int fd) .bits_per_word = bits, }; + if (mode & SPI_TX_QUAD) + tr.tx_nbits = 4; + else if (mode & SPI_TX_DUAL) + tr.tx_nbits = 2; + if (mode & SPI_RX_QUAD) + tr.rx_nbits = 4; + else if (mode & SPI_RX_DUAL) + tr.rx_nbits = 2; + if (!(mode & SPI_LOOP)) { + if (mode & (SPI_TX_QUAD | SPI_TX_DUAL)) + tr.rx_buf = 0; + else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL)) + tr.tx_buf = 0; + } + ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); if (ret < 1) pabort("can't send spi message"); @@ -83,7 +98,9 @@ static void print_usage(const char *prog) " -C --cs-high chip select active high\n" " -3 --3wire SI/SO signals shared\n" " -N --no-cs no chip select\n" - " -R --ready slave pulls low to pause\n"); + " -R --ready slave pulls low to pause\n" + " -2 --dual dual transfer\n" + " -4 --quad quad transfer\n"); exit(1); } @@ -103,11 +120,13 @@ static void parse_opts(int argc, char *argv[]) { "3wire", 0, 0, '3' }, { "no-cs", 0, 0, 'N' }, { "ready", 0, 0, 'R' }, + { "dual", 0, 0, '2' }, + { "quad", 0, 0, '4' }, { NULL, 0, 0, 0 }, }; int c; - c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL); + c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24", lopts, NULL); if (c == -1) break; @@ -149,11 +168,23 @@ static void parse_opts(int argc, char *argv[]) case 'R': mode |= SPI_READY; break; + case '2': + mode |= SPI_TX_DUAL; + break; + case '4': + mode |= SPI_TX_QUAD; + break; default: print_usage(argv[0]); break; } } + if (mode & SPI_LOOP) { + if (mode & SPI_TX_DUAL) + mode |= SPI_RX_DUAL; + if (mode & SPI_TX_QUAD) + mode |= SPI_RX_QUAD; + } } int main(int argc, char *argv[]) @@ -170,11 +201,11 @@ int main(int argc, char *argv[]) /* * spi mode */ - ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); + ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode); if (ret == -1) pabort("can't set spi mode"); - ret = ioctl(fd, SPI_IOC_RD_MODE, &mode); + ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode); if (ret == -1) pabort("can't get spi mode"); @@ -200,7 +231,7 @@ int main(int argc, char *argv[]) if (ret == -1) pabort("can't get max speed hz"); - printf("spi mode: %d\n", mode); + printf("spi mode: 0x%x\n", mode); printf("bits per word: %d\n", bits); printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); From 4189a728ae26832edfabca300313e7fef2818d6f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:40:19 +0100 Subject: [PATCH 22/39] spi: spidev_fdx: Add support for Dual/Quad SPI Transfers Use SPI_IOC_RD_MODE32 to print the full SPI mode, now in hex. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- Documentation/spi/spidev_fdx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/spi/spidev_fdx.c b/Documentation/spi/spidev_fdx.c index 36ec0774ca0b..0ea3e51292fc 100644 --- a/Documentation/spi/spidev_fdx.c +++ b/Documentation/spi/spidev_fdx.c @@ -78,10 +78,10 @@ static void do_msg(int fd, int len) static void dumpstat(const char *name, int fd) { - __u8 mode, lsb, bits; - __u32 speed; + __u8 lsb, bits; + __u32 mode, speed; - if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) { + if (ioctl(fd, SPI_IOC_RD_MODE32, &mode) < 0) { perror("SPI rd_mode"); return; } @@ -98,7 +98,7 @@ static void dumpstat(const char *name, int fd) return; } - printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n", + printf("%s: spi mode 0x%x, %d bits %sper word, %d Hz max\n", name, mode, bits, lsb ? "(lsb first) " : "", speed); } From 32d3b2d1ddeafe105ab6f738fba427242141194e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:21:08 +0100 Subject: [PATCH 23/39] spi: sh-msiof: Improve bindings Documentation: - Add missing "interrupt-parent", "#address-cells", "#size-cells", and "clocks" properties, - Add missing default values for "num-cs", "renesas,tx-fifo-size" and "renesas,rx-fifo-size", - Add a reference to the pinctrl documentation. Implementation: - As "num-cs" is marked optional, provide a sensible default. Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/sh-msiof.txt | 24 +++++++++++++------ drivers/spi/spi-sh-msiof.c | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt index e6222106ca36..eae3c8c9300e 100644 --- a/Documentation/devicetree/bindings/spi/sh-msiof.txt +++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt @@ -1,12 +1,22 @@ Renesas MSIOF spi controller Required properties: -- compatible : "renesas,sh-msiof" for SuperH or - "renesas,sh-mobile-msiof" for SH Mobile series -- reg : Offset and length of the register set for the device -- interrupts : interrupt line used by MSIOF +- compatible : "renesas,sh-msiof" for SuperH, or + "renesas,sh-mobile-msiof" for SH Mobile series. +- reg : Offset and length of the register set for the device +- interrupt-parent : The phandle for the interrupt controller that + services interrupts for this device +- interrupts : Interrupt specifier +- #address-cells : Must be <1> +- #size-cells : Must be <0> Optional properties: -- num-cs : total number of chip-selects -- renesas,tx-fifo-size : Overrides the default tx fifo size given in words -- renesas,rx-fifo-size : Overrides the default rx fifo size given in words +- clocks : Must contain a reference to the functional clock. +- num-cs : Total number of chip-selects (default is 1) +- renesas,tx-fifo-size : Overrides the default tx fifo size given in words + (default is 64) +- renesas,rx-fifo-size : Overrides the default rx fifo size given in words + (default is 64) + +Pinctrl properties might be needed, too. See +Documentation/devicetree/bindings/pinctrl/renesas,*. diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 6e2ba62ceb63..181efd049d12 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -664,7 +664,7 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) { struct sh_msiof_spi_info *info; struct device_node *np = dev->of_node; - u32 num_cs = 0; + u32 num_cs = 1; info = devm_kzalloc(dev, sizeof(struct sh_msiof_spi_info), GFP_KERNEL); if (!info) { From 50a7e23f53677918bf521b09ce9bb20fb87cd175 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:21:09 +0100 Subject: [PATCH 24/39] spi: sh-msiof: Move default FIFO sizes to device ID data As different variants of MSIOF have different FIFO sizes, move the default FIFO sizes to a new struct sh_msiof_chipdata, pointed to from the device ID data. [Moved ifdef to fix build -- broonie] Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 50 ++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 181efd049d12..38d6b70e9be2 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -30,11 +31,18 @@ #include + +struct sh_msiof_chipdata { + u16 tx_fifo_size; + u16 rx_fifo_size; +}; + struct sh_msiof_spi_priv { struct spi_bitbang bitbang; /* must be first for spi_bitbang.c */ void __iomem *mapbase; struct clk *clk; struct platform_device *pdev; + const struct sh_msiof_chipdata *chipdata; struct sh_msiof_spi_info *info; struct completion done; unsigned long flags; @@ -113,10 +121,6 @@ struct sh_msiof_spi_priv { #define STR_REOF 0x00000080 /* Frame Reception End */ -#define DEFAULT_TX_FIFO_SIZE 64 -#define DEFAULT_RX_FIFO_SIZE 64 - - static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs) { switch (reg_offs) { @@ -659,6 +663,18 @@ static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs, return 0; } +static const struct sh_msiof_chipdata sh_data = { + .tx_fifo_size = 64, + .rx_fifo_size = 64, +}; + +static const struct of_device_id sh_msiof_match[] = { + { .compatible = "renesas,sh-msiof", .data = &sh_data }, + { .compatible = "renesas,sh-mobile-msiof", .data = &sh_data }, + {}, +}; +MODULE_DEVICE_TABLE(of, sh_msiof_match); + #ifdef CONFIG_OF static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) { @@ -694,6 +710,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) { struct resource *r; struct spi_master *master; + const struct of_device_id *of_id; struct sh_msiof_spi_priv *p; int i; int ret; @@ -707,10 +724,15 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) p = spi_master_get_devdata(master); platform_set_drvdata(pdev, p); - if (pdev->dev.of_node) + + of_id = of_match_device(sh_msiof_match, &pdev->dev); + if (of_id) { + p->chipdata = of_id->data; p->info = sh_msiof_spi_parse_dt(&pdev->dev); - else + } else { + p->chipdata = (const void *)pdev->id_entry->driver_data; p->info = dev_get_platdata(&pdev->dev); + } if (!p->info) { dev_err(&pdev->dev, "failed to obtain device info\n"); @@ -757,11 +779,9 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) p->pdev = pdev; pm_runtime_enable(&pdev->dev); - /* The standard version of MSIOF use 64 word FIFOs */ - p->tx_fifo_size = DEFAULT_TX_FIFO_SIZE; - p->rx_fifo_size = DEFAULT_RX_FIFO_SIZE; - /* Platform data may override FIFO sizes */ + p->tx_fifo_size = p->chipdata->tx_fifo_size; + p->rx_fifo_size = p->chipdata->rx_fifo_size; if (p->info->tx_fifo_override) p->tx_fifo_size = p->info->tx_fifo_override; if (p->info->rx_fifo_override) @@ -811,18 +831,16 @@ static int sh_msiof_spi_remove(struct platform_device *pdev) return ret; } -#ifdef CONFIG_OF -static const struct of_device_id sh_msiof_match[] = { - { .compatible = "renesas,sh-msiof", }, - { .compatible = "renesas,sh-mobile-msiof", }, +static struct platform_device_id spi_driver_ids[] = { + { "spi_sh_msiof", (kernel_ulong_t)&sh_data }, {}, }; -MODULE_DEVICE_TABLE(of, sh_msiof_match); -#endif +MODULE_DEVICE_TABLE(platform, spi_driver_ids); static struct platform_driver sh_msiof_spi_drv = { .probe = sh_msiof_spi_probe, .remove = sh_msiof_spi_remove, + .id_table = spi_driver_ids, .driver = { .name = "spi_sh_msiof", .owner = THIS_MODULE, From beb74bb0875579c409778d853b8a050c124b3c79 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:21:10 +0100 Subject: [PATCH 25/39] spi: sh-msiof: Add support for R-Car H2 and M2 Add support for the MSIOF variant in the R-Car H2 (r8a7790) and M2 (r8a7791) SoCs. Binding documentation: - Add future-proof "renesas,msiof-" compatible values, - The default for "renesas,rx-fifo-size" is 256 on R-Car H2 and M2, - "renesas,tx-fifo-size" and "renesas,rx-fifo-size" are deprecated for soctype-specific bindings, - Add example bindings. Implementation: - MSIOF on R-Car H2 and M2 requires the transmission of dummy data if data is being received only (cfr. "Set SICTR.TSCKE to 1" and "Write dummy transmission data to SITFDR" in paragraph "Transmit and Receive Procedures" of the Hardware User's Manual). - As RX depends on TX, MSIOF on R-Car H2 and M2 also lacks the RSCR register (Receive Clock Select Register), and some bits in the RMDR1 (Receive Mode Register 1) and TMDR2 (Transmit Mode Register 2) registers. - Use the recently introduced SPI_MASTER_MUST_TX flag to enable support for dummy transmission in the SPI core, and to differentiate from other MSIOF implementations in code paths that need this. - New DT compatible values ("renesas,msiof-r8a7790" and "renesas,msiof-r8a7791") are added, as well as new platform device names ("spi_r8a7790_msiof" and "spi_r8a7791_msiof"). - The default RX FIFO size is 256 words on R-Car H2 and M2. This is loosely based on a set of patches from Takashi Yoshii . Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/sh-msiof.txt | 23 +++++++++++++++++-- drivers/spi/spi-sh-msiof.c | 23 ++++++++++++++++--- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt index eae3c8c9300e..1f0cb33763a1 100644 --- a/Documentation/devicetree/bindings/spi/sh-msiof.txt +++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt @@ -1,8 +1,13 @@ Renesas MSIOF spi controller Required properties: -- compatible : "renesas,sh-msiof" for SuperH, or +- compatible : "renesas,msiof-" for SoCs, + "renesas,sh-msiof" for SuperH, or "renesas,sh-mobile-msiof" for SH Mobile series. + Examples with soctypes are: + "renesas,msiof-sh7724" (SH) + "renesas,msiof-r8a7790" (R-Car H2) + "renesas,msiof-r8a7791" (R-Car M2) - reg : Offset and length of the register set for the device - interrupt-parent : The phandle for the interrupt controller that services interrupts for this device @@ -13,10 +18,24 @@ Required properties: Optional properties: - clocks : Must contain a reference to the functional clock. - num-cs : Total number of chip-selects (default is 1) + +Optional properties, deprecated for soctype-specific bindings: - renesas,tx-fifo-size : Overrides the default tx fifo size given in words (default is 64) - renesas,rx-fifo-size : Overrides the default rx fifo size given in words - (default is 64) + (default is 64, or 256 on R-Car H2 and M2) Pinctrl properties might be needed, too. See Documentation/devicetree/bindings/pinctrl/renesas,*. + +Example: + + msiof0: spi@e6e20000 { + compatible = "renesas,msiof-r8a7791"; + reg = <0 0xe6e20000 0 0x0064>; + interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 38d6b70e9be2..e7f4797fa59d 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -35,6 +35,7 @@ struct sh_msiof_chipdata { u16 tx_fifo_size; u16 rx_fifo_size; + u16 master_flags; }; struct sh_msiof_spi_priv { @@ -215,7 +216,8 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_clk_table) - 1); sh_msiof_write(p, TSCR, sh_msiof_spi_clk_table[k].scr); - sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr); + if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX)) + sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr); } static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, @@ -238,6 +240,10 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, tmp |= !cs_high << MDR1_SYNCAC_SHIFT; tmp |= lsb_first << MDR1_BITLSB_SHIFT; sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON); + if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) { + /* These bits are reserved if RX needs TX */ + tmp &= ~0x0000ffff; + } sh_msiof_write(p, RMDR1, tmp); tmp = 0; @@ -258,7 +264,7 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p, { u32 dr2 = MDR2_BITLEN1(bits) | MDR2_WDLEN1(words); - if (tx_buf) + if (tx_buf || (p->chipdata->master_flags & SPI_MASTER_MUST_TX)) sh_msiof_write(p, TMDR2, dr2); else sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1); @@ -666,11 +672,20 @@ static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs, static const struct sh_msiof_chipdata sh_data = { .tx_fifo_size = 64, .rx_fifo_size = 64, + .master_flags = 0, +}; + +static const struct sh_msiof_chipdata r8a779x_data = { + .tx_fifo_size = 64, + .rx_fifo_size = 256, + .master_flags = SPI_MASTER_MUST_TX, }; static const struct of_device_id sh_msiof_match[] = { { .compatible = "renesas,sh-msiof", .data = &sh_data }, { .compatible = "renesas,sh-mobile-msiof", .data = &sh_data }, + { .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data }, + { .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data }, {}, }; MODULE_DEVICE_TABLE(of, sh_msiof_match); @@ -790,7 +805,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) /* init master and bitbang code */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE; - master->flags = 0; + master->flags = p->chipdata->master_flags; master->bus_num = pdev->id; master->dev.of_node = pdev->dev.of_node; master->num_chipselect = p->info->num_chipselect; @@ -833,6 +848,8 @@ static int sh_msiof_spi_remove(struct platform_device *pdev) static struct platform_device_id spi_driver_ids[] = { { "spi_sh_msiof", (kernel_ulong_t)&sh_data }, + { "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data }, + { "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data }, {}, }; MODULE_DEVICE_TABLE(platform, spi_driver_ids); From c833ff7304511805ce5a3378d1637e39e00e00ea Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:21:11 +0100 Subject: [PATCH 26/39] spi: sh-msiof: Move clock management to (un)prepare_message() Move clock management and pin configuration from the bitbang chipselect() method to the SPI core prepare_message() and unprepare_message() methods. As spi_master.{,un}prepare_message() is guaranteed to be called in matching pairs, the clock management synchronization is no longer needed. As sh_msiof_spi_set_pin_regs() is no longer called at spi_master.setup() time (through spi_bitbang_setup() and the spi_bitbang.chipselect() callback), we now have to take care of that ourselves. Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 61 ++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index e7f4797fa59d..efeda03bbace 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -46,7 +46,6 @@ struct sh_msiof_spi_priv { const struct sh_msiof_chipdata *chipdata; struct sh_msiof_spi_info *info; struct completion done; - unsigned long flags; int tx_fifo_size; int rx_fifo_size; }; @@ -459,6 +458,7 @@ static int sh_msiof_spi_setup_transfer(struct spi_device *spi, static int sh_msiof_spi_setup(struct spi_device *spi) { struct device_node *np = spi->master->dev.of_node; + struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); if (!np) { /* @@ -468,12 +468,46 @@ static int sh_msiof_spi_setup(struct spi_device *spi) spi->cs_gpio = (uintptr_t)spi->controller_data; } + /* Configure pins before deasserting CS */ + sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL), + !!(spi->mode & SPI_CPHA), + !!(spi->mode & SPI_3WIRE), + !!(spi->mode & SPI_LSB_FIRST), + !!(spi->mode & SPI_CS_HIGH)); + return spi_bitbang_setup(spi); } +static int sh_msiof_prepare_message(struct spi_master *master, + struct spi_message *msg) +{ + struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); + const struct spi_device *spi = msg->spi; + + pm_runtime_get_sync(&p->pdev->dev); + clk_enable(p->clk); + + /* Configure pins before asserting CS */ + sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL), + !!(spi->mode & SPI_CPHA), + !!(spi->mode & SPI_3WIRE), + !!(spi->mode & SPI_LSB_FIRST), + !!(spi->mode & SPI_CS_HIGH)); + return 0; +} + +static int sh_msiof_unprepare_message(struct spi_master *master, + struct spi_message *msg) +{ + struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); + + clk_disable(p->clk); + pm_runtime_put(&p->pdev->dev); + return 0; +} + static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on) { - struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); int value; /* chip select is active low unless SPI_CS_HIGH is set */ @@ -482,29 +516,8 @@ static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on) else value = (is_on == BITBANG_CS_ACTIVE) ? 0 : 1; - if (is_on == BITBANG_CS_ACTIVE) { - if (!test_and_set_bit(0, &p->flags)) { - pm_runtime_get_sync(&p->pdev->dev); - clk_enable(p->clk); - } - - /* Configure pins before asserting CS */ - sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL), - !!(spi->mode & SPI_CPHA), - !!(spi->mode & SPI_3WIRE), - !!(spi->mode & SPI_LSB_FIRST), - !!(spi->mode & SPI_CS_HIGH)); - } - if (spi->cs_gpio >= 0) gpio_set_value(spi->cs_gpio, value); - - if (is_on == BITBANG_CS_INACTIVE) { - if (test_and_clear_bit(0, &p->flags)) { - clk_disable(p->clk); - pm_runtime_put(&p->pdev->dev); - } - } } static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, @@ -811,6 +824,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) master->num_chipselect = p->info->num_chipselect; master->setup = sh_msiof_spi_setup; master->cleanup = spi_bitbang_cleanup; + master->prepare_message = sh_msiof_prepare_message; + master->unprepare_message = sh_msiof_unprepare_message; p->bitbang.master = master; p->bitbang.chipselect = sh_msiof_spi_chipselect; From 2416289c714343ea855e725d59d42668a9ab3cf6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:21:12 +0100 Subject: [PATCH 27/39] spi: sh-msiof: Convert to let spi core validate xfer->bits_per_word Set bits_per_word_mask so the spi core will reject transfers that attempt to use an unsupported bits_per_word value. Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index efeda03bbace..a0380b7c977f 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -439,22 +439,6 @@ static u32 sh_msiof_spi_hz(struct spi_device *spi, struct spi_transfer *t) return hz; } -static int sh_msiof_spi_setup_transfer(struct spi_device *spi, - struct spi_transfer *t) -{ - int bits; - - /* noting to check hz values against since parent clock is disabled */ - - bits = sh_msiof_spi_bits(spi, t); - if (bits < 8) - return -EINVAL; - if (bits > 32) - return -EINVAL; - - return spi_bitbang_setup_transfer(spi, t); -} - static int sh_msiof_spi_setup(struct spi_device *spi) { struct device_node *np = spi->master->dev.of_node; @@ -826,10 +810,11 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) master->cleanup = spi_bitbang_cleanup; master->prepare_message = sh_msiof_prepare_message; master->unprepare_message = sh_msiof_unprepare_message; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); p->bitbang.master = master; p->bitbang.chipselect = sh_msiof_spi_chipselect; - p->bitbang.setup_transfer = sh_msiof_spi_setup_transfer; + p->bitbang.setup_transfer = spi_bitbang_setup_transfer; p->bitbang.txrx_bufs = sh_msiof_spi_txrx; p->bitbang.txrx_word[SPI_MODE_0] = sh_msiof_spi_txrx_word; p->bitbang.txrx_word[SPI_MODE_1] = sh_msiof_spi_txrx_word; From 1bd6363bc0c69ff6120b53daa35cf9459c3628ad Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:21:13 +0100 Subject: [PATCH 28/39] spi: sh-msiof: Use core message handling instead of spi-bitbang The only remaining feature of spi-bitbang used by this driver is the chipselect() callback, which just does conditional GPIO. This is handled fine by the SPI core's spi_set_cs(), hence switch the driver to use the core message handling through our own transfer_one() method. As the (optional) GPIO CS is no longer deasserted at spi_master.setup() time (through spi_bitbang_setup() and the spi_bitbang.chipselect() callback), we now have to take care of that ourselves. Remove the call to spi_master_put() in sh_msiof_spi_remove(), as our SPI master is now registered using devm_spi_register_master() (spi_bitbang_start() uses the non-managed version). Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 1 - drivers/spi/spi-sh-msiof.c | 67 ++++++++++++-------------------------- 2 files changed, 20 insertions(+), 48 deletions(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ba9310bc9acb..16f2987c29dc 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -416,7 +416,6 @@ config SPI_SH_MSIOF tristate "SuperH MSIOF SPI controller" depends on HAVE_CLK depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST - select SPI_BITBANG help SPI driver for SuperH and SH Mobile MSIOF blocks. diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index a0380b7c977f..db687011dc4f 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -27,7 +27,6 @@ #include #include -#include #include @@ -39,7 +38,6 @@ struct sh_msiof_chipdata { }; struct sh_msiof_spi_priv { - struct spi_bitbang bitbang; /* must be first for spi_bitbang.c */ void __iomem *mapbase; struct clk *clk; struct platform_device *pdev; @@ -459,7 +457,10 @@ static int sh_msiof_spi_setup(struct spi_device *spi) !!(spi->mode & SPI_LSB_FIRST), !!(spi->mode & SPI_CS_HIGH)); - return spi_bitbang_setup(spi); + if (spi->cs_gpio >= 0) + gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); + + return 0; } static int sh_msiof_prepare_message(struct spi_master *master, @@ -490,20 +491,6 @@ static int sh_msiof_unprepare_message(struct spi_master *master, return 0; } -static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on) -{ - int value; - - /* chip select is active low unless SPI_CS_HIGH is set */ - if (spi->mode & SPI_CS_HIGH) - value = (is_on == BITBANG_CS_ACTIVE) ? 1 : 0; - else - value = (is_on == BITBANG_CS_ACTIVE) ? 0 : 1; - - if (spi->cs_gpio >= 0) - gpio_set_value(spi->cs_gpio, value); -} - static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int), @@ -573,9 +560,11 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, return ret; } -static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t) +static int sh_msiof_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) { - struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); + struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int); void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int); int bits; @@ -656,13 +645,6 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t) words -= n; } - return bytes_done; -} - -static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs, - u32 word, u8 bits) -{ - BUG(); /* unused but needed by bitbang code */ return 0; } @@ -799,7 +781,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) if (p->info->rx_fifo_override) p->rx_fifo_size = p->info->rx_fifo_override; - /* init master and bitbang code */ + /* init master code */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE; master->flags = p->chipdata->master_flags; @@ -807,24 +789,20 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) master->dev.of_node = pdev->dev.of_node; master->num_chipselect = p->info->num_chipselect; master->setup = sh_msiof_spi_setup; - master->cleanup = spi_bitbang_cleanup; master->prepare_message = sh_msiof_prepare_message; master->unprepare_message = sh_msiof_unprepare_message; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); + master->transfer_one = sh_msiof_transfer_one; - p->bitbang.master = master; - p->bitbang.chipselect = sh_msiof_spi_chipselect; - p->bitbang.setup_transfer = spi_bitbang_setup_transfer; - p->bitbang.txrx_bufs = sh_msiof_spi_txrx; - p->bitbang.txrx_word[SPI_MODE_0] = sh_msiof_spi_txrx_word; - p->bitbang.txrx_word[SPI_MODE_1] = sh_msiof_spi_txrx_word; - p->bitbang.txrx_word[SPI_MODE_2] = sh_msiof_spi_txrx_word; - p->bitbang.txrx_word[SPI_MODE_3] = sh_msiof_spi_txrx_word; + ret = devm_spi_register_master(&pdev->dev, master); + if (ret < 0) { + dev_err(&pdev->dev, "spi_register_master error.\n"); + goto err2; + } - ret = spi_bitbang_start(&p->bitbang); - if (ret == 0) - return 0; + return 0; + err2: pm_runtime_disable(&pdev->dev); clk_unprepare(p->clk); err1: @@ -835,15 +813,10 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) static int sh_msiof_spi_remove(struct platform_device *pdev) { struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev); - int ret; - ret = spi_bitbang_stop(&p->bitbang); - if (!ret) { - pm_runtime_disable(&pdev->dev); - clk_unprepare(p->clk); - spi_master_put(p->bitbang.master); - } - return ret; + pm_runtime_disable(&pdev->dev); + clk_unprepare(p->clk); + return 0; } static struct platform_device_id spi_driver_ids[] = { From 80d68ca5a52176a140e1daa527d0b698feb69c83 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 27 Feb 2014 10:27:30 +0800 Subject: [PATCH 29/39] spi: sh-hspi: Remove hspi_cleanup function hspi_cleanup() is doing nothing except print a non-useful debug message, so remove it. Also remove unused hspi2info macro. Signed-off-by: Axel Lin Acked-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-hspi.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index dbd2c44f95e9..dad800b9887f 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -46,8 +46,6 @@ /* SPSR */ #define RXFL (1 << 2) -#define hspi2info(h) (h->dev->platform_data) - struct hspi_priv { void __iomem *addr; struct spi_master *master; @@ -230,14 +228,6 @@ static int hspi_transfer_one_message(struct spi_master *master, return ret; } -static void hspi_cleanup(struct spi_device *spi) -{ - struct hspi_priv *hspi = spi_master_get_devdata(spi->master); - struct device *dev = hspi->dev; - - dev_dbg(dev, "%s cleanup\n", spi->modalias); -} - static int hspi_probe(struct platform_device *pdev) { struct resource *res; @@ -285,7 +275,6 @@ static int hspi_probe(struct platform_device *pdev) master->num_chipselect = 1; master->bus_num = pdev->id; - master->cleanup = hspi_cleanup; master->mode_bits = SPI_CPOL | SPI_CPHA; master->dev.of_node = pdev->dev.of_node; master->auto_runtime_pm = true; From e428a420078eac26039b53af464355332809be52 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 2 Mar 2014 23:01:50 +0800 Subject: [PATCH 30/39] spi: sh-hspi: Remove duplicate code to set default transfer speed In the implementation of __spi_validate(), spi core will use spi device's max speed as default transfer speed if it is not set for this transfer. So we can remove the same logic in hspi_hw_setup(). Signed-off-by: Axel Lin Acked-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-hspi.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index dad800b9887f..180eecf72428 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -111,14 +111,9 @@ static void hspi_hw_setup(struct hspi_priv *hspi, { struct spi_device *spi = msg->spi; struct device *dev = hspi->dev; - u32 target_rate; u32 spcr, idiv_clk; u32 rate, best_rate, min, tmp; - target_rate = t ? t->speed_hz : 0; - if (!target_rate) - target_rate = spi->max_speed_hz; - /* * find best IDIV/CLKCx settings */ @@ -138,7 +133,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi, rate /= (((idiv_clk & 0x1F) + 1) * 2); /* save best settings */ - tmp = abs(target_rate - rate); + tmp = abs(t->speed_hz - rate); if (tmp < min) { min = tmp; spcr = idiv_clk; @@ -151,7 +146,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi, if (spi->mode & SPI_CPOL) spcr |= 1 << 6; - dev_dbg(dev, "speed %d/%d\n", target_rate, best_rate); + dev_dbg(dev, "speed %d/%d\n", t->speed_hz, best_rate); hspi_write(hspi, SPCR, spcr); hspi_write(hspi, SPSR, 0x0); From b14158603288b9d898716b41f2f0acb7d49dad2c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 2 Mar 2014 22:30:32 +0800 Subject: [PATCH 31/39] spi: sh-msiof: Kill sh_msiof_spi_bits and sh_msiof_spi_hz functions In the implementation of __spi_validate(), spi core will set transfer bits_per_word and max speed as spi device default if it is not set for this transfer. So we can remove the same implementation in this driver. Signed-off-by: Axel Lin Acked-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index db687011dc4f..3ffb8eed5ac5 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -417,26 +417,6 @@ static void sh_msiof_spi_read_fifo_s32u(struct sh_msiof_spi_priv *p, put_unaligned(swab32(sh_msiof_read(p, RFDR) >> fs), &buf_32[k]); } -static int sh_msiof_spi_bits(struct spi_device *spi, struct spi_transfer *t) -{ - int bits; - - bits = t ? t->bits_per_word : 0; - if (!bits) - bits = spi->bits_per_word; - return bits; -} - -static u32 sh_msiof_spi_hz(struct spi_device *spi, struct spi_transfer *t) -{ - u32 hz; - - hz = t ? t->speed_hz : 0; - if (!hz) - hz = spi->max_speed_hz; - return hz; -} - static int sh_msiof_spi_setup(struct spi_device *spi) { struct device_node *np = spi->master->dev.of_node; @@ -574,7 +554,7 @@ static int sh_msiof_transfer_one(struct spi_master *master, int n; bool swab; - bits = sh_msiof_spi_bits(spi, t); + bits = t->bits_per_word; if (bits <= 8 && t->len > 15 && !(t->len & 3)) { bits = 32; @@ -624,8 +604,7 @@ static int sh_msiof_transfer_one(struct spi_master *master, } /* setup clocks (clock already enabled in chipselect()) */ - sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), - sh_msiof_spi_hz(spi, t)); + sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz); /* transfer in fifo sized chunks */ words = t->len / bytes_per_word; From eeb7139524d1851c29b5c02b3dcd6679299a104e Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Sat, 1 Mar 2014 12:38:17 +0800 Subject: [PATCH 32/39] spi: sirf: provide a shortcut for spi command-data mode there are many SPI clients which use the following protocal: step 1: send command bytes to clients(rx buffer is empty) step 2: send data bytes to clients or receive data bytes from clients. SiRFprimaII provides a shortcut for this kind of SPI transfer. when tx buf is less or equal than 4 bytes and rx buf is null in a transfer, we think it as 'command' data and use hardware command register for the transfer. here we can save some CPU loading than doing both tx and rx for a normal transfer. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index dc962a17f373..a72b8f87a156 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -131,6 +131,8 @@ #define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \ ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE)) +#define SIRFSOC_MAX_CMD_BYTES 4 + struct sirfsoc_spi { struct spi_bitbang bitbang; struct completion rx_done; @@ -161,6 +163,12 @@ struct sirfsoc_spi { void *dummypage; int word_width; /* in bytes */ + /* + * if tx size is not more than 4 and rx size is NULL, use + * command model + */ + bool tx_by_cmd; + int chipselect[0]; }; @@ -259,6 +267,12 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id) writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS); + if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) { + complete(&sspi->tx_done); + writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); + return IRQ_HANDLED; + } + /* Error Conditions */ if (spi_stat & SIRFSOC_SPI_RX_OFLOW || spi_stat & SIRFSOC_SPI_TX_UFLOW) { @@ -309,6 +323,34 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); + /* + * fill tx_buf into command register and wait for its completion + */ + if (sspi->tx_by_cmd) { + u32 cmd; + memcpy(&cmd, sspi->tx, t->len); + + if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST)) + cmd = cpu_to_be32(cmd) >> + ((SIRFSOC_MAX_CMD_BYTES - t->len) * 8); + if (sspi->word_width == 2 && t->len == 4 && + (!(spi->mode & SPI_LSB_FIRST))) + cmd = ((cmd & 0xffff) << 16) | (cmd >> 16); + + writel(cmd, sspi->base + SIRFSOC_SPI_CMD); + writel(SIRFSOC_SPI_FRM_END_INT_EN, + sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_CMD_TX_EN, + sspi->base + SIRFSOC_SPI_TX_RX_EN); + + if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { + dev_err(&spi->dev, "transfer timeout\n"); + return 0; + } + + return t->len; + } + if (sspi->left_tx_word == 1) { writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | SIRFSOC_SPI_ENA_AUTO_CLR, @@ -509,6 +551,14 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) writel(txfifo_ctrl, sspi->base + SIRFSOC_SPI_TXFIFO_CTRL); writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL); + if (t && t->tx_buf && !t->rx_buf && (t->len <= SIRFSOC_MAX_CMD_BYTES)) { + regval |= (SIRFSOC_SPI_CMD_BYTE_NUM((t->len - 1)) | + SIRFSOC_SPI_CMD_MODE); + sspi->tx_by_cmd = true; + } else { + regval &= ~SIRFSOC_SPI_CMD_MODE; + sspi->tx_by_cmd = false; + } writel(regval, sspi->base + SIRFSOC_SPI_CTRL); if (IS_DMA_VALID(t)) { From f9ee821ebc5e58ff5da08d625ea4e2d74b221317 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 10:43:26 +0100 Subject: [PATCH 33/39] spi: sh-msiof: Remove "renesas,msiof-sh7724" from bindings It's not implemented in the driver, so it's a bad example. Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/sh-msiof.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt index 1f0cb33763a1..f24baf3b6cc1 100644 --- a/Documentation/devicetree/bindings/spi/sh-msiof.txt +++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt @@ -5,7 +5,6 @@ Required properties: "renesas,sh-msiof" for SuperH, or "renesas,sh-mobile-msiof" for SH Mobile series. Examples with soctypes are: - "renesas,msiof-sh7724" (SH) "renesas,msiof-r8a7790" (R-Car H2) "renesas,msiof-r8a7791" (R-Car M2) - reg : Offset and length of the register set for the device From c3003ce144fe0279e4299030b1cfad6f4b39116a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 10:40:51 +0100 Subject: [PATCH 34/39] spi: sh-spi: Improve bindings - Add future-proof "renesas,hspi-" compatible values, - Add missing "interrupt-parent", "#address-cells", and "#size-cells" properties, - Add reference to pinctrl documentation, - Add example bindings. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/sh-hspi.txt | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/sh-hspi.txt b/Documentation/devicetree/bindings/spi/sh-hspi.txt index 30b57b1c8a13..319bad4af875 100644 --- a/Documentation/devicetree/bindings/spi/sh-hspi.txt +++ b/Documentation/devicetree/bindings/spi/sh-hspi.txt @@ -1,7 +1,29 @@ Renesas HSPI. Required properties: -- compatible : "renesas,hspi" -- reg : Offset and length of the register set for the device -- interrupts : interrupt line used by HSPI +- compatible : "renesas,hspi-", "renesas,hspi" as fallback. + Examples with soctypes are: + - "renesas,hspi-r8a7778" (R-Car M1) + - "renesas,hspi-r8a7779" (R-Car H1) +- reg : Offset and length of the register set for the device +- interrupt-parent : The phandle for the interrupt controller that + services interrupts for this device +- interrupts : Interrupt specifier +- #address-cells : Must be <1> +- #size-cells : Must be <0> + +Pinctrl properties might be needed, too. See +Documentation/devicetree/bindings/pinctrl/renesas,*. + +Example: + + hspi0: spi@fffc7000 { + compatible = "renesas,hspi-r8a7778", "renesas,hspi"; + reg = <0xfffc7000 0x18>; + interrupt-parent = <&gic>; + interrupts = <0 63 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; From 3abf0edd2c16326727326c35704ab9cad0529eda Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 10:59:10 +0100 Subject: [PATCH 35/39] spi: sh-hspi: Add missing call to pm_runtime_disable() in failure path Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-hspi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 180eecf72428..89cfedf6d21a 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -279,11 +279,13 @@ static int hspi_probe(struct platform_device *pdev) ret = devm_spi_register_master(&pdev->dev, master); if (ret < 0) { dev_err(&pdev->dev, "spi_register_master error.\n"); - goto error1; + goto error2; } return 0; + error2: + pm_runtime_disable(&pdev->dev); error1: clk_put(clk); error0: From e2a0ba547ba31cd7b217cc948d93e4edc78cbcb1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 10:59:11 +0100 Subject: [PATCH 36/39] spi: sh-msiof: Convert to spi core auto_runtime_pm framework Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 3ffb8eed5ac5..b6b013a2f397 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -449,9 +449,6 @@ static int sh_msiof_prepare_message(struct spi_master *master, struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); const struct spi_device *spi = msg->spi; - pm_runtime_get_sync(&p->pdev->dev); - clk_enable(p->clk); - /* Configure pins before asserting CS */ sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL), !!(spi->mode & SPI_CPHA), @@ -461,16 +458,6 @@ static int sh_msiof_prepare_message(struct spi_master *master, return 0; } -static int sh_msiof_unprepare_message(struct spi_master *master, - struct spi_message *msg) -{ - struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); - - clk_disable(p->clk); - pm_runtime_put(&p->pdev->dev); - return 0; -} - static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int), @@ -743,12 +730,6 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) goto err1; } - ret = clk_prepare(p->clk); - if (ret < 0) { - dev_err(&pdev->dev, "unable to prepare clock\n"); - goto err1; - } - p->pdev = pdev; pm_runtime_enable(&pdev->dev); @@ -769,8 +750,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) master->num_chipselect = p->info->num_chipselect; master->setup = sh_msiof_spi_setup; master->prepare_message = sh_msiof_prepare_message; - master->unprepare_message = sh_msiof_unprepare_message; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); + master->auto_runtime_pm = true; master->transfer_one = sh_msiof_transfer_one; ret = devm_spi_register_master(&pdev->dev, master); @@ -783,7 +764,6 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) err2: pm_runtime_disable(&pdev->dev); - clk_unprepare(p->clk); err1: spi_master_put(master); return ret; @@ -791,10 +771,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) static int sh_msiof_spi_remove(struct platform_device *pdev) { - struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev); - pm_runtime_disable(&pdev->dev); - clk_unprepare(p->clk); return 0; } From 09e99bca8324c3335794b86802486bb5191861d5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Feb 2014 18:39:33 +0800 Subject: [PATCH 37/39] spi: sc18is602: Convert to let spi core validate transfer speed Set master->max_speed_hz and master->min_speed_hz then spi core will handle checking transfer speed. So we can remove the same checking in this driver. This patch also remove testing if hz is 0 because spi->max_speed_hz will be default set to master->min_speed_hz if it was not set. So the transfer speed will never set to 0. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-sc18is602.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c index 7fba10bba3b0..237f2e7a7179 100644 --- a/drivers/spi/spi-sc18is602.c +++ b/drivers/spi/spi-sc18is602.c @@ -183,17 +183,9 @@ static int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode) static int sc18is602_check_transfer(struct spi_device *spi, struct spi_transfer *t, int tlen) { - uint32_t hz; - if (t && t->len + tlen > SC18IS602_BUFSIZ) return -EINVAL; - hz = spi->max_speed_hz; - if (t && t->speed_hz) - hz = t->speed_hz; - if (hz == 0) - return -EINVAL; - return 0; } @@ -207,14 +199,13 @@ static int sc18is602_transfer_one(struct spi_master *master, hw->tlen = 0; list_for_each_entry(t, &m->transfers, transfer_list) { - u32 hz = t->speed_hz ? : spi->max_speed_hz; bool do_transfer; status = sc18is602_check_transfer(spi, t, hw->tlen); if (status < 0) break; - status = sc18is602_setup_transfer(hw, hz, spi->mode); + status = sc18is602_setup_transfer(hw, t->speed_hz, spi->mode); if (status < 0) break; @@ -305,6 +296,8 @@ static int sc18is602_probe(struct i2c_client *client, master->setup = sc18is602_setup; master->transfer_one_message = sc18is602_transfer_one; master->dev.of_node = np; + master->min_speed_hz = hw->freq / 128; + master->max_speed_hz = hw->freq / 4; error = devm_spi_register_master(dev, master); if (error) From a82ba3a318dd5eaf1f3dcbc335f81770d557a4fc Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 5 Mar 2014 15:19:09 +0800 Subject: [PATCH 38/39] spi: sirf: Add missing spi_master_{resume,suspend} calls to PM callbacks This is required since commit 2025172e3280 "spi/bitbang: Use core message pump". spi-bitbang now uses core message pump, so it needs to call spi_master_suspend/ spi_master_resume to stop/start the queue while suspend/resume. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index a72b8f87a156..1a77ad52812f 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -748,6 +748,11 @@ static int spi_sirfsoc_suspend(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); struct sirfsoc_spi *sspi = spi_master_get_devdata(master); + int ret; + + ret = spi_master_suspend(master); + if (ret) + return ret; clk_disable(sspi->clk); return 0; @@ -764,7 +769,7 @@ static int spi_sirfsoc_resume(struct device *dev) writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); - return 0; + return spi_master_resume(master); } #endif From ed8eb250d7b097dbd888e46ad0d35a2cb1858221 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 13 Mar 2014 10:32:37 +0800 Subject: [PATCH 39/39] spi: sh-sci: Prevent NULL pointer dereference If sp->info is NULL, we will hit NULL pointer dereference in probe() while setting bus_num and num_chipselect for master: sp->bitbang.master->bus_num = sp->info->bus_num; sp->bitbang.master->num_chipselect = sp->info->num_chipselect; Thus add NULL test for sp->info in probe() to prevent NULL pointer dereference. Signed-off-by: Axel Lin Reviewed-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-sci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c index 38eb24df796c..41b1346b29d5 100644 --- a/drivers/spi/spi-sh-sci.c +++ b/drivers/spi/spi-sh-sci.c @@ -109,7 +109,7 @@ static void sh_sci_spi_chipselect(struct spi_device *dev, int value) { struct sh_sci_spi *sp = spi_master_get_devdata(dev->master); - if (sp->info && sp->info->chip_select) + if (sp->info->chip_select) (sp->info->chip_select)(sp->info, dev->chip_select, value); } @@ -131,6 +131,11 @@ static int sh_sci_spi_probe(struct platform_device *dev) platform_set_drvdata(dev, sp); sp->info = dev_get_platdata(&dev->dev); + if (!sp->info) { + dev_err(&dev->dev, "platform data is missing\n"); + ret = -ENOENT; + goto err1; + } /* setup spi bitbang adaptor */ sp->bitbang.master = master;