diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/Kconfig | 8 | ||||
-rw-r--r-- | drivers/spi/spi-ath79.c | 34 | ||||
-rw-r--r-- | drivers/spi/spi-atmel.c | 292 | ||||
-rw-r--r-- | drivers/spi/spi-bcm2835.c | 393 | ||||
-rw-r--r-- | drivers/spi/spi-bitbang.c | 17 | ||||
-rw-r--r-- | drivers/spi/spi-davinci.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-cpm.c | 40 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-dspi.c | 307 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-espi.c | 51 | ||||
-rw-r--r-- | drivers/spi/spi-omap2-mcspi.c | 270 | ||||
-rw-r--r-- | drivers/spi/spi-orion.c | 70 | ||||
-rw-r--r-- | drivers/spi/spi.c | 36 |
12 files changed, 1169 insertions, 351 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 198f96b..7183be8 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -77,7 +77,9 @@ config SPI_ATMEL config SPI_BCM2835 tristate "BCM2835 SPI controller" + depends on GPIOLIB depends on ARCH_BCM2835 || COMPILE_TEST + depends on GPIOLIB help This selects a driver for the Broadcom BCM2835 SPI master. @@ -220,7 +222,7 @@ config SPI_FALCON config SPI_GPIO tristate "GPIO-based bitbanging SPI Master" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST select SPI_BITBANG help This simple GPIO bitbanging SPI master uses the arch-neutral GPIO @@ -302,7 +304,7 @@ config SPI_FSL_SPI config SPI_FSL_DSPI tristate "Freescale DSPI controller" select REGMAP_MMIO - depends on SOC_VF610 || COMPILE_TEST + depends on SOC_VF610 || SOC_LS1021A || COMPILE_TEST help This enables support for the Freescale DSPI controller in master mode. VF610 platform uses the controller. @@ -326,7 +328,7 @@ config SPI_MESON_SPIFC config SPI_OC_TINY tristate "OpenCores tiny SPI" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST select SPI_BITBANG help This is the driver for OpenCores tiny SPI master controller. diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index b02eb4a..bf1f9b3 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -79,10 +79,8 @@ static void ath79_spi_chipselect(struct spi_device *spi, int is_active) } if (spi->chip_select) { - struct ath79_spi_controller_data *cdata = spi->controller_data; - /* SPI is normally active-low */ - gpio_set_value(cdata->gpio, cs_high); + gpio_set_value(spi->cs_gpio, cs_high); } else { if (cs_high) sp->ioc_base |= AR71XX_SPI_IOC_CS0; @@ -117,11 +115,10 @@ static void ath79_spi_disable(struct ath79_spi *sp) static int ath79_spi_setup_cs(struct spi_device *spi) { - struct ath79_spi_controller_data *cdata; + struct ath79_spi *sp = ath79_spidev_to_sp(spi); int status; - cdata = spi->controller_data; - if (spi->chip_select && !cdata) + if (spi->chip_select && !gpio_is_valid(spi->cs_gpio)) return -EINVAL; status = 0; @@ -134,8 +131,15 @@ static int ath79_spi_setup_cs(struct spi_device *spi) else flags |= GPIOF_INIT_HIGH; - status = gpio_request_one(cdata->gpio, flags, + status = gpio_request_one(spi->cs_gpio, flags, dev_name(&spi->dev)); + } else { + if (spi->mode & SPI_CS_HIGH) + sp->ioc_base &= ~AR71XX_SPI_IOC_CS0; + else + sp->ioc_base |= AR71XX_SPI_IOC_CS0; + + ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); } return status; @@ -144,8 +148,7 @@ static int ath79_spi_setup_cs(struct spi_device *spi) static void ath79_spi_cleanup_cs(struct spi_device *spi) { if (spi->chip_select) { - struct ath79_spi_controller_data *cdata = spi->controller_data; - gpio_free(cdata->gpio); + gpio_free(spi->cs_gpio); } } @@ -217,6 +220,7 @@ static int ath79_spi_probe(struct platform_device *pdev) } sp = spi_master_get_devdata(master); + master->dev.of_node = pdev->dev.of_node; platform_set_drvdata(pdev, sp); pdata = dev_get_platdata(&pdev->dev); @@ -253,7 +257,7 @@ static int ath79_spi_probe(struct platform_device *pdev) goto err_put_master; } - ret = clk_enable(sp->clk); + ret = clk_prepare_enable(sp->clk); if (ret) goto err_put_master; @@ -277,7 +281,7 @@ static int ath79_spi_probe(struct platform_device *pdev) err_disable: ath79_spi_disable(sp); err_clk_disable: - clk_disable(sp->clk); + clk_disable_unprepare(sp->clk); err_put_master: spi_master_put(sp->bitbang.master); @@ -290,7 +294,7 @@ static int ath79_spi_remove(struct platform_device *pdev) spi_bitbang_stop(&sp->bitbang); ath79_spi_disable(sp); - clk_disable(sp->clk); + clk_disable_unprepare(sp->clk); spi_master_put(sp->bitbang.master); return 0; @@ -301,12 +305,18 @@ static void ath79_spi_shutdown(struct platform_device *pdev) ath79_spi_remove(pdev); } +static const struct of_device_id ath79_spi_of_match[] = { + { .compatible = "qca,ar7100-spi", }, + { }, +}; + static struct platform_driver ath79_spi_driver = { .probe = ath79_spi_probe, .remove = ath79_spi_remove, .shutdown = ath79_spi_shutdown, .driver = { .name = DRV_NAME, + .of_match_table = ath79_spi_of_match, }, }; module_platform_driver(ath79_spi_driver); diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index a2f40b1..c9eca34 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -41,6 +41,8 @@ #define SPI_CSR1 0x0034 #define SPI_CSR2 0x0038 #define SPI_CSR3 0x003c +#define SPI_FMR 0x0040 +#define SPI_FLR 0x0044 #define SPI_VERSION 0x00fc #define SPI_RPR 0x0100 #define SPI_RCR 0x0104 @@ -62,6 +64,14 @@ #define SPI_SWRST_SIZE 1 #define SPI_LASTXFER_OFFSET 24 #define SPI_LASTXFER_SIZE 1 +#define SPI_TXFCLR_OFFSET 16 +#define SPI_TXFCLR_SIZE 1 +#define SPI_RXFCLR_OFFSET 17 +#define SPI_RXFCLR_SIZE 1 +#define SPI_FIFOEN_OFFSET 30 +#define SPI_FIFOEN_SIZE 1 +#define SPI_FIFODIS_OFFSET 31 +#define SPI_FIFODIS_SIZE 1 /* Bitfields in MR */ #define SPI_MSTR_OFFSET 0 @@ -114,6 +124,22 @@ #define SPI_TXEMPTY_SIZE 1 #define SPI_SPIENS_OFFSET 16 #define SPI_SPIENS_SIZE 1 +#define SPI_TXFEF_OFFSET 24 +#define SPI_TXFEF_SIZE 1 +#define SPI_TXFFF_OFFSET 25 +#define SPI_TXFFF_SIZE 1 +#define SPI_TXFTHF_OFFSET 26 +#define SPI_TXFTHF_SIZE 1 +#define SPI_RXFEF_OFFSET 27 +#define SPI_RXFEF_SIZE 1 +#define SPI_RXFFF_OFFSET 28 +#define SPI_RXFFF_SIZE 1 +#define SPI_RXFTHF_OFFSET 29 +#define SPI_RXFTHF_SIZE 1 +#define SPI_TXFPTEF_OFFSET 30 +#define SPI_TXFPTEF_SIZE 1 +#define SPI_RXFPTEF_OFFSET 31 +#define SPI_RXFPTEF_SIZE 1 /* Bitfields in CSR0 */ #define SPI_CPOL_OFFSET 0 @@ -157,6 +183,22 @@ #define SPI_TXTDIS_OFFSET 9 #define SPI_TXTDIS_SIZE 1 +/* Bitfields in FMR */ +#define SPI_TXRDYM_OFFSET 0 +#define SPI_TXRDYM_SIZE 2 +#define SPI_RXRDYM_OFFSET 4 +#define SPI_RXRDYM_SIZE 2 +#define SPI_TXFTHRES_OFFSET 16 +#define SPI_TXFTHRES_SIZE 6 +#define SPI_RXFTHRES_OFFSET 24 +#define SPI_RXFTHRES_SIZE 6 + +/* Bitfields in FLR */ +#define SPI_TXFL_OFFSET 0 +#define SPI_TXFL_SIZE 6 +#define SPI_RXFL_OFFSET 16 +#define SPI_RXFL_SIZE 6 + /* Constants for BITS */ #define SPI_BITS_8_BPT 0 #define SPI_BITS_9_BPT 1 @@ -167,6 +209,9 @@ #define SPI_BITS_14_BPT 6 #define SPI_BITS_15_BPT 7 #define SPI_BITS_16_BPT 8 +#define SPI_ONE_DATA 0 +#define SPI_TWO_DATA 1 +#define SPI_FOUR_DATA 2 /* Bit manipulation macros */ #define SPI_BIT(name) \ @@ -185,11 +230,31 @@ __raw_readl((port)->regs + SPI_##reg) #define spi_writel(port, reg, value) \ __raw_writel((value), (port)->regs + SPI_##reg) + +#define spi_readw(port, reg) \ + __raw_readw((port)->regs + SPI_##reg) +#define spi_writew(port, reg, value) \ + __raw_writew((value), (port)->regs + SPI_##reg) + +#define spi_readb(port, reg) \ + __raw_readb((port)->regs + SPI_##reg) +#define spi_writeb(port, reg, value) \ + __raw_writeb((value), (port)->regs + SPI_##reg) #else #define spi_readl(port, reg) \ readl_relaxed((port)->regs + SPI_##reg) #define spi_writel(port, reg, value) \ writel_relaxed((value), (port)->regs + SPI_##reg) + +#define spi_readw(port, reg) \ + readw_relaxed((port)->regs + SPI_##reg) +#define spi_writew(port, reg, value) \ + writew_relaxed((value), (port)->regs + SPI_##reg) + +#define spi_readb(port, reg) \ + readb_relaxed((port)->regs + SPI_##reg) +#define spi_writeb(port, reg, value) \ + writeb_relaxed((value), (port)->regs + SPI_##reg) #endif /* use PIO for small transfers, avoiding DMA setup/teardown overhead and * cache operations; better heuristics consider wordsize and bitrate. @@ -246,11 +311,14 @@ struct atmel_spi { bool use_dma; bool use_pdc; + bool use_cs_gpios; /* dmaengine data */ struct atmel_spi_dma dma; bool keep_cs; bool cs_active; + + u32 fifo_size; }; /* Controller-specific per-slave state */ @@ -321,7 +389,8 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) } mr = spi_readl(as, MR); - gpio_set_value(asd->npcs_pin, active); + if (as->use_cs_gpios) + gpio_set_value(asd->npcs_pin, active); } else { u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; int i; @@ -337,7 +406,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) mr = spi_readl(as, MR); mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); - if (spi->chip_select != 0) + if (as->use_cs_gpios && spi->chip_select != 0) gpio_set_value(asd->npcs_pin, active); spi_writel(as, MR, mr); } @@ -366,7 +435,9 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) asd->npcs_pin, active ? " (low)" : "", mr); - if (atmel_spi_is_v2(as) || spi->chip_select != 0) + if (!as->use_cs_gpios) + spi_writel(as, CR, SPI_BIT(LASTXFER)); + else if (atmel_spi_is_v2(as) || spi->chip_select != 0) gpio_set_value(asd->npcs_pin, !active); } @@ -406,6 +477,20 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, slave_config->dst_maxburst = 1; slave_config->device_fc = false; + /* + * This driver uses fixed peripheral select mode (PS bit set to '0' in + * the Mode Register). + * So according to the datasheet, when FIFOs are available (and + * enabled), the Transmit FIFO operates in Multiple Data Mode. + * In this mode, up to 2 data, not 4, can be written into the Transmit + * Data Register in a single access. + * However, the first data has to be written into the lowest 16 bits and + * the second data into the highest 16 bits of the Transmit + * Data Register. For 8bit data (the most frequent case), it would + * require to rework tx_buf so each data would actualy fit 16 bits. + * So we'd rather write only one data at the time. Hence the transmit + * path works the same whether FIFOs are available (and enabled) or not. + */ slave_config->direction = DMA_MEM_TO_DEV; if (dmaengine_slave_config(as->dma.chan_tx, slave_config)) { dev_err(&as->pdev->dev, @@ -413,6 +498,14 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, err = -EINVAL; } + /* + * This driver configures the spi controller for master mode (MSTR bit + * set to '1' in the Mode Register). + * So according to the datasheet, when FIFOs are available (and + * enabled), the Receive FIFO operates in Single Data Mode. + * So the receive path works the same whether FIFOs are available (and + * enabled) or not. + */ slave_config->direction = DMA_DEV_TO_MEM; if (dmaengine_slave_config(as->dma.chan_rx, slave_config)) { dev_err(&as->pdev->dev, @@ -502,10 +595,10 @@ static void dma_callback(void *data) } /* - * Next transfer using PIO. + * Next transfer using PIO without FIFO. */ -static void atmel_spi_next_xfer_pio(struct spi_master *master, - struct spi_transfer *xfer) +static void atmel_spi_next_xfer_single(struct spi_master *master, + struct spi_transfer *xfer) { struct atmel_spi *as = spi_master_get_devdata(master); unsigned long xfer_pos = xfer->len - as->current_remaining_bytes; @@ -538,6 +631,99 @@ static void atmel_spi_next_xfer_pio(struct spi_master *master, } /* + * Next transfer using PIO with FIFO. + */ +static void atmel_spi_next_xfer_fifo(struct spi_master *master, + struct spi_transfer *xfer) +{ + struct atmel_spi *as = spi_master_get_devdata(master); + u32 current_remaining_data, num_data; + u32 offset = xfer->len - as->current_remaining_bytes; + const u16 *words = (const u16 *)((u8 *)xfer->tx_buf + offset); + const u8 *bytes = (const u8 *)((u8 *)xfer->tx_buf + offset); + u16 td0, td1; + u32 fifomr; + + dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_fifo\n"); + + /* Compute the number of data to transfer in the current iteration */ + current_remaining_data = ((xfer->bits_per_word > 8) ? + ((u32)as->current_remaining_bytes >> 1) : + (u32)as->current_remaining_bytes); + num_data = min(current_remaining_data, as->fifo_size); + + /* Flush RX and TX FIFOs */ + spi_writel(as, CR, SPI_BIT(RXFCLR) | SPI_BIT(TXFCLR)); + while (spi_readl(as, FLR)) + cpu_relax(); + + /* Set RX FIFO Threshold to the number of data to transfer */ + fifomr = spi_readl(as, FMR); + spi_writel(as, FMR, SPI_BFINS(RXFTHRES, num_data, fifomr)); + + /* Clear FIFO flags in the Status Register, especially RXFTHF */ + (void)spi_readl(as, SR); + + /* Fill TX FIFO */ + while (num_data >= 2) { + if (xfer->tx_buf) { + if (xfer->bits_per_word > 8) { + td0 = *words++; + td1 = *words++; + } else { + td0 = *bytes++; + td1 = *bytes++; + } + } else { + td0 = 0; + td1 = 0; + } + + spi_writel(as, TDR, (td1 << 16) | td0); + num_data -= 2; + } + + if (num_data) { + if (xfer->tx_buf) { + if (xfer->bits_per_word > 8) + td0 = *words++; + else + td0 = *bytes++; + } else { + td0 = 0; + } + + spi_writew(as, TDR, td0); + num_data--; + } + + dev_dbg(master->dev.parent, + " start fifo xfer %p: len %u tx %p rx %p bitpw %d\n", + xfer, xfer->len, xfer->tx_buf, xfer->rx_buf, + xfer->bits_per_word); + + /* + * Enable RX FIFO Threshold Flag interrupt to be notified about + * transfer completion. + */ + spi_writel(as, IER, SPI_BIT(RXFTHF) | SPI_BIT(OVRES)); +} + +/* + * Next transfer using PIO. + */ +static void atmel_spi_next_xfer_pio(struct spi_master *master, + struct spi_transfer *xfer) +{ + struct atmel_spi *as = spi_master_get_devdata(master); + + if (as->fifo_size) + atmel_spi_next_xfer_fifo(master, xfer); + else + atmel_spi_next_xfer_single(master, xfer); +} + +/* * Submit next transfer for DMA. */ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, @@ -839,13 +1025,8 @@ static void atmel_spi_disable_pdc_transfer(struct atmel_spi *as) spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); } -/* Called from IRQ - * - * Must update "current_remaining_bytes" to keep track of data - * to transfer. - */ static void -atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer) +atmel_spi_pump_single_data(struct atmel_spi *as, struct spi_transfer *xfer) { u8 *rxp; u16 *rxp16; @@ -872,6 +1053,57 @@ atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer) } } +static void +atmel_spi_pump_fifo_data(struct atmel_spi *as, struct spi_transfer *xfer) +{ + u32 fifolr = spi_readl(as, FLR); + u32 num_bytes, num_data = SPI_BFEXT(RXFL, fifolr); + u32 offset = xfer->len - as->current_remaining_bytes; + u16 *words = (u16 *)((u8 *)xfer->rx_buf + offset); + u8 *bytes = (u8 *)((u8 *)xfer->rx_buf + offset); + u16 rd; /* RD field is the lowest 16 bits of RDR */ + + /* Update the number of remaining bytes to transfer */ + num_bytes = ((xfer->bits_per_word > 8) ? + (num_data << 1) : + num_data); + + if (as->current_remaining_bytes > num_bytes) + as->current_remaining_bytes -= num_bytes; + else + as->current_remaining_bytes = 0; + + /* Handle odd number of bytes when data are more than 8bit width */ + if (xfer->bits_per_word > 8) + as->current_remaining_bytes &= ~0x1; + + /* Read data */ + while (num_data) { + rd = spi_readl(as, RDR); + if (xfer->rx_buf) { + if (xfer->bits_per_word > 8) + *words++ = rd; + else + *bytes++ = rd; + } + num_data--; + } +} + +/* Called from IRQ + * + * Must update "current_remaining_bytes" to keep track of data + * to transfer. + */ +static void +atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer) +{ + if (as->fifo_size) + atmel_spi_pump_fifo_data(as, xfer); + else + atmel_spi_pump_single_data(as, xfer); +} + /* Interrupt * * No need for locking in this Interrupt handler: done_status is the @@ -912,7 +1144,7 @@ atmel_spi_pio_interrupt(int irq, void *dev_id) complete(&as->xfer_completion); - } else if (pending & SPI_BIT(RDRF)) { + } else if (pending & (SPI_BIT(RDRF) | SPI_BIT(RXFTHF))) { atmel_spi_lock(as); if (as->current_remaining_bytes) { @@ -996,6 +1228,8 @@ static int atmel_spi_setup(struct spi_device *spi) csr |= SPI_BIT(CPOL); if (!(spi->mode & SPI_CPHA)) csr |= SPI_BIT(NCPHA); + if (!as->use_cs_gpios) + csr |= SPI_BIT(CSAAT); /* DLYBS is mostly irrelevant since we manage chipselect using GPIOs. * @@ -1009,7 +1243,9 @@ static int atmel_spi_setup(struct spi_device *spi) /* chipselect must have been muxed as GPIO (e.g. in board setup) */ npcs_pin = (unsigned long)spi->controller_data; - if (gpio_is_valid(spi->cs_gpio)) + if (!as->use_cs_gpios) + npcs_pin = spi->chip_select; + else if (gpio_is_valid(spi->cs_gpio)) npcs_pin = spi->cs_gpio; asd = spi->controller_state; @@ -1018,15 +1254,19 @@ static int atmel_spi_setup(struct spi_device *spi) if (!asd) return -ENOMEM; - ret = gpio_request(npcs_pin, dev_name(&spi->dev)); - if (ret) { - kfree(asd); - return ret; + if (as->use_cs_gpios) { + ret = gpio_request(npcs_pin, dev_name(&spi->dev)); + if (ret) { + kfree(asd); + return ret; + } + + gpio_direction_output(npcs_pin, + !(spi->mode & SPI_CS_HIGH)); } asd->npcs_pin = npcs_pin; spi->controller_state = asd; - gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH)); } asd->csr = csr; @@ -1338,6 +1578,13 @@ static int atmel_spi_probe(struct platform_device *pdev) atmel_get_caps(as); + as->use_cs_gpios = true; + if (atmel_spi_is_v2(as) && + !of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) { + as->use_cs_gpios = false; + master->num_chipselect = 4; + } + as->use_dma = false; as->use_pdc = false; if (as->caps.has_dma_support) { @@ -1380,6 +1627,13 @@ static int atmel_spi_probe(struct platform_device *pdev) spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); spi_writel(as, CR, SPI_BIT(SPIEN)); + as->fifo_size = 0; + if (!of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size", + &as->fifo_size)) { + dev_info(&pdev->dev, "Using FIFO (%u data)\n", as->fifo_size); + spi_writel(as, CR, SPI_BIT(FIFOEN)); + } + /* go! */ dev_info(&pdev->dev, "Atmel SPI Controller at 0x%08lx (irq %d)\n", (unsigned long)regs->start, irq); diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index f63864a..59705ab 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -20,18 +20,22 @@ * GNU General Public License for more details. */ +#include <asm/page.h> #include <linux/clk.h> #include <linux/completion.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> #include <linux/err.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_irq.h> -#include <linux/of_gpio.h> +#include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/of_irq.h> #include <linux/spi/spi.h> /* SPI register offsets */ @@ -69,7 +73,8 @@ #define BCM2835_SPI_CS_CS_01 0x00000001 #define BCM2835_SPI_POLLING_LIMIT_US 30 -#define BCM2835_SPI_TIMEOUT_MS 30000 +#define BCM2835_SPI_POLLING_JIFFIES 2 +#define BCM2835_SPI_DMA_MIN_LENGTH 96 #define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ | SPI_NO_CS | SPI_3WIRE) @@ -83,6 +88,7 @@ struct bcm2835_spi { u8 *rx_buf; int tx_len; int rx_len; + bool dma_pending; }; static inline u32 bcm2835_rd(struct bcm2835_spi *bs, unsigned reg) @@ -128,12 +134,15 @@ static void bcm2835_spi_reset_hw(struct spi_master *master) /* Disable SPI interrupts and transfer */ cs &= ~(BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD | + BCM2835_SPI_CS_DMAEN | BCM2835_SPI_CS_TA); /* and reset RX/TX FIFOS */ cs |= BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX; /* and reset the SPI_HW */ bcm2835_wr(bs, BCM2835_SPI_CS, cs); + /* as well as DLEN */ + bcm2835_wr(bs, BCM2835_SPI_DLEN, 0); } static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) @@ -157,43 +166,6 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int bcm2835_spi_transfer_one_poll(struct spi_master *master, - struct spi_device *spi, - struct spi_transfer *tfr, - u32 cs, - unsigned long xfer_time_us) -{ - struct bcm2835_spi *bs = spi_master_get_devdata(master); - unsigned long timeout = jiffies + - max(4 * xfer_time_us * HZ / 1000000, 2uL); - - /* enable HW block without interrupts */ - bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA); - - /* set timeout to 4x the expected time, or 2 jiffies */ - /* loop until finished the transfer */ - while (bs->rx_len) { - /* read from fifo as much as possible */ - bcm2835_rd_fifo(bs); - /* fill in tx fifo as much as possible */ - bcm2835_wr_fifo(bs); - /* if we still expect some data after the read, - * check for a possible timeout - */ - if (bs->rx_len && time_after(jiffies, timeout)) { - /* Transfer complete - reset SPI HW */ - bcm2835_spi_reset_hw(master); - /* and return timeout */ - return -ETIMEDOUT; - } - } - - /* Transfer complete - reset SPI HW */ - bcm2835_spi_reset_hw(master); - /* and return without waiting for completion */ - return 0; -} - static int bcm2835_spi_transfer_one_irq(struct spi_master *master, struct spi_device *spi, struct spi_transfer *tfr, @@ -230,6 +202,329 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master, return 1; } +/* + * DMA support + * + * this implementation has currently a few issues in so far as it does + * not work arrount limitations of the HW. + * + * the main one being that DMA transfers are limited to 16 bit + * (so 0 to 65535 bytes) by the SPI HW due to BCM2835_SPI_DLEN + * + * also we currently assume that the scatter-gather fragments are + * all multiple of 4 (except the last) - otherwise we would need + * to reset the FIFO before subsequent transfers... + * this also means that tx/rx transfers sg's need to be of equal size! + * + * there may be a few more border-cases we may need to address as well + * but unfortunately this would mean splitting up the scatter-gather + * list making it slightly unpractical... + */ +static void bcm2835_spi_dma_done(void *data) +{ + struct spi_master *master = data; + struct bcm2835_spi *bs = spi_master_get_devdata(master); + + /* reset fifo and HW */ + bcm2835_spi_reset_hw(master); + + /* and terminate tx-dma as we do not have an irq for it + * because when the rx dma will terminate and this callback + * is called the tx-dma must have finished - can't get to this + * situation otherwise... + */ + dmaengine_terminate_all(master->dma_tx); + + /* mark as no longer pending */ + bs->dma_pending = 0; + + /* and mark as completed */; + complete(&master->xfer_completion); +} + +static int bcm2835_spi_prepare_sg(struct spi_master *master, + struct spi_transfer *tfr, + bool is_tx) +{ + struct dma_chan *chan; + struct scatterlist *sgl; + unsigned int nents; + enum dma_transfer_direction dir; + unsigned long flags; + + struct dma_async_tx_descriptor *desc; + dma_cookie_t cookie; + + if (is_tx) { + dir = DMA_MEM_TO_DEV; + chan = master->dma_tx; + nents = tfr->tx_sg.nents; + sgl = tfr->tx_sg.sgl; + flags = 0 /* no tx interrupt */; + + } else { + dir = DMA_DEV_TO_MEM; + chan = master->dma_rx; + nents = tfr->rx_sg.nents; + sgl = tfr->rx_sg.sgl; + flags = DMA_PREP_INTERRUPT; + } + /* prepare the channel */ + desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags); + if (!desc) + return -EINVAL; + + /* set callback for rx */ + if (!is_tx) { + desc->callback = bcm2835_spi_dma_done; + desc->callback_param = master; + } + + /* submit it to DMA-engine */ + cookie = dmaengine_submit(desc); + + return dma_submit_error(cookie); +} + +static inline int bcm2835_check_sg_length(struct sg_table *sgt) +{ + int i; + struct scatterlist *sgl; + + /* check that the sg entries are word-sized (except for last) */ + for_each_sg(sgt->sgl, sgl, (int)sgt->nents - 1, i) { + if (sg_dma_len(sgl) % 4) + return -EFAULT; + } + + return 0; +} + +static int bcm2835_spi_transfer_one_dma(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *tfr, + u32 cs) +{ + struct bcm2835_spi *bs = spi_master_get_devdata(master); + int ret; + + /* check that the scatter gather segments are all a multiple of 4 */ + if (bcm2835_check_sg_length(&tfr->tx_sg) || + bcm2835_check_sg_length(&tfr->rx_sg)) { + dev_warn_once(&spi->dev, + "scatter gather segment length is not a multiple of 4 - falling back to interrupt mode\n"); + return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs); + } + + /* setup tx-DMA */ + ret = bcm2835_spi_prepare_sg(master, tfr, true); + if (ret) + return ret; + + /* start TX early */ + dma_async_issue_pending(master->dma_tx); + + /* mark as dma pending */ + bs->dma_pending = 1; + + /* set the DMA length */ + bcm2835_wr(bs, BCM2835_SPI_DLEN, tfr->len); + + /* start the HW */ + bcm2835_wr(bs, BCM2835_SPI_CS, + cs | BCM2835_SPI_CS_TA | BCM2835_SPI_CS_DMAEN); + + /* setup rx-DMA late - to run transfers while + * mapping of the rx buffers still takes place + * this saves 10us or more. + */ + ret = bcm2835_spi_prepare_sg(master, tfr, false); + if (ret) { + /* need to reset on errors */ + dmaengine_terminate_all(master->dma_tx); + bcm2835_spi_reset_hw(master); + return ret; + } + + /* start rx dma late */ + dma_async_issue_pending(master->dma_rx); + + /* wait for wakeup in framework */ + return 1; +} + +static bool bcm2835_spi_can_dma(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *tfr) +{ + /* only run for gpio_cs */ + if (!gpio_is_valid(spi->cs_gpio)) + return false; + + /* we start DMA efforts only on bigger transfers */ + if (tfr->len < BCM2835_SPI_DMA_MIN_LENGTH) + return false; + + /* BCM2835_SPI_DLEN has defined a max transfer size as + * 16 bit, so max is 65535 + * we can revisit this by using an alternative transfer + * method - ideally this would get done without any more + * interaction... + */ + if (tfr->len > 65535) { + dev_warn_once(&spi->dev, + "transfer size of %d too big for dma-transfer\n", + tfr->len); + return false; + } + + /* if we run rx/tx_buf with word aligned addresses then we are OK */ + if ((((size_t)tfr->rx_buf & 3) == 0) && + (((size_t)tfr->tx_buf & 3) == 0)) + return true; + + /* otherwise we only allow transfers within the same page + * to avoid wasting time on dma_mapping when it is not practical + */ + if (((size_t)tfr->tx_buf & PAGE_MASK) + tfr->len > PAGE_SIZE) { + dev_warn_once(&spi->dev, + "Unaligned spi tx-transfer bridging page\n"); + return false; + } + if (((size_t)tfr->rx_buf & PAGE_MASK) + tfr->len > PAGE_SIZE) { + dev_warn_once(&spi->dev, + "Unaligned spi tx-transfer bridging page\n"); + return false; + } + + /* return OK */ + return true; +} + +static void bcm2835_dma_release(struct spi_master *master) +{ + if (master->dma_tx) { + dmaengine_terminate_all(master->dma_tx); + dma_release_channel(master->dma_tx); + master->dma_tx = NULL; + } + if (master->dma_rx) { + dmaengine_terminate_all(master->dma_rx); + dma_release_channel(master->dma_rx); + master->dma_rx = NULL; + } +} + +static void bcm2835_dma_init(struct spi_master *master, struct device *dev) +{ + struct dma_slave_config slave_config; + const __be32 *addr; + dma_addr_t dma_reg_base; + int ret; + + /* base address in dma-space */ + addr = of_get_address(master->dev.of_node, 0, NULL, NULL); + if (!addr) { + dev_err(dev, "could not get DMA-register address - not using dma mode\n"); + goto err; + } + dma_reg_base = be32_to_cpup(addr); + + /* get tx/rx dma */ + master->dma_tx = dma_request_slave_channel(dev, "tx"); + if (!master->dma_tx) { + dev_err(dev, "no tx-dma configuration found - not using dma mode\n"); + goto err; + } + master->dma_rx = dma_request_slave_channel(dev, "rx"); + if (!master->dma_rx) { + dev_err(dev, "no rx-dma configuration found - not using dma mode\n"); + goto err_release; + } + + /* configure DMAs */ + slave_config.direction = DMA_MEM_TO_DEV; + slave_config.dst_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO); + slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + + ret = dmaengine_slave_config(master->dma_tx, &slave_config); + if (ret) + goto err_config; + + slave_config.direction = DMA_DEV_TO_MEM; + slave_config.src_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO); + slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + + ret = dmaengine_slave_config(master->dma_rx, &slave_config); + if (ret) + goto err_config; + + /* all went well, so set can_dma */ + master->can_dma = bcm2835_spi_can_dma; + master->max_dma_len = 65535; /* limitation by BCM2835_SPI_DLEN */ + /* need to do TX AND RX DMA, so we need dummy buffers */ + master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX; + + return; + +err_config: + dev_err(dev, "issue configuring dma: %d - not using DMA mode\n", + ret); +err_release: + bcm2835_dma_release(master); +err: + return; +} + +static int bcm2835_spi_transfer_one_poll(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *tfr, + u32 cs, + unsigned long xfer_time_us) +{ + struct bcm2835_spi *bs = spi_master_get_devdata(master); + unsigned long timeout; + + /* enable HW block without interrupts */ + bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA); + + /* fill in the fifo before timeout calculations + * if we are interrupted here, then the data is + * getting transferred by the HW while we are interrupted + */ + bcm2835_wr_fifo(bs); + + /* set the timeout */ + timeout = jiffies + BCM2835_SPI_POLLING_JIFFIES; + + /* loop until finished the transfer */ + while (bs->rx_len) { + /* fill in tx fifo with remaining data */ + bcm2835_wr_fifo(bs); + + /* read from fifo as much as possible */ + bcm2835_rd_fifo(bs); + + /* if there is still data pending to read + * then check the timeout + */ + if (bs->rx_len && time_after(jiffies, timeout)) { + dev_dbg_ratelimited(&spi->dev, + "timeout period reached: jiffies: %lu remaining tx/rx: %d/%d - falling back to interrupt mode\n", + jiffies - timeout, + bs->tx_len, bs->rx_len); + /* fall back to interrupt mode */ + return bcm2835_spi_transfer_one_irq(master, spi, + tfr, cs); + } + } + + /* Transfer complete - reset SPI HW */ + bcm2835_spi_reset_hw(master); + /* and return without waiting for completion */ + return 0; +} + static int bcm2835_spi_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *tfr) @@ -289,12 +584,26 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, return bcm2835_spi_transfer_one_poll(master, spi, tfr, cs, xfer_time_us); + /* run in dma mode if conditions are right */ + if (master->can_dma && bcm2835_spi_can_dma(master, spi, tfr)) + return bcm2835_spi_transfer_one_dma(master, spi, tfr, cs); + + /* run in interrupt-mode */ return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs); } static void bcm2835_spi_handle_err(struct spi_master *master, struct spi_message *msg) { + struct bcm2835_spi *bs = spi_master_get_devdata(master); + + /* if an error occurred and we have an active dma, then terminate */ + if (bs->dma_pending) { + dmaengine_terminate_all(master->dma_tx); + dmaengine_terminate_all(master->dma_rx); + bs->dma_pending = 0; + } + /* and reset */ bcm2835_spi_reset_hw(master); } @@ -464,6 +773,8 @@ static int bcm2835_spi_probe(struct platform_device *pdev) goto out_clk_disable; } + bcm2835_dma_init(master, &pdev->dev); + /* initialise the hardware with the default polarities */ bcm2835_wr(bs, BCM2835_SPI_CS, BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); @@ -494,6 +805,8 @@ static int bcm2835_spi_remove(struct platform_device *pdev) clk_disable_unprepare(bs->clk); + bcm2835_dma_release(master); + return 0; } diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 5ef6638..840a498 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -180,7 +180,6 @@ int spi_bitbang_setup(struct spi_device *spi) { struct spi_bitbang_cs *cs = spi->controller_state; struct spi_bitbang *bitbang; - int retval; unsigned long flags; bitbang = spi_master_get_devdata(spi->master); @@ -197,9 +196,11 @@ int spi_bitbang_setup(struct spi_device *spi) if (!cs->txrx_word) return -EINVAL; - retval = bitbang->setup_transfer(spi, NULL); - if (retval < 0) - return retval; + if (bitbang->setup_transfer) { + int retval = bitbang->setup_transfer(spi, NULL); + if (retval < 0) + return retval; + } dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs); @@ -295,9 +296,11 @@ static int spi_bitbang_transfer_one(struct spi_master *master, /* init (-1) or override (1) transfer params */ if (do_setup != 0) { - status = bitbang->setup_transfer(spi, t); - if (status < 0) - break; + if (bitbang->setup_transfer) { + status = bitbang->setup_transfer(spi, t); + if (status < 0) + break; + } if (do_setup == -1) do_setup = 0; } diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 5e99106..987afeb 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -265,7 +265,7 @@ static inline int davinci_spi_get_prescale(struct davinci_spi *dspi, ret = DIV_ROUND_UP(clk_get_rate(dspi->clk), max_speed_hz); - if (ret < 3 || ret > 256) + if (ret < 1 || ret > 256) return -EINVAL; return ret - 1; diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c index 9c46a30..896add8 100644 --- a/drivers/spi/spi-fsl-cpm.c +++ b/drivers/spi/spi-fsl-cpm.c @@ -24,6 +24,7 @@ #include <linux/of_address.h> #include <linux/spi/spi.h> #include <linux/types.h> +#include <linux/platform_device.h> #include "spi-fsl-cpm.h" #include "spi-fsl-lib.h" @@ -269,17 +270,6 @@ static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi) if (mspi->flags & SPI_CPM2) { pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64); out_be16(spi_base, pram_ofs); - } else { - struct spi_pram __iomem *pram = spi_base; - u16 rpbase = in_be16(&pram->rpbase); - - /* Microcode relocation patch applied? */ - if (rpbase) { - pram_ofs = rpbase; - } else { - pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64); - out_be16(spi_base, pram_ofs); - } } iounmap(spi_base); @@ -292,7 +282,6 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) struct device_node *np = dev->of_node; const u32 *iprop; int size; - unsigned long pram_ofs; unsigned long bds_ofs; if (!(mspi->flags & SPI_CPM_MODE)) @@ -319,8 +308,26 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) } } - pram_ofs = fsl_spi_cpm_get_pram(mspi); - if (IS_ERR_VALUE(pram_ofs)) { + if (mspi->flags & SPI_CPM1) { + struct resource *res; + void *pram; + + res = platform_get_resource(to_platform_device(dev), + IORESOURCE_MEM, 1); + pram = devm_ioremap_resource(dev, res); + if (IS_ERR(pram)) + mspi->pram = NULL; + else + mspi->pram = pram; + } else { + unsigned long pram_ofs = fsl_spi_cpm_get_pram(mspi); + + if (IS_ERR_VALUE(pram_ofs)) + mspi->pram = NULL; + else + mspi->pram = cpm_muram_addr(pram_ofs); + } + if (mspi->pram == NULL) { dev_err(dev, "can't allocate spi parameter ram\n"); goto err_pram; } @@ -346,8 +353,6 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) goto err_dummy_rx; } - mspi->pram = cpm_muram_addr(pram_ofs); - mspi->tx_bd = cpm_muram_addr(bds_ofs); mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd)); @@ -375,7 +380,8 @@ err_dummy_rx: err_dummy_tx: cpm_muram_free(bds_ofs); err_bds: - cpm_muram_free(pram_ofs); + if (!(mspi->flags & SPI_CPM1)) + cpm_muram_free(cpm_muram_offset(mspi->pram)); err_pram: fsl_spi_free_dummy_rx(); return -ENOMEM; diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 5fe54cd..86bcdd6 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -24,6 +24,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> @@ -47,6 +48,7 @@ #define SPI_MCR_CLR_RXF (1 << 10) #define SPI_TCR 0x08 +#define SPI_TCR_GET_TCNT(x) (((x) & 0xffff0000) >> 16) #define SPI_CTAR(x) (0x0c + (((x) & 0x3) * 4)) #define SPI_CTAR_FMSZ(x) (((x) & 0x0000000f) << 27) @@ -67,9 +69,11 @@ #define SPI_SR 0x2c #define SPI_SR_EOQF 0x10000000 +#define SPI_SR_TCFQF 0x80000000 #define SPI_RSER 0x30 #define SPI_RSER_EOQFE 0x10000000 +#define SPI_RSER_TCFQE 0x80000000 #define SPI_PUSHR 0x34 #define SPI_PUSHR_CONT (1 << 31) @@ -102,12 +106,35 @@ #define SPI_CS_ASSERT 0x02 #define SPI_CS_DROP 0x04 +#define SPI_TCR_TCNT_MAX 0x10000 + struct chip_data { u32 mcr_val; u32 ctar_val; u16 void_write_data; }; +enum dspi_trans_mode { + DSPI_EOQ_MODE = 0, + DSPI_TCFQ_MODE, +}; + +struct fsl_dspi_devtype_data { + enum dspi_trans_mode trans_mode; +}; + +static const struct fsl_dspi_devtype_data vf610_data = { + .trans_mode = DSPI_EOQ_MODE, +}; + +static const struct fsl_dspi_devtype_data ls1021a_v1_data = { + .trans_mode = DSPI_TCFQ_MODE, +}; + +static const struct fsl_dspi_devtype_data ls2085a_data = { + .trans_mode = DSPI_TCFQ_MODE, +}; + struct fsl_dspi { struct spi_master *master; struct platform_device *pdev; @@ -128,9 +155,12 @@ struct fsl_dspi { u8 cs; u16 void_write_data; u32 cs_change; + struct fsl_dspi_devtype_data *devtype_data; wait_queue_head_t waitq; u32 waitflags; + + u32 spi_tcnt; }; static inline int is_double_byte_mode(struct fsl_dspi *dspi) @@ -213,63 +243,60 @@ static void ns_delay_scale(char *psc, char *sc, int delay_ns, } } -static int dspi_transfer_write(struct fsl_dspi *dspi) +static u32 dspi_data_to_pushr(struct fsl_dspi *dspi, int tx_word) { - int tx_count = 0; - int tx_word; u16 d16; - u8 d8; - u32 dspi_pushr = 0; - int first = 1; - tx_word = is_double_byte_mode(dspi); + if (!(dspi->dataflags & TRAN_STATE_TX_VOID)) + d16 = tx_word ? *(u16 *)dspi->tx : *(u8 *)dspi->tx; + else + d16 = dspi->void_write_data; - /* If we are in word mode, but only have a single byte to transfer - * then switch to byte mode temporarily. Will switch back at the - * end of the transfer. - */ - if (tx_word && (dspi->len == 1)) { - dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM; - regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs), - SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8)); - tx_word = 0; - } + dspi->tx += tx_word + 1; + dspi->len -= tx_word + 1; - while (dspi->len && (tx_count < DSPI_FIFO_SIZE)) { - if (tx_word) { - if (dspi->len == 1) - break; + return SPI_PUSHR_TXDATA(d16) | + SPI_PUSHR_PCS(dspi->cs) | + SPI_PUSHR_CTAS(dspi->cs) | + SPI_PUSHR_CONT; +} - if (!(dspi->dataflags & TRAN_STATE_TX_VOID)) { - d16 = *(u16 *)dspi->tx; - dspi->tx += 2; - } else { - d16 = dspi->void_write_data; - } +static void dspi_data_from_popr(struct fsl_dspi *dspi, int rx_word) +{ + u16 d; + unsigned int val; - dspi_pushr = SPI_PUSHR_TXDATA(d16) | - SPI_PUSHR_PCS(dspi->cs) | - SPI_PUSHR_CTAS(dspi->cs) | - SPI_PUSHR_CONT; + regmap_read(dspi->regmap, SPI_POPR, &val); + d = SPI_POPR_RXDATA(val); - dspi->len -= 2; - } else { - if (!(dspi->dataflags & TRAN_STATE_TX_VOID)) { + if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) + rx_word ? (*(u16 *)dspi->rx = d) : (*(u8 *)dspi->rx = d); - d8 = *(u8 *)dspi->tx; - dspi->tx++; - } else { - d8 = (u8)dspi->void_write_data; - } + dspi->rx += rx_word + 1; +} - dspi_pushr = SPI_PUSHR_TXDATA(d8) | - SPI_PUSHR_PCS(dspi->cs) | - SPI_PUSHR_CTAS(dspi->cs) | - SPI_PUSHR_CONT; +static int dspi_eoq_write(struct fsl_dspi *dspi) +{ + int tx_count = 0; + int tx_word; + u32 dspi_pushr = 0; + + tx_word = is_double_byte_mode(dspi); - dspi->len--; + while (dspi->len && (tx_count < DSPI_FIFO_SIZE)) { + /* If we are in word mode, only have a single byte to transfer + * switch to byte mode temporarily. Will switch back at the + * end of the transfer. + */ + if (tx_word && (dspi->len == 1)) { + dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM; + regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs), + SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8)); + tx_word = 0; } + dspi_pushr = dspi_data_to_pushr(dspi, tx_word); + if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1) { /* last transfer in the transfer */ dspi_pushr |= SPI_PUSHR_EOQ; @@ -278,11 +305,6 @@ static int dspi_transfer_write(struct fsl_dspi *dspi) } else if (tx_word && (dspi->len == 1)) dspi_pushr |= SPI_PUSHR_EOQ; - if (first) { - first = 0; - dspi_pushr |= SPI_PUSHR_CTCNT; /* clear counter */ - } - regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr); tx_count++; @@ -291,40 +313,55 @@ static int dspi_transfer_write(struct fsl_dspi *dspi) return tx_count * (tx_word + 1); } -static int dspi_transfer_read(struct fsl_dspi *dspi) +static int dspi_eoq_read(struct fsl_dspi *dspi) { int rx_count = 0; int rx_word = is_double_byte_mode(dspi); - u16 d; while ((dspi->rx < dspi->rx_end) && (rx_count < DSPI_FIFO_SIZE)) { - if (rx_word) { - unsigned int val; + if (rx_word && (dspi->rx_end - dspi->rx) == 1) + rx_word = 0; - if ((dspi->rx_end - dspi->rx) == 1) - break; + dspi_data_from_popr(dspi, rx_word); + rx_count++; + } - regmap_read(dspi->regmap, SPI_POPR, &val); - d = SPI_POPR_RXDATA(val); + return rx_count; +} - if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) - *(u16 *)dspi->rx = d; - dspi->rx += 2; +static int dspi_tcfq_write(struct fsl_dspi *dspi) +{ + int tx_word; + u32 dspi_pushr = 0; - } else { - unsigned int val; + tx_word = is_double_byte_mode(dspi); - regmap_read(dspi->regmap, SPI_POPR, &val); - d = SPI_POPR_RXDATA(val); - if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) - *(u8 *)dspi->rx = d; - dspi->rx++; - } - rx_count++; + if (tx_word && (dspi->len == 1)) { + dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM; + regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs), + SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8)); + tx_word = 0; } - return rx_count; + dspi_pushr = dspi_data_to_pushr(dspi, tx_word); + + if ((dspi->cs_change) && (!dspi->len)) + dspi_pushr &= ~SPI_PUSHR_CONT; + + regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr); + + return tx_word + 1; +} + +static void dspi_tcfq_read(struct fsl_dspi *dspi) +{ + int rx_word = is_double_byte_mode(dspi); + + if (rx_word && (dspi->rx_end - dspi->rx) == 1) + rx_word = 0; + + dspi_data_from_popr(dspi, rx_word); } static int dspi_transfer_one_message(struct spi_master *master, @@ -334,6 +371,12 @@ static int dspi_transfer_one_message(struct spi_master *master, struct spi_device *spi = message->spi; struct spi_transfer *transfer; int status = 0; + enum dspi_trans_mode trans_mode; + u32 spi_tcr; + + regmap_read(dspi->regmap, SPI_TCR, &spi_tcr); + dspi->spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr); + message->actual_length = 0; list_for_each_entry(transfer, &message->transfers, transfer_list) { @@ -341,10 +384,10 @@ static int dspi_transfer_one_message(struct spi_master *master, dspi->cur_msg = message; dspi->cur_chip = spi_get_ctldata(spi); dspi->cs = spi->chip_select; + dspi->cs_change = 0; if (dspi->cur_transfer->transfer_list.next == &dspi->cur_msg->transfers) - transfer->cs_change = 1; - dspi->cs_change = transfer->cs_change; + dspi->cs_change = 1; dspi->void_write_data = dspi->cur_chip->void_write_data; dspi->dataflags = 0; @@ -370,8 +413,22 @@ static int dspi_transfer_one_message(struct spi_master *master, regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), dspi->cur_chip->ctar_val); - regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE); - message->actual_length += dspi_transfer_write(dspi); + trans_mode = dspi->devtype_data->trans_mode; + switch (trans_mode) { + case DSPI_EOQ_MODE: + regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE); + dspi_eoq_write(dspi); + break; + case DSPI_TCFQ_MODE: + regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_TCFQE); + dspi_tcfq_write(dspi); + break; + default: + dev_err(&dspi->pdev->dev, "unsupported trans_mode %u\n", + trans_mode); + status = -EINVAL; + goto out; + } if (wait_event_interruptible(dspi->waitq, dspi->waitflags)) dev_err(&dspi->pdev->dev, "wait transfer complete fail!\n"); @@ -381,6 +438,7 @@ static int dspi_transfer_one_message(struct spi_master *master, udelay(transfer->delay_usecs); } +out: message->status = status; spi_finalize_current_message(master); @@ -460,27 +518,89 @@ static void dspi_cleanup(struct spi_device *spi) static irqreturn_t dspi_interrupt(int irq, void *dev_id) { struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id; - struct spi_message *msg = dspi->cur_msg; + enum dspi_trans_mode trans_mode; + u32 spi_sr, spi_tcr; + u32 spi_tcnt, tcnt_diff; + int tx_word; - regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF); - dspi_transfer_read(dspi); - - if (!dspi->len) { + regmap_read(dspi->regmap, SPI_SR, &spi_sr); + regmap_write(dspi->regmap, SPI_SR, spi_sr); + + + if (spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF)) { + tx_word = is_double_byte_mode(dspi); + + regmap_read(dspi->regmap, SPI_TCR, &spi_tcr); + spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr); + /* + * The width of SPI Transfer Counter in SPI_TCR is 16bits, + * so the max couner is 65535. When the counter reach 65535, + * it will wrap around, counter reset to zero. + * spi_tcnt my be less than dspi->spi_tcnt, it means the + * counter already wrapped around. + * SPI Transfer Counter is a counter of transmitted frames. + * The size of frame maybe two bytes. + */ + tcnt_diff = ((spi_tcnt + SPI_TCR_TCNT_MAX) - dspi->spi_tcnt) + % SPI_TCR_TCNT_MAX; + tcnt_diff *= (tx_word + 1); if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) - regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs), - SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16)); + tcnt_diff--; + + msg->actual_length += tcnt_diff; + + dspi->spi_tcnt = spi_tcnt; + + trans_mode = dspi->devtype_data->trans_mode; + switch (trans_mode) { + case DSPI_EOQ_MODE: + dspi_eoq_read(dspi); + break; + case DSPI_TCFQ_MODE: + dspi_tcfq_read(dspi); + break; + default: + dev_err(&dspi->pdev->dev, "unsupported trans_mode %u\n", + trans_mode); + return IRQ_HANDLED; + } - dspi->waitflags = 1; - wake_up_interruptible(&dspi->waitq); - } else - msg->actual_length += dspi_transfer_write(dspi); + if (!dspi->len) { + if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) { + regmap_update_bits(dspi->regmap, + SPI_CTAR(dspi->cs), + SPI_FRAME_BITS_MASK, + SPI_FRAME_BITS(16)); + dspi->dataflags &= ~TRAN_STATE_WORD_ODD_NUM; + } + + dspi->waitflags = 1; + wake_up_interruptible(&dspi->waitq); + } else { + switch (trans_mode) { + case DSPI_EOQ_MODE: + dspi_eoq_write(dspi); + break; + case DSPI_TCFQ_MODE: + dspi_tcfq_write(dspi); + break; + default: + dev_err(&dspi->pdev->dev, + "unsupported trans_mode %u\n", + trans_mode); + } + } + } return IRQ_HANDLED; } static const struct of_device_id fsl_dspi_dt_ids[] = { - { .compatible = "fsl,vf610-dspi", .data = NULL, }, + { .compatible = "fsl,vf610-dspi", .data = (void *)&vf610_data, }, + { .compatible = "fsl,ls1021a-v1.0-dspi", + .data = (void *)&ls1021a_v1_data, }, + { .compatible = "fsl,ls2085a-dspi", .data = (void *)&ls2085a_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_dspi_dt_ids); @@ -494,6 +614,8 @@ static int dspi_suspend(struct device *dev) spi_master_suspend(master); clk_disable_unprepare(dspi->clk); + pinctrl_pm_select_sleep_state(dev); + return 0; } @@ -502,6 +624,8 @@ static int dspi_resume(struct device *dev) struct spi_master *master = dev_get_drvdata(dev); struct fsl_dspi *dspi = spi_master_get_devdata(master); + pinctrl_pm_select_default_state(dev); + clk_prepare_enable(dspi->clk); spi_master_resume(master); @@ -526,6 +650,8 @@ static int dspi_probe(struct platform_device *pdev) struct resource *res; void __iomem *base; int ret = 0, cs_num, bus_num; + const struct of_device_id *of_id = + of_match_device(fsl_dspi_dt_ids, &pdev->dev); master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi)); if (!master) @@ -559,6 +685,13 @@ static int dspi_probe(struct platform_device *pdev) } master->bus_num = bus_num; + dspi->devtype_data = (struct fsl_dspi_devtype_data *)of_id->data; + if (!dspi->devtype_data) { + dev_err(&pdev->dev, "can't get devtype_data\n"); + ret = -EFAULT; + goto out_master_put; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) { @@ -566,7 +699,7 @@ static int dspi_probe(struct platform_device *pdev) goto out_master_put; } - dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base, + dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base, &dspi_regmap_config); if (IS_ERR(dspi->regmap)) { dev_err(&pdev->dev, "failed to init regmap: %ld\n", diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index d0a73a0..d3f05a0 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -359,14 +359,16 @@ static void fsl_espi_rw_trans(struct spi_message *m, struct fsl_espi_transfer *trans, u8 *rx_buff) { struct fsl_espi_transfer *espi_trans = trans; - unsigned int n_tx = espi_trans->n_tx; - unsigned int n_rx = espi_trans->n_rx; + unsigned int total_len = espi_trans->len; struct spi_transfer *t; u8 *local_buf; u8 *rx_buf = rx_buff; unsigned int trans_len; unsigned int addr; - int i, pos, loop; + unsigned int tx_only; + unsigned int rx_pos = 0; + unsigned int pos; + int i, loop; local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL); if (!local_buf) { @@ -374,36 +376,48 @@ static void fsl_espi_rw_trans(struct spi_message *m, return; } - for (pos = 0, loop = 0; pos < n_rx; pos += trans_len, loop++) { - trans_len = n_rx - pos; - if (trans_len > SPCOM_TRANLEN_MAX - n_tx) - trans_len = SPCOM_TRANLEN_MAX - n_tx; + for (pos = 0, loop = 0; pos < total_len; pos += trans_len, loop++) { + trans_len = total_len - pos; i = 0; + tx_only = 0; list_for_each_entry(t, &m->transfers, transfer_list) { if (t->tx_buf) { memcpy(local_buf + i, t->tx_buf, t->len); i += t->len; + if (!t->rx_buf) + tx_only += t->len; } } + /* Add additional TX bytes to compensate SPCOM_TRANLEN_MAX */ + if (loop > 0) + trans_len += tx_only; + + if (trans_len > SPCOM_TRANLEN_MAX) + trans_len = SPCOM_TRANLEN_MAX; + + /* Update device offset */ if (pos > 0) { addr = fsl_espi_cmd2addr(local_buf); - addr += pos; + addr += rx_pos; fsl_espi_addr2cmd(addr, local_buf); } - espi_trans->n_tx = n_tx; - espi_trans->n_rx = trans_len; - espi_trans->len = trans_len + n_tx; + espi_trans->len = trans_len; espi_trans->tx_buf = local_buf; espi_trans->rx_buf = local_buf; fsl_espi_do_trans(m, espi_trans); - memcpy(rx_buf + pos, espi_trans->rx_buf + n_tx, trans_len); + /* If there is at least one RX byte then copy it to rx_buf */ + if (tx_only < SPCOM_TRANLEN_MAX) + memcpy(rx_buf + rx_pos, espi_trans->rx_buf + tx_only, + trans_len - tx_only); + + rx_pos += trans_len - tx_only; if (loop > 0) - espi_trans->actual_length += espi_trans->len - n_tx; + espi_trans->actual_length += espi_trans->len - tx_only; else espi_trans->actual_length += espi_trans->len; } @@ -418,6 +432,7 @@ static int fsl_espi_do_one_msg(struct spi_master *master, u8 *rx_buf = NULL; unsigned int n_tx = 0; unsigned int n_rx = 0; + unsigned int xfer_len = 0; struct fsl_espi_transfer espi_trans; list_for_each_entry(t, &m->transfers, transfer_list) { @@ -427,11 +442,13 @@ static int fsl_espi_do_one_msg(struct spi_master *master, n_rx += t->len; rx_buf = t->rx_buf; } + if ((t->tx_buf) || (t->rx_buf)) + xfer_len += t->len; } espi_trans.n_tx = n_tx; espi_trans.n_rx = n_rx; - espi_trans.len = n_tx + n_rx; + espi_trans.len = xfer_len; espi_trans.actual_length = 0; espi_trans.status = 0; @@ -544,9 +561,13 @@ void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) /* spin until TX is done */ ret = spin_event_timeout(((events = mpc8xxx_spi_read_reg( - ®_base->event)) & SPIE_NF) == 0, 1000, 0); + ®_base->event)) & SPIE_NF), 1000, 0); if (!ret) { dev_err(mspi->dev, "tired waiting for SPIE_NF\n"); + + /* Clear the SPIE bits */ + mpc8xxx_spi_write_reg(®_base->event, events); + complete(&mspi->done); return; } } diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 4df8942..5867384 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -35,6 +35,7 @@ #include <linux/gcd.h> #include <linux/spi/spi.h> +#include <linux/gpio.h> #include <linux/platform_data/spi-omap2-mcspi.h> @@ -242,17 +243,27 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable) mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0); } -static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active) +static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) { u32 l; - l = mcspi_cached_chconf0(spi); - if (cs_active) - l |= OMAP2_MCSPI_CHCONF_FORCE; - else - l &= ~OMAP2_MCSPI_CHCONF_FORCE; + /* The controller handles the inverted chip selects + * using the OMAP2_MCSPI_CHCONF_EPOL bit so revert + * the inversion from the core spi_set_cs function. + */ + if (spi->mode & SPI_CS_HIGH) + enable = !enable; - mcspi_write_chconf0(spi, l); + if (spi->controller_state) { + l = mcspi_cached_chconf0(spi); + + if (enable) + l &= ~OMAP2_MCSPI_CHCONF_FORCE; + else + l |= OMAP2_MCSPI_CHCONF_FORCE; + + mcspi_write_chconf0(spi, l); + } } static void omap2_mcspi_set_master_mode(struct spi_master *master) @@ -1011,6 +1022,15 @@ static int omap2_mcspi_setup(struct spi_device *spi) return ret; } + if (gpio_is_valid(spi->cs_gpio)) { + ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev)); + if (ret) { + dev_err(&spi->dev, "failed to request gpio\n"); + return ret; + } + gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); + } + ret = pm_runtime_get_sync(mcspi->dev); if (ret < 0) return ret; @@ -1050,9 +1070,13 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) mcspi_dma->dma_tx = NULL; } } + + if (gpio_is_valid(spi->cs_gpio)) + gpio_free(spi->cs_gpio); } -static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) +static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi, + struct spi_device *spi, struct spi_transfer *t) { /* We only enable one channel at a time -- the one whose message is @@ -1062,18 +1086,14 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) * chipselect with the FORCE bit ... CS != channel enable. */ - struct spi_device *spi; - struct spi_transfer *t = NULL; struct spi_master *master; struct omap2_mcspi_dma *mcspi_dma; - int cs_active = 0; struct omap2_mcspi_cs *cs; struct omap2_mcspi_device_config *cd; int par_override = 0; int status = 0; u32 chconf; - spi = m->spi; master = spi->master; mcspi_dma = mcspi->dma_channels + spi->chip_select; cs = spi->controller_state; @@ -1090,103 +1110,84 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) par_override = 1; omap2_mcspi_set_enable(spi, 0); - list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { - status = -EINVAL; - break; - } - if (par_override || - (t->speed_hz != spi->max_speed_hz) || - (t->bits_per_word != spi->bits_per_word)) { - par_override = 1; - status = omap2_mcspi_setup_transfer(spi, t); - if (status < 0) - break; - if (t->speed_hz == spi->max_speed_hz && - t->bits_per_word == spi->bits_per_word) - par_override = 0; - } - if (cd && cd->cs_per_word) { - chconf = mcspi->ctx.modulctrl; - chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE; - mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf); - mcspi->ctx.modulctrl = - mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL); - } + if (gpio_is_valid(spi->cs_gpio)) + omap2_mcspi_set_cs(spi, spi->mode & SPI_CS_HIGH); - if (!cs_active) { - omap2_mcspi_force_cs(spi, 1); - cs_active = 1; - } - - chconf = mcspi_cached_chconf0(spi); - chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK; - chconf &= ~OMAP2_MCSPI_CHCONF_TURBO; + if (par_override || + (t->speed_hz != spi->max_speed_hz) || + (t->bits_per_word != spi->bits_per_word)) { + par_override = 1; + status = omap2_mcspi_setup_transfer(spi, t); + if (status < 0) + goto out; + if (t->speed_hz == spi->max_speed_hz && + t->bits_per_word == spi->bits_per_word) + par_override = 0; + } + if (cd && cd->cs_per_word) { + chconf = mcspi->ctx.modulctrl; + chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE; + mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf); + mcspi->ctx.modulctrl = + mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL); + } - if (t->tx_buf == NULL) - chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY; - else if (t->rx_buf == NULL) - chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY; - - if (cd && cd->turbo_mode && t->tx_buf == NULL) { - /* Turbo mode is for more than one word */ - if (t->len > ((cs->word_len + 7) >> 3)) - chconf |= OMAP2_MCSPI_CHCONF_TURBO; - } + chconf = mcspi_cached_chconf0(spi); + chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK; + chconf &= ~OMAP2_MCSPI_CHCONF_TURBO; + + if (t->tx_buf == NULL) + chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY; + else if (t->rx_buf == NULL) + chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY; + + if (cd && cd->turbo_mode && t->tx_buf == NULL) { + /* Turbo mode is for more than one word */ + if (t->len > ((cs->word_len + 7) >> 3)) + chconf |= OMAP2_MCSPI_CHCONF_TURBO; + } - mcspi_write_chconf0(spi, chconf); + mcspi_write_chconf0(spi, chconf); - if (t->len) { - unsigned count; + if (t->len) { + unsigned count; - if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && - (m->is_dma_mapped || t->len >= DMA_MIN_BYTES)) - omap2_mcspi_set_fifo(spi, t, 1); + if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && + (t->len >= DMA_MIN_BYTES)) + omap2_mcspi_set_fifo(spi, t, 1); - omap2_mcspi_set_enable(spi, 1); + omap2_mcspi_set_enable(spi, 1); - /* RX_ONLY mode needs dummy data in TX reg */ - if (t->tx_buf == NULL) - writel_relaxed(0, cs->base - + OMAP2_MCSPI_TX0); + /* RX_ONLY mode needs dummy data in TX reg */ + if (t->tx_buf == NULL) + writel_relaxed(0, cs->base + + OMAP2_MCSPI_TX0); - if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && - (m->is_dma_mapped || t->len >= DMA_MIN_BYTES)) - count = omap2_mcspi_txrx_dma(spi, t); - else - count = omap2_mcspi_txrx_pio(spi, t); - m->actual_length += count; + if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && + (t->len >= DMA_MIN_BYTES)) + count = omap2_mcspi_txrx_dma(spi, t); + else + count = omap2_mcspi_txrx_pio(spi, t); - if (count != t->len) { - status = -EIO; - break; - } + if (count != t->len) { + status = -EIO; + goto out; } + } - if (t->delay_usecs) - udelay(t->delay_usecs); - - /* ignore the "leave it on after last xfer" hint */ - if (t->cs_change) { - omap2_mcspi_force_cs(spi, 0); - cs_active = 0; - } + omap2_mcspi_set_enable(spi, 0); - omap2_mcspi_set_enable(spi, 0); + if (mcspi->fifo_depth > 0) + omap2_mcspi_set_fifo(spi, t, 0); - if (mcspi->fifo_depth > 0) - omap2_mcspi_set_fifo(spi, t, 0); - } +out: /* Restore defaults if they were overriden */ if (par_override) { par_override = 0; status = omap2_mcspi_setup_transfer(spi, NULL); } - if (cs_active) - omap2_mcspi_force_cs(spi, 0); - if (cd && cd->cs_per_word) { chconf = mcspi->ctx.modulctrl; chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE; @@ -1197,70 +1198,64 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) omap2_mcspi_set_enable(spi, 0); + if (gpio_is_valid(spi->cs_gpio)) + omap2_mcspi_set_cs(spi, !(spi->mode & SPI_CS_HIGH)); + if (mcspi->fifo_depth > 0 && t) omap2_mcspi_set_fifo(spi, t, 0); - m->status = status; + return status; } -static int omap2_mcspi_transfer_one_message(struct spi_master *master, - struct spi_message *m) +static int omap2_mcspi_transfer_one(struct spi_master *master, + struct spi_device *spi, struct spi_transfer *t) { - struct spi_device *spi; struct omap2_mcspi *mcspi; struct omap2_mcspi_dma *mcspi_dma; - struct spi_transfer *t; + const void *tx_buf = t->tx_buf; + void *rx_buf = t->rx_buf; + unsigned len = t->len; - spi = m->spi; mcspi = spi_master_get_devdata(master); mcspi_dma = mcspi->dma_channels + spi->chip_select; - m->actual_length = 0; - m->status = 0; - - list_for_each_entry(t, &m->transfers, transfer_list) { - const void *tx_buf = t->tx_buf; - void *rx_buf = t->rx_buf; - unsigned len = t->len; - - if ((len && !(rx_buf || tx_buf))) { - dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n", - t->speed_hz, - len, - tx_buf ? "tx" : "", - rx_buf ? "rx" : "", - t->bits_per_word); - return -EINVAL; - } - if (m->is_dma_mapped || len < DMA_MIN_BYTES) - continue; + if ((len && !(rx_buf || tx_buf))) { + dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n", + t->speed_hz, + len, + tx_buf ? "tx" : "", + rx_buf ? "rx" : "", + t->bits_per_word); + return -EINVAL; + } - if (mcspi_dma->dma_tx && tx_buf != NULL) { - t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf, - len, DMA_TO_DEVICE); - if (dma_mapping_error(mcspi->dev, t->tx_dma)) { - dev_dbg(mcspi->dev, "dma %cX %d bytes error\n", - 'T', len); - return -EINVAL; - } + if (len < DMA_MIN_BYTES) + goto skip_dma_map; + + if (mcspi_dma->dma_tx && tx_buf != NULL) { + t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf, + len, DMA_TO_DEVICE); + if (dma_mapping_error(mcspi->dev, t->tx_dma)) { + dev_dbg(mcspi->dev, "dma %cX %d bytes error\n", + 'T', len); + return -EINVAL; } - if (mcspi_dma->dma_rx && rx_buf != NULL) { - t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len, - DMA_FROM_DEVICE); - if (dma_mapping_error(mcspi->dev, t->rx_dma)) { - dev_dbg(mcspi->dev, "dma %cX %d bytes error\n", - 'R', len); - if (tx_buf != NULL) - dma_unmap_single(mcspi->dev, t->tx_dma, - len, DMA_TO_DEVICE); - return -EINVAL; - } + } + if (mcspi_dma->dma_rx && rx_buf != NULL) { + t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len, + DMA_FROM_DEVICE); + if (dma_mapping_error(mcspi->dev, t->rx_dma)) { + dev_dbg(mcspi->dev, "dma %cX %d bytes error\n", + 'R', len); + if (tx_buf != NULL) + dma_unmap_single(mcspi->dev, t->tx_dma, + len, DMA_TO_DEVICE); + return -EINVAL; } } - omap2_mcspi_work(mcspi, m); - spi_finalize_current_message(master); - return 0; +skip_dma_map: + return omap2_mcspi_work_one(mcspi, spi, t); } static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) @@ -1339,7 +1334,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); master->setup = omap2_mcspi_setup; master->auto_runtime_pm = true; - master->transfer_one_message = omap2_mcspi_transfer_one_message; + master->transfer_one = omap2_mcspi_transfer_one; + master->set_cs = omap2_mcspi_set_cs; master->cleanup = omap2_mcspi_cleanup; master->dev.of_node = node; master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ; diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 8616647..8cad107 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -61,6 +61,12 @@ enum orion_spi_type { struct orion_spi_dev { enum orion_spi_type typ; + /* + * min_divisor and max_hz should be exclusive, the only we can + * have both is for managing the armada-370-spi case with old + * device tree + */ + unsigned long max_hz; unsigned int min_divisor; unsigned int max_divisor; u32 prescale_mask; @@ -385,16 +391,54 @@ static const struct orion_spi_dev orion_spi_dev_data = { .prescale_mask = ORION_SPI_CLK_PRESCALE_MASK, }; -static const struct orion_spi_dev armada_spi_dev_data = { +static const struct orion_spi_dev armada_370_spi_dev_data = { .typ = ARMADA_SPI, - .min_divisor = 1, + .min_divisor = 4, + .max_divisor = 1920, + .max_hz = 50000000, + .prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK, +}; + +static const struct orion_spi_dev armada_xp_spi_dev_data = { + .typ = ARMADA_SPI, + .max_hz = 50000000, + .max_divisor = 1920, + .prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK, +}; + +static const struct orion_spi_dev armada_375_spi_dev_data = { + .typ = ARMADA_SPI, + .min_divisor = 15, .max_divisor = 1920, .prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK, }; static const struct of_device_id orion_spi_of_match_table[] = { - { .compatible = "marvell,orion-spi", .data = &orion_spi_dev_data, }, - { .compatible = "marvell,armada-370-spi", .data = &armada_spi_dev_data, }, + { + .compatible = "marvell,orion-spi", + .data = &orion_spi_dev_data, + }, + { + .compatible = "marvell,armada-370-spi", + .data = &armada_370_spi_dev_data, + }, + { + .compatible = "marvell,armada-375-spi", + .data = &armada_375_spi_dev_data, + }, + { + .compatible = "marvell,armada-380-spi", + .data = &armada_xp_spi_dev_data, + }, + { + .compatible = "marvell,armada-390-spi", + .data = &armada_xp_spi_dev_data, + }, + { + .compatible = "marvell,armada-xp-spi", + .data = &armada_xp_spi_dev_data, + }, + {} }; MODULE_DEVICE_TABLE(of, orion_spi_of_match_table); @@ -454,7 +498,23 @@ static int orion_spi_probe(struct platform_device *pdev) goto out; tclk_hz = clk_get_rate(spi->clk); - master->max_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->min_divisor); + + /* + * With old device tree, armada-370-spi could be used with + * Armada XP, however for this SoC the maximum frequency is + * 50MHz instead of tclk/4. On Armada 370, tclk cannot be + * higher than 200MHz. So, in order to be able to handle both + * SoCs, we can take the minimum of 50MHz and tclk/4. + */ + if (of_device_is_compatible(pdev->dev.of_node, + "marvell,armada-370-spi")) + master->max_speed_hz = min(devdata->max_hz, + DIV_ROUND_UP(tclk_hz, devdata->min_divisor)); + else if (devdata->min_divisor) + master->max_speed_hz = + DIV_ROUND_UP(tclk_hz, devdata->min_divisor); + else + master->max_speed_hz = devdata->max_hz; master->min_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->max_divisor); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index d5d7d22..cf8b91b 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -571,7 +571,7 @@ static int __spi_map_msg(struct spi_master *master, struct spi_message *msg) return 0; } -static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg) +static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg) { struct spi_transfer *xfer; struct device *tx_dev, *rx_dev; @@ -599,13 +599,32 @@ static inline int __spi_map_msg(struct spi_master *master, return 0; } -static inline int spi_unmap_msg(struct spi_master *master, - struct spi_message *msg) +static inline int __spi_unmap_msg(struct spi_master *master, + struct spi_message *msg) { return 0; } #endif /* !CONFIG_HAS_DMA */ +static inline int spi_unmap_msg(struct spi_master *master, + struct spi_message *msg) +{ + struct spi_transfer *xfer; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + /* + * Restore the original value of tx_buf or rx_buf if they are + * NULL. + */ + if (xfer->tx_buf == master->dummy_tx) + xfer->tx_buf = NULL; + if (xfer->rx_buf == master->dummy_rx) + xfer->rx_buf = NULL; + } + + return __spi_unmap_msg(master, msg); +} + static int spi_map_msg(struct spi_master *master, struct spi_message *msg) { struct spi_transfer *xfer; @@ -979,9 +998,6 @@ void spi_finalize_current_message(struct spi_master *master) spin_lock_irqsave(&master->queue_lock, flags); mesg = master->cur_msg; - master->cur_msg = NULL; - - queue_kthread_work(&master->kworker, &master->pump_messages); spin_unlock_irqrestore(&master->queue_lock, flags); spi_unmap_msg(master, mesg); @@ -994,9 +1010,13 @@ void spi_finalize_current_message(struct spi_master *master) } } - trace_spi_message_done(mesg); - + spin_lock_irqsave(&master->queue_lock, flags); + master->cur_msg = NULL; master->cur_msg_prepared = false; + queue_kthread_work(&master->kworker, &master->pump_messages); + spin_unlock_irqrestore(&master->queue_lock, flags); + + trace_spi_message_done(mesg); mesg->state = NULL; if (mesg->complete) |