diff options
-rw-r--r-- | Documentation/devicetree/bindings/spi/sh-msiof.txt | 6 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/spi/spi-davinci.txt | 10 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/spi/spi-rspi.txt | 5 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/spi/spi-sprd-adi.txt | 58 | ||||
-rw-r--r-- | drivers/spi/Kconfig | 13 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/spi-armada-3700.c | 17 | ||||
-rw-r--r-- | drivers/spi/spi-axi-spi-engine.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-dspi.c | 66 | ||||
-rw-r--r-- | drivers/spi/spi-imx.c | 256 | ||||
-rw-r--r-- | drivers/spi/spi-mxs.c | 120 | ||||
-rw-r--r-- | drivers/spi/spi-orion.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-rspi.c | 6 | ||||
-rw-r--r-- | drivers/spi/spi-s3c64xx.c | 3 | ||||
-rw-r--r-- | drivers/spi/spi-sh-msiof.c | 12 | ||||
-rw-r--r-- | drivers/spi/spi-sprd-adi.c | 418 | ||||
-rw-r--r-- | drivers/spi/spi-tegra114.c | 6 | ||||
-rw-r--r-- | drivers/spi/spi.c | 9 | ||||
-rw-r--r-- | include/linux/spi/spi-fsl-dspi.h | 31 |
19 files changed, 926 insertions, 116 deletions
diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt index e865855726a2..bdd83959019c 100644 --- a/Documentation/devicetree/bindings/spi/sh-msiof.txt +++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt @@ -1,7 +1,9 @@ Renesas MSIOF spi controller Required properties: -- compatible : "renesas,msiof-r8a7790" (R-Car H2) +- compatible : "renesas,msiof-r8a7743" (RZ/G1M) + "renesas,msiof-r8a7745" (RZ/G1E) + "renesas,msiof-r8a7790" (R-Car H2) "renesas,msiof-r8a7791" (R-Car M2-W) "renesas,msiof-r8a7792" (R-Car V2H) "renesas,msiof-r8a7793" (R-Car M2-N) @@ -10,7 +12,7 @@ Required properties: "renesas,msiof-r8a7796" (R-Car M3-W) "renesas,msiof-sh73a0" (SH-Mobile AG5) "renesas,sh-mobile-msiof" (generic SH-Mobile compatibile device) - "renesas,rcar-gen2-msiof" (generic R-Car Gen2 compatible device) + "renesas,rcar-gen2-msiof" (generic R-Car Gen2 and RZ/G1 compatible device) "renesas,rcar-gen3-msiof" (generic R-Car Gen3 compatible device) "renesas,sh-msiof" (deprecated) diff --git a/Documentation/devicetree/bindings/spi/spi-davinci.txt b/Documentation/devicetree/bindings/spi/spi-davinci.txt index f5916c92fe91..1925277bfc1e 100644 --- a/Documentation/devicetree/bindings/spi/spi-davinci.txt +++ b/Documentation/devicetree/bindings/spi/spi-davinci.txt @@ -24,6 +24,16 @@ Required properties: based on a specific SoC configuration. - interrupts: interrupt number mapped to CPU. - clocks: spi clk phandle + For 66AK2G this property should be set per binding, + Documentation/devicetree/bindings/clock/ti,sci-clk.txt + +SoC-specific Required Properties: + +The following are mandatory properties for Keystone 2 66AK2G SoCs only: + +- power-domains: Should contain a phandle to a PM domain provider node + and an args specifier containing the SPI device id + value. This property is as per the binding, Optional: - cs-gpios: gpio chip selects diff --git a/Documentation/devicetree/bindings/spi/spi-rspi.txt b/Documentation/devicetree/bindings/spi/spi-rspi.txt index 8f4169f63936..3b02b3a7cfb2 100644 --- a/Documentation/devicetree/bindings/spi/spi-rspi.txt +++ b/Documentation/devicetree/bindings/spi/spi-rspi.txt @@ -5,11 +5,14 @@ Required properties: "renesas,rspi-<soctype>", "renesas,rspi" as fallback. For Renesas Serial Peripheral Interface on RZ/A1H: "renesas,rspi-<soctype>", "renesas,rspi-rz" as fallback. - For Quad Serial Peripheral Interface on R-Car Gen2: + For Quad Serial Peripheral Interface on R-Car Gen2 and + RZ/G1 devices: "renesas,qspi-<soctype>", "renesas,qspi" as fallback. Examples with soctypes are: - "renesas,rspi-sh7757" (SH) - "renesas,rspi-r7s72100" (RZ/A1H) + - "renesas,qspi-r8a7743" (RZ/G1M) + - "renesas,qspi-r8a7745" (RZ/G1E) - "renesas,qspi-r8a7790" (R-Car H2) - "renesas,qspi-r8a7791" (R-Car M2-W) - "renesas,qspi-r8a7792" (R-Car V2H) diff --git a/Documentation/devicetree/bindings/spi/spi-sprd-adi.txt b/Documentation/devicetree/bindings/spi/spi-sprd-adi.txt new file mode 100644 index 000000000000..8de589b376ce --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-sprd-adi.txt @@ -0,0 +1,58 @@ +Spreadtrum ADI controller + +ADI is the abbreviation of Anolog-Digital interface, which is used to access +analog chip (such as PMIC) from digital chip. ADI controller follows the SPI +framework for its hardware implementation is alike to SPI bus and its timing +is compatile to SPI timing. + +ADI controller has 50 channels including 2 software read/write channels and +48 hardware channels to access analog chip. For 2 software read/write channels, +users should set ADI registers to access analog chip. For hardware channels, +we can configure them to allow other hardware components to use it independently, +which means we can just link one analog chip address to one hardware channel, +then users can access the mapped analog chip address by this hardware channel +triggered by hardware components instead of ADI software channels. + +Thus we introduce one property named "sprd,hw-channels" to configure hardware +channels, the first value specifies the hardware channel id which is used to +transfer data triggered by hardware automatically, and the second value specifies +the analog chip address where user want to access by hardware components. + +Since we have multi-subsystems will use unique ADI to access analog chip, when +one system is reading/writing data by ADI software channels, that should be under +one hardware spinlock protection to prevent other systems from reading/writing +data by ADI software channels at the same time, or two parallel routine of setting +ADI registers will make ADI controller registers chaos to lead incorrect results. +Then we need one hardware spinlock to synchronize between the multiple subsystems. + +Required properties: +- compatible: Should be "sprd,sc9860-adi". +- reg: Offset and length of ADI-SPI controller register space. +- hwlocks: Reference to a phandle of a hwlock provider node. +- hwlock-names: Reference to hwlock name strings defined in the same order + as the hwlocks, should be "adi". +- #address-cells: Number of cells required to define a chip select address + on the ADI-SPI bus. Should be set to 1. +- #size-cells: Size of cells required to define a chip select address size + on the ADI-SPI bus. Should be set to 0. + +Optional properties: +- sprd,hw-channels: This is an array of channel values up to 49 channels. + The first value specifies the hardware channel id which is used to + transfer data triggered by hardware automatically, and the second + value specifies the analog chip address where user want to access + by hardware components. + +SPI slave nodes must be children of the SPI controller node and can contain +properties described in Documentation/devicetree/bindings/spi/spi-bus.txt. + +Example: + adi_bus: spi@40030000 { + compatible = "sprd,sc9860-adi"; + reg = <0 0x40030000 0 0x10000>; + hwlocks = <&hwlock1 0>; + hwlock-names = "adi"; + #address-cells = <1>; + #size-cells = <0>; + sprd,hw-channels = <30 0x8c20>; + }; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index a75f2a2cf780..603783976b81 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -1,10 +1,6 @@ # # SPI driver configuration # -# NOTE: the reason this doesn't show SPI slave support is mostly that -# nobody's needed a slave side API yet. The master-role API is not -# fully appropriate there, so it'd need some thought to do well. -# menuconfig SPI bool "SPI support" depends on HAS_IOMEM @@ -379,7 +375,7 @@ config SPI_FSL_DSPI tristate "Freescale DSPI controller" select REGMAP_MMIO depends on HAS_DMA - depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST + depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || M5441x || COMPILE_TEST help This enables support for the Freescale DSPI controller in master mode. VF610 platform uses the controller. @@ -626,6 +622,13 @@ config SPI_SIRF help SPI driver for CSR SiRFprimaII SoCs +config SPI_SPRD_ADI + tristate "Spreadtrum ADI controller" + depends on ARCH_SPRD || COMPILE_TEST + depends on HWSPINLOCK || (COMPILE_TEST && !HWSPINLOCK) + help + ADI driver based on SPI for Spreadtrum SoCs. + config SPI_STM32 tristate "STMicroelectronics STM32 SPI controller" depends on ARCH_STM32 || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 8e0cda73b324..34c5f2832ddf 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -91,6 +91,7 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o obj-$(CONFIG_SPI_SIRF) += spi-sirf.o +obj-$(CONFIG_SPI_SPRD_ADI) += spi-sprd-adi.o obj-$(CONFIG_SPI_STM32) += spi-stm32.o obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index 568e1c65aa82..77fe55ce790c 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -213,7 +213,7 @@ static void a3700_spi_mode_set(struct a3700_spi *a3700_spi, } static void a3700_spi_clock_set(struct a3700_spi *a3700_spi, - unsigned int speed_hz, u16 mode) + unsigned int speed_hz) { u32 val; u32 prescale; @@ -231,17 +231,6 @@ static void a3700_spi_clock_set(struct a3700_spi *a3700_spi, val |= A3700_SPI_CLK_CAPT_EDGE; spireg_write(a3700_spi, A3700_SPI_IF_TIME_REG, val); } - - val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); - val &= ~(A3700_SPI_CLK_POL | A3700_SPI_CLK_PHA); - - if (mode & SPI_CPOL) - val |= A3700_SPI_CLK_POL; - - if (mode & SPI_CPHA) - val |= A3700_SPI_CLK_PHA; - - spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val); } static void a3700_spi_bytelen_set(struct a3700_spi *a3700_spi, unsigned int len) @@ -423,7 +412,7 @@ static void a3700_spi_transfer_setup(struct spi_device *spi, a3700_spi = spi_master_get_devdata(spi->master); - a3700_spi_clock_set(a3700_spi, xfer->speed_hz, spi->mode); + a3700_spi_clock_set(a3700_spi, xfer->speed_hz); byte_len = xfer->bits_per_word >> 3; @@ -584,6 +573,8 @@ static int a3700_spi_prepare_message(struct spi_master *master, a3700_spi_bytelen_set(a3700_spi, 4); + a3700_spi_mode_set(a3700_spi, spi->mode); + return 0; } diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c index 6ab4c7700228..68cfc351b47f 100644 --- a/drivers/spi/spi-axi-spi-engine.c +++ b/drivers/spi/spi-axi-spi-engine.c @@ -553,7 +553,7 @@ err_put_master: static int spi_engine_remove(struct platform_device *pdev) { - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct spi_engine *spi_engine = spi_master_get_devdata(master); int irq = platform_get_irq(pdev, 0); @@ -561,6 +561,8 @@ static int spi_engine_remove(struct platform_device *pdev) free_irq(irq, master); + spi_master_put(master); + writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING); writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE); writel_relaxed(0x01, spi_engine->base + SPI_ENGINE_REG_RESET); diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index d89127f4a46d..f652f70cb8db 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -32,6 +32,7 @@ #include <linux/regmap.h> #include <linux/sched.h> #include <linux/spi/spi.h> +#include <linux/spi/spi-fsl-dspi.h> #include <linux/spi/spi_bitbang.h> #include <linux/time.h> @@ -151,6 +152,11 @@ static const struct fsl_dspi_devtype_data ls2085a_data = { .max_clock_factor = 8, }; +static const struct fsl_dspi_devtype_data coldfire_data = { + .trans_mode = DSPI_EOQ_MODE, + .max_clock_factor = 8, +}; + struct fsl_dspi_dma { /* Length of transfer in words of DSPI_FIFO_SIZE */ u32 curr_xfer_len; @@ -741,6 +747,7 @@ static int dspi_setup(struct spi_device *spi) { struct chip_data *chip; struct fsl_dspi *dspi = spi_master_get_devdata(spi->master); + struct fsl_dspi_platform_data *pdata; u32 cs_sck_delay = 0, sck_cs_delay = 0; unsigned char br = 0, pbr = 0, pcssck = 0, cssck = 0; unsigned char pasc = 0, asc = 0, fmsz = 0; @@ -761,11 +768,18 @@ static int dspi_setup(struct spi_device *spi) return -ENOMEM; } - of_property_read_u32(spi->dev.of_node, "fsl,spi-cs-sck-delay", - &cs_sck_delay); + pdata = dev_get_platdata(&dspi->pdev->dev); - of_property_read_u32(spi->dev.of_node, "fsl,spi-sck-cs-delay", - &sck_cs_delay); + if (!pdata) { + of_property_read_u32(spi->dev.of_node, "fsl,spi-cs-sck-delay", + &cs_sck_delay); + + of_property_read_u32(spi->dev.of_node, "fsl,spi-sck-cs-delay", + &sck_cs_delay); + } else { + cs_sck_delay = pdata->cs_sck_delay; + sck_cs_delay = pdata->sck_cs_delay; + } chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF; @@ -949,6 +963,7 @@ static int dspi_probe(struct platform_device *pdev) struct fsl_dspi *dspi; struct resource *res; void __iomem *base; + struct fsl_dspi_platform_data *pdata; int ret = 0, cs_num, bus_num; master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi)); @@ -969,25 +984,34 @@ static int dspi_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_MASK(4) | SPI_BPW_MASK(8) | SPI_BPW_MASK(16); - ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num); - if (ret < 0) { - dev_err(&pdev->dev, "can't get spi-num-chipselects\n"); - goto out_master_put; - } - master->num_chipselect = cs_num; + pdata = dev_get_platdata(&pdev->dev); + if (pdata) { + master->num_chipselect = pdata->cs_num; + master->bus_num = pdata->bus_num; - ret = of_property_read_u32(np, "bus-num", &bus_num); - if (ret < 0) { - dev_err(&pdev->dev, "can't get bus-num\n"); - goto out_master_put; - } - master->bus_num = bus_num; + dspi->devtype_data = &coldfire_data; + } else { - dspi->devtype_data = of_device_get_match_data(&pdev->dev); - if (!dspi->devtype_data) { - dev_err(&pdev->dev, "can't get devtype_data\n"); - ret = -EFAULT; - goto out_master_put; + ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num); + if (ret < 0) { + dev_err(&pdev->dev, "can't get spi-num-chipselects\n"); + goto out_master_put; + } + master->num_chipselect = cs_num; + + ret = of_property_read_u32(np, "bus-num", &bus_num); + if (ret < 0) { + dev_err(&pdev->dev, "can't get bus-num\n"); + goto out_master_put; + } + master->bus_num = bus_num; + + dspi->devtype_data = of_device_get_match_data(&pdev->dev); + 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); diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index babb15f07995..79ddefe4180d 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -53,10 +53,13 @@ /* generic defines to abstract from the different register layouts */ #define MXC_INT_RR (1 << 0) /* Receive data ready interrupt */ #define MXC_INT_TE (1 << 1) /* Transmit FIFO empty interrupt */ +#define MXC_INT_RDR BIT(4) /* Receive date threshold interrupt */ /* The maximum bytes that a sdma BD can transfer.*/ #define MAX_SDMA_BD_BYTES (1 << 15) #define MX51_ECSPI_CTRL_MAX_BURST 512 +/* The maximum bytes that IMX53_ECSPI can transfer in slave mode.*/ +#define MX53_MAX_TRANSFER_BYTES 512 enum spi_imx_devtype { IMX1_CSPI, @@ -76,7 +79,9 @@ struct spi_imx_devtype_data { void (*trigger)(struct spi_imx_data *); int (*rx_available)(struct spi_imx_data *); void (*reset)(struct spi_imx_data *); + void (*disable)(struct spi_imx_data *); bool has_dmamode; + bool has_slavemode; unsigned int fifo_size; bool dynamic_burst; enum spi_imx_devtype devtype; @@ -108,6 +113,11 @@ struct spi_imx_data { unsigned int dynamic_burst, read_u32; unsigned int word_mask; + /* Slave mode */ + bool slave_mode; + bool slave_aborted; + unsigned int slave_burst; + /* DMA */ bool usedma; u32 wml; @@ -221,6 +231,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, if (!master->dma_rx) return false; + if (spi_imx->slave_mode) + return false; + bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word); if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4) @@ -262,6 +275,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, #define MX51_ECSPI_INT 0x10 #define MX51_ECSPI_INT_TEEN (1 << 0) #define MX51_ECSPI_INT_RREN (1 << 3) +#define MX51_ECSPI_INT_RDREN (1 << 4) #define MX51_ECSPI_DMA 0x14 #define MX51_ECSPI_DMA_TX_WML(wml) ((wml) & 0x3f) @@ -378,6 +392,44 @@ static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx) spi_imx_buf_tx_u16(spi_imx); } +static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx) +{ + u32 val = be32_to_cpu(readl(spi_imx->base + MXC_CSPIRXDATA)); + + if (spi_imx->rx_buf) { + int n_bytes = spi_imx->slave_burst % sizeof(val); + + if (!n_bytes) + n_bytes = sizeof(val); + + memcpy(spi_imx->rx_buf, + ((u8 *)&val) + sizeof(val) - n_bytes, n_bytes); + + spi_imx->rx_buf += n_bytes; + spi_imx->slave_burst -= n_bytes; + } +} + +static void mx53_ecspi_tx_slave(struct spi_imx_data *spi_imx) +{ + u32 val = 0; + int n_bytes = spi_imx->count % sizeof(val); + + if (!n_bytes) + n_bytes = sizeof(val); + + if (spi_imx->tx_buf) { + memcpy(((u8 *)&val) + sizeof(val) - n_bytes, + spi_imx->tx_buf, n_bytes); + val = cpu_to_be32(val); + spi_imx->tx_buf += n_bytes; + } + + spi_imx->count -= n_bytes; + + writel(val, spi_imx->base + MXC_CSPITXDATA); +} + /* MX51 eCSPI */ static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx, unsigned int fspi, unsigned int *fres) @@ -427,6 +479,9 @@ static void mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int enable) if (enable & MXC_INT_RR) val |= MX51_ECSPI_INT_RREN; + if (enable & MXC_INT_RDR) + val |= MX51_ECSPI_INT_RDREN; + writel(val, spi_imx->base + MX51_ECSPI_INT); } @@ -439,6 +494,15 @@ static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx) writel(reg, spi_imx->base + MX51_ECSPI_CTRL); } +static void mx51_ecspi_disable(struct spi_imx_data *spi_imx) +{ + u32 ctrl; + + ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL); + ctrl &= ~MX51_ECSPI_CTRL_ENABLE; + writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); +} + static int mx51_ecspi_config(struct spi_device *spi) { struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); @@ -446,14 +510,11 @@ static int mx51_ecspi_config(struct spi_device *spi) u32 clk = spi_imx->speed_hz, delay, reg; u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG); - /* - * The hardware seems to have a race condition when changing modes. The - * current assumption is that the selection of the channel arrives - * earlier in the hardware than the mode bits when they are written at - * the same time. - * So set master mode for all channels as we do not support slave mode. - */ - ctrl |= MX51_ECSPI_CTRL_MODE_MASK; + /* set Master or Slave mode */ + if (spi_imx->slave_mode) + ctrl &= ~MX51_ECSPI_CTRL_MODE_MASK; + else + ctrl |= MX51_ECSPI_CTRL_MODE_MASK; /* * Enable SPI_RDY handling (falling edge/level triggered). @@ -468,9 +529,22 @@ static int mx51_ecspi_config(struct spi_device *spi) /* set chip select to use */ ctrl |= MX51_ECSPI_CTRL_CS(spi->chip_select); - ctrl |= (spi_imx->bits_per_word - 1) << MX51_ECSPI_CTRL_BL_OFFSET; + if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx)) + ctrl |= (spi_imx->slave_burst * 8 - 1) + << MX51_ECSPI_CTRL_BL_OFFSET; + else + ctrl |= (spi_imx->bits_per_word - 1) + << MX51_ECSPI_CTRL_BL_OFFSET; - cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select); + /* + * eCSPI burst completion by Chip Select signal in Slave mode + * is not functional for imx53 Soc, config SPI burst completed when + * BURST_LENGTH + 1 bits are received + */ + if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx)) + cfg &= ~MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select); + else + cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select); if (spi->mode & SPI_CPHA) cfg |= MX51_ECSPI_CONFIG_SCLKPHA(spi->chip_select); @@ -805,6 +879,7 @@ static struct spi_imx_devtype_data imx1_cspi_devtype_data = { .fifo_size = 8, .has_dmamode = false, .dynamic_burst = false, + .has_slavemode = false, .devtype = IMX1_CSPI, }; @@ -817,6 +892,7 @@ static struct spi_imx_devtype_data imx21_cspi_devtype_data = { .fifo_size = 8, .has_dmamode = false, .dynamic_burst = false, + .has_slavemode = false, .devtype = IMX21_CSPI, }; @@ -830,6 +906,7 @@ static struct spi_imx_devtype_data imx27_cspi_devtype_data = { .fifo_size = 8, .has_dmamode = false, .dynamic_burst = false, + .has_slavemode = false, .devtype = IMX27_CSPI, }; @@ -842,6 +919,7 @@ static struct spi_imx_devtype_data imx31_cspi_devtype_data = { .fifo_size = 8, .has_dmamode = false, .dynamic_burst = false, + .has_slavemode = false, .devtype = IMX31_CSPI, }; @@ -855,6 +933,7 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = { .fifo_size = 8, .has_dmamode = true, .dynamic_burst = false, + .has_slavemode = false, .devtype = IMX35_CSPI, }; @@ -867,6 +946,8 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = { .fifo_size = 64, .has_dmamode = true, .dynamic_burst = true, + .has_slavemode = true, + .disable = mx51_ecspi_disable, .devtype = IMX51_ECSPI, }; @@ -878,6 +959,8 @@ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = { .reset = mx51_ecspi_reset, .fifo_size = 64, .has_dmamode = true, + .has_slavemode = true, + .disable = mx51_ecspi_disable, .devtype = IMX53_ECSPI, }; @@ -945,14 +1028,16 @@ static void spi_imx_push(struct spi_imx_data *spi_imx) spi_imx->txfifo++; } - spi_imx->devtype_data->trigger(spi_imx); + if (!spi_imx->slave_mode) + spi_imx->devtype_data->trigger(spi_imx); } static irqreturn_t spi_imx_isr(int irq, void *dev_id) { struct spi_imx_data *spi_imx = dev_id; - while (spi_imx->devtype_data->rx_available(spi_imx)) { + while (spi_imx->txfifo && + spi_imx->devtype_data->rx_available(spi_imx)) { spi_imx->rx(spi_imx); spi_imx->txfifo--; } @@ -1034,7 +1119,7 @@ static int spi_imx_setupxfer(struct spi_device *spi, spi_imx->speed_hz = t->speed_hz; /* Initialize the functions for transfer */ - if (spi_imx->devtype_data->dynamic_burst) { + if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode) { u32 mask; spi_imx->dynamic_burst = 0; @@ -1078,6 +1163,12 @@ static int spi_imx_setupxfer(struct spi_device *spi, return ret; } + if (is_imx53_ecspi(spi_imx) && spi_imx->slave_mode) { + spi_imx->rx = mx53_ecspi_rx_slave; + spi_imx->tx = mx53_ecspi_tx_slave; + spi_imx->slave_burst = t->len; + } + spi_imx->devtype_data->config(spi); return 0; @@ -1262,11 +1353,61 @@ static int spi_imx_pio_transfer(struct spi_device *spi, return transfer->len; } +static int spi_imx_pio_transfer_slave(struct spi_device *spi, + struct spi_transfer *transfer) +{ + struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); + int ret = transfer->len; + + if (is_imx53_ecspi(spi_imx) && + transfer->len > MX53_MAX_TRANSFER_BYTES) { + dev_err(&spi->dev, "Transaction too big, max size is %d bytes\n", + MX53_MAX_TRANSFER_BYTES); + return -EMSGSIZE; + } + + spi_imx->tx_buf = transfer->tx_buf; + spi_imx->rx_buf = transfer->rx_buf; + spi_imx->count = transfer->len; + spi_imx->txfifo = 0; + + reinit_completion(&spi_imx->xfer_done); + spi_imx->slave_aborted = false; + + spi_imx_push(spi_imx); + + spi_imx->devtype_data->intctrl(spi_imx, MXC_INT_TE | MXC_INT_RDR); + + if (wait_for_completion_interruptible(&spi_imx->xfer_done) || + spi_imx->slave_aborted) { + dev_dbg(&spi->dev, "interrupted\n"); + ret = -EINTR; + } + + /* ecspi has a HW issue when works in Slave mode, + * after 64 words writtern to TXFIFO, even TXFIFO becomes empty, + * ECSPI_TXDATA keeps shift out the last word data, + * so we have to disable ECSPI when in slave mode after the + * transfer completes + */ + if (spi_imx->devtype_data->disable) + spi_imx->devtype_data->disable(spi_imx); + + return ret; +} + static int spi_imx_transfer(struct spi_device *spi, struct spi_transfer *transfer) { struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); + /* flush rxfifo before transfer */ + while (spi_imx->devtype_data->rx_available(spi_imx)) + spi_imx->rx(spi_imx); + + if (spi_imx->slave_mode) + return spi_imx_pio_transfer_slave(spi, transfer); + if (spi_imx->usedma) return spi_imx_dma_transfer(spi_imx, transfer); else @@ -1323,6 +1464,16 @@ spi_imx_unprepare_message(struct spi_master *master, struct spi_message *msg) return 0; } +static int spi_imx_slave_abort(struct spi_master *master) +{ + struct spi_imx_data *spi_imx = spi_master_get_devdata(master); + + spi_imx->slave_aborted = true; + complete(&spi_imx->xfer_done); + + return 0; +} + static int spi_imx_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1334,13 +1485,23 @@ static int spi_imx_probe(struct platform_device *pdev) struct spi_imx_data *spi_imx; struct resource *res; int i, ret, irq, spi_drctl; + const struct spi_imx_devtype_data *devtype_data = of_id ? of_id->data : + (struct spi_imx_devtype_data *)pdev->id_entry->driver_data; + bool slave_mode; if (!np && !mxc_platform_info) { dev_err(&pdev->dev, "can't get the platform data\n"); return -EINVAL; } - master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data)); + slave_mode = devtype_data->has_slavemode && + of_property_read_bool(np, "spi-slave"); + if (slave_mode) + master = spi_alloc_slave(&pdev->dev, + sizeof(struct spi_imx_data)); + else + master = spi_alloc_master(&pdev->dev, + sizeof(struct spi_imx_data)); if (!master) return -ENOMEM; @@ -1358,20 +1519,29 @@ static int spi_imx_probe(struct platform_device *pdev) spi_imx = spi_master_get_devdata(master); spi_imx->bitbang.master = master; spi_imx->dev = &pdev->dev; + spi_imx->slave_mode = slave_mode; - spi_imx->devtype_data = of_id ? of_id->data : - (struct spi_imx_devtype_data *)pdev->id_entry->driver_data; + spi_imx->devtype_data = devtype_data; + /* Get number of chip selects, either platform data or OF */ if (mxc_platform_info) { master->num_chipselect = mxc_platform_info->num_chipselect; - master->cs_gpios = devm_kzalloc(&master->dev, - sizeof(int) * master->num_chipselect, GFP_KERNEL); - if (!master->cs_gpios) - return -ENOMEM; + if (mxc_platform_info->chipselect) { + master->cs_gpios = devm_kzalloc(&master->dev, + sizeof(int) * master->num_chipselect, GFP_KERNEL); + if (!master->cs_gpios) + return -ENOMEM; + + for (i = 0; i < master->num_chipselect; i++) + master->cs_gpios[i] = mxc_platform_info->chipselect[i]; + } + } else { + u32 num_cs; - for (i = 0; i < master->num_chipselect; i++) - master->cs_gpios[i] = mxc_platform_info->chipselect[i]; - } + if (!of_property_read_u32(np, "num-cs", &num_cs)) + master->num_chipselect = num_cs; + /* If not preset, default value of 1 is used */ + } spi_imx->bitbang.chipselect = spi_imx_chipselect; spi_imx->bitbang.setup_transfer = spi_imx_setupxfer; @@ -1380,6 +1550,7 @@ static int spi_imx_probe(struct platform_device *pdev) spi_imx->bitbang.master->cleanup = spi_imx_cleanup; spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message; spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message; + spi_imx->bitbang.master->slave_abort = spi_imx_slave_abort; spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ | SPI_NO_CS; if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) || @@ -1451,37 +1622,38 @@ static int spi_imx_probe(struct platform_device *pdev) spi_imx->devtype_data->intctrl(spi_imx, 0); master->dev.of_node = pdev->dev.of_node; + + /* Request GPIO CS lines, if any */ + if (!spi_imx->slave_mode && master->cs_gpios) { + for (i = 0; i < master->num_chipselect; i++) { + if (!gpio_is_valid(master->cs_gpios[i])) + continue; + + ret = devm_gpio_request(&pdev->dev, + master->cs_gpios[i], + DRIVER_NAME); + if (ret) { + dev_err(&pdev->dev, "Can't get CS GPIO %i\n", + master->cs_gpios[i]); + goto out_spi_bitbang; + } + } + } + ret = spi_bitbang_start(&spi_imx->bitbang); if (ret) { dev_err(&pdev->dev, "bitbang start failed with %d\n", ret); goto out_clk_put; } - if (!master->cs_gpios) { - dev_err(&pdev->dev, "No CS GPIOs available\n"); - ret = -EINVAL; - goto out_clk_put; - } - - for (i = 0; i < master->num_chipselect; i++) { - if (!gpio_is_valid(master->cs_gpios[i])) - continue; - - ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i], - DRIVER_NAME); - if (ret) { - dev_err(&pdev->dev, "Can't get CS GPIO %i\n", - master->cs_gpios[i]); - goto out_clk_put; - } - } - dev_info(&pdev->dev, "probed\n"); clk_disable(spi_imx->clk_ipg); clk_disable(spi_imx->clk_per); return ret; +out_spi_bitbang: + spi_bitbang_stop(&spi_imx->bitbang); out_clk_put: clk_disable_unprepare(spi_imx->clk_ipg); out_put_per: diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 5b0e9a3e83f6..3d216b950b41 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -44,6 +44,7 @@ #include <linux/completion.h> #include <linux/gpio.h> #include <linux/regulator/consumer.h> +#include <linux/pm_runtime.h> #include <linux/module.h> #include <linux/stmp_device.h> #include <linux/spi/spi.h> @@ -442,6 +443,85 @@ static int mxs_spi_transfer_one(struct spi_master *master, return status; < |