diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/Kconfig | 23 | ||||
-rw-r--r-- | drivers/spi/Makefile | 2 | ||||
-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-imx.c | 2 | ||||
-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-pxa2xx-pci.c | 8 | ||||
-rw-r--r-- | drivers/spi/spi-pxa2xx-pxadma.c | 487 | ||||
-rw-r--r-- | drivers/spi/spi-pxa2xx.c | 159 | ||||
-rw-r--r-- | drivers/spi/spi-pxa2xx.h | 6 | ||||
-rw-r--r-- | drivers/spi/spi-rb4xx.c | 210 | ||||
-rw-r--r-- | drivers/spi/spi-rspi.c | 23 | ||||
-rw-r--r-- | drivers/spi/spi-sh-msiof.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi.c | 36 |
21 files changed, 1497 insertions, 937 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 198f96b..ec40a27 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. @@ -393,16 +395,9 @@ config SPI_PPC4xx help This selects a driver for the PPC4xx SPI Controller. -config SPI_PXA2XX_PXADMA - bool "PXA2xx SSP legacy PXA DMA API support" - depends on SPI_PXA2XX && ARCH_PXA - help - Enable PXA private legacy DMA API support. Note that this is - deprecated in favor of generic DMA engine API. - config SPI_PXA2XX_DMA def_bool y - depends on SPI_PXA2XX && !SPI_PXA2XX_PXADMA + depends on SPI_PXA2XX config SPI_PXA2XX tristate "PXA2xx SSP SPI master" @@ -428,6 +423,12 @@ config SPI_ROCKCHIP The main usecase of this controller is to use spi flash as boot device. +config SPI_RB4XX + tristate "Mikrotik RB4XX SPI master" + depends on SPI_MASTER && ATH79 + help + SPI controller driver for the Mikrotik RB4xx series boards. + config SPI_RSPI tristate "Renesas RSPI/QSPI controller" depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index d8cbf65..2e7089f 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -60,12 +60,12 @@ obj-$(CONFIG_SPI_ORION) += spi-orion.o obj-$(CONFIG_SPI_PL022) += spi-pl022.o obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o spi-pxa2xx-platform-objs := spi-pxa2xx.o -spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA) += spi-pxa2xx-pxadma.o spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o obj-$(CONFIG_SPI_QUP) += spi-qup.o obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o +obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o obj-$(CONFIG_SPI_RSPI) += spi-rspi.o obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o spi-s3c24xx-hw-y := spi-s3c24xx.o 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-imx.c b/drivers/spi/spi-imx.c index f08e812..eb7d3a6 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -674,7 +674,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = { .devtype = IMX51_ECSPI, }; -static struct platform_device_id spi_imx_devtype[] = { +static const struct platform_device_id spi_imx_devtype[] = { { .name = "imx1-cspi", .driver_data = (kernel_ulong_t) &imx1_cspi_devtype_data, diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 4df89420..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-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index fa7399e..3cfd435 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -62,7 +62,7 @@ static struct pxa_spi_info spi_info_configs[] = { .max_clk_rate = 3686400, }, [PORT_BYT] = { - .type = LPSS_SSP, + .type = LPSS_BYT_SSP, .port_id = 0, .num_chipselect = 1, .max_clk_rate = 50000000, @@ -70,7 +70,7 @@ static struct pxa_spi_info spi_info_configs[] = { .rx_param = &byt_rx_param, }, [PORT_BSW0] = { - .type = LPSS_SSP, + .type = LPSS_BYT_SSP, .port_id = 0, .num_chipselect = 1, .max_clk_rate = 50000000, @@ -78,7 +78,7 @@ static struct pxa_spi_info spi_info_configs[] = { .rx_param = &bsw0_rx_param, }, [PORT_BSW1] = { - .type = LPSS_SSP, + .type = LPSS_BYT_SSP, .port_id = 1, .num_chipselect = 1, .max_clk_rate = 50000000, @@ -86,7 +86,7 @@ static struct pxa_spi_info spi_info_configs[] = { .rx_param = &bsw1_rx_param, }, [PORT_BSW2] = { - .type = LPSS_SSP, + .type = LPSS_BYT_SSP, .port_id = 2, .num_chipselect = 1, .max_clk_rate = 50000000, diff --git a/drivers/spi/spi-pxa2xx-pxadma.c b/drivers/spi/spi-pxa2xx-pxadma.c deleted file mode 100644 index 2e0796a..0000000 --- a/drivers/spi/spi-pxa2xx-pxadma.c +++ /dev/null @@ -1,487 +0,0 @@ -/* - * PXA2xx SPI private DMA support. - * - * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/dma-mapping.h> -#include <linux/pxa2xx_ssp.h> -#include <linux/spi/spi.h> -#include <linux/spi/pxa2xx_spi.h> - -#include <mach/dma.h> -#include "spi-pxa2xx.h" - -#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR) -#define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK) - -bool pxa2xx_spi_dma_is_possible(size_t len) -{ - /* Try to map dma buffer and do a dma transfer if successful, but - * only if the length is non-zero and less than MAX_DMA_LEN. - * - * Zero-length non-descriptor DMA is illegal on PXA2xx; force use - * of PIO instead. Care is needed above because the transfer may - * have have been passed with buffers that are already dma mapped. - * A zero-length transfer in PIO mode will not try to write/read - * to/from the buffers - * - * REVISIT large transfers are exactly where we most want to be - * using DMA. If this happens much, split those transfers into - * multiple DMA segments rather than forcing PIO. - */ - return len > 0 && len <= MAX_DMA_LEN; -} - -int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data) -{ - struct spi_message *msg = drv_data->cur_msg; - struct device *dev = &msg->spi->dev; - - if (!drv_data->cur_chip->enable_dma) - return 0; - - if (msg->is_dma_mapped) - return drv_data->rx_dma && drv_data->tx_dma; - - if (!IS_DMA_ALIGNED(drv_data->rx) || !IS_DMA_ALIGNED(drv_data->tx)) - return 0; - - /* Modify setup if rx buffer is null */ - if (drv_data->rx == NULL) { - *drv_data->null_dma_buf = 0; - drv_data->rx = drv_data->null_dma_buf; - drv_data->rx_map_len = 4; - } else - drv_data->rx_map_len = drv_data->len; - - - /* Modify setup if tx buffer is null */ - if (drv_data->tx == NULL) { - *drv_data->null_dma_buf = 0; - drv_data->tx = drv_data->null_dma_buf; - drv_data->tx_map_len = 4; - } else - drv_data->tx_map_len = drv_data->len; - - /* Stream map the tx buffer. Always do DMA_TO_DEVICE first - * so we flush the cache *before* invalidating it, in case - * the tx and rx buffers overlap. - */ - drv_data->tx_dma = dma_map_single(dev, drv_data->tx, - drv_data->tx_map_len, DMA_TO_DEVICE); - if (dma_mapping_error(dev, drv_data->tx_dma)) - return 0; - - /* Stream map the rx buffer */ - drv_data->rx_dma = dma_map_single(dev, drv_data->rx, - drv_data->rx_map_len, DMA_FROM_DEVICE); - if (dma_mapping_error(dev, drv_data->rx_dma)) { - dma_unmap_single(dev, drv_data->tx_dma, - drv_data->tx_map_len, DMA_TO_DEVICE); - return 0; - } - - return 1; -} - -static void pxa2xx_spi_unmap_dma_buffers(struct driver_data *drv_data) -{ - struct device *dev; - - if (!drv_data->dma_mapped) - return; - - if (!drv_data->cur_msg->is_dma_mapped) { - dev = &drv_data->cur_msg->spi->dev; - dma_unmap_single(dev, drv_data->rx_dma, - drv_data->rx_map_len, DMA_FROM_DEVICE); - dma_unmap_single(dev, drv_data->tx_dma, - drv_data->tx_map_len, DMA_TO_DEVICE); - } - - drv_data->dma_mapped = 0; -} - -static int wait_ssp_rx_stall(struct driver_data *drv_data) -{ - unsigned long limit = loops_per_jiffy << 1; - - while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY) && --limit) - cpu_relax(); - - return limit; -} - -static int wait_dma_channel_stop(int channel) -{ - unsigned long limit = loops_per_jiffy << 1; - - while (!(DCSR(channel) & DCSR_STOPSTATE) && --limit) - cpu_relax(); - - return limit; -} - -static void pxa2xx_spi_dma_error_stop(struct driver_data *drv_data, - const char *msg) -{ - /* Stop and reset */ - DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; - DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; - write_SSSR_CS(drv_data, drv_data->clear_sr); - pxa2xx_spi_write(drv_data, SSCR1, - pxa2xx_spi_read(drv_data, SSCR1) - & ~drv_data->dma_cr1); - if (!pxa25x_ssp_comp(drv_data)) - pxa2xx_spi_write(drv_data, SSTO, 0); - pxa2xx_spi_flush(drv_data); - pxa2xx_spi_write(drv_data, SSCR0, - pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE); - - pxa2xx_spi_unmap_dma_buffers(drv_data); - - dev_err(&drv_data->pdev->dev, "%s\n", msg); - - drv_data->cur_msg->state = ERROR_STATE; - tasklet_schedule(&drv_data->pump_transfers); -} - -static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data) -{ - struct spi_message *msg = drv_data->cur_msg; - - /* Clear and disable interrupts on SSP and DMA channels*/ - pxa2xx_spi_write(drv_data, SSCR1, - pxa2xx_spi_read(drv_data, SSCR1) - & ~drv_data->dma_cr1); - write_SSSR_CS(drv_data, drv_data->clear_sr); - DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; - DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; - - if (wait_dma_channel_stop(drv_data->rx_channel) == 0) - dev_err(&drv_data->pdev->dev, - "dma_handler: dma rx channel stop failed\n"); - - if (wait_ssp_rx_stall(drv_data->ioaddr) == 0) - dev_err(&drv_data->pdev->dev, - "dma_transfer: ssp rx stall failed\n"); - - pxa2xx_spi_unmap_dma_buffers(drv_data); - - /* update the buffer pointer for the amount completed in dma */ - drv_data->rx += drv_data->len - - (DCMD(drv_data->rx_channel) & DCMD_LENGTH); - - /* read trailing data from fifo, it does not matter how many - * bytes are in the fifo just read until buffer is full - * or fifo is empty, which ever occurs first */ - drv_data->read(drv_data); - - /* return count of what was actually read */ - msg->actual_length += drv_data->len - - (drv_data->rx_end - drv_data->rx); - - /* Transfer delays and chip select release are - * handled in pump_transfers or giveback - */ - - /* Move to next transfer */ - msg->state = pxa2xx_spi_next_transfer(drv_data); - - /* Schedule transfer tasklet */ - tasklet_schedule(&drv_data->pump_transfers); -} - -void pxa2xx_spi_dma_handler(int channel, void *data) -{ - struct driver_data *drv_data = data; - u32 irq_status = DCSR(channel) & DMA_INT_MASK; - - if (irq_status & DCSR_BUSERR) { - - if (channel == drv_data->tx_channel) - pxa2xx_spi_dma_error_stop(drv_data, - "dma_handler: bad bus address on tx channel"); - else - pxa2xx_spi_dma_error_stop(drv_data, - "dma_handler: bad bus address on rx channel"); - return; - } - - /* PXA255x_SSP has no timeout interrupt, wait for tailing bytes */ - if ((channel == drv_data->tx_channel) - && (irq_status & DCSR_ENDINTR) - && (drv_data->ssp_type == PXA25x_SSP)) { - - /* Wait for rx to stall */ - if (wait_ssp_rx_stall(drv_data) == 0) - dev_err(&drv_data->pdev->dev, - "dma_handler: ssp rx stall failed\n"); - - /* finish this transfer, start the next */ - pxa2xx_spi_dma_transfer_complete(drv_data); - } -} - -irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) -{ - u32 irq_status; - - irq_status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr; - if (irq_status & SSSR_ROR) { - pxa2xx_spi_dma_error_stop(drv_data, - "dma_transfer: fifo overrun"); - return IRQ_HANDLED; - } - - /* Check for false positive timeout */ - if ((irq_status & SSSR_TINT) - && (DCSR(drv_data->tx_channel) & DCSR_RUN)) { - pxa2xx_spi_write(drv_data, SSSR, SSSR_TINT); - return IRQ_HANDLED; - } - - if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) { - - /* Clear and disable timeout interrupt, do the rest in - * dma_transfer_complete */ - if (!pxa25x_ssp_comp(drv_data)) - pxa2xx_spi_write(drv_data, SSTO, 0); - - /* finish this transfer, start the next */ - pxa2xx_spi_dma_transfer_complete(drv_data); - - return IRQ_HANDLED; - } - - /* Opps problem detected */ - return IRQ_NONE; -} - -int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst) -{ - u32 dma_width; - - switch (drv_data->n_bytes) { - case 1: - dma_width = DCMD_WIDTH1; - break; - case 2: - dma_width = DCMD_WIDTH2; - break; - default: - dma_width = DCMD_WIDTH4; - break; - } - - /* Setup rx DMA Channel */ - DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; - DSADR(drv_data->rx_channel) = drv_data->ssdr_physical; - DTADR(drv_data->rx_channel) = drv_data->rx_dma; - if (drv_data->rx == drv_data->null_dma_buf) - /* No target address increment */ - DCMD(drv_data->rx_channel) = DCMD_FLOWSRC - | dma_width - | dma_burst - | drv_data->len; - else - DCMD(drv_data->rx_channel) = DCMD_INCTRGADDR - | DCMD_FLOWSRC - | dma_width - | dma_burst - | drv_data->len; - - /* Setup tx DMA Channel */ - DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; - DSADR(drv_data->tx_channel) = drv_data->tx_dma; - DTADR(drv_data->tx_channel) = drv_data->ssdr_physical; - if (drv_data->tx == drv_data->null_dma_buf) - /* No source address increment */ - DCMD(drv_data->tx_channel) = DCMD_FLOWTRG - | dma_width - | dma_burst - | drv_data->len; - else - DCMD(drv_data->tx_channel) = DCMD_INCSRCADDR - | DCMD_FLOWTRG - | dma_width - | dma_burst - | drv_data->len; - - /* Enable dma end irqs on SSP to detect end of transfer */ - if (drv_data->ssp_type == PXA25x_SSP) - DCMD(drv_data->tx_channel) |= DCMD_ENDIRQEN; - - return 0; -} - -void pxa2xx_spi_dma_start(struct driver_data *drv_data) -{ - DCSR(drv_data->rx_channel) |= DCSR_RUN; - DCSR(drv_data->tx_channel) |= DCSR_RUN; -} - -int pxa2xx_spi_dma_setup(struct driver_data *drv_data) -{ - struct device *dev = &drv_data->pdev->dev; - struct ssp_device *ssp = drv_data->ssp; - - /* Get two DMA channels (rx and tx) */ - drv_data->rx_channel = pxa_request_dma("pxa2xx_spi_ssp_rx", - DMA_PRIO_HIGH, - pxa2xx_spi_dma_handler, - drv_data); - if (drv_data->rx_channel < 0) { - dev_err(dev, "problem (%d) requesting rx channel\n", - drv_data->rx_channel); - return -ENODEV; - } - drv_data->tx_channel = pxa_request_dma("pxa2xx_spi_ssp_tx", - DMA_PRIO_MEDIUM, - pxa2xx_spi_dma_handler, - drv_data); - if (drv_data->tx_channel < 0) { - dev_err(dev, "problem (%d) requesting tx channel\n", - drv_data->tx_channel); - pxa_free_dma(drv_data->rx_channel); - return -ENODEV; - } - - DRCMR(ssp->drcmr_rx) = DRCMR_MAPVLD | drv_data->rx_channel; - DRCMR(ssp->drcmr_tx) = DRCMR_MAPVLD | drv_data->tx_channel; - - return 0; -} - -void pxa2xx_spi_dma_release(struct driver_data *drv_data) -{ - struct ssp_device *ssp = drv_data->ssp; - - DRCMR(ssp->drcmr_rx) = 0; - DRCMR(ssp->drcmr_tx) = 0; - - if (drv_data->tx_channel != 0) - pxa_free_dma(drv_data->tx_channel); - if (drv_data->rx_channel != 0) - pxa_free_dma(drv_data->rx_channel); -} - -void pxa2xx_spi_dma_resume(struct driver_data *drv_data) -{ - if (drv_data->rx_channel != -1) - DRCMR(drv_data->ssp->drcmr_rx) = - DRCMR_MAPVLD | drv_data->rx_channel; - if (drv_data->tx_channel != -1) - DRCMR(drv_data->ssp->drcmr_tx) = - DRCMR_MAPVLD | drv_data->tx_channel; -} - -int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip, - struct spi_device *spi, - u8 bits_per_word, u32 *burst_code, - u32 *threshold) -{ - struct pxa2xx_spi_chip *chip_info = - (struct pxa2xx_spi_chip *)spi->controller_data; - int bytes_per_word; - int burst_bytes; - int thresh_words; - int req_burst_size; - int retval = 0; - - /* Set the threshold (in registers) to equal the same amount of data - * as represented by burst size (in bytes). The computation below - * is (burst_size rounded up to nearest 8 byte, word or long word) - * divided by (bytes/register); the tx threshold is the inverse of - * the rx, so that there will always be enough data in the rx fifo - * to satisfy a burst, and there will always be enough space in the - * tx fifo to accept a burst (a tx burst will overwrite the fifo if - * there is not enough space), there must always remain enough empty - * space in the rx fifo for any data loaded to the tx fifo. - * Whenever burst_size (in bytes) equals bits/word, the fifo threshold - * will be 8, or half the fifo; - * The threshold can only be set to 2, 4 or 8, but not 16, because - * to burst 16 to the tx fifo, the fifo would have to be empty; - * however, the minimum fifo trigger level is 1, and the tx will - * request service when the fifo is at this level, with only 15 spaces. - */ - - /* find bytes/word */ - if (bits_per_word <= 8) - bytes_per_word = 1; - else if (bits_per_word <= 16) - bytes_per_word = 2; - else - bytes_per_word = 4; - - /* use struct pxa2xx_spi_chip->dma_burst_size if available */ - if (chip_info) - req_burst_size = chip_info->dma_burst_size; - else { - switch (chip->dma_burst_size) { - default: - /* if the default burst size is not set, - * do it now */ - chip->dma_burst_size = DCMD_BURST8; - case DCMD_BURST8: - req_burst_size = 8; - break; - case DCMD_BURST16: - req_burst_size = 16; - break; - case DCMD_BURST32: - req_burst_size = 32; - break; - } - } - if (req_burst_size <= 8) { - *burst_code = DCMD_BURST8; - burst_bytes = 8; - } else if (req_burst_size <= 16) { - if (bytes_per_word == 1) { - /* don't burst more than 1/2 the fifo */ - *burst_code = DCMD_BURST8; - burst_bytes = 8; - retval = 1; - } else { - *burst_code = DCMD_BURST16; - burst_bytes = 16; - } - } else { - if (bytes_per_word == 1) { - /* don't burst more than 1/2 the fifo */ - *burst_code = DCMD_BURST8; - burst_bytes = 8; - retval = 1; - } else if (bytes_per_word == 2) { - /* don't burst more than 1/2 the fifo */ - *burst_code = DCMD_BURST16; - burst_bytes = 16; - retval = 1; - } else { - *burst_code = DCMD_BURST32; - burst_bytes = 32; - } - } - - thresh_words = burst_bytes / bytes_per_word; - - /* thresh_words will be between 2 and 8 */ - *threshold = (SSCR1_RxTresh(thresh_words) & SSCR1_RFT) - | (SSCR1_TxTresh(16-thresh_words) & SSCR1_TFT); - - return retval; -} diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index e3223ac..7293d6d 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -60,21 +60,60 @@ MODULE_ALIAS("platform:pxa2xx-spi"); | QUARK_X1000_SSCR1_TFT \ | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) -#define LPSS_RX_THRESH_DFLT 64 -#define LPSS_TX_LOTHRESH_DFLT 160 -#define LPSS_TX_HITHRESH_DFLT 224 - -/* Offset from drv_data->lpss_base */ -#define GENERAL_REG 0x08 #define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24) -#define SSP_REG 0x0c -#define SPI_CS_CONTROL 0x18 #define SPI_CS_CONTROL_SW_MODE BIT(0) #define SPI_CS_CONTROL_CS_HIGH BIT(1) +struct lpss_config { + /* LPSS offset from drv_data->ioaddr */ + unsigned offset; + /* Register offsets from drv_data->lpss_base or -1 */ + int reg_general; + int reg_ssp; + int reg_cs_ctrl; + /* FIFO thresholds */ + u32 rx_threshold; + u32 tx_threshold_lo; + u32 tx_threshold_hi; +}; + +/* Keep these sorted with enum pxa_ssp_type */ +static const struct lpss_config lpss_platforms[] = { + { /* LPSS_LPT_SSP */ + .offset = 0x800, + .reg_general = 0x08, + .reg_ssp = 0x0c, + .reg_cs_ctrl = 0x18, + .rx_threshold = 64, + .tx_threshold_lo = 160, + .tx_threshold_hi = 224, + }, + { /* LPSS_BYT_SSP */ + .offset = 0x400, + .reg_general = 0x08, + .reg_ssp = 0x0c, + .reg_cs_ctrl = 0x18, + .rx_threshold = 64, + .tx_threshold_lo = 160, + .tx_threshold_hi = 224, + }, +}; + +static inline const struct lpss_config +*lpss_get_config(const struct driver_data *drv_data) +{ + return &lpss_platforms[drv_data->ssp_type - LPSS_LPT_SSP]; +} + static bool is_lpss_ssp(const struct driver_data *drv_data) { - return drv_data->ssp_type == LPSS_SSP; + switch (drv_data->ssp_type) { + case LPSS_LPT_SSP: + case LPSS_BYT_SSP: + return true; + default: + return false; + } } static bool is_quark_x1000_ssp(const struct driver_data *drv_data) @@ -192,63 +231,43 @@ static void __lpss_ssp_write_priv(struct driver_data *drv_data, */ static void lpss_ssp_setup(struct driver_data *drv_data) { - unsigned offset = 0x400; - u32 value, orig; - - /* - * Perform auto-detection of the LPSS SSP private registers. They - * can be either at 1k or 2k offset from the base address. - */ - orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL); - - /* Test SPI_CS_CONTROL_SW_MODE bit enabling */ - value = orig | SPI_CS_CONTROL_SW_MODE; - writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL); - value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL); - if (value != (orig | SPI_CS_CONTROL_SW_MODE)) { - offset = 0x800; - goto detection_done; - } - - orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL); - - /* Test SPI_CS_CONTROL_SW_MODE bit disabling */ - value = orig & ~SPI_CS_CONTROL_SW_MODE; - writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL); - value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL); - if (value != (orig & ~SPI_CS_CONTROL_SW_MODE)) { - offset = 0x800; - goto detection_done; - } + const struct lpss_config *config; + u32 value; -detection_done: - /* Now set the LPSS base */ - drv_data->lpss_base = drv_data->ioaddr + offset; + config = lpss_get_config(drv_data); + drv_data->lpss_base = drv_data->ioaddr + config->offset; /* Enable software chip select control */ value = SPI_CS_CONTROL_SW_MODE | SPI_CS_CONTROL_CS_HIGH; - __lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value); + __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value); /* Enable multiblock DMA transfers */ if (drv_data->master_info->enable_dma) { - __lpss_ssp_write_priv(drv_data, SSP_REG, 1); - - value = __lpss_ssp_read_priv(drv_data, GENERAL_REG); - value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE; - __lpss_ssp_write_priv(drv_data, GENERAL_REG, value); + __lpss_ssp_write_priv(drv_data, config->reg_ssp, 1); + + if (config->reg_general >= 0) { + value = __lpss_ssp_read_priv(drv_data, + config->reg_general); + value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE; + __lpss_ssp_write_priv(drv_data, + config->reg_general, value); + } } } static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) { + const struct lpss_config *config; u32 value; - value = __lpss_ssp_read_priv(drv_data, SPI_CS_CONTROL); + config = lpss_get_config(drv_data); + + value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl); if (enable) value &= ~SPI_CS_CONTROL_CS_HIGH; else value |= SPI_CS_CONTROL_CS_HIGH; - __lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value); + __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value); } static void cs_assert(struct driver_data *drv_data) @@ -1075,6 +1094,7 @@ static int setup(struct spi_device *spi) { struct pxa2xx_spi_chip *chip_info = NULL; struct chip_data *chip; + const struct lpss_config *config; struct driver_data *drv_data = spi_master_get_devdata(spi->master); unsigned int clk_div; uint tx_thres, tx_hi_thres, rx_thres; @@ -1085,10 +1105,12 @@ static int setup(struct spi_device *spi) tx_hi_thres = 0; rx_thres = RX_THRESH_QUARK_X1000_DFLT; break; - case LPSS_SSP: - tx_thres = LPSS_TX_LOTHRESH_DFLT; - tx_hi_thres = LPSS_TX_HITHRESH_DFLT; - rx_thres = LPSS_RX_THRESH_DFLT; + case LPSS_LPT_SSP: + case LPSS_BYT_SSP: + config = lpss_get_config(drv_data); + tx_thres = config->tx_threshold_lo; + tx_hi_thres = config->tx_threshold_hi; + rx_thres = config->rx_threshold; break; default: tx_thres = TX_THRESH_DFLT; @@ -1242,6 +1264,18 @@ static void cleanup(struct spi_device *spi) } #ifdef CONFIG_ACPI + +static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { + { "INT33C0", LPSS_LPT_SSP }, + { "INT33C1", LPSS_LPT_SSP }, + { "INT3430", LPSS_LPT_SSP }, + { "INT3431", LPSS_LPT_SSP }, + { "80860F0E", LPSS_BYT_SSP }, + { "8086228E", LPSS_BYT_SSP }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); + static struct pxa2xx_spi_master * pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) { @@ -1249,12 +1283,19 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) struct acpi_device *adev; struct ssp_device *ssp; struct resource *res; - int devid; + const struct acpi_device_id *id; + int devid, type; if (!ACPI_HANDLE(&pdev->dev) || acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev)) return NULL; + id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev); + if (id) + type = (int)id->driver_data; + else + return NULL; + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return NULL; @@ -1272,7 +1313,7 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) ssp->clk = devm_clk_get(&pdev->dev, NULL); ssp->irq = platform_get_irq(pdev, 0); - ssp->type = LPSS_SSP; + ssp->type = type; ssp->pdev = pdev; ssp->port_id = -1; @@ -1285,16 +1326,6 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) return pdata; } -static struct acpi_device_id pxa2xx_spi_acpi_match[] = { - { "INT33C0", 0 }, - { "INT33C1", 0 }, - { "INT3430", 0 }, - { "INT3431", 0 }, - { "80860F0E", 0 }, - { "8086228E", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); #else static inline struct pxa2xx_spi_master * pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 85a58c9..9f01e9c 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -162,11 +162,7 @@ extern void *pxa2xx_spi_next_transfer(struct driver_data *drv_data); /* * Select the right DMA implementation. */ -#if defined(CONFIG_SPI_PXA2XX_PXADMA) -#define SPI_PXA2XX_USE_DMA 1 -#define MAX_DMA_LEN 8191 -#define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TINTE) -#elif defined(CONFIG_SPI_PXA2XX_DMA) +#if defined(CONFIG_SPI_PXA2XX_DMA) #define SPI_PXA2XX_USE_DMA 1 #define MAX_DMA_LEN SZ_64K #define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TRAIL) diff --git a/drivers/spi/spi-rb4xx.c b/drivers/spi/spi-rb4xx.c new file mode 100644 index 0000000..3641d0e --- /dev/null +++ b/drivers/spi/spi-rb4xx.c @@ -0,0 +1,210 @@ +/* + * SPI controller driver for the Mikrotik RB4xx boards + * + * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2015 Bert Vermeulen <bert@biot.com> + * + * This file was based on the patches for Linux 2.6.27.39 published by + * MikroTik for their RouterBoard 4xx series devices. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/spi/spi.h> + +#include <asm/mach-ath79/ar71xx_regs.h> + +struct rb4xx_spi { + void __iomem *base; + struct clk *clk; +}; + +static inline u32 rb4xx_read(struct rb4xx_spi *rbspi, u32 reg) +{ + return __raw_readl(rbspi->base + reg); +} + +static inline void rb4xx_write(struct rb4xx_spi *rbspi, u32 reg, u32 value) +{ + __raw_writel(value, rbspi->base + reg); +} + +static inline void do_spi_clk(struct rb4xx_spi *rbspi, u32 spi_ioc, int value) +{ + u32 regval; + + regval = spi_ioc; + if (value & BIT(0)) + regval |= AR71XX_SPI_IOC_DO; + + rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval); + rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK); +} + +static void do_spi_byte(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte) +{ + int i; + + for (i = 7; i >= 0; i--) + do_spi_clk(rbspi, spi_ioc, byte >> i); +} + +/* The CS2 pin is used to clock in a second bit per clock cycle. */ +static inline void do_spi_clk_two(struct rb4xx_spi *rbspi, u32 spi_ioc, + u8 value) +{ + u32 regval; + + regval = spi_ioc; + if (value & BIT(1)) + regval |= AR71XX_SPI_IOC_DO; + if (value & BIT(0)) + regval |= AR71XX_SPI_IOC_CS2; + + rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval); + rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK); +} + +/* Two bits at a time, msb first */ +static void do_spi_byte_two(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte) +{ + do_spi_clk_two(rbspi, spi_ioc, byte >> 6); + do_spi_clk_two(rbspi, spi_ioc, byte >> 4); + do_spi_clk_two(rbspi, spi_ioc, byte >> 2); + do_spi_clk_two(rbspi, spi_ioc, byte >> 0); +} + +static void rb4xx_set_cs(struct spi_device *spi, bool enable) +{ + struct rb4xx_spi *rbspi = spi_master_get_devdata(spi->master); + + /* + * Setting CS is done along with bitbanging the actual values, + * since it's all on the same hardware register. However the + * CPLD needs CS deselected after every command. + */ + if (enable) + rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, + AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1); +} + +static int rb4xx_transfer_one(struct spi_master *master, + struct spi_device *spi, struct spi_transfer *t) +{ + struct rb4xx_spi *rbspi = spi_master_get_devdata(master); + int i; + u32 spi_ioc; + u8 *rx_buf; + const u8 *tx_buf; + + /* + * Prime the SPI register with the SPI device selected. The m25p80 boot + * flash and CPLD share the CS0 pin. This works because the CPLD's + * command set was designed to almost not clash with that of the + * boot flash. + */ + if (spi->chip_select == 2) + /* MMC */ + spi_ioc = AR71XX_SPI_IOC_CS0; + else + /* Boot flash and CPLD */ + spi_ioc = AR71XX_SPI_IOC_CS1; + + tx_buf = t->tx_buf; + rx_buf = t->rx_buf; + for (i = 0; i < t->len; ++i) { + if (t->tx_nbits == SPI_NBITS_DUAL) + /* CPLD can use two-wire transfers */ + do_spi_byte_two(rbspi, spi_ioc, tx_buf[i]); + else + do_spi_byte(rbspi, spi_ioc, tx_buf[i]); + if (!rx_buf) + continue; + rx_buf[i] = rb4xx_read(rbspi, AR71XX_SPI_REG_RDS); + } + spi_finalize_current_transfer(master); + + return 0; +} + +static int rb4xx_spi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct clk *ahb_clk; + struct rb4xx_spi *rbspi; + struct resource *r; + int err; + void __iomem *spi_base; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + spi_base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(spi_base)) + return PTR_ERR(spi_base); + + master = spi_alloc_master(&pdev->dev, sizeof(*rbspi)); + if (!master) + return -ENOMEM; + + ahb_clk = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(ahb_clk)) + return PTR_ERR(ahb_clk); + + master->bus_num = 0; + master->num_chipselect = 3; + master->mode_bits = SPI_TX_DUAL; + master->bits_per_word_mask = BIT(7); + master->flags = SPI_MASTER_MUST_TX; + master->transfer_one = rb4xx_transfer_one; + master->set_cs = rb4xx_set_cs; + + err = devm_spi_register_master(&pdev->dev, master); + if (err) { + dev_err(&pdev->dev, "failed to register SPI master\n"); + return err; + } + + err = clk_prepare_enable(ahb_clk); + if (err) + return err; + + rbspi = spi_master_get_devdata(master); + rbspi->base = spi_base; + rbspi->clk = ahb_clk; + platform_set_drvdata(pdev, rbspi); + + /* Enable SPI */ + rb4xx_write(rbspi, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO); + + return 0; +} + +static int rb4xx_spi_remove(struct platform_device *pdev) +{ + struct rb4xx_spi *rbspi = platform_get_drvdata(pdev); + + clk_disable_unprepare(rbspi->clk); + + return 0; +} + +static struct platform_driver rb4xx_spi_drv = { + .probe = rb4xx_spi_probe, + .remove = rb4xx_spi_remove, + .driver = { + .name = "rb4xx-spi", + }, +}; + +module_platform_driver(rb4xx_spi_drv); + +MODULE_DESCRIPTION("Mikrotik RB4xx SPI controller driver"); +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); +MODULE_AUTHOR("Bert Vermeulen <bert@biot.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index f6bac9e..f9189a0 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -665,15 +665,12 @@ static bool rspi_can_dma(struct spi_master *master, struct spi_device *spi, static int rspi_dma_check_then_transfer(struct rspi_data *rspi, struct spi_transfer *xfer) { - if (rspi->master->can_dma && __rspi_can_dma(rspi, xfer)) { - /* rx_buf can be NULL on RSPI on SH in TX-only Mode */ - int ret = rspi_dma_transfer(rspi, &xfer->tx_sg, - xfer->rx_buf ? &xfer->rx_sg : NULL); - if (ret != -EAGAIN) - return 0; - } + if (!rspi->master->can_dma || !__rspi_can_dma(rspi, xfer)) + return -EAGAIN; - return -EAGAIN; + /* rx_buf can be NULL on RSPI on SH in TX-only Mode */ + return rspi_dma_transfer(rspi, &xfer->tx_sg, + xfer->rx_buf ? &xfer->rx_sg : NULL); } static int rspi_common_transfer(struct rspi_data *rspi, @@ -724,7 +721,7 @@ static int rspi_rz_transfer_one(struct spi_master *master, return rspi_common_transfer(rspi, xfer); } -static int qspi_trigger_transfer_out_int(struct rspi_data *rspi, const u8 *tx, +static int qspi_trigger_transfer_out_in(struct rspi_data *rspi, const u8 *tx, u8 *rx, unsigned int len) { int i, n, ret; @@ -771,12 +768,8 @@ static int qspi_transfer_out_in(struct rspi_data *rspi, if (ret != -EAGAIN) return ret; - ret = qspi_trigger_transfer_out_int(rspi, xfer->tx_buf, + return qspi_trigger_transfer_out_in(rspi, xfer->tx_buf, xfer->rx_buf, xfer->len); - if (ret < 0) - return ret; - - return 0; } static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer) @@ -1300,7 +1293,7 @@ error1: return ret; } -static struct platform_device_id spi_driver_ids[] = { +static const struct platform_device_id spi_driver_ids[] = { { "rspi", (kernel_ulong_t)&rspi_ops }, { "rspi-rz", (kernel_ulong_t)&rspi_rz_ops }, { "qspi", (kernel_ulong_t)&qspi_ops }, diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index bcc7c63..d3370a6 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -1263,7 +1263,7 @@ static int sh_msiof_spi_remove(struct platform_device *pdev) return 0; } -static struct platform_device_id spi_driver_ids[] = { +static const 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 }, 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) |