summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt5
-rw-r--r--Documentation/devicetree/bindings/spi/spi-bus.txt35
-rw-r--r--Documentation/devicetree/bindings/spi/spi-clps711x.txt33
-rw-r--r--Documentation/devicetree/bindings/spi/spi-davinci.txt2
-rw-r--r--Documentation/devicetree/bindings/spi/spi-orion.txt49
-rw-r--r--Documentation/devicetree/bindings/spi/spi-rockchip.txt11
-rw-r--r--Documentation/devicetree/bindings/spi/spi-samsung.txt15
-rw-r--r--Documentation/devicetree/bindings/spi/ti_qspi.txt2
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/spi/Kconfig1
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi-bfin-sport.c15
-rw-r--r--drivers/spi/spi-bfin5xx.c15
-rw-r--r--drivers/spi/spi-cavium-octeon.c104
-rw-r--r--drivers/spi/spi-cavium.c151
-rw-r--r--drivers/spi/spi-cavium.h (renamed from arch/mips/include/asm/octeon/cvmx-mpi-defs.h)59
-rw-r--r--drivers/spi/spi-clps711x.c69
-rw-r--r--drivers/spi/spi-imx.c191
-rw-r--r--drivers/spi/spi-loopback-test.c2
-rw-r--r--drivers/spi/spi-mpc52xx-psc.c17
-rw-r--r--drivers/spi/spi-octeon.c255
-rw-r--r--drivers/spi/spi-omap2-mcspi.c145
-rw-r--r--drivers/spi/spi-orion.c88
-rw-r--r--drivers/spi/spi-pic32-sqi.c7
-rw-r--r--drivers/spi/spi-pic32.c5
-rw-r--r--drivers/spi/spi-pxa2xx-dma.c170
-rw-r--r--drivers/spi/spi-pxa2xx-pci.c128
-rw-r--r--drivers/spi/spi-pxa2xx.c55
-rw-r--r--drivers/spi/spi-pxa2xx.h9
-rw-r--r--drivers/spi/spi-rockchip.c20
-rw-r--r--drivers/spi/spi-s3c64xx.c206
-rw-r--r--drivers/spi/spi-sh-msiof.c18
-rw-r--r--drivers/spi/spi-sh.c16
-rw-r--r--drivers/spi/spi-sun4i.c8
-rw-r--r--drivers/spi/spi-sun6i.c7
-rw-r--r--drivers/spi/spi-ti-qspi.c2
-rw-r--r--drivers/spi/spi-topcliff-pch.c26
-rw-r--r--drivers/spi/spi-txx9.c11
-rw-r--r--drivers/spi/spi-xilinx.c8
-rw-r--r--drivers/spi/spi.c66
-rw-r--r--drivers/spi/spidev.c41
-rw-r--r--include/linux/platform_data/spi-s3c64xx.h1
-rw-r--r--include/linux/spi/spi.h10
43 files changed, 1140 insertions, 940 deletions
diff --git a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt
index 523341a0e113..8bc95e2fc47f 100644
--- a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt
+++ b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt
@@ -11,7 +11,6 @@ Required properties:
- "fsl,imx51-ecspi" for SPI compatible with the one integrated on i.MX51
- reg : Offset and length of the register set for the device
- interrupts : Should contain CSPI/eCSPI interrupt
-- fsl,spi-num-chipselects : Contains the number of the chipselect
- cs-gpios : Specifies the gpio pins to be used for chipselects.
- clocks : Clock specifiers for both ipg and per clocks.
- clock-names : Clock names should include both "ipg" and "per"
@@ -21,6 +20,9 @@ See the clock consumer binding,
Documentation/devicetree/bindings/dma/dma.txt
- dma-names: DMA request names should include "tx" and "rx" if present.
+Obsolete properties:
+- fsl,spi-num-chipselects : Contains the number of the chipselect
+
Example:
ecspi@70010000 {
@@ -29,7 +31,6 @@ ecspi@70010000 {
compatible = "fsl,imx51-ecspi";
reg = <0x70010000 0x4000>;
interrupts = <36>;
- fsl,spi-num-chipselects = <2>;
cs-gpios = <&gpio3 24 0>, /* GPIO3_24 */
<&gpio3 25 0>; /* GPIO3_25 */
dmas = <&sdma 3 7 1>, <&sdma 4 7 2>;
diff --git a/Documentation/devicetree/bindings/spi/spi-bus.txt b/Documentation/devicetree/bindings/spi/spi-bus.txt
index 42d595425dfb..17822860cb98 100644
--- a/Documentation/devicetree/bindings/spi/spi-bus.txt
+++ b/Documentation/devicetree/bindings/spi/spi-bus.txt
@@ -8,11 +8,10 @@ in slave mode.
The SPI master node requires the following properties:
- #address-cells - number of cells required to define a chip select
- address on the SPI bus.
+ address on the SPI bus.
- #size-cells - should be zero.
- compatible - name of SPI bus controller following generic names
- recommended practice.
-- cs-gpios - (optional) gpios chip select.
+ recommended practice.
No other properties are required in the SPI bus node. It is assumed
that a driver for an SPI bus device will understand that it is an SPI bus.
However, the binding does not attempt to define the specific method for
@@ -22,11 +21,12 @@ assumption that board specific platform code will be used to manage
chip selects. Individual drivers can define additional properties to
support describing the chip select layout.
-Optional property:
-- num-cs : total number of chipselects
+Optional properties:
+- cs-gpios - gpios chip select.
+- num-cs - total number of chipselects.
-If cs-gpios is used the number of chip select will automatically increased
-with max(cs-gpios > hw cs)
+If cs-gpios is used the number of chip selects will be increased automatically
+with max(cs-gpios > hw cs).
So if for example the controller has 2 CS lines, and the cs-gpios
property looks like this:
@@ -45,29 +45,30 @@ SPI slave nodes must be children of the SPI master node and can
contain the following properties.
- reg - (required) chip select address of device.
- compatible - (required) name of SPI device following generic names
- recommended practice
-- spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz
+ recommended practice.
+- spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz.
- spi-cpol - (optional) Empty property indicating device requires
- inverse clock polarity (CPOL) mode
+ inverse clock polarity (CPOL) mode.
- spi-cpha - (optional) Empty property indicating device requires
- shifted clock phase (CPHA) mode
+ shifted clock phase (CPHA) mode.
- spi-cs-high - (optional) Empty property indicating device requires
- chip select active high
+ chip select active high.
- spi-3wire - (optional) Empty property indicating device requires
- 3-wire mode.
+ 3-wire mode.
- spi-lsb-first - (optional) Empty property indicating device requires
LSB first mode.
-- spi-tx-bus-width - (optional) The bus width(number of data wires) that
+- spi-tx-bus-width - (optional) The bus width (number of data wires) that is
used for MOSI. Defaults to 1 if not present.
-- spi-rx-bus-width - (optional) The bus width(number of data wires) that
+- spi-rx-bus-width - (optional) The bus width (number of data wires) that is
used for MISO. Defaults to 1 if not present.
- spi-rx-delay-us - (optional) Microsecond delay after a read transfer.
- spi-tx-delay-us - (optional) Microsecond delay after a write transfer.
Some SPI controllers and devices support Dual and Quad SPI transfer mode.
-It allows data in the SPI system to be transferred in 2 wires(DUAL) or 4 wires(QUAD).
+It allows data in the SPI system to be transferred using 2 wires (DUAL) or 4
+wires (QUAD).
Now the value that spi-tx-bus-width and spi-rx-bus-width can receive is
-only 1(SINGLE), 2(DUAL) and 4(QUAD).
+only 1 (SINGLE), 2 (DUAL) and 4 (QUAD).
Dual/Quad mode is not allowed when 3-wire mode is used.
If a gpio chipselect is used for the SPI slave the gpio number will be passed
diff --git a/Documentation/devicetree/bindings/spi/spi-clps711x.txt b/Documentation/devicetree/bindings/spi/spi-clps711x.txt
new file mode 100644
index 000000000000..4c3ec13f423f
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-clps711x.txt
@@ -0,0 +1,33 @@
+Serial Peripheral Interface on Cirrus Logic CL-PS71xx, EP72xx, EP73xx
+
+Required properties
+- #address-cells: must be <1>
+- #size-cells: must be <0>
+- compatible: should include "cirrus,ep7209-spi"
+- reg: Address and length of one register range
+- interrupts: one interrupt line
+- clocks: One entry, refers to the SPI bus clock
+- cs-gpios: Specifies the gpio pins to be used for chipselects.
+ See: Documentation/devicetree/bindings/spi/spi-bus.txt
+
+An additional register is present in the system controller,
+which is assumed to be in the same device tree, with and marked
+as compatible with "cirrus,ep7209-syscon3".
+
+Example:
+
+spi@80000500 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "cirrus,ep7209-spi";
+ reg = <0x80000500 0x4>;
+ interrupts = <15>;
+ clocks = <&clks CLPS711X_CLK_SPI>;
+ status = "disabled";
+};
+
+syscon3: syscon@80002200 {
+ compatible = "cirrus,ep7209-syscon3", "syscon";
+ reg = <0x80002200 0x40>;
+};
+
diff --git a/Documentation/devicetree/bindings/spi/spi-davinci.txt b/Documentation/devicetree/bindings/spi/spi-davinci.txt
index d1e914adcf6e..f5916c92fe91 100644
--- a/Documentation/devicetree/bindings/spi/spi-davinci.txt
+++ b/Documentation/devicetree/bindings/spi/spi-davinci.txt
@@ -21,7 +21,7 @@ Required properties:
IP to the interrupt controller within the SoC. Possible values
are 0 and 1. Manual says one of the two possible interrupt
lines can be tied to the interrupt controller. Set this
- based on a specifc SoC configuration.
+ based on a specific SoC configuration.
- interrupts: interrupt number mapped to CPU.
- clocks: spi clk phandle
diff --git a/Documentation/devicetree/bindings/spi/spi-orion.txt b/Documentation/devicetree/bindings/spi/spi-orion.txt
index 98bc69815eb3..4f629cc7634a 100644
--- a/Documentation/devicetree/bindings/spi/spi-orion.txt
+++ b/Documentation/devicetree/bindings/spi/spi-orion.txt
@@ -8,7 +8,15 @@ Required properties:
- "marvell,armada-380-spi", for the Armada 38x SoCs
- "marvell,armada-390-spi", for the Armada 39x SoCs
- "marvell,armada-xp-spi", for the Armada XP SoCs
-- reg : offset and length of the register set for the device
+- reg : offset and length of the register set for the device.
+ This property can optionally have additional entries to configure
+ the SPI direct access mode that some of the Marvell SoCs support
+ additionally to the normal indirect access (PIO) mode. The values
+ for the MBus "target" and "attribute" are defined in the Marvell
+ SoC "Functional Specifications" Manual in the chapter "Marvell
+ Core Processor Address Decoding".
+ The eight register sets following the control registers refer to
+ chip-select lines 0 through 7 respectively.
- cell-index : Which of multiple SPI controllers is this.
Optional properties:
- interrupts : Is currently not used.
@@ -23,3 +31,42 @@ Example:
interrupts = <23>;
status = "disabled";
};
+
+Example with SPI direct mode support (optionally):
+ spi0: spi@10600 {
+ compatible = "marvell,orion-spi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <0>;
+ reg = <MBUS_ID(0xf0, 0x01) 0x10600 0x28>, /* control */
+ <MBUS_ID(0x01, 0x1e) 0 0xffffffff>, /* CS0 */
+ <MBUS_ID(0x01, 0x5e) 0 0xffffffff>, /* CS1 */
+ <MBUS_ID(0x01, 0x9e) 0 0xffffffff>, /* CS2 */
+ <MBUS_ID(0x01, 0xde) 0 0xffffffff>, /* CS3 */
+ <MBUS_ID(0x01, 0x1f) 0 0xffffffff>, /* CS4 */
+ <MBUS_ID(0x01, 0x5f) 0 0xffffffff>, /* CS5 */
+ <MBUS_ID(0x01, 0x9f) 0 0xffffffff>, /* CS6 */
+ <MBUS_ID(0x01, 0xdf) 0 0xffffffff>; /* CS7 */
+ interrupts = <23>;
+ status = "disabled";
+ };
+
+To enable the direct mode, the board specific 'ranges' property in the
+'soc' node needs to add the entries for the desired SPI controllers
+and its chip-selects that are used in the direct mode instead of PIO
+mode. Here an example for this (SPI controller 0, device 1 and SPI
+controller 1, device 2 are used in direct mode. All other SPI device
+are used in the default indirect (PIO) mode):
+ soc {
+ /*
+ * Enable the SPI direct access by configuring an entry
+ * here in the board-specific ranges property
+ */
+ ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000>, /* internal regs */
+ <MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000>, /* BootROM */
+ <MBUS_ID(0x01, 0x5e) 0 0 0xf1100000 0x10000>, /* SPI0-DEV1 */
+ <MBUS_ID(0x01, 0x9a) 0 0 0xf1110000 0x10000>; /* SPI1-DEV2 */
+
+For further information on the MBus bindings, please see the MBus
+DT documentation:
+Documentation/devicetree/bindings/bus/mvebu-mbus.txt
diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.txt b/Documentation/devicetree/bindings/spi/spi-rockchip.txt
index 1b14d69d8903..d2ca153614f9 100644
--- a/Documentation/devicetree/bindings/spi/spi-rockchip.txt
+++ b/Documentation/devicetree/bindings/spi/spi-rockchip.txt
@@ -6,10 +6,13 @@ and display controllers using the SPI communication interface.
Required Properties:
- compatible: should be one of the following.
- "rockchip,rk3066-spi" for rk3066.
- "rockchip,rk3188-spi", "rockchip,rk3066-spi" for rk3188.
- "rockchip,rk3288-spi", "rockchip,rk3066-spi" for rk3288.
- "rockchip,rk3399-spi", "rockchip,rk3066-spi" for rk3399.
+ "rockchip,rk3036-spi" for rk3036 SoCS.
+ "rockchip,rk3066-spi" for rk3066 SoCs.
+ "rockchip,rk3188-spi" for rk3188 SoCs.
+ "rockchip,rk3228-spi" for rk3228 SoCS.
+ "rockchip,rk3288-spi" for rk3288 SoCs.
+ "rockchip,rk3368-spi" for rk3368 SoCs.
+ "rockchip,rk3399-spi" for rk3399 SoCs.
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: The interrupt number to the cpu. The interrupt specifier format
diff --git a/Documentation/devicetree/bindings/spi/spi-samsung.txt b/Documentation/devicetree/bindings/spi/spi-samsung.txt
index 6dbdeb3c361a..49028a4f5df1 100644
--- a/Documentation/devicetree/bindings/spi/spi-samsung.txt
+++ b/Documentation/devicetree/bindings/spi/spi-samsung.txt
@@ -9,7 +9,8 @@ Required SoC Specific Properties:
- samsung,s3c2443-spi: for s3c2443, s3c2416 and s3c2450 platforms
- samsung,s3c6410-spi: for s3c6410 platforms
- samsung,s5pv210-spi: for s5pv210 and s5pc110 platforms
- - samsung,exynos7-spi: for exynos7 platforms
+ - samsung,exynos5433-spi: for exynos5433 compatible controllers
+ - samsung,exynos7-spi: for exynos7 platforms <DEPRECATED>
- reg: physical base address of the controller and length of memory mapped
region.
@@ -23,6 +24,15 @@ Required SoC Specific Properties:
- dma-names: Names for the dma channels. There must be at least one channel
named "tx" for transmit and named "rx" for receive.
+- clocks: specifies the clock IDs provided to the SPI controller; they are
+ required for interacting with the controller itself, for synchronizing the bus
+ and as I/O clock (the latter is required by exynos5433 and exynos7).
+
+- clock-names: string names of the clocks in the 'clocks' property; for all the
+ the devices the names must be "spi", "spi_busclkN" (where N is determined by
+ "samsung,spi-src-clk"), while Exynos5433 should specify a third clock
+ "spi_ioclk" for the I/O clock.
+
Required Board Specific Properties:
- #address-cells: should be 1.
@@ -40,6 +50,9 @@ Optional Board Specific Properties:
- cs-gpios: should specify GPIOs used for chipselects (see spi-bus.txt)
+- no-cs-readback: the CS line is disconnected, therefore the device should not
+ operate based on CS signalling.
+
SPI Controller specific data in SPI slave nodes:
- The spi slave nodes should provide the following information which is required
diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt
index 50b14f6b53a3..e65fde4a7388 100644
--- a/Documentation/devicetree/bindings/spi/ti_qspi.txt
+++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt
@@ -20,7 +20,7 @@ Optional properties:
chipselect register and offset of that register.
NOTE: TI QSPI controller requires different pinmux and IODelay
-paramaters for Mode-0 and Mode-3 operations, which needs to be set up by
+parameters for Mode-0 and Mode-3 operations, which needs to be set up by
the bootloader (U-Boot). Default configuration only supports Mode-0
operation. Hence, "spi-cpol" and "spi-cpha" DT properties cannot be
specified in the slave nodes of TI QSPI controller without appropriate
diff --git a/MAINTAINERS b/MAINTAINERS
index 3a7b3998e845..403c162b0b28 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10921,6 +10921,7 @@ L: linux-spi@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
Q: http://patchwork.kernel.org/project/spi-devel-general/list/
S: Maintained
+F: Documentation/devicetree/bindings/spi/
F: Documentation/spi/
F: drivers/spi/
F: include/linux/spi/
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 4b931ec8d90b..d6fb8d4b7786 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -411,6 +411,7 @@ config SPI_OMAP24XX
tristate "McSPI driver for OMAP"
depends on HAS_DMA
depends on ARCH_OMAP2PLUS || COMPILE_TEST
+ select SG_SPLIT
help
SPI master controller for OMAP24XX and later Multichannel SPI
(McSPI) modules.
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3c74d003535b..185367ef6576 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_SPI_MT65XX) += spi-mt65xx.o
obj-$(CONFIG_SPI_MXS) += spi-mxs.o
obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o
obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o
+spi-octeon-objs := spi-cavium.o spi-cavium-octeon.o
obj-$(CONFIG_SPI_OCTEON) += spi-octeon.o
obj-$(CONFIG_SPI_OMAP_UWIRE) += spi-omap-uwire.o
obj-$(CONFIG_SPI_OMAP_100K) += spi-omap-100k.o
diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c
index 6c967555a56a..01d0ba9c5942 100644
--- a/drivers/spi/spi-bfin-sport.c
+++ b/drivers/spi/spi-bfin-sport.c
@@ -64,8 +64,6 @@ struct bfin_sport_spi_master_data {
/* Pin request list */
u16 *pin_req;
- /* Driver message queue */
- struct workqueue_struct *workqueue;
struct work_struct pump_messages;
spinlock_t lock;
struct list_head queue;
@@ -300,7 +298,7 @@ bfin_sport_spi_giveback(struct bfin_sport_spi_master_data *drv_data)
drv_data->cur_msg = NULL;
drv_data->cur_transfer = NULL;
drv_data->cur_chip = NULL;
- queue_work(drv_data->workqueue, &drv_data->pump_messages);
+ schedule_work(&drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags);
if (!drv_data->cs_change)
@@ -556,7 +554,7 @@ bfin_sport_spi_transfer(struct spi_device *spi, struct spi_message *msg)
list_add_tail(&msg->queue, &drv_data->queue);
if (drv_data->run && !drv_data->busy)
- queue_work(drv_data->workqueue, &drv_data->pump_messages);
+ schedule_work(&drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags);
@@ -666,12 +664,7 @@ bfin_sport_spi_init_queue(struct bfin_sport_spi_master_data *drv_data)
tasklet_init(&drv_data->pump_transfers,
bfin_sport_spi_pump_transfers, (unsigned long)drv_data);
- /* init messages workqueue */
INIT_WORK(&drv_data->pump_messages, bfin_sport_spi_pump_messages);
- drv_data->workqueue =
- create_singlethread_workqueue(dev_name(drv_data->master->dev.parent));
- if (drv_data->workqueue == NULL)
- return -EBUSY;
return 0;
}
@@ -694,7 +687,7 @@ bfin_sport_spi_start_queue(struct bfin_sport_spi_master_data *drv_data)
drv_data->cur_chip = NULL;
spin_unlock_irqrestore(&drv_data->lock, flags);
- queue_work(drv_data->workqueue, &drv_data->pump_messages);
+ schedule_work(&drv_data->pump_messages);
return 0;
}
@@ -738,7 +731,7 @@ bfin_sport_spi_destroy_queue(struct bfin_sport_spi_master_data *drv_data)
if (status)
return status;
- destroy_workqueue(drv_data->workqueue);
+ flush_work(&drv_data->pump_messages);
return 0;
}
diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c
index 1e91325bf39c..249c7a3677c9 100644
--- a/drivers/spi/spi-bfin5xx.c
+++ b/drivers/spi/spi-bfin5xx.c
@@ -67,8 +67,6 @@ struct bfin_spi_master_data {
/* BFIN hookup */
struct bfin5xx_spi_master *master_info;
- /* Driver message queue */
- struct workqueue_struct *workqueue;
struct work_struct pump_messages;
spinlock_t lock;
struct list_head queue;
@@ -359,7 +357,7 @@ static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data)
drv_data->cur_msg = NULL;
drv_data->cur_transfer = NULL;
drv_data->cur_chip = NULL;
- queue_work(drv_data->workqueue, &drv_data->pump_messages);
+ schedule_work(&drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags);
msg->state = NULL;
@@ -946,7 +944,7 @@ static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg)
list_add_tail(&msg->queue, &drv_data->queue);
if (drv_data->running && !drv_data->busy)
- queue_work(drv_data->workqueue, &drv_data->pump_messages);
+ schedule_work(&drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags);
@@ -1177,12 +1175,7 @@ static int bfin_spi_init_queue(struct bfin_spi_master_data *drv_data)
tasklet_init(&drv_data->pump_transfers,
bfin_spi_pump_transfers, (unsigned long)drv_data);
- /* init messages workqueue */
INIT_WORK(&drv_data->pump_messages, bfin_spi_pump_messages);
- drv_data->workqueue = create_singlethread_workqueue(
- dev_name(drv_data->master->dev.parent));
- if (drv_data->workqueue == NULL)
- return -EBUSY;
return 0;
}
@@ -1204,7 +1197,7 @@ static int bfin_spi_start_queue(struct bfin_spi_master_data *drv_data)
drv_data->cur_chip = NULL;
spin_unlock_irqrestore(&drv_data->lock, flags);
- queue_work(drv_data->workqueue, &drv_data->pump_messages);
+ schedule_work(&drv_data->pump_messages);
return 0;
}
@@ -1246,7 +1239,7 @@ static int bfin_spi_destroy_queue(struct bfin_spi_master_data *drv_data)
if (status != 0)
return status;
- destroy_workqueue(drv_data->workqueue);
+ flush_work(&drv_data->pump_messages);
return 0;
}
diff --git a/drivers/spi/spi-cavium-octeon.c b/drivers/spi/spi-cavium-octeon.c
new file mode 100644
index 000000000000..ee4703e84622
--- /dev/null
+++ b/drivers/spi/spi-cavium-octeon.c
@@ -0,0 +1,104 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2011, 2012 Cavium, Inc.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <asm/octeon/octeon.h>
+
+#include "spi-cavium.h"
+
+static int octeon_spi_probe(struct platform_device *pdev)
+{
+ struct resource *res_mem;
+ void __iomem *reg_base;
+ struct spi_master *master;
+ struct octeon_spi *p;
+ int err = -ENOENT;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct octeon_spi));
+ if (!master)
+ return -ENOMEM;
+ p = spi_master_get_devdata(master);
+ platform_set_drvdata(pdev, master);
+
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg_base = devm_ioremap_resource(&pdev->dev, res_mem);
+ if (IS_ERR(reg_base)) {
+ err = PTR_ERR(reg_base);
+ goto fail;
+ }
+
+ p->register_base = reg_base;
+ p->sys_freq = octeon_get_io_clock_rate();
+
+ p->regs.config = 0;
+ p->regs.status = 0x08;
+ p->regs.tx = 0x10;
+ p->regs.data = 0x80;
+
+ master->num_chipselect = 4;
+ master->mode_bits = SPI_CPHA |
+ SPI_CPOL |
+ SPI_CS_HIGH |
+ SPI_LSB_FIRST |
+ SPI_3WIRE;
+
+ master->transfer_one_message = octeon_spi_transfer_one_message;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
+
+ master->dev.of_node = pdev->dev.of_node;
+ err = devm_spi_register_master(&pdev->dev, master);
+ if (err) {
+ dev_err(&pdev->dev, "register master failed: %d\n", err);
+ goto fail;
+ }
+
+ dev_info(&pdev->dev, "OCTEON SPI bus driver\n");
+
+ return 0;
+fail:
+ spi_master_put(master);
+ return err;
+}
+
+static int octeon_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct octeon_spi *p = spi_master_get_devdata(master);
+
+ /* Clear the CSENA* and put everything in a known state. */
+ writeq(0, p->register_base + OCTEON_SPI_CFG(p));
+
+ return 0;
+}
+
+static const struct of_device_id octeon_spi_match[] = {
+ { .compatible = "cavium,octeon-3010-spi", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, octeon_spi_match);
+
+static struct platform_driver octeon_spi_driver = {
+ .driver = {
+ .name = "spi-octeon",
+ .of_match_table = octeon_spi_match,
+ },
+ .probe = octeon_spi_probe,
+ .remove = octeon_spi_remove,
+};
+
+module_platform_driver(octeon_spi_driver);
+
+MODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver");
+MODULE_AUTHOR("David Daney");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-cavium.c b/drivers/spi/spi-cavium.c
new file mode 100644
index 000000000000..5aaf21582cb5
--- /dev/null
+++ b/drivers/spi/spi-cavium.c
@@ -0,0 +1,151 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2011, 2012 Cavium, Inc.
+ */
+
+#include <linux/spi/spi.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "spi-cavium.h"
+
+static void octeon_spi_wait_ready(struct octeon_spi *p)
+{
+ union cvmx_mpi_sts mpi_sts;
+ unsigned int loops = 0;
+
+ do {
+ if (loops++)
+ __delay(500);
+ mpi_sts.u64 = readq(p->register_base + OCTEON_SPI_STS(p));
+ } while (mpi_sts.s.busy);
+}
+
+static int octeon_spi_do_transfer(struct octeon_spi *p,
+ struct spi_message *msg,
+ struct spi_transfer *xfer,
+ bool last_xfer)
+{
+ struct spi_device *spi = msg->spi;
+ union cvmx_mpi_cfg mpi_cfg;
+ union cvmx_mpi_tx mpi_tx;
+ unsigned int clkdiv;
+ int mode;
+ bool cpha, cpol;
+ const u8 *tx_buf;
+ u8 *rx_buf;
+ int len;
+ int i;
+
+ mode = spi->mode;
+ cpha = mode & SPI_CPHA;
+ cpol = mode & SPI_CPOL;
+
+ clkdiv = p->sys_freq / (2 * xfer->speed_hz);
+
+ mpi_cfg.u64 = 0;
+
+ mpi_cfg.s.clkdiv = clkdiv;
+ mpi_cfg.s.cshi = (mode & SPI_CS_HIGH) ? 1 : 0;
+ mpi_cfg.s.lsbfirst = (mode & SPI_LSB_FIRST) ? 1 : 0;
+ mpi_cfg.s.wireor = (mode & SPI_3WIRE) ? 1 : 0;
+ mpi_cfg.s.idlelo = cpha != cpol;
+ mpi_cfg.s.cslate = cpha ? 1 : 0;
+ mpi_cfg.s.enable = 1;
+
+ if (spi->chip_select < 4)
+ p->cs_enax |= 1ull << (12 + spi->chip_select);
+ mpi_cfg.u64 |= p->cs_enax;
+
+ if (mpi_cfg.u64 != p->last_cfg) {
+ p->last_cfg = mpi_cfg.u64;
+ writeq(mpi_cfg.u64, p->register_base + OCTEON_SPI_CFG(p));
+ }
+ tx_buf = xfer->tx_buf;
+ rx_buf = xfer->rx_buf;
+ len = xfer->len;
+ while (len > OCTEON_SPI_MAX_BYTES) {
+ for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) {
+ u8 d;
+ if (tx_buf)
+ d = *tx_buf++;
+ else
+ d = 0;
+ writeq(d, p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));
+ }
+ mpi_tx.u64 = 0;
+ mpi_tx.s.csid = spi->chip_select;
+ mpi_tx.s.leavecs = 1;
+ mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0;
+ mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES;
+ writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX(p));
+
+ octeon_spi_wait_ready(p);
+ if (rx_buf)
+ for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) {
+ u64 v = readq(p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));
+ *rx_buf++ = (u8)v;
+ }
+ len -= OCTEON_SPI_MAX_BYTES;
+ }
+
+ for (i = 0; i < len; i++) {
+ u8 d;
+ if (tx_buf)
+ d = *tx_buf++;
+ else
+ d = 0;
+ writeq(d, p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));
+ }
+
+ mpi_tx.u64 = 0;
+ mpi_tx.s.csid = spi->chip_select;
+ if (last_xfer)
+ mpi_tx.s.leavecs = xfer->cs_change;
+ else
+ mpi_tx.s.leavecs = !xfer->cs_change;
+ mpi_tx.s.txnum = tx_buf ? len : 0;
+ mpi_tx.s.totnum = len;
+ writeq(mpi_tx.u64, p->register_base + OCTEON_SPI_TX(p));
+
+ octeon_spi_wait_ready(p);
+ if (rx_buf)
+ for (i = 0; i < len; i++) {
+ u64 v = readq(p->register_base + OCTEON_SPI_DAT0(p) + (8 * i));
+ *rx_buf++ = (u8)v;
+ }
+
+ if (xfer->delay_usecs)
+ udelay(xfer->delay_usecs);
+
+ return xfer->len;
+}
+
+int octeon_spi_transfer_one_message(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct octeon_spi *p = spi_master_get_devdata(master);
+ unsigned int total_len = 0;
+ int status = 0;
+ struct spi_transfer *xfer;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ bool last_xfer = list_is_last(&xfer->transfer_list,
+ &msg->transfers);
+ int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer);
+ if (r < 0) {
+ status = r;
+ goto err;
+ }
+ total_len += r;
+ }
+err:
+ msg->status = status;
+ msg->actual_length = total_len;
+ spi_finalize_current_message(master);
+ return status;
+}
diff --git a/arch/mips/include/asm/octeon/cvmx-mpi-defs.h b/drivers/spi/spi-cavium.h
index 4615b102625b..88c5f36e7ea7 100644
--- a/arch/mips/include/asm/octeon/cvmx-mpi-defs.h
+++ b/drivers/spi/spi-cavium.h
@@ -1,32 +1,33 @@
-/***********************license start***************
- * Author: Cavium Networks
- *
- * Contact: support@caviumnetworks.com
- * This file is part of the OCTEON SDK
- *
- * Copyright (c) 2003-2012 Cavium Networks
- *
- * This file 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.
- *
- * This file is distributed in the hope that it will be useful, but
- * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
- * NONINFRINGEMENT. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * or visit http://www.gnu.org/licenses/.
- *
- * This file may also be available under a different license from Cavium.
- * Contact Cavium Networks for more information
- ***********************license end**************************************/
+#ifndef __SPI_CAVIUM_H
+#define __SPI_CAVIUM_H
-#ifndef __CVMX_MPI_DEFS_H__
-#define __CVMX_MPI_DEFS_H__
+#define OCTEON_SPI_MAX_BYTES 9
+#define OCTEON_SPI_MAX_CLOCK_HZ 16000000
+
+struct octeon_spi_regs {
+ int config;
+ int status;
+ int tx;
+ int data;
+};
+
+struct octeon_spi {
+ void __iomem *register_base;
+ u64 last_cfg;
+ u64 cs_enax;
+ int sys_freq;
+ struct octeon_spi_regs regs;
+};
+
+#define OCTEON_SPI_CFG(x) (x->regs.config)
+#define OCTEON_SPI_STS(x) (x->regs.status)
+#define OCTEON_SPI_TX(x) (x->regs.tx)
+#define OCTEON_SPI_DAT0(x) (x->regs.data)
+
+int octeon_spi_transfer_one_message(struct spi_master *master,
+ struct spi_message *msg);
+
+/* MPI register descriptions */
#define CVMX_MPI_CFG (CVMX_ADD_IO_SEG(0x0001070000001000ull))
#define CVMX_MPI_DATX(offset) (CVMX_ADD_IO_SEG(0x0001070000001080ull) + ((offset) & 15) * 8)
@@ -325,4 +326,4 @@ union cvmx_mpi_tx {
struct cvmx_mpi_tx_cn61xx cnf71xx;
};
-#endif
+#endif /* __SPI_CAVIUM_H */
diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c
index 8c30de0315e7..18193df2eba8 100644
--- a/drivers/spi/spi-clps711x.c
+++ b/drivers/spi/spi-clps711x.c
@@ -1,7 +1,7 @@
/*
* CLPS711X SPI bus driver
*
- * Copyright (C) 2012-2014 Alexander Shiyan <shc_work@mail.ru>
+ * Copyright (C) 2012-2016 Alexander Shiyan <shc_work@mail.ru>
*
* 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
@@ -12,7 +12,6 @@
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/gpio.h>
-#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
@@ -20,9 +19,8 @@
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/clps711x.h>
#include <linux/spi/spi.h>
-#include <linux/platform_data/spi-clps711x.h>
-#define DRIVER_NAME "spi-clps711x"
+#define DRIVER_NAME "clps711x-spi"
#define SYNCIO_FRMLEN(x) ((x) << 8)
#define SYNCIO_TXFRMEN (1 << 14)
@@ -40,6 +38,17 @@ struct spi_clps711x_data {
static int spi_clps711x_setup(struct spi_device *spi)
{
+ if (!spi->controller_state) {
+ int ret;
+
+ ret = devm_gpio_request(&spi->master->dev, spi->cs_gpio,
+ dev_name(&spi->master->dev));
+ if (ret)
+ return ret;
+
+ spi->controller_state = spi;
+ }
+
/* We are expect that SPI-device is not selected */
gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
@@ -104,20 +113,9 @@ static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
static int spi_clps711x_probe(struct platform_device *pdev)
{
struct spi_clps711x_data *hw;
- struct spi_clps711x_pdata *pdata = dev_get_platdata(&pdev->dev);
struct spi_master *master;
struct resource *res;
- int i, irq, ret;
-
- if (!pdata) {
- dev_err(&pdev->dev, "No platform data supplied\n");
- return -EINVAL;
- }
-
- if (pdata->num_chipselect < 1) {
- dev_err(&pdev->dev, "At least one CS must be defined\n");
- return -EINVAL;
- }
+ int irq, ret;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -127,40 +125,24 @@ static int spi_clps711x_probe(struct platform_device *pdev)
if (!master)
return -ENOMEM;
- master->cs_gpios = devm_kzalloc(&pdev->dev, sizeof(int) *
- pdata->num_chipselect, GFP_KERNEL);
- if (!master->cs_gpios) {
- ret = -ENOMEM;
- goto err_out;
- }
-
- master->bus_num = pdev->id;
+ master->bus_num = -1;
master->mode_bits = SPI_CPHA | SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8);
- master->num_chipselect = pdata->num_chipselect;
+ master->dev.of_node = pdev->dev.of_node;
master->setup = spi_clps711x_setup;
master->prepare_message = spi_clps711x_prepare_message;
master->transfer_one = spi_clps711x_transfer_one;
hw = spi_master_get_devdata(master);
- for (i = 0; i < master->num_chipselect; i++) {
- master->cs_gpios[i] = pdata->chipselect[i];
- 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", i);
- goto err_out;
- }
- }
-
hw->spi_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(hw->spi_clk)) {
ret = PTR_ERR(hw->spi_clk);
goto err_out;
}
- hw->syscon = syscon_regmap_lookup_by_pdevname("syscon.3");
+ hw->syscon =
+ syscon_regmap_lookup_by_compatible("cirrus,ep7209-syscon3");
if (IS_ERR(hw->syscon)) {
ret = PTR_ERR(hw->syscon);
goto err_out;
@@ -185,14 +167,8 @@ static int spi_clps711x_probe(struct platform_device *pdev)
goto err_out;
ret = devm_spi_register_master(&pdev->dev, master);
- if (!ret) {
- dev_info(&pdev->dev,
- "SPI bus driver initialized. Master clock %u Hz\n",
- master->max_speed_hz);
+ if (!ret)
return 0;
- }
-
- dev_err(&pdev->dev, "Failed to register master\n");
err_out:
spi_master_put(master);
@@ -200,9 +176,16 @@ err_out:
return ret;
}
+static const struct of_device_id clps711x_spi_dt_ids[] = {
+ { .compatible = "cirrus,ep7209-spi", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, clps711x_spi_dt_ids);
+
static struct platform_driver clps711x_spi_driver = {
.driver = {
.name = DRIVER_NAME,
+ .of_match_table = clps711x_spi_dt_ids,
},
.probe = spi_clps711x_probe,
};
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 50769078e72e..f63cb30f9010 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -59,8 +59,6 @@
struct spi_imx_config {
unsigned int speed_hz;
unsigned int bpw;
- unsigned int mode;
- u8 cs;
};
enum spi_imx_devtype {
@@ -76,7 +74,7 @@ struct spi_imx_data;
struct spi_imx_devtype_data {
void (*intctrl)(struct spi_imx_data *, int);
- int (*config)(struct spi_imx_data *, struct spi_imx_config *);
+ int (*config)(struct spi_device *, struct spi_imx_config *);
void (*trigger)(struct spi_imx_data *);
int (*rx_available)(struct spi_imx_data *);
void (*reset)(struct spi_imx_data *);
@@ -112,7 +110,6 @@ struct spi_imx_data {
struct completion dma_tx_completion;
const struct spi_imx_devtype_data *devtype_data;
- int chipselect[0];
};
static inline int is_imx27_cspi(struct spi_imx_data *d)
@@ -312,7 +309,7 @@ static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx,
(post << MX51_ECSPI_CTRL_POSTDIV_OFFSET);
}
-static void __maybe_unused mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int enable)
+static void mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int enable)
{
unsigned val = 0;
@@ -325,7 +322,7 @@ static void __maybe_unused mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int
writel(val, spi_imx->base + MX51_ECSPI_INT);
}
-static void __maybe_unused mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
+static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
{
u32 reg;
@@ -334,9 +331,10 @@ static void __maybe_unused mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
}
-static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
- struct spi_imx_config *config)
+static int mx51_ecspi_config(struct spi_device *spi,
+ struct spi_imx_config *config)
{
+ struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
u32 ctrl = MX51_ECSPI_CTRL_ENABLE;
u32 clk = config->speed_hz, delay, reg;
u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
@@ -355,28 +353,28 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
spi_imx->spi_bus_clk = clk;
/* set chip select to use */
- ctrl |= MX51_ECSPI_CTRL_CS(config->cs);
+ ctrl |= MX51_ECSPI_CTRL_CS(spi->chip_select);
ctrl |= (config->bpw - 1) << MX51_ECSPI_CTRL_BL_OFFSET;
- cfg |= MX51_ECSPI_CONFIG_SBBCTRL(config->cs);
+ cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select);
- if (config->mode & SPI_CPHA)
- cfg |= MX51_ECSPI_CONFIG_SCLKPHA(config->cs);
+ if (spi->mode & SPI_CPHA)
+ cfg |= MX51_ECSPI_CONFIG_SCLKPHA(spi->chip_select);
else
- cfg &= ~MX51_ECSPI_CONFIG_SCLKPHA(config->cs);
+ cfg &= ~MX51_ECSPI_CONFIG_SCLKPHA(spi->chip_select);
- if (config->mode & SPI_CPOL) {
- cfg |= MX51_ECSPI_CONFIG_SCLKPOL(config->cs);
- cfg |= MX51_ECSPI_CONFIG_SCLKCTL(config->cs);
+ if (spi->mode & SPI_CPOL) {
+ cfg |= MX51_ECSPI_CONFIG_SCLKPOL(spi->chip_select);
+ cfg |= MX51_ECSPI_CONFIG_SCLKCTL(spi->chip_select);
} else {
- cfg &= ~MX51_ECSPI_CONFIG_SCLKPOL(config->cs);
- cfg &= ~MX51_ECSPI_CONFIG_SCLKCTL(config->cs);
+ cfg &= ~MX51_ECSPI_CONFIG_SCLKPOL(spi->chip_select);
+ cfg &= ~MX51_ECSPI_CONFIG_SCLKCTL(spi->chip_select);
}
- if (config->mode & SPI_CS_HIGH)
- cfg |= MX51_ECSPI_CONFIG_SSBPOL(config->cs);
+ if (spi->mode & SPI_CS_HIGH)
+ cfg |= MX51_ECSPI_CONFIG_SSBPOL(spi->chip_select);
else
- cfg &= ~MX51_ECSPI_CONFIG_SSBPOL(config->cs);
+ cfg &= ~MX51_ECSPI_CONFIG_SSBPOL(spi->chip_select);
if (spi_imx->usedma)
ctrl |= MX51_ECSPI_CTRL_SMC;
@@ -385,7 +383,7 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
reg = readl(spi_imx->base + MX51_ECSPI_TESTREG);
- if (config->mode & SPI_LOOP)
+ if (spi->mode & SPI_LOOP)
reg |= MX51_ECSPI_TESTREG_LBC;
else
reg &= ~MX51_ECSPI_TESTREG_LBC;
@@ -424,12 +422,12 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
return 0;
}
-static int __maybe_unused mx51_ecspi_rx_available(struct spi_imx_data *spi_imx)
+static int mx51_ecspi_rx_available(struct spi_imx_data *spi_imx)
{
return readl(spi_imx->base + MX51_ECSPI_STAT) & MX51_ECSPI_STAT_RR;
}
-static void __maybe_unused mx51_ecspi_reset(struct spi_imx_data *spi_imx)
+static void mx51_ecspi_reset(struct spi_imx_data *spi_imx)
{
/* drain receive buffer */
while (mx51_ecspi_rx_available(spi_imx))
@@ -459,7 +457,7 @@ static void __maybe_unused mx51_ecspi_reset(struct spi_imx_data *spi_imx)
* the i.MX35 has a slightly different register layout for bits
* we do not use here.
*/
-static void __maybe_unused mx31_intctrl(struct spi_imx_data *spi_imx, int enable)
+static void mx31_intctrl(struct spi_imx_data *spi_imx, int enable)
{
unsigned int val = 0;
@@ -471,7 +469,7 @@ static void __maybe_unused mx31_intctrl(struct spi_imx_data *spi_imx, int enable
writel(val, spi_imx->base + MXC_CSPIINT);
}
-static void __maybe_unused mx31_trigger(struct spi_imx_data *spi_imx)
+static void mx31_trigger(struct spi_imx_data *spi_imx)
{
unsigned int reg;
@@ -480,11 +478,10 @@ static void __maybe_unused mx31_trigger(struct spi_imx_data *spi_imx)
writel(reg, spi_imx->base + MXC_CSPICTRL);
}
-static int __maybe_unused mx31_config(struct spi_imx_data *spi_imx,
- struct spi_imx_config *config)
+static int mx31_config(struct spi_device *spi, struct spi_imx_config *config)
{
+ struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER;
- int cs = spi_imx->chipselect[config->cs];
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) <<
MX31_CSPICTRL_DR_SHIFT;
@@ -496,14 +493,14 @@ static int __maybe_unused mx31_config(struct spi_imx_data *spi_imx,
reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT;
}
- if (config->mode & SPI_CPHA)
+ if (spi->mode & SPI_CPHA)
reg |= MX31_CSPICTRL_PHA;
- if (config->mode & SPI_CPOL)
+ if (spi->mode & SPI_CPOL)
reg |= MX31_CSPICTRL_POL;
- if (config->mode & SPI_CS_HIGH)
+ if (spi->mode & SPI_CS_HIGH)
reg |= MX31_CSPICTRL_SSPOL;
- if (cs < 0)
- reg |= (cs + 32) <<
+ if (spi->cs_gpio < 0)
+ reg |= (spi->cs_gpio + 32) <<
(is_imx35_cspi(spi_imx) ? MX35_CSPICTRL_CS_SHIFT :
MX31_CSPICTRL_CS_SHIFT);
@@ -512,12 +509,12 @@ static int __maybe_unused mx31_config(struct spi_imx_data *spi_imx,
return 0;
}
-static int __maybe_unused mx31_rx_available(struct spi_imx_data *spi_imx)
+static int mx31_rx_available(struct spi_imx_data *spi_imx)
{
return readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR;
}
-static void __maybe_unused mx31_reset(struct spi_imx_data *spi_imx)
+static void mx31_reset(struct spi_imx_data *spi_imx)
{
/* drain receive buffer */
while (readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR)
@@ -537,7 +534,7 @@ static void __maybe_unused mx31_reset(struct spi_imx_data *spi_imx)
#define MX21_CSPICTRL_DR_SHIFT 14
#define MX21_CSPICTRL_CS_SHIFT 19
-static void __maybe_unused mx21_intctrl(struct spi_imx_data *spi_imx, int enable)
+static void mx21_intctrl(struct spi_imx_data *spi_imx, int enable)
{
unsigned int val = 0;
@@ -549,7 +546,7 @@ static void __maybe_unused mx21_intctrl(struct spi_imx_data *spi_imx, int enable
writel(val, spi_imx->base + MXC_CSPIINT);
}
-static void __maybe_unused mx21_trigger(struct spi_imx_data *spi_imx)
+static void mx21_trigger(struct spi_imx_data *spi_imx)
{
unsigned int reg;
@@ -558,37 +555,36 @@ static void __maybe_unused mx21_trigger(struct spi_imx_data *spi_imx)
writel(reg, spi_imx->base + MXC_CSPICTRL);
}
-static int __maybe_unused mx21_config(struct spi_imx_data *spi_imx,
- struct spi_imx_config *config)
+static int mx21_config(struct spi_device *spi, struct spi_imx_config *config)
{
+ struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_MASTER;
- int cs = spi_imx->chipselect[config->cs];
unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18;
reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, config->speed_hz, max) <<
MX21_CSPICTRL_DR_SHIFT;
reg |= config->bpw - 1;
- if (config->mode & SPI_CPHA)
+ if (spi->mode & SPI_CPHA)
reg |= MX21_CSPICTRL_PHA;
- if (config->mode & SPI_CPOL)
+ if (spi->mode & SPI_CPOL)
reg |= MX21_CSPICTRL_POL;
- if (config->mode & SPI_CS_HIGH)
+ if (spi->mode & SPI_CS_HIGH)
reg |= MX21_CSPICTRL_SSPOL;
- if (cs < 0)
- reg |= (cs + 32) << MX21_CSPICTRL_CS_SHIFT;
+ if (spi->cs_gpio < 0)
+ reg |= (spi->cs_gpio + 32) << MX21_CSPICTRL_CS_SHIFT;
writel(reg, spi_imx->base + MXC_CSPICTRL);
return 0;
}
-static int __maybe_unused mx21_rx_available(struct spi_imx_data *spi_imx)
+static int mx21_rx_available(struct spi_imx_data *spi_imx)
{
return readl(spi_imx->base + MXC_CSPIINT) & MX21_INTREG_RR;
}
-static void __maybe_unused mx21_reset(struct spi_imx_data *spi_imx)
+static void mx21_reset(struct spi_imx_data *spi_imx)
{
writel(1, spi_imx->base + MXC_RESET);
}
@@ -604,7 +600,7 @@ static void __maybe_unused mx21_reset(struct spi_imx_data *spi_imx)
#define MX1_CSPICTRL_MASTER (1 << 10)
#define MX1_CSPICTRL_DR_SHIFT 13
-static void __maybe_unused mx1_intctrl(struct spi_imx_data *spi_imx, int enable)
+static void mx1_intctrl(struct spi_imx_data *spi_imx, int enable)
{
unsigned int val = 0;
@@ -616,7 +612,7 @@ static void __maybe_unused mx1_intctrl(struct spi_imx_data *spi_imx, int enable)
writel(val, spi_imx->base + MXC_CSPIINT);
}
-static void __maybe_unused mx1_trigger(struct spi_imx_data *spi_imx)
+static void mx1_trigger(struct spi_imx_data *spi_imx)
{
unsigned int reg;
@@ -625,18 +621,18 @@ static void __maybe_unused mx1_trigger(struct spi_imx_data *spi_imx)
writel(reg, spi_imx->base + MXC_CSPICTRL);
}
-static int __maybe_unused mx1_config(struct spi_imx_data *spi_imx,
- struct spi_imx_config *config)
+static int mx1_config(struct spi_device *spi, struct spi_imx_config *config)
{
+ struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER;
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) <<
MX1_CSPICTRL_DR_SHIFT;
reg |= config->bpw - 1;
- if (config->mode & SPI_CPHA)
+ if (spi->mode & SPI_CPHA)
reg |= MX1_CSPICTRL_PHA;
- if (config->mode & SPI_CPOL)
+ if (spi->mode & SPI_CPOL)
reg |= MX1_CSPICTRL_POL;
writel(reg, spi_imx->base + MXC_CSPICTRL);
@@ -644,12 +640,12 @@ static int __maybe_unused mx1_config(struct spi_imx_data *spi_imx,
return 0;
}
-static int __maybe_unused mx1_rx_available(struct spi_imx_data *spi_imx)
+static int mx1_rx_available(struct spi_imx_data *spi_imx)
{
return readl(spi_imx->base + MXC_CSPIINT) & MX1_INTREG_RR;
}
-static void __maybe_unused mx1_reset(struct spi_imx_data *spi_imx)
+static void mx1_reset(struct spi_imx_data *spi_imx)
{
writel(1, spi_imx->base + MXC_RESET);
}
@@ -747,15 +743,13 @@ MODULE_DEVICE_TABLE(of, spi_imx_dt_ids);
static void spi_imx_chipselect(struct spi_device *spi, int is_active)
{
- struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
- int gpio = spi_imx->chipselect[spi->chip_select];
int active = is_active != BITBANG_CS_INACTIVE;
int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH);
- if (!gpio_is_valid(gpio))
+ if (!gpio_is_valid(spi->cs_gpio))
return;
- gpio_set_value(gpio, dev_is_lowactive ^ active);
+ gpio_set_value(spi->cs_gpio, dev_is_lowactive ^ active);
}
static void spi_imx_push(struct spi_imx_data *spi_imx)
@@ -859,8 +853,6 @@ static int spi_imx_setupxfer(struct spi_device *spi,
config.bpw = t ? t->bits_per_word : spi->bits_per_word;
config.speed_hz = t ? t->speed_hz : spi->max_speed_hz;
- config.mode = spi->mode;
- config.cs = spi->chip_select;
if (!config.speed_hz)
config.speed_hz = spi->max_speed_hz;
@@ -891,7 +883,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,
return ret;
}
- spi_imx->devtype_data->config(spi_imx, &config);
+ spi_imx->devtype_data->config(spi, &config);
return 0;
}
@@ -1050,6 +1042,8 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
struct spi_transfer *transfer)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
+ unsigned long transfer_timeout;
+ unsigned long timeout;
spi_imx->tx_buf = transfer->tx_buf;
spi_imx->rx_buf = transfer->rx_buf;
@@ -1062,7 +1056,15 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
spi_imx->devtype_data->intctrl(spi_imx, MXC_INT_TE);
- wait_for_completion(&spi_imx->xfer_done);
+ transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
+
+ timeout = wait_for_completion_timeout(&spi_imx->xfer_done,
+ transfer_timeout);
+ if (!timeout) {
+ dev_err(&spi->dev, "I/O Error in PIO\n");
+ spi_imx->devtype_data->reset(spi_imx);
+ return -ETIMEDOUT;
+ }
return transfer->len;
}
@@ -1080,14 +1082,12 @@ static int spi_imx_transfer(struct spi_device *spi,
static int spi_imx_setup(struct spi_device *spi)
{
- struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
- int gpio = spi_imx->chipselect[spi->chip_select];
-
dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__,
spi->mode, spi->bits_per_word, spi->max_speed_hz);
- if (gpio_is_valid(gpio))
- gpio_direction_output(gpio, spi->mode & SPI_CS_HIGH ? 0 : 1);
+ if (gpio_is_valid(spi->cs_gpio))
+ gpio_direction_output(spi->cs_gpio,
+ spi->mode & SPI_CS_HIGH ? 0 : 1);
spi_imx_chipselect(spi, BITBANG_CS_INACTIVE);
@@ -1137,31 +1137,21 @@ static int spi_imx_probe(struct platform_device *pdev)
struct spi_master *master;
struct spi_imx_data *spi_imx;
struct resource *res;
- int i, ret, num_cs, irq;
+ int i, ret, irq;
if (!np && !mxc_platform_info) {
dev_err(&pdev->dev, "can't get the platform data\n");
return -EINVAL;
}
- ret = of_property_read_u32(np, "fsl,spi-num-chipselects", &num_cs);
- if (ret < 0) {
- if (mxc_platform_info)
- num_cs = mxc_platform_info->num_chipselect;
- else
- return ret;
- }
-
- master = spi_alloc_master(&pdev->dev,
- sizeof(struct spi_imx_data) + sizeof(int) * num_cs);
+ master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data));
if (!master)
return -ENOMEM;
platform_set_drvdata(pdev, master);
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
- master->bus_num = pdev->id;
- master->num_chipselect = num_cs;
+ master->bus_num = np ? -1 : pdev->id;
spi_imx = spi_master_get_devdata(master);
spi_imx->bitbang.master = master;
@@ -1170,22 +1160,16 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->devtype_data = of_id ? of_id->data :
(struct spi_imx_devtype_data *)pdev->id_entry->driver_data;
- for (i = 0; i < master->num_chipselect; i++) {
- int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
- if (!gpio_is_valid(cs_gpio) && mxc_platform_info)
- cs_gpio = mxc_platform_info->chipselect[i];
+ 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;
- spi_imx->chipselect[i] = cs_gpio;
- if (!gpio_is_valid(cs_gpio))
- continue;
-
- ret = devm_gpio_request(&pdev->dev, spi_imx->chipselect[i],
- DRIVER_NAME);
- if (ret) {
- dev_err(&pdev->dev, "can't get cs gpios\n");
- goto out_master_put;
- }
- }
+ for (i = 0; i < master->num_chipselect; i++)
+ master->cs_gpios[i] = mxc_platform_info->chipselect[i];
+ }
spi_imx->bitbang.chipselect = spi_imx_chipselect;
spi_imx->bitbang.setup_transfer = spi_imx_setupxfer;
@@ -1267,6 +1251,19 @@ static int spi_imx_probe(struct platform_device *pdev)
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);
diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c
index cf4bb36bee25..faa1b133b0f1 100644
--- a/drivers/spi/spi-loopback-test.c
+++ b/drivers/spi/spi-loopback-test.c
@@ -536,7 +536,7 @@ static int spi_test_check_loopback_result(struct spi_device *spi,
mismatch_error:
dev_err(&spi->dev,
- "loopback strangeness - transfer missmatch on byte %04zx - expected 0x%02x, but got 0x%02x\n",
+ "loopback strangeness - transfer mismatch on byte %04zx - expected 0x%02x, but got 0x%02x\n",
i, txb, rxb);
return -EINVAL;
diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c
index 72d11ebefb28..42a8b8521f8f 100644
--- a/drivers/spi/spi-mpc52xx-psc.c
+++ b/drivers/spi/spi-mpc52xx-psc.c
@@ -42,7 +42,6 @@ struct mpc52xx_psc_spi {
u8 bits_per_word;
u8 busy;
- struct workqueue_struct *workqueue;
struct work_struct work;
struct list_head queue;
@@ -299,7 +298,7 @@ static int mpc52xx_psc_spi_transfer(struct spi_device *spi,
spin_lock_irqsave(&mps->lock, flags);
list_add_tail(&m->queue, &mps->queue);
- queue_work(mps->workqueue, &mps->work);
+ schedule_work(&mps->work);
spin_unlock_irqrestore(&mps->lock, flags);
return 0;
@@ -425,21 +424,12 @@ static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
INIT_WORK(&mps->work, mpc52xx_psc_spi_work);
INIT_LIST_HEAD(&mps->queue);
- mps->workqueue = create_singlethread_workqueue(
- dev_name(master->dev.parent));
- if (mps->workqueue == NULL) {
- ret = -EBUSY;
- goto free_irq;
- }
-
ret = spi_register_master(master);
if (ret < 0)
- goto unreg_master;
+ goto free_irq;
return ret;
-unreg_master:
- destroy_workqueue(mps->workqueue);
free_irq:
free_irq(mps->irq, mps);
free_master:
@@ -484,8 +474,7 @@ static int mpc52xx_psc_spi_of_remove(struct platform_device *op)
struct spi_master *master = spi_master_get(platform_get_drvdata(op));
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
- flush_workqueue(mps->workqueue);
- destroy_workqueue(mps->workqueue);
+ flush_work(&mps->work);
spi_unregister_master(master);
free_irq(mps->irq, mps);
if (mps->psc)
diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c
deleted file mode 100644
index 3b170093989f..000000000000
--- a/drivers/spi/spi-octeon.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2011, 2012 Cavium, Inc.
- */
-
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/spi/spi.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/of.h>
-
-#include <asm/octeon/octeon.h>
-#include <asm/octeon/cvmx-mpi-defs.h>
-
-#define OCTEON_SPI_CFG 0
-#define OCTEON_SPI_STS 0x08
-#define OCTEON_SPI_TX 0x10
-#define OCTEON_SPI_DAT0 0x80
-
-#define OCTEON_SPI_MAX_BYTES 9
-
-#define OCTEON_SPI_MAX_CLOCK_HZ 16000000
-
-struct octeon_spi {
- u64 register_base;
- u64 last_cfg;
- u64 cs_enax;
-};
-
-static void octeon_spi_wait_ready(struct octeon_spi *p)
-{
- union cvmx_mpi_sts mpi_sts;
- unsigned int loops = 0;
-
- do {
- if (loops++)
- __delay(500);
- mpi_sts.u64 = cvmx_read_csr(p->register_base + OCTEON_SPI_STS);
- } while (mpi_sts.s.busy);
-}
-
-static int octeon_spi_do_transfer(struct octeon_spi *p,
- struct spi_message *msg,
- struct spi_transfer *xfer,
- bool last_xfer)
-{
- struct spi_device *spi = msg->spi;
- union cvmx_mpi_cfg mpi_cfg;
- union cvmx_mpi_tx mpi_tx;
- unsigned int clkdiv;
- unsigned int speed_hz;
- int mode;
- bool cpha, cpol;
- const u8 *tx_buf;
- u8 *rx_buf;
- int len;
- int i;
-
- mode = spi->mode;
- cpha = mode & SPI_CPHA;
- cpol = mode & SPI_CPOL;
-
- speed_hz = xfer->speed_hz;
-
- clkdiv = octeon_get_io_clock_rate() / (2 * speed_hz);
-
- mpi_cfg.u64 = 0;
-
- mpi_cfg.s.clkdiv = clkdiv;
- mpi_cfg.s.cshi = (mode & SPI_CS_HIGH) ? 1 : 0;
- mpi_cfg.s.lsbfirst = (mode & SPI_LSB_FIRST) ? 1 : 0;
- mpi_cfg.s.wireor = (mode & SPI_3WIRE) ? 1 : 0;
- mpi_cfg.s.idlelo = cpha != cpol;
- mpi_cfg.s.cslate = cpha ? 1 : 0;
- mpi_cfg.s.enable = 1;
-
- if (spi->chip_select < 4)
- p->cs_enax |= 1ull << (12 + spi->chip_select);
- mpi_cfg.u64 |= p->cs_enax;
-
- if (mpi_cfg.u64 != p->last_cfg) {
- p->last_cfg = mpi_cfg.u64;
- cvmx_write_csr(p->register_base + OCTEON_SPI_CFG, mpi_cfg.u64);
- }
- tx_buf = xfer->tx_buf;
- rx_buf = xfer->rx_buf;
- len = xfer->len;
- while (len > OCTEON_SPI_MAX_BYTES) {
- for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) {
- u8 d;
- if (tx_buf)
- d = *tx_buf++;
- else
- d = 0;
- cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d);
- }
- mpi_tx.u64 = 0;
- mpi_tx.s.csid = spi->chip_select;
- mpi_tx.s.leavecs = 1;
- mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0;
- mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES;
- cvmx_write_csr(p->register_base + OCTEON_SPI_TX, mpi_tx.u64);
-
- octeon_spi_wait_ready(p);
- if (rx_buf)
- for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) {
- u64 v = cvmx_read_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i));
- *rx_buf++ = (u8)v;
- }
- len -= OCTEON_SPI_MAX_BYTES;
- }
-
- for (i = 0; i < len; i++) {
- u8 d;
- if (tx_buf)
- d = *tx_buf++;
- else
- d = 0;
- cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d);
- }
-
- mpi_tx.u64 = 0;
- mpi_tx.s.csid = spi->chip_select;
- if (last_xfer)
- mpi_tx.s.leavecs = xfer->cs_change;
- else
- mpi_tx.s.leavecs = !xfer->cs_change;
- mpi_tx.s.txnum = tx_buf ? len : 0;
- mpi_tx.s.totnum = len;
- cvmx_write_csr(p->register_base + OCTEON_SPI_TX, mpi_tx.u64);
-
- octeon_spi_wait_ready(p);
- if (rx_buf)
- for (i = 0; i < len; i++) {
- u64 v = cvmx_read_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i));
- *rx_buf++ = (u8)v;
- }
-
- if (xfer->delay_usecs)
- udelay(xfer->delay_usecs);
-
- return xfer->len;
-}
-
-static int octeon_spi_transfer_one_message(struct spi_master *master,
- struct spi_message *msg)
-{
- struct octeon_spi *p = spi_master_get_devdata(master);
- unsigned int total_len = 0;
- int status = 0;
- struct spi_transfer *xfer;
-
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- bool last_xfer = list_is_last(&xfer->transfer_list,
- &msg->transfers);
- int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer);
- if (r < 0) {
- status = r;
- goto err;
- }
- total_len += r;
- }
-err:
- msg->status = status;
- msg->actual_length = total_len;
- spi_finalize_current_message(master);
- return status;
-}
-
-static int octeon_spi_probe(struct platform_device *pdev)
-{
- struct resource *res_mem;
- void __iomem *reg_base;
- struct spi_master *master;
- struct octeon_spi *p;
- int err = -ENOENT;
-
- master = spi_alloc_master(&pdev->dev, sizeof(struct octeon_spi));
- if (!master)
- return -ENOMEM;
- p = spi_master_get_devdata(master);
- platform_set_drvdata(pdev, master);
-
- res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- reg_base = devm_ioremap_resource(&pdev->dev, res_mem);
- if (IS_ERR(reg_base)) {
- err = PTR_ERR(reg_base);
- goto fail;
- }
-
- p->register_base = (u64)reg_base;
-
- master->num_chipselect = 4;
- master->mode_bits = SPI_CPHA |
- SPI_CPOL |
- SPI_CS_HIGH |
- SPI_LSB_FIRST |
- SPI_3WIRE;
-
- master->transfer_one_message = octeon_spi_transfer_one_message;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
-
- master->dev.of_node = pdev->dev.of_node;
- err = devm_spi_register_master(&pdev->dev, master);
- if (err) {
- dev_err(&pdev->dev, "register master failed: %d\n", err);
- goto fail;
- }
-
- dev_info(&pdev->dev, "OCTEON SPI bus driver\n");
-
- return 0;
-fail:
- spi_master_put(master);
- return err;
-}
-
-static int octeon_spi_remove(struct platform_device *pdev)
-{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct octeon_spi *p = spi_master_get_devdata(master);
- u64 register_base = p->register_base;
-
- /* Clear the CSENA* and put everything in a known state. */
- cvmx_write_csr(register_base + OCTEON_SPI_CFG, 0);
-
- return 0;
-}
-
-static const struct of_device_id octeon_spi_match[] = {
- { .compatible = "cavium,octeon-3010-spi", },
- {},
-};
-MODULE_DEVICE_TABLE(of, octeon_spi_match);
-
-static struct platform_driver octeon_spi_driver = {
- .driver = {
- .name = "spi-octeon",
- .of_match_table = octeon_spi_match,
- },
- .probe = octeon_spi_probe,
- .remove = octeon_spi_remove,
-};
-
-module_platform_driver(octeon_spi_driver);
-
-MODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver");
-MODULE_AUTHOR("David Daney");
-MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 1d237e93a289..d5157b2222ce 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -419,16 +419,13 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
if (mcspi_dma->dma_tx) {
struct dma_async_tx_descriptor *tx;
- struct scatterlist sg;
dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
- sg_init_table(&sg, 1);
- sg_dma_address(&sg) = xfer->tx_dma;
- sg_dma_len(&sg) = xfer->len;
-
- tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, &sg, 1,
- DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl,
+ xfer->tx_sg.nents,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (tx) {
tx->callback = omap2_mcspi_tx_callback;
tx->callback_param = spi;
@@ -449,7 +446,10 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
{
struct omap2_mcspi *mcspi;
struct omap2_mcspi_dma *mcspi_dma;
- unsigned int count, dma_count;
+ unsigned int count, transfer_reduction = 0;
+ struct scatterlist *sg_out[2];
+ int nb_sizes = 0, out_mapped_nents[2], ret, x;
+ size_t sizes[2];
u32 l;
int elements = 0;
int word_len, element_count;
@@ -457,10 +457,14 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
mcspi = spi_master_get_devdata(spi->master);
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
count = xfer->len;
- dma_count = xfer->len;
+ /*
+ * In the "End-of-Transfer Procedure" section for DMA RX in OMAP35x TRM
+ * it mentions reducing DMA transfer length by one element in master
+ * normal mode.
+ */
if (mcspi->fifo_depth == 0)
- dma_count -= es;
+ transfer_reduction = es;
word_len = cs->word_len;
l = mcspi_cached_chconf0(spi);
@@ -474,20 +478,46 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
if (mcspi_dma->dma_rx) {
struct dma_async_tx_descriptor *tx;
- struct scatterlist sg;
dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
+ /*
+ * Reduce DMA transfer length by one more if McSPI is
+ * configured in turbo mode.
+ */
if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
- dma_count -= es;
+ transfer_reduction += es;
+
+ if (transfer_reduction) {
+ /* Split sgl into two. The second sgl won't be used. */
+ sizes[0] = count - transfer_reduction;
+ sizes[1] = transfer_reduction;
+ nb_sizes = 2;
+ } else {
+ /*
+ * Don't bother splitting the sgl. This essentially
+ * clones the original sgl.
+ */
+ sizes[0] = count;
+ nb_sizes = 1;
+ }
+
+ ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents,
+ 0, nb_sizes,
+ sizes,
+ sg_out, out_mapped_nents,
+ GFP_KERNEL);
- sg_init_table(&sg, 1);
- sg_dma_address(&sg) = xfer->rx_dma;
- sg_dma_len(&sg) = dma_count;
+ if (ret < 0) {
+ dev_err(&spi->dev, "sg_split failed\n");
+ return 0;
+ }
- tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1,
- DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT |
- DMA_CTRL_ACK);
+ tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx,
+ sg_out[0],
+ out_mapped_nents[0],
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (tx) {
tx->callback = omap2_mcspi_rx_callback;
tx->callback_param = spi;
@@ -501,12 +531,17 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
omap2_mcspi_set_dma_req(spi, 1, 1);
wait_for_completion(&mcspi_dma->dma_rx_completion);
- dma_unmap_single(mcspi->dev, xfer->rx_dma, count,
- DMA_FROM_DEVICE);
+
+ for (x = 0; x < nb_sizes; x++)
+ kfree(sg_out[x]);
if (mcspi->fifo_depth > 0)
return count;
+ /*
+ * Due to the DMA transfer length reduction the missing bytes must
+ * be read manually to receive all of the expected data.
+ */
omap2_mcspi_set_enable(spi, 0);
elements = element_count - 1;
@@ -615,8 +650,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
if (tx != NULL) {
wait_for_completion(&mcspi_dma->dma_tx_completion);
- dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len,
- DMA_TO_DEVICE);
if (mcspi->fifo_depth > 0) {
irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS;
@@ -1074,8 +1107,9 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
gpio_free(spi->cs_gpio);
}
-static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
- struct spi_device *spi, struct spi_transfer *t)
+static int omap2_mcspi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *t)
{
/* We only enable one channel at a time -- the one whose message is
@@ -1085,7 +1119,7 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
* chipselect with the FORCE bit ... CS != channel enable.
*/
- struct spi_master *master;
+ struct omap2_mcspi *mcspi;
struct omap2_mcspi_dma *mcspi_dma;
struct omap2_mcspi_cs *cs;
struct omap2_mcspi_device_config *cd;
@@ -1093,7 +1127,7 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
int status = 0;
u32 chconf;
- master = spi->master;
+ mcspi = spi_master_get_devdata(master);
mcspi_dma = mcspi->dma_channels + spi->chip_select;
cs = spi->controller_state;
cd = spi->controller_data;
@@ -1153,7 +1187,8 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
unsigned count;
if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
- (t->len >= DMA_MIN_BYTES))
+ master->cur_msg_mapped &&
+ master->can_dma(master, spi, t))
omap2_mcspi_set_fifo(spi, t, 1);
omap2_mcspi_set_enable(spi, 1);
@@ -1164,7 +1199,8 @@ static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
+ OMAP2_MCSPI_TX0);
if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
- (t->len >= DMA_MIN_BYTES))
+ master->cur_msg_mapped &&
+ master->can_dma(master, spi, t))
count = omap2_mcspi_txrx_dma(spi, t);
else
count = omap2_mcspi_txrx_pio(spi, t);
@@ -1233,55 +1269,11 @@ static int omap2_mcspi_prepare_message(struct spi_master *master,
return 0;
}
-static int omap2_mcspi_transfer_one(struct spi_master *master,
- struct spi_device *spi, struct spi_transfer *t)
+static bool omap2_mcspi_can_dma(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
{
- struct omap2_mcspi *mcspi;
- struct omap2_mcspi_dma *mcspi_dma;
- const void *tx_buf = t->tx_buf;
- void *rx_buf = t->rx_buf;
- unsigned len = t->len;
-
- mcspi = spi_master_get_devdata(master);
- mcspi_dma = mcspi->dma_channels + spi->chip_select;
-
- 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 (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;
- }
- }
-
-skip_dma_map:
- return omap2_mcspi_work_one(mcspi, spi, t);
+ return (xfer->len >= DMA_MIN_BYTES);
}
static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
@@ -1361,6 +1353,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
master->setup = omap2_mcspi_setup;
master->auto_runtime_pm = true;
master->prepare_message = omap2_mcspi_prepare_message;
+ master->can_dma = omap2_mcspi_can_dma;
master->transfer_one = omap2_mcspi_transfer_one;
master->set_cs = omap2_mcspi_set_cs;
master->cleanup = omap2_mcspi_cleanup;
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index a87cfd4ba17b..ded37025b445 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/sizes.h>
@@ -43,6 +44,9 @@
#define ORION_SPI_INT_CAUSE_REG 0x10
#define ORION_SPI_TIMING_PARAMS_REG 0x18
+/* Register for the "Direct Mode" */
+#define SPI_DIRECT_WRITE_CONFIG_REG 0x20
+
#define ORION_SPI_TMISO_SAMPLE_MASK (0x3 << 6)
#define ORION_SPI_TMISO_SAMPLE_1 (1 << 6)
#define ORION_SPI_TMISO_SAMPLE_2 (2 << 6)
@@ -78,11 +82,18 @@ struct orion_spi_dev {
bool is_errata_50mhz_ac;
};
+struct orion_direct_acc {
+ void __iomem *vaddr;
+ u32 size;
+};
+
struct orion_spi {
struct spi_master *master;
void __iomem *base;
struct clk *clk;
const struct orion_spi_dev *devdata;
+
+ struct orion_direct_acc direct_access[ORION_NUM_CHIPSELECTS];
};
static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg)
@@ -372,10 +383,39 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
{
unsigned int count;
int word_len;
+ struct orion_spi *orion_spi;
+ int cs = spi->chip_select;
word_len = spi->bits_per_word;
count = xfer->len;
+ orion_spi = spi_master_get_devdata(spi->master);
+
+ /*
+ * Use SPI direct write mode if base address is available. Otherwise
+ * fall back to PIO mode for this transfer.
+ */
+ if ((orion_spi->direct_access[cs].vaddr) && (xfer->tx_buf) &&
+ (word_len == 8)) {
+ unsigned int cnt = count / 4;
+ unsigned int rem = count % 4;
+
+ /*
+ * Send the TX-data to the SPI device via the direct
+ * mapped address window
+ */
+ iowrite32_rep(orion_spi->direct_access[cs].vaddr,
+ xfer->tx_buf, cnt);
+ if (rem) {
+ u32 *buf = (u32 *)xfer->tx_buf;
+
+ iowrite8_rep(orion_spi->direct_access[cs].vaddr,
+ &buf[cnt], rem);
+ }
+
+ return count;
+ }
+
if (word_len == 8) {
const u8 *tx = xfer->tx_buf;
u8 *rx = xfer->rx_buf;
@@ -425,6 +465,10 @@ static int orion_spi_reset(struct orion_spi *orion_spi)
{
/* Verify that the CS is deasserted */
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
+
+ /* Don't deassert CS between the direct mapped SPI transfers */
+ writel(0, spi_reg(orion_spi, SPI_DIRECT_WRITE_CONFIG_REG));
+
return 0;
}
@@ -504,6 +548,7 @@ static int orion_spi_probe(struct platform_device *pdev)
struct resource *r;
unsigned long tclk_hz;
int status = 0;
+ struct device_node *np;
master = spi_alloc_master(&pdev->dev, sizeof(*spi));
if (master == NULL) {
@@ -576,6 +621,49 @@ static int orion_spi_probe(struct platform_device *pdev)
goto out_rel_clk;
}
+ /* Scan all SPI devices of this controller for direct mapped devices */
+ for_each_available_child_of_node(pdev->dev.of_node, np) {
+ u32 cs;
+
+ /* Get chip-select number from the "reg" property */
+ status = of_property_read_u32(np, "reg", &cs);
+ if (status) {
+ dev_err(&pdev->dev,
+ "%s has no valid 'reg' property (%d)\n",
+ np->full_name, status);
+ status = 0;
+ continue;
+ }
+
+ /*
+ * Check if an address is configured for this SPI device. If
+ * not, the MBus mapping via the 'ranges' property in the 'soc'
+ * node is not configured and this device should not use the
+ * direct mode. In this case, just continue with the next
+ * device.
+ */
+ status = of_address_to_resource(pdev->dev.of_node, cs + 1, r);
+ if (status)
+ continue;
+
+ /*
+ * Only map one page for direct access. This is enough for the
+ * simple TX transfer which only writes to the first word.
+ * This needs to get extended for the direct SPI-NOR / SPI-NAND
+ * support, once this gets implemented.
+ */
+ spi->direct_access[cs].vaddr = devm_ioremap(&pdev->dev,
+ r->start,
+ PAGE_SIZE);
+ if (!spi->direct_access[cs].vaddr) {
+ status = -ENOMEM;
+ goto out_rel_clk;
+ }
+ spi->direct_access[cs].size = PAGE_SIZE;
+
+ dev_info(&pdev->dev, "CS%d configured for direct access\n", cs);
+ }
+
pm_runtime_set_active(&pdev->dev);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
diff --git a/drivers/spi/spi-pic32-sqi.c b/drivers/spi/spi-pic32-sqi.c
index ca3c8d94b290..c41abddab318 100644
--- a/drivers/spi/spi-pic32-sqi.c
+++ b/drivers/spi/spi-pic32-sqi.c
@@ -354,6 +354,7 @@ static int pic32_sqi_one_message(struct spi_master *master,
struct spi_transfer *xfer;
struct pic32_sqi *sqi;
int ret = 0, mode;
+ unsigned long timeout;
u32 val;
sqi = spi_master_get_devdata(master);
@@ -419,10 +420,10 @@ static int pic32_sqi_one_message(struct spi_master *master,
writel(val, sqi->regs + PESQI_BD_CTRL_REG);
/* wait for xfer completion */
- ret = wait_for_completion_timeout(&sqi->xfer_done, 5 * HZ);
- if (ret <= 0) {
+ timeout = wait_for_completion_timeout(&sqi->xfer_done, 5 * HZ);
+ if (timeout == 0) {
dev_err(&sqi->master->dev, "wait timedout/interrupted\n");
- ret = -EIO;
+ ret = -ETIMEDOUT;
msg->status = ret;
} else {
/* success */
diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c
index 73db87f805a1..fefb688a3432 100644
--- a/drivers/spi/spi-pic32.c
+++ b/drivers/spi/spi-pic32.c
@@ -507,6 +507,7 @@ static int pic32_spi_one_transfer(struct spi_master *master,
{
struct pic32_spi *pic32s;
bool dma_issued = false;
+ unsigned long timeout;
int ret;
pic32s = spi_master_get_devdata(master);
@@ -553,8 +554,8 @@ static int pic32_spi_one_transfer(struct spi_master *master,
}
/* wait for completion */
- ret = wait_for_completion_timeout(&pic32s->xfer_done, 2 * HZ);
- if (ret <= 0) {
+ timeout = wait_for_completion_timeout(&pic32s->xfer_done, 2 * HZ);
+ if (timeout == 0) {
dev_err(&spi->dev, "wait error/timedout\n");
if (dma_issued) {
dmaengine_terminate_all(master->dma_rx);
diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c
index a18a03d0afb7..db3ae1dd829e 100644
--- a/drivers/spi/spi-pxa2xx-dma.c
+++ b/drivers/spi/spi-pxa2xx-dma.c
@@ -20,79 +20,6 @@
#include "spi-pxa2xx.h"
-static int pxa2xx_spi_map_dma_buffer(struct driver_data *drv_data,
- enum dma_data_direction dir)
-{
- int i, nents, len = drv_data->len;
- struct scatterlist *sg;
- struct device *dmadev;
- struct sg_table *sgt;
- void *buf, *pbuf;
-
- if (dir == DMA_TO_DEVICE) {
- dmadev = drv_data->tx_chan->device->dev;
- sgt = &drv_data->tx_sgt;
- buf = drv_data->tx;
- } else {
- dmadev = drv_data->rx_chan->device->dev;
- sgt = &drv_data->rx_sgt;
- buf = drv_data->rx;
- }
-
- nents = DIV_ROUND_UP(len, SZ_2K);
- if (nents != sgt->nents) {
- int ret;
-
- sg_free_table(sgt);
- ret = sg_alloc_table(sgt, nents, GFP_ATOMIC);
- if (ret)
- return ret;
- }
-
- pbuf = buf;
- for_each_sg(sgt->sgl, sg, sgt->nents, i) {
- size_t bytes = min_t(size_t, len, SZ_2K);
-
- sg_set_buf(sg, pbuf, bytes);
- pbuf += bytes;
- len -= bytes;
- }
-
- nents = dma_map_sg(dmadev, sgt->sgl, sgt->nents, dir);
- if (!nents)
- return -ENOMEM;
-
- return nents;
-}
-
-static void pxa2xx_spi_unmap_dma_buffer(struct driver_data *drv_data,
- enum dma_data_direction dir)
-{
- struct device *dmadev;
- struct sg_table *sgt;
-
- if (dir == DMA_TO_DEVICE) {
- dmadev = drv_data->tx_chan->device->dev;
- sgt = &drv_data->tx_sgt;
- } else {
- dmadev = drv_data->rx_chan->device->dev;
- sgt = &drv_data->rx_sgt;
- }
-
- dma_unmap_sg(dmadev, sgt->sgl, sgt->nents, dir);
-}
-
-static void pxa2xx_spi_unmap_dma_buffers(struct driver_data *drv_data)
-{
- if (!drv_data->dma_mapped)
- return;
-
- pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_FROM_DEVICE);
- pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_TO_DEVICE);
-
- drv_data->dma_mapped = 0;
-}
-
static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
bool error)
{
@@ -125,8 +52,6 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
pxa2xx_spi_write(drv_data, SSTO, 0);
if (!error) {
- pxa2xx_spi_unmap_dma_buffers(drv_data);
-
msg->actual_length += drv_data->len;
msg->state = pxa2xx_spi_next_transfer(drv_data);
} else {
@@ -152,11 +77,12 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
enum dma_transfer_direction dir)
{
struct chip_data *chip = drv_data->cur_chip;
+ struct spi_transfer *xfer = drv_data->cur_transfer;
enum dma_slave_buswidth width;
struct dma_slave_config cfg;
struct dma_chan *chan;
struct sg_table *sgt;
- int nents, ret;
+ int ret;
switch (drv_data->n_bytes) {
case 1:
@@ -178,17 +104,15 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
cfg.dst_addr_width = width;
cfg.dst_maxburst = chip->dma_burst_size;
- sgt = &drv_data->tx_sgt;
- nents = drv_data->tx_nents;
- chan = drv_data->tx_chan;
+ sgt = &xfer->tx_sg;
+ chan = drv_data->master->dma_tx;
} else {
cfg.src_addr = drv_data->ssdr_physical;
cfg.src_addr_width = width;
cfg.src_maxburst = chip->dma_burst_size;
- sgt = &drv_data->rx_sgt;
- nents = drv_data->rx_nents;
- chan = drv_data->rx_chan;
+ sgt = &xfer->rx_sg;
+ chan = drv_data->master->dma_rx;
}
ret = dmaengine_slave_config(chan, &cfg);
@@ -197,46 +121,10 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
return NULL;
}
- return dmaengine_prep_slave_sg(chan, sgt->sgl, nents, dir,
+ return dmaengine_prep_slave_sg(chan, sgt->sgl, sgt->nents, dir,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
}
-bool pxa2xx_spi_dma_is_possible(size_t len)
-{
- return len <= MAX_DMA_LEN;
-}
-
-int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data)
-{
- const struct chip_data *chip = drv_data->cur_chip;
- int ret;
-
- if (!chip->enable_dma)
- return 0;
-
- /* Don't bother with DMA if we can't do even a single burst */
- if (drv_data->len < chip->dma_burst_size)
- return 0;
-
- ret = pxa2xx_spi_map_dma_buffer(drv_data, DMA_TO_DEVICE);
- if (ret <= 0) {
- dev_warn(&drv_data->pdev->dev, "failed to DMA map TX\n");
- return 0;
- }
-
- drv_data->tx_nents = ret;
-
- ret = pxa2xx_spi_map_dma_buffer(drv_data, DMA_FROM_DEVICE);
- if (ret <= 0) {
- pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_TO_DEVICE);
- dev_warn(&drv_data->pdev->dev, "failed to DMA map RX\n");
- return 0;
- }
-
- drv_data->rx_nents = ret;
- return 1;
-}
-
irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
{
u32 status;
@@ -245,8 +133,8 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
if (status & SSSR_ROR) {
dev_err(&drv_data->pdev->dev, "FIFO overrun\n");
- dmaengine_terminate_async(drv_data->rx_chan);
- dmaengine_terminate_async(drv_data->tx_chan);
+ dmaengine_terminate_async(drv_data->master->dma_rx);
+ dmaengine_terminate_async(drv_data->master->dma_tx);
pxa2xx_spi_dma_transfer_complete(drv_data, true);
return IRQ_HANDLED;
@@ -285,16 +173,15 @@ int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst)
return 0;
err_rx:
- dmaengine_terminate_async(drv_data->tx_chan);
+ dmaengine_terminate_async(drv_data->master->dma_tx);
err_tx:
- pxa2xx_spi_unmap_dma_buffers(drv_data);
return err;
}
void pxa2xx_spi_dma_start(struct driver_data *drv_data)
{
- dma_async_issue_pending(drv_data->rx_chan);
- dma_async_issue_pending(drv_data->tx_chan);
+ dma_async_issue_pending(drv_data->master->dma_rx);
+ dma_async_issue_pending(drv_data->master->dma_tx);
atomic_set(&drv_data->dma_running, 1);
}
@@ -303,21 +190,22 @@ int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
{
struct pxa2xx_spi_master *pdata = drv_data->master_info;
struct device *dev = &drv_data->pdev->dev;
+ struct spi_master *master = drv_data->master;
dma_cap_mask_t mask;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- drv_data->tx_chan = dma_request_slave_channel_compat(mask,
+ master->dma_tx = dma_request_slave_channel_compat(mask,
pdata->dma_filter, pdata->tx_param, dev, "tx");
- if (!drv_data->tx_chan)
+ if (!master->dma_tx)
return -ENODEV;
- drv_data->rx_chan = dma_request_slave_channel_compat(mask,
+ master->dma_rx = dma_request_slave_channel_compat(mask,
pdata->dma_filter, pdata->rx_param, dev, "rx");
- if (!drv_data->rx_chan) {
- dma_release_channel(drv_data->tx_chan);
- drv_data->tx_chan = NULL;
+ if (!master->dma_rx) {
+ dma_release_channel(master->dma_tx);
+ master->dma_tx = NULL;
return -ENODEV;
}
@@ -326,17 +214,17 @@ int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
void pxa2xx_spi_dma_release(struct driver_data *drv_data)
{
- if (drv_data->rx_chan) {
- dmaengine_terminate_sync(drv_data->rx_chan);
- dma_release_channel(drv_data->rx_chan);
- sg_free_table(&drv_data->rx_sgt);
- drv_data->rx_chan = NULL;
+ struct spi_master *master = drv_data->master;
+
+ if (master->dma_rx) {
+ dmaengine_terminate_sync(master->dma_rx);
+ dma_release_channel(master->dma_rx);
+ master->dma_rx = NULL;
}
- if (drv_data->tx_chan) {
- dmaengine_terminate_sync(drv_data->tx_chan);
- dma_release_channel(drv_data->tx_chan);
- sg_free_table(&drv_data->tx_sgt);
- drv_data->tx_chan = NULL;
+ if (master->dma_tx) {
+ dmaengine_terminate_sync(master->dma_tx);
+ dma_release_channel(master->dma_tx);
+ master->dma_tx = NULL;
}
}
diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c
index 5202de94f792..f3df522db93b 100644
--- a/drivers/spi/spi-pxa2xx-pci.c
+++ b/drivers/spi/spi-pxa2xx-pci.c
@@ -1,24 +1,26 @@
/*
* CE4100's SPI device is more or less the same one as found on PXA
*
+ * Copyright (C) 2016, Intel Corporation
*/
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
-#include <linux/of_device.h>
-#include <linux/module.h>
#include <linux/spi/pxa2xx_spi.h>
-#include <linux/clk-provider.h>
#include <linux/dmaengine.h>
#include <linux/platform_data/dma-dw.h>
enum {
- PORT_CE4100,
+ PORT_QUARK_X1000,
PORT_BYT,
+ PORT_MRFLD,
PORT_BSW0,
PORT_BSW1,
PORT_BSW2,
- PORT_QUARK_X1000,
+ PORT_CE4100,
PORT_LPT,
};
@@ -29,8 +31,11 @@ struct pxa_spi_info {
unsigned long max_clk_rate;
/* DMA channel request parameters */
+ bool (*dma_filter)(struct dma_chan *chan, void *param);
void *tx_param;
void *rx_param;
+
+ int (*setup)(struct pci_dev *pdev, struct pxa_spi_info *c);
};
static struct dw_dma_slave byt_tx_param = { .dst_id = 0 };
@@ -57,6 +62,56 @@ static bool lpss_dma_filter(struct dma_chan *chan, void *param)
return true;
}
+static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c)
+{
+ struct pci_dev *dma_dev;
+
+ c->num_chipselect = 1;
+ c->max_clk_rate = 50000000;
+
+ dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
+
+ if (c->tx_param) {
+ struct dw_dma_slave *slave = c->tx_param;
+
+ slave->dma_dev = &dma_dev->dev;
+ slave->m_master = 0;
+ slave->p_master = 1;
+ }
+
+ if (c->rx_param) {
+ struct dw_dma_slave *slave = c->rx_param;
+
+ slave->dma_dev = &dma_dev->dev;
+ slave->m_master = 0;
+ slave->p_master = 1;
+ }
+
+ c->dma_filter = lpss_dma_filter;
+ return 0;
+}
+
+static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c)
+{
+ switch (PCI_FUNC(dev->devfn)) {
+ case 0:
+ c->port_id = 3;
+ c->num_chipselect = 1;
+ break;
+ case 1:
+ c->port_id = 5;
+ c->num_chipselect = 4;
+ break;
+ case 2:
+ c->port_id = 6;
+ c->num_chipselect = 1;
+ break;
+ default:
+ return -ENODEV;
+ }
+ return 0;
+}
+
static struct pxa_spi_info spi_info_configs[] = {
[PORT_CE4100] = {
.type = PXA25x_SSP,
@@ -67,35 +122,36 @@ static struct pxa_spi_info spi_info_configs[] = {
[PORT_BYT] = {
.type = LPSS_BYT_SSP,
.port_id = 0,
- .num_chipselect = 1,
- .max_clk_rate = 50000000,
+ .setup = lpss_spi_setup,
.tx_param = &byt_tx_param,
.rx_param = &byt_rx_param,
},
[PORT_BSW0] = {
- .type = LPSS_BYT_SSP,
+ .type = LPSS_BSW_SSP,
.port_id = 0,
- .num_chipselect = 1,
- .max_clk_rate = 50000000,
+ .setup = lpss_spi_setup,
.tx_param = &bsw0_tx_param,
.rx_param = &bsw0_rx_param,
},
[PORT_BSW1] = {
- .type = LPSS_BYT_SSP,
+ .type = LPSS_BSW_SSP,
.port_id = 1,
- .num_chipselect = 1,
- .max_clk_rate = 50000000,
+ .setup = lpss_spi_setup,
.tx_param = &bsw1_tx_param,
.rx_param = &bsw1_rx_param,
},
[PORT_BSW2] = {
- .type = LPSS_BYT_SSP,
+ .type = LPSS_BSW_SSP,
.port_id = 2,
- .num_chipselect = 1,
- .max_clk_rate = 50000000,
+ .setup = lpss_spi_setup,
.tx_param = &bsw2_tx_param,
.rx_param = &bsw2_rx_param,
},
+ [PORT_MRFLD] = {
+ .type = PXA27x_SSP,
+ .max_clk_rate = 25000000,
+ .setup = mrfld_spi_setup,
+ },
[PORT_QUARK_X1000] = {
.type = QUARK_X1000_SSP,
.port_id = -1,
@@ -105,8 +161,7 @@ static struct pxa_spi_info spi_info_configs[] = {
[PORT_LPT] = {
.type = LPSS_LPT_SSP,
.port_id = 0,
- .num_chipselect = 1,
- .max_clk_rate = 50000000,
+ .setup = lpss_spi_setup,
.tx_param = &lpt_tx_param,
.rx_param = &lpt_rx_param,
},
@@ -122,7 +177,6 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
struct ssp_device *ssp;
struct pxa_spi_info *c;
char buf[40];
- struct pci_dev *dma_dev;
ret = pcim_enable_device(dev);
if (ret)
@@ -133,30 +187,15 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
return ret;
c = &spi_info_configs[ent->driver_data];
-
- memset(&spi_pdata, 0, sizeof(spi_pdata));
- spi_pdata.num_chipselect = (c->num_chipselect > 0) ?
- c->num_chipselect : dev->devfn;
-
- dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
-
- if (c->tx_param) {
- struct dw_dma_slave *slave = c->tx_param;
-
- slave->dma_dev = &dma_dev->dev;
- slave->m_master = 0;
- slave->p_master = 1;
+ if (c->setup) {
+ ret = c->setup(dev, c);
+ if (ret)
+ return ret;
}
- if (c->rx_param) {
- struct dw_dma_slave *slave = c->rx_param;
-
- slave->dma_dev = &dma_dev->dev;
- slave->m_master = 0;
- slave->p_master = 1;
- }
-
- spi_pdata.dma_filter = lpss_dma_filter;
+ memset(&spi_pdata, 0, sizeof(spi_pdata));
+ spi_pdata.num_chipselect = (c->num_chipselect > 0) ? c->num_chipselect : dev->devfn;
+ spi_pdata.dma_filter = c->dma_filter;
spi_pdata.tx_param = c->tx_param;
spi_pdata.rx_param = c->rx_param;
spi_pdata.enable_dma = c->rx_param && c->tx_param;
@@ -164,10 +203,6 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
ssp = &spi_pdata.ssp;
ssp->phys_base = pci_resource_start(dev, 0);
ssp->mmio_base = pcim_iomap_table(dev)[0];
- if (!ssp->mmio_base) {
- dev_err(&dev->dev, "failed to ioremap() registers\n");
- return -EIO;
- }
ssp->irq = dev->irq;
ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn;
ssp->type = c->type;
@@ -208,12 +243,13 @@ static void pxa2xx_spi_pci_remove(struct pci_dev *dev)
}
static const struct pci_device_id pxa2xx_spi_pci_devices[] = {
- { PCI_VDEVICE(INTEL, 0x2e6a), PORT_CE4100 },
{ PCI_VDEVICE(INTEL, 0x0935), PORT_QUARK_X1000 },
{ PCI_VDEVICE(INTEL, 0x0f0e), PORT_BYT },
+ { PCI_VDEVICE(INTEL, 0x1194), PORT_MRFLD },
{ PCI_VDEVICE(INTEL, 0x228e), PORT_BSW0 },
{ PCI_VDEVICE(INTEL, 0x2290), PORT_BSW1 },
{ PCI_VDEVICE(INTEL, 0x22ac), PORT_BSW2 },
+ { PCI_VDEVICE(INTEL, 0x2e6a), PORT_CE4100 },
{ PCI_VDEVICE(INTEL, 0x9ce6), PORT_LPT },
{ },
};
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index fe07c0592b44..87150a1049bd 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -585,7 +585,14 @@ static void reset_sccr1(struct driver_data *drv_data)
u32 sccr1_reg;
sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1;
- sccr1_reg &= ~SSCR1_RFT;
+ switch (drv_data->ssp_type) {
+ case QUARK_X1000_SSP:
+ sccr1_reg &= ~QUARK_X1000_SSCR1_RFT;
+ break;
+ default:
+ sccr1_reg &= ~SSCR1_RFT;
+ break;
+ }
sccr1_reg |= chip->threshold;
pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg);
}
@@ -912,9 +919,21 @@ static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data,
return clk_div << 8;
}
+static bool pxa2xx_spi_can_dma(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct chip_data *chip = spi_get_ctldata(spi);
+
+ return chip->enable_dma &&
+ xfer->len <= MAX_DMA_LEN &&
+ xfer->len >= chip->dma_burst_size;
+}
+
static void pump_transfers(unsigned long data)
{
struct driver_data *drv_data = (struct driver_data *)data;
+ struct spi_master *master = drv_data->master;
struct spi_message *message = NULL;
struct spi_transfer *transfer = NULL;
struct spi_transfer *previous = NULL;
@@ -928,6 +947,7 @@ static void pump_transfers(unsigned long data)
u32 dma_burst = drv_data->cur_chip->dma_burst_size;
u32 change_mask = pxa2xx_spi_get_ssrc1_change_mask(drv_data);
int err;
+ int dma_mapped;
/* Get current state information */
message = drv_data->cur_msg;
@@ -962,7 +982,7 @@ static void pump_transfers(unsigned long data)
}
/* Check if we can DMA this transfer */
- if (!pxa2xx_spi_dma_is_possible(transfer->len) && chip->enable_dma) {
+ if (transfer->len > MAX_DMA_LEN && chip->enable_dma) {
/* reject already-mapped transfers; PIO won't always work */
if (message->is_dma_mapped
@@ -1039,10 +1059,10 @@ static void pump_transfers(unsigned long data)
message->state = RUNNING_STATE;
- drv_data->dma_mapped = 0;
- if (pxa2xx_spi_dma_is_possible(drv_data->len))
- drv_data->dma_mapped = pxa2xx_spi_map_dma_buffers(drv_data);
- if (drv_data->dma_mapped) {
+ dma_mapped = master->can_dma &&
+ master->can_dma(master, message->spi, transfer) &&
+ master->cur_msg_mapped;
+ if (dma_mapped) {
/* Ensure we have the correct interrupt handler */
drv_data->transfer_handler = pxa2xx_spi_dma_transfer;
@@ -1072,14 +1092,14 @@ static void pump_transfers(unsigned long data)
cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, bits);
if (!pxa25x_ssp_comp(drv_data))
dev_dbg(&message->spi->dev, "%u Hz actual, %s\n",
- drv_data->master->max_speed_hz
+ master->max_speed_hz
/ (1 + ((cr0 & SSCR0_SCR(0xfff)) >> 8)),
- drv_data->dma_mapped ? "DMA" : "PIO");
+ dma_mapped ? "DMA" : "PIO");
else
dev_dbg(&message->spi->dev, "%u Hz actual, %s\n",
- drv_data->master->max_speed_hz / 2
+ master->max_speed_hz / 2
/ (1 + ((cr0 & SSCR0_SCR(0x0ff)) >> 8)),
- drv_data->dma_mapped ? "DMA" : "PIO");
+ dma_mapped ? "DMA" : "PIO");
if (is_lpss_ssp(drv_data)) {
if ((pxa2xx_spi_read(drv_data, SSIRF) & 0xff)
@@ -1240,7 +1260,7 @@ static int setup(struct spi_device *spi)
chip->frm = spi->chip_select;
} else
chip->gpio_cs = -1;
- chip->enable_dma = 0;
+ chip->enable_dma = drv_data->master_info->enable_dma;
chip->timeout = TIMOUT_DFLT;
}
@@ -1259,17 +1279,9 @@ static int setup(struct spi_device *spi)
tx_hi_thres = chip_info->tx_hi_threshold;
if (chip_info->rx_threshold)
rx_thres = chip_info->rx_threshold;
- chip->enable_dma = drv_data->master_info->enable_dma;
chip->dma_threshold = 0;
if (chip_info->enable_loopback)
chip->cr1 = SSCR1_LBM;
- } else if (ACPI_HANDLE(&spi->dev)) {
- /*
- * Slave devices enumerated from ACPI namespace don't
- * usually have chip_info but we still might want to use
- * DMA with them.
- */
- chip->enable_dma = drv_data->master_info->enable_dma;
}
chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres);
@@ -1389,6 +1401,9 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
/* SPT-H */
{ PCI_VDEVICE(INTEL, 0xa129), LPSS_SPT_SSP },
{ PCI_VDEVICE(INTEL, 0xa12a), LPSS_SPT_SSP },
+ /* KBL-H */
+ { PCI_VDEVICE(INTEL, 0xa2a9), LPSS_SPT_SSP },
+ { PCI_VDEVICE(INTEL, 0xa2aa), LPSS_SPT_SSP },
/* BXT A-Step */
{ PCI_VDEVICE(INTEL, 0x0ac2), LPSS_BXT_SSP },
{ PCI_VDEVICE(INTEL, 0x0ac4), LPSS_BXT_SSP },
@@ -1601,6 +1616,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
if (status) {
dev_dbg(dev, "no DMA channels available, using PIO\n");
platform_info->enable_dma = false;
+ } else {
+ master->can_dma = pxa2xx_spi_can_dma;
}
}
diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h
index e6b09000ff14..d217ad55cc12 100644
--- a/drivers/spi/spi-pxa2xx.h
+++ b/drivers/spi/spi-pxa2xx.h
@@ -50,12 +50,6 @@ struct driver_data {
struct tasklet_struct pump_transfers;
/* DMA engine support */
- struct dma_chan *rx_chan;
- struct dma_chan *tx_chan;
- struct sg_table rx_sgt;
- struct sg_table tx_sgt;
- int rx_nents;
- int tx_nents;
atomic_t dma_running;
/* Current message transfer state info */
@@ -67,7 +61,6 @@ struct driver_data {
void *tx_end;
void *rx;
void *rx_end;
- int dma_mapped;
u8 n_bytes;
int (*write)(struct driver_data *drv_data);
int (*read)(struct driver_data *drv_data);
@@ -145,8 +138,6 @@ extern void *pxa2xx_spi_next_transfer(struct driver_data *drv_data);
#define MAX_DMA_LEN SZ_64K
#define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TRAIL)
-extern bool pxa2xx_spi_dma_is_possible(size_t len);
-extern int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data);
extern irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data);
extern int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst);
extern void pxa2xx_spi_dma_start(struct driver_data *drv_data);
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 1026e180eed7..0f89c2169c24 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -142,6 +142,12 @@
/* sclk_out: spi master internal logic in rk3x can support 50Mhz */
#define MAX_SCLK_OUT 50000000
+/*
+ * SPI_CTRLR1 is 16-bits, so we should support lengths of 0xffff + 1. However,
+ * the controller seems to hang when given 0x10000, so stick with this for now.
+ */
+#define ROCKCHIP_SPI_MAX_TRANLEN 0xffff
+
enum rockchip_ssi_type {
SSI_MOTO_SPI = 0,
SSI_TI_SSP,
@@ -573,6 +579,11 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
dev_dbg(rs->dev, "cr0 0x%x, div %d\n", cr0, div);
}
+static size_t rockchip_spi_max_transfer_size(struct spi_device *spi)
+{
+ return ROCKCHIP_SPI_MAX_TRANLEN;
+}
+
static int rockchip_spi_transfer_one(
struct spi_master *master,
struct spi_device *spi,
@@ -589,6 +600,11 @@ static int rockchip_spi_transfer_one(
return -EINVAL;
}
+ if (xfer->len > ROCKCHIP_SPI_MAX_TRANLEN) {
+ dev_err(rs->dev, "Transfer is too long (%d)\n", xfer->len);
+ return -EINVAL;
+ }
+
rs->speed = xfer->speed_hz;
rs->bpw = xfer->bits_per_word;
rs->n_bytes = rs->bpw >> 3;
@@ -730,6 +746,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
master->prepare_message = rockchip_spi_prepare_message;
master->unprepare_message = rockchip_spi_unprepare_message;
master->transfer_one = rockchip_spi_transfer_one;
+ master->max_transfer_size = rockchip_spi_max_transfer_size;
master->handle_err = rockchip_spi_handle_err;
rs->dma_tx.ch = dma_request_chan(rs->dev, "tx");
@@ -894,9 +911,12 @@ static const struct dev_pm_ops rockchip_spi_pm = {
};
static const struct of_device_id rockchip_spi_dt_match[] = {
+ { .compatible = "rockchip,rk3036-spi", },
{ .compatible = "rockchip,rk3066-spi", },
{ .compatible = "rockchip,rk3188-spi", },
+ { .compatible = "rockchip,rk3228-spi", },
{ .compatible = "rockchip,rk3288-spi", },
+ { .compatible = "rockchip,rk3368-spi", },
{ .compatible = "rockchip,rk3399-spi", },
{ },
};
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 5a76a50063b5..3c09e94cf827 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -156,12 +156,14 @@ struct s3c64xx_spi_port_config {
int quirks;
bool high_speed;
bool clk_from_cmu;
+ bool clk_ioclk;
};
/**
* struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver.
* @clk: Pointer to the spi clock.
* @src_clk: Pointer to the clock used to generate SPI signals.
+ * @ioclk: Pointer to the i/o clock between master and slave
* @master: Pointer to the SPI Protocol master.
* @cntrlr_info: Platform specific data for the controller this driver manages.
* @tgl_spi: Pointer to the last CS left untoggled by the cs_change hint.
@@ -181,6 +183,7 @@ struct s3c64xx_spi_driver_data {
void __iomem *regs;
struct clk *clk;
struct clk *src_clk;
+ struct clk *ioclk;
struct platform_device *pdev;
struct spi_master *master;
struct s3c64xx_spi_info *cntrlr_info;
@@ -310,44 +313,63 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
dma_async_issue_pending(dma->ch);
}
+static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct s3c64xx_spi_driver_data *sdd =
+ spi_master_get_devdata(spi->master);
+
+ if (sdd->cntrlr_info->no_cs)
+ return;
+
+ if (enable) {
+ if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) {
+ writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ } else {
+ u32 ssel = readl(sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+
+ ssel |= (S3C64XX_SPI_SLAVE_AUTO |
+ S3C64XX_SPI_SLAVE_NSC_CNT_2);
+ writel(ssel, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ }
+ } else {
+ if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
+ writel(S3C64XX_SPI_SLAVE_SIG_INACT,
+ sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ }
+}
+
static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
{
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
dma_filter_fn filter = sdd->cntrlr_info->filter;
struct device *dev = &sdd->pdev->dev;
dma_cap_mask_t mask;
- int ret;
- if (!is_polling(sdd)) {
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
-
- /* Acquire DMA channels */
- sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter,
- sdd->cntrlr_info->dma_rx, dev, "rx");
- if (!sdd->rx_dma.ch) {
- dev_err(dev, "Failed to get RX DMA channel\n");
- ret = -EBUSY;
- goto out;
- }
- spi->dma_rx = sdd->rx_dma.ch;
-
- sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
- sdd->cntrlr_info->dma_tx, dev, "tx");
- if (!sdd->tx_dma.ch) {
- dev_err(dev, "Failed to get TX DMA channel\n");
- ret = -EBUSY;
- goto out_rx;
- }
- spi->dma_tx = sdd->tx_dma.ch;
+ if (is_polling(sdd))
+ return 0;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ /* Acquire DMA channels */
+ sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter,
+ sdd->cntrlr_info->dma_rx, dev, "rx");
+ if (!sdd->rx_dma.ch) {
+ dev_err(dev, "Failed to get RX DMA channel\n");
+ return -EBUSY;
}
+ spi->dma_rx = sdd->rx_dma.ch;
- return 0;
+ sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
+ sdd->cntrlr_info->dma_tx, dev, "tx");
+ if (!sdd->tx_dma.ch) {
+ dev_err(dev, "Failed to get TX DMA channel\n");
+ dma_release_channel(sdd->rx_dma.ch);
+ return -EBUSY;
+ }
+ spi->dma_tx = sdd->tx_dma.ch;
-out_rx:
- dma_release_channel(sdd->rx_dma.ch);
-out:
- return ret;
+ return 0;
}
static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
@@ -577,9 +599,7 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
u32 val;
/* Disable Clock */
- if (sdd->port_conf->clk_from_cmu) {
- clk_disable_unprepare(sdd->src_clk);
- } else {
+ if (!sdd->port_conf->clk_from_cmu) {
val = readl(regs + S3C64XX_SPI_CLK_CFG);
val &= ~S3C64XX_SPI_ENCLK_ENABLE;
writel(val, regs + S3C64XX_SPI_CLK_CFG);
@@ -622,11 +642,8 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
writel(val, regs + S3C64XX_SPI_MODE_CFG);
if (sdd->port_conf->clk_from_cmu) {
- /* Configure Clock */
- /* There is half-multiplier before the SPI */
+ /* The src_clk clock is divided internally by 2 */
clk_set_rate(sdd->src_clk, sdd->cur_speed * 2);
- /* Enable Clock */
- clk_prepare_enable(sdd->src_clk);
} else {
/* Configure Clock */
val = readl(regs + S3C64XX_SPI_CLK_CFG);
@@ -651,16 +668,6 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master,
struct spi_device *spi = msg->spi;
struct s3c64xx_spi_csinfo *cs = spi->controller_data;
- /* If Master's(controller) state differs from that needed by Slave */
- if (sdd->cur_speed != spi->max_speed_hz
- || sdd->cur_mode != spi->mode
- || sdd->cur_bpw != spi->bits_per_word) {
- sdd->cur_bpw = spi->bits_per_word;
- sdd->cur_speed = spi->max_speed_hz;
- sdd->cur_mode = spi->mode;
- s3c64xx_spi_config(sdd);
- }
-
/* Configure feedback delay */
writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
@@ -687,6 +694,7 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
sdd->cur_bpw = bpw;
sdd->cur_speed = speed;
+ sdd->cur_mode = spi->mode;
s3c64xx_spi_config(sdd);
}
@@ -706,12 +714,7 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
enable_datapath(sdd, spi, xfer, use_dma);
/* Start the signals */
- if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
- writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
- else
- writel(readl(sdd->regs + S3C64XX_SPI_SLAVE_SEL)
- | S3C64XX_SPI_SLAVE_AUTO | S3C64XX_SPI_SLAVE_NSC_CNT_2,
- sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ s3c64xx_spi_set_cs(spi, true);
spin_unlock_irqrestore(&sdd->lock, flags);
@@ -861,16 +864,15 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
pm_runtime_mark_last_busy(&sdd->pdev->dev);
pm_runtime_put_autosuspend(&sdd->pdev->dev);
- if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
- writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ s3c64xx_spi_set_cs(spi, false);
+
return 0;
setup_exit:
pm_runtime_mark_last_busy(&sdd->pdev->dev);
pm_runtime_put_autosuspend(&sdd->pdev->dev);
/* setup() returns with device de-selected */
- if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
- writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ s3c64xx_spi_set_cs(spi, false);
if (gpio_is_valid(spi->cs_gpio))
gpio_free(spi->cs_gpio);
@@ -944,7 +946,9 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
sdd->cur_speed = 0;
- if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
+ if (sci->no_cs)
+ writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ else if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
/* Disable Interrupts - we use Polling if not DMA mode */
@@ -999,6 +1003,8 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
sci->num_cs = temp;
}
+ sci->no_cs = of_property_read_bool(dev->of_node, "broken-cs");
+
return sci;
}
#else
@@ -1076,7 +1082,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev, "failed to get alias id, errno %d\n",
ret);
- goto err0;
+ goto err_deref_master;
}
sdd->port_id = ret;
} else {
@@ -1114,13 +1120,13 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(sdd->regs)) {
ret = PTR_ERR(sdd->regs);
- goto err0;
+ goto err_deref_master;
}
if (sci->cfg_gpio && sci->cfg_gpio()) {
dev_err(&pdev->dev, "Unable to config gpio\n");
ret = -EBUSY;
- goto err0;
+ goto err_deref_master;
}
/* Setup clocks */
@@ -1128,13 +1134,13 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
if (IS_ERR(sdd->clk)) {
dev_err(&pdev->dev, "Unable to acquire clock 'spi'\n");
ret = PTR_ERR(sdd->clk);
- goto err0;
+ goto err_deref_master;
}
- if (clk_prepare_enable(sdd->clk)) {
+ ret = clk_prepare_enable(sdd->clk);
+ if (ret) {
dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n");
- ret = -EBUSY;
- goto err0;
+ goto err_deref_master;
}
sprintf(clk_name, "spi_busclk%d", sci->src_clk_nr);
@@ -1143,13 +1149,28 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"Unable to acquire clock '%s'\n", clk_name);
ret = PTR_ERR(sdd->src_clk);
- goto err2;
+ goto err_disable_clk;
}
- if (clk_prepare_enable(sdd->src_clk)) {
+ ret = clk_prepare_enable(sdd->src_clk);
+ if (ret) {
dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", clk_name);
- ret = -EBUSY;
- goto err2;
+ goto err_disable_clk;
+ }
+
+ if (sdd->port_conf->clk_ioclk) {
+ sdd->ioclk = devm_clk_get(&pdev->dev, "spi_ioclk");
+ if (IS_ERR(sdd->ioclk)) {
+ dev_err(&pdev->dev, "Unable to acquire 'ioclk'\n");
+ ret = PTR_ERR(sdd->ioclk);
+ goto err_disable_src_clk;
+ }
+
+ ret = clk_prepare_enable(sdd->ioclk);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't enable clock 'ioclk'\n");
+ goto err_disable_src_clk;
+ }
}
pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT);
@@ -1169,7 +1190,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
if (ret != 0) {
dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n",
irq, ret);
- goto err3;
+ goto err_pm_put;
}
writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN |
@@ -1179,7 +1200,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
ret = devm_spi_register_master(&pdev->dev, master);
if (ret != 0) {
dev_err(&pdev->dev, "cannot register SPI master: %d\n", ret);
- goto err3;
+ goto err_pm_put;
}
dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n",
@@ -1193,15 +1214,17 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
return 0;
-err3:
+err_pm_put:
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
+ clk_disable_unprepare(sdd->ioclk);
+err_disable_src_clk:
clk_disable_unprepare(sdd->src_clk);
-err2:
+err_disable_clk:
clk_disable_unprepare(sdd->clk);
-err0:
+err_deref_master:
spi_master_put(master);
return ret;
@@ -1209,13 +1232,15 @@ err0:
static int s3c64xx_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
+ struct spi_master *master = platform_get_drvdata(pdev);
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
pm_runtime_get_sync(&pdev->dev);
writel(0, sdd->regs + S3C64XX_SPI_INT_EN);
+ clk_disable_unprepare(sdd->ioclk);
+
clk_disable_unprepare(sdd->src_clk);
clk_disable_unprepare(sdd->clk);
@@ -1274,6 +1299,7 @@ static int s3c64xx_spi_runtime_suspend(struct device *dev)
clk_disable_unprepare(sdd->clk);
clk_disable_unprepare(sdd->src_clk);
+ clk_disable_unprepare(sdd->ioclk);
return 0;
}
@@ -1284,17 +1310,28 @@ static int s3c64xx_spi_runtime_resume(struct device *dev)
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
int ret;
+ if (sdd->port_conf->clk_ioclk) {
+ ret = clk_prepare_enable(sdd->ioclk);
+ if (ret != 0)
+ return ret;
+ }
+
ret = clk_prepare_enable(sdd->src_clk);
if (ret != 0)
- return ret;
+ goto err_disable_ioclk;
ret = clk_prepare_enable(sdd->clk);
- if (ret != 0) {
- clk_disable_unprepare(sdd->src_clk);
- return ret;
- }
+ if (ret != 0)
+ goto err_disable_src_clk;
return 0;
+
+err_disable_src_clk:
+ clk_disable_unprepare(sdd->src_clk);
+err_disable_ioclk:
+ clk_disable_unprepare(sdd->ioclk);
+
+ return ret;
}
#endif /* CONFIG_PM */
@@ -1350,6 +1387,16 @@ static struct s3c64xx_spi_port_config exynos7_spi_port_config = {
.quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
};
+static struct s3c64xx_spi_port_config exynos5433_spi_port_config = {
+ .fifo_lvl_mask = { 0x1ff, 0x7f, 0x7f, 0x7f, 0x7f, 0x1ff},
+ .rx_lvl_offset = 15,
+ .tx_st_done = 25,
+ .high_speed = true,
+ .clk_from_cmu = true,
+ .clk_ioclk = true,
+ .quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
+};
+
static const struct platform_device_id s3c64xx_spi_driver_ids[] = {
{
.name = "s3c2443-spi",
@@ -1380,6 +1427,9 @@ static const struct of_device_id s3c64xx_spi_dt_match[] = {
{ .compatible = "samsung,exynos7-spi",
.data = (void *)&exynos7_spi_port_config,
},
+ { .compatible = "samsung,exynos5433-spi",
+ .data = (void *)&exynos5433_spi_port_config,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match);
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index a7934ab00b96..0f83ad1d5a58 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -45,7 +45,6 @@ struct sh_msiof_spi_priv {
void __iomem *mapbase;
struct clk *clk;
struct platform_device *pdev;
- const struct sh_msiof_chipdata *chipdata;
struct sh_msiof_spi_info *info;
struct completion done;
unsigned int tx_fifo_size;
@@ -271,7 +270,7 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
scr = sh_msiof_spi_div_table[k].brdv | SCR_BRPS(brps);
sh_msiof_write(p, TSCR, scr);
- if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX))
+ if (!(p->master->flags & SPI_MASTER_MUST_TX))
sh_msiof_write(p, RSCR, scr);
}
@@ -336,7 +335,7 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
tmp |= lsb_first << MDR1_BITLSB_SHIFT;
tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p);
sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
- if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) {
+ if (p->master->flags & SPI_MASTER_MUST_TX) {
/* These bits are reserved if RX needs TX */
tmp &= ~0x0000ffff;
}
@@ -360,7 +359,7 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p,
{
u32 dr2 = MDR2_BITLEN1(bits) | MDR2_WDLEN1(words);
- if (tx_buf || (p->chipdata->master_flags & SPI_MASTER_MUST_TX))
+ if (tx_buf || (p->master->flags & SPI_MASTER_MUST_TX))
sh_msiof_write(p, TMDR2, dr2);
else
sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1);
@@ -1152,6 +1151,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
{
struct resource *r;
struct spi_master *master;
+ const struct sh_msiof_chipdata *chipdata;
const struct of_device_id *of_id;
struct sh_msiof_spi_priv *p;
int i;
@@ -1170,10 +1170,10 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
of_id = of_match_device(sh_msiof_match, &pdev->dev);
if (of_id) {
- p->chipdata = of_id->data;
+ chipdata = of_id->data;
p->info = sh_msiof_spi_parse_dt(&pdev->dev);
} else {
- p->chipdata = (const void *)pdev->id_entry->driver_data;
+ chipdata = (const void *)pdev->id_entry->driver_data;
p->info = dev_get_platdata(&pdev->dev);
}
@@ -1217,8 +1217,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
/* Platform data may override FIFO sizes */
- p->tx_fifo_size = p->chipdata->tx_fifo_size;
- p->rx_fifo_size = p->chipdata->rx_fifo_size;
+ p->tx_fifo_size = chipdata->tx_fifo_size;
+ p->rx_fifo_size = chipdata->rx_fifo_size;
if (p->info->tx_fifo_override)
p->tx_fifo_size = p->info->tx_fifo_override;
if (p->info->rx_fifo_override)
@@ -1227,7 +1227,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
/* init master code */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE;
- master->flags = p->chipdata->master_flags;
+ master->flags = chipdata->master_flags;
master->bus_num = pdev->id;
master->dev.of_node = pdev->dev.of_node;
master->num_chipselect = p->info->num_chipselect;
diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c
index 502501187c9e..2bf53f0e27d9 100644
--- a/drivers/spi/spi-sh.c
+++ b/drivers/spi/spi-sh.c
@@ -82,7 +82,6 @@ struct spi_sh_data {
int irq;
struct spi_master *master;
struct list_head queue;
- struct workqueue_struct *workqueue;
struct work_struct ws;
unsigned long cr1;
wait_queue_head_t wait;
@@ -380,7 +379,7 @@ static int spi_sh_transfer(struct spi_device *spi, struct spi_message *mesg)
spi_sh_clear_bit(ss, SPI_SH_SSA, SPI_SH_CR1);
list_add_tail(&mesg->queue, &ss->queue);
- queue_work(ss->workqueue, &ss->ws);
+ schedule_work(&ss->ws);
spin_unlock_irqrestore(&ss->lock, flags);
@@ -425,7 +424,7 @@ static int spi_sh_remove(struct platform_device *pdev)
struct spi_sh_data *ss = platform_get_drvdata(pdev);
spi_unregister_master(ss->master);
- destroy_workqueue(ss->workqueue);
+ flush_work(&ss->ws);
free_irq(ss->irq, ss);
return 0;
@@ -484,18 +483,11 @@ static int spi_sh_probe(struct platform_device *pdev)
spin_lock_init(&ss->lock);
INIT_WORK(&ss->ws, spi_sh_work);
init_waitqueue_head(&ss->wait);
- ss->workqueue = create_singlethread_workqueue(
- dev_name(master->dev.parent));
- if (ss->workqueue == NULL) {
- dev_err(&pdev->dev, "create workqueue error\n");
- ret = -EBUSY;
- goto error1;
- }
ret = request_irq(irq, spi_sh_irq, 0, "spi_sh", ss);
if (ret < 0) {
dev_err(&pdev->dev, "request_irq error\n");
- goto error2;
+ goto error1;
}
master->num_chipselect = 2;
@@ -514,8 +506,6 @@ static int spi_sh_probe(struct platform_device *pdev)
error3:
free_irq(irq, ss);
- error2:
- destroy_workqueue(ss->workqueue);
error1:
spi_master_put(master);
diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index cf007f3b83ec..4969dc10684a 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -167,6 +167,11 @@ static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
}
+static size_t sun4i_spi_max_transfer_size(struct spi_device *spi)
+{
+ return SUN4I_FIFO_DEPTH - 1;
+}
+
static int sun4i_spi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *tfr)
@@ -402,6 +407,8 @@ static int sun4i_spi_probe(struct platform_device *pdev)
}
sspi->master = master;
+ master->max_speed_hz = 100 * 1000 * 1000;
+ master->min_speed_hz = 3 * 1000;
master->set_cs = sun4i_spi_set_cs;
master->transfer_one = sun4i_spi_transfer_one;
master->num_chipselect = 4;
@@ -409,6 +416,7 @@ static int sun4i_spi_probe(struct platform_device *pdev)
master->bits_per_word_mask = SPI_BPW_MASK(8);
master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true;
+ master->max_transfer_size = sun4i_spi_max_transfer_size;
sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(sspi->hclk)) {
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 7fce79a60608..9918a57a6a6e 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -153,6 +153,10 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
}
+static size_t sun6i_spi_max_transfer_size(struct spi_device *spi)
+{
+ return SUN6I_FIFO_DEPTH - 1;
+}
static int sun6i_spi_transfer_one(struct spi_master *master,
struct spi_device *spi,
@@ -394,6 +398,8 @@ static int sun6i_spi_probe(struct platform_device *pdev)
}
sspi->master = master;
+ master->max_speed_hz = 100 * 1000 * 1000;
+ master->min_speed_hz = 3 * 1000;
master->set_cs = sun6i_spi_set_cs;
master->transfer_one = sun6i_spi_transfer_one;
master->num_chipselect = 4;
@@ -401,6 +407,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
master->bits_per_word_mask = SPI_BPW_MASK(8);
master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true;
+ master->max_transfer_size = sun6i_spi_max_transfer_size;
sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(sspi->hclk)) {
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
index 29ea8d2f9824..ac0b072815a3 100644
--- a/drivers/spi/spi-ti-qspi.c
+++ b/drivers/spi/spi-ti-qspi.c
@@ -141,7 +141,7 @@ static int ti_qspi_setup(struct spi_device *spi)
u32 clk_ctrl_reg, clk_rate, clk_mask;
if (spi->master->busy) {
- dev_dbg(qspi->dev, "master busy doing other trasnfers\n");
+ dev_dbg(qspi->dev, "master busy doing other transfers\n");
return -EBUSY;
}
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index 93dfcee0f987..c54ee6674471 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -133,8 +133,6 @@ struct pch_spi_dma_ctrl {
* @io_remap_addr: The remapped PCI base address
* @master: Pointer to the SPI master structure
* @work: Reference to work queue handler
- * @wk: Workqueue for carrying out execution of the
- * requests
* @wait: Wait queue for waking up upon receiving an
* interrupt.
* @transfer_complete: Status of SPI Transfer
@@ -169,7 +167,6 @@ struct pch_spi_data {
unsigned long io_base_addr;
struct spi_master *master;
struct work_struct work;
- struct workqueue_struct *wk;
wait_queue_head_t wait;
u8 transfer_complete;
u8 bcurrent_msg_processing;
@@ -517,8 +514,7 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
dev_dbg(&pspi->dev, "%s - Invoked list_add_tail\n", __func__);
- /* schedule work queue to run */
- queue_work(data->wk, &data->work);
+ schedule_work(&data->work);
dev_dbg(&pspi->dev, "%s - Invoked queue work\n", __func__);
retval = 0;
@@ -674,7 +670,7 @@ static void pch_spi_nomore_transfer(struct pch_spi_data *data)
*more messages)
*/
dev_dbg(&data->master->dev, "%s:Invoke queue_work\n", __func__);
- queue_work(data->wk, &data->work);
+ schedule_work(&data->work);
} else if (data->board_dat->suspend_sts ||
data->status == STATUS_EXITING) {
dev_dbg(&data->master->dev,
@@ -1266,14 +1262,7 @@ static void pch_spi_free_resources(struct pch_spi_board_data *board_dat,
{
dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__);
- /* free workqueue */
- if (data->wk != NULL) {
- destroy_workqueue(data->wk);
- data->wk = NULL;
- dev_dbg(&board_dat->pdev->dev,
- "%s destroy_workqueue invoked successfully\n",
- __func__);
- }
+ flush_work(&data->work);
}
static int pch_spi_get_resources(struct pch_spi_board_data *board_dat,
@@ -1283,14 +1272,6 @@ static int pch_spi_get_resources(struct pch_spi_board_data *board_dat,
dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__);
- /* create workqueue */
- data->wk = create_singlethread_workqueue(KBUILD_MODNAME);
- if (!data->wk) {
- dev_err(&board_dat->pdev->dev,
- "%s create_singlet hread_workqueue failed\n", __func__);
- retval = -EBUSY;
- goto err_return;
- }
/* reset PCH SPI h/w */
pch_spi_reset(data->master);
@@ -1299,7 +1280,6 @@ static int pch_spi_get_resources(struct pch_spi_board_data *board_dat,
dev_dbg(&board_dat->pdev->dev, "%s data->irq_reg_sts=true\n", __func__);
-err_return:
if (retval != 0) {
dev_err(&board_dat->pdev->dev,
"%s FAIL:invoking pch_spi_free_resources\n", __func__);
diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c
index d69f8f8f3fa6..7492ea346b43 100644
--- a/drivers/spi/spi-txx9.c
+++ b/drivers/spi/spi-txx9.c
@@ -72,7 +72,6 @@
struct txx9spi {
- struct workqueue_struct *workqueue;
struct work_struct work;
spinlock_t lock; /* protect 'queue' */
struct list_head queue;
@@ -315,7 +314,7 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
spin_lock_irqsave(&c->lock, flags);
list_add_tail(&m->queue, &c->queue);
- queue_work(c->workqueue, &c->work);
+ schedule_work(&c->work);
spin_unlock_irqrestore(&c->lock, flags);
return 0;
@@ -374,10 +373,6 @@ static int txx9spi_probe(struct platform_device *dev)
if (ret)
goto exit;
- c->workqueue = create_singlethread_workqueue(
- dev_name(master->dev.parent));
- if (!c->workqueue)
- goto exit_busy;
c->last_chipselect = -1;
dev_info(&dev->dev, "at %#llx, irq %d, %dMHz\n",
@@ -400,8 +395,6 @@ static int txx9spi_probe(struct platform_device *dev)
exit_busy:
ret = -EBUSY;
exit:
- if (c->workqueue)
- destroy_workqueue(c->workqueue);
clk_disable(c->clk);
spi_master_put(master);
return ret;
@@ -412,7 +405,7 @@ static int txx9spi_remove(struct platform_device *dev)
struct spi_master *master = platform_get_drvdata(dev);
struct txx9spi *c = spi_master_get_devdata(master);
- destroy_workqueue(c->workqueue);
+ flush_work(&c->work);
clk_disable(c->clk);
return 0;
}
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 3009121173cd..bc7100b93dfc 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -341,9 +341,10 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */
complete(&xspi->done);
+ return IRQ_HANDLED;
}
- return IRQ_HANDLED;
+ return IRQ_NONE;
}
static int xilinx_spi_find_buffer_size(struct xilinx_spi *xspi)
@@ -455,7 +456,10 @@ static int xilinx_spi_probe(struct platform_device *pdev)
xspi->buffer_size = xilinx_spi_find_buffer_size(xspi);
xspi->irq = platform_get_irq(pdev, 0);
- if (xspi->irq >= 0) {
+ if (xspi->irq < 0 && xspi->irq != -ENXIO) {
+ ret = xspi->irq;
+ goto put_master;
+ } else if (xspi->irq >= 0) {
/* Register for SPI Interrupt */
ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
dev_name(&pdev->dev), xspi);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 7589c8af4368..51ad42fad567 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -851,6 +851,20 @@ static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
return 0;
}
#else /* !CONFIG_HAS_DMA */
+static inline int spi_map_buf(struct spi_master *master,
+ struct device *dev, struct sg_table *sgt,
+ void *buf, size_t len,
+ enum dma_data_direction dir)
+{
+ return -EINVAL;
+}
+
+static inline void spi_unmap_buf(struct spi_master *master,
+ struct device *dev, struct sg_table *sgt,
+ enum dma_data_direction dir)
+{
+}
+
static inline int __spi_map_msg(struct spi_master *master,
struct spi_message *msg)
{
@@ -1057,7 +1071,6 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
* __spi_pump_messages - function which processes spi message queue
* @master: master to process queue for
* @in_kthread: true if we are in the context of the message pump thread
- * @bus_locked: true if the bus mutex is held when calling this function
*
* This function checks if there is any spi message in the queue that
* needs processing and if so call out to the driver to initialize hardware
@@ -1067,8 +1080,7 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
* inside spi_sync(); the queue extraction handling at the top of the
* function should deal with this safely.
*/
-static void __spi_pump_messages(struct spi_master *master, bool in_kthread,
- bool bus_locked)
+static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
{
unsigned long flags;
bool was_busy = false;
@@ -1140,6 +1152,8 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread,
master->busy = true;
spin_unlock_irqrestore(&master->queue_lock, flags);
+ mutex_lock(&master->io_mutex);
+
if (!was_busy && master->auto_runtime_pm) {
ret = pm_runtime_get_sync(master->dev.parent);
if (ret < 0) {
@@ -1164,9 +1178,6 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread,
}
}
- if (!bus_locked)
- mutex_lock(&master->bus_lock_mutex);
-
trace_spi_message_start(master->cur_msg);
if (master->prepare_message) {
@@ -1196,8 +1207,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread,
}
out:
- if (!bus_locked)
- mutex_unlock(&master->bus_lock_mutex);
+ mutex_unlock(&master->io_mutex);
/* Prod the scheduler in case transfer_one() was busy waiting */
if (!ret)
@@ -1213,7 +1223,7 @@ static void spi_pump_messages(struct kthread_work *work)
struct spi_master *master =
container_of(work, struct spi_master, pump_messages);
- __spi_pump_messages(master, true, master->bus_lock_flag);
+ __spi_pump_messages(master, true);
}
static int spi_init_queue(struct spi_master *master)
@@ -1886,6 +1896,7 @@ int spi_register_master(struct spi_master *master)
spin_lock_init(&master->queue_lock);
spin_lock_init(&master->bus_lock_spinlock);
mutex_init(&master->bus_lock_mutex);
+ mutex_init(&master->io_mutex);
master->bus_lock_flag = 0;
init_completion(&master->xfer_completion);
if (!master->max_dma_len)
@@ -2738,6 +2749,7 @@ int spi_flash_read(struct spi_device *spi,
{
struct spi_master *master = spi->master;
+ struct device *rx_dev = NULL;
int ret;
if ((msg->opcode_nbits == SPI_NBITS_DUAL ||
@@ -2763,9 +2775,24 @@ int spi_flash_read(struct spi_device *spi,
return ret;
}
}
+
mutex_lock(&master->bus_lock_mutex);
+ mutex_lock(&master->io_mutex);
+ if (master->dma_rx) {
+ rx_dev = master->dma_rx->device->dev;
+ ret = spi_map_buf(master, rx_dev, &msg->rx_sg,
+ msg->buf, msg->len,
+ DMA_FROM_DEVICE);
+ if (!ret)
+ msg->cur_msg_mapped = true;
+ }
ret = master->spi_flash_read(spi, msg);
+ if (msg->cur_msg_mapped)
+ spi_unmap_buf(master, rx_dev, &msg->rx_sg,
+ DMA_FROM_DEVICE);
+ mutex_unlock(&master->io_mutex);
mutex_unlock(&master->bus_lock_mutex);
+
if (master->auto_runtime_pm)
pm_runtime_put(master->dev.parent);
@@ -2785,8 +2812,7 @@ static void spi_complete(void *arg)
complete(arg);
}
-static int __spi_sync(struct spi_device *spi, struct spi_message *message,
- int bus_locked)
+static int __spi_sync(struct spi_device *spi, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done);
int status;
@@ -2804,9 +2830,6 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_sync);
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync);
- if (!bus_locked)
- mutex_lock(&master->bus_lock_mutex);
-
/* If we're not using the legacy transfer method then we will
* try to transfer in the calling context so special case.
* This code would be less tricky if we could remove the
@@ -2824,9 +2847,6 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
status = spi_async_locked(spi, message);
}
- if (!bus_locked)
- mutex_unlock(&master->bus_lock_mutex);
-
if (status == 0) {
/* Push out the messages in the calling context if we
* can.
@@ -2836,7 +2856,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
spi_sync_immediate);
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics,
spi_sync_immediate);
- __spi_pump_messages(master, false, bus_locked);
+ __spi_pump_messages(master, false);
}
wait_for_completion(&done);
@@ -2869,7 +2889,13 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
*/
int spi_sync(struct spi_device *spi, struct spi_message *message)
{
- return __spi_sync(spi, message, spi->master->bus_lock_flag);
+ int ret;
+
+ mutex_lock(&spi->master->bus_lock_mutex);
+ ret = __spi_sync(spi, message);
+ mutex_unlock(&spi->master->bus_lock_mutex);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(spi_sync);
@@ -2891,7 +2917,7 @@ EXPORT_SYMBOL_GPL(spi_sync);
*/
int spi_sync_locked(struct spi_device *spi, struct spi_message *message)
{
- return __spi_sync(spi, message, 1);
+ return __spi_sync(spi, message);
}
EXPORT_SYMBOL_GPL(spi_sync_locked);
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index e3c19f30f591..2e05046f866b 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -29,6 +29,7 @@
#include <linux/compat.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/acpi.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
@@ -700,6 +701,43 @@ static const struct of_device_id spidev_dt_ids[] = {
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
#endif
+#ifdef CONFIG_ACPI
+
+/* Dummy SPI devices not to be used in production systems */
+#define SPIDEV_ACPI_DUMMY 1
+
+static const struct acpi_device_id spidev_acpi_ids[] = {
+ /*
+ * The ACPI SPT000* devices are only meant for development and
+ * testing. Systems used in production should have a proper ACPI
+ * description of the connected peripheral and they should also use
+ * a proper driver instead of poking directly to the SPI bus.
+ */
+ { "SPT0001", SPIDEV_ACPI_DUMMY },
+ { "SPT0002", SPIDEV_ACPI_DUMMY },
+ { "SPT0003", SPIDEV_ACPI_DUMMY },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, spidev_acpi_ids);
+
+static void spidev_probe_acpi(struct spi_device *spi)
+{
+ const struct acpi_device_id *id;
+
+ if (!has_acpi_companion(&spi->dev))
+ return;
+
+ id = acpi_match_device(spidev_acpi_ids, &spi->dev);
+ if (WARN_ON(!id))
+ return;
+
+ if (id->driver_data == SPIDEV_ACPI_DUMMY)
+ dev_warn(&spi->dev, "do not use this driver in production systems!\n");
+}
+#else
+static inline void spidev_probe_acpi(struct spi_device *spi) {}
+#endif
+
/*-------------------------------------------------------------------------*/
static int spidev_probe(struct spi_device *spi)
@@ -719,6 +757,8 @@ static int spidev_probe(struct spi_device *spi)
!of_match_device(spidev_dt_ids, &spi->dev));
}
+ spidev_probe_acpi(spi);
+
/* Allocate driver data */
spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
if (!spidev)
@@ -789,6 +829,7 @@ static struct spi_driver spidev_spi_driver = {
.driver = {
.name = "spidev",
.of_match_table = of_match_ptr(spidev_dt_ids),
+ .acpi_match_table = ACPI_PTR(spidev_acpi_ids),
},
.probe = spidev_probe,
.remove = spidev_remove,
diff --git a/include/linux/platform_data/spi-s3c64xx.h b/include/linux/platform_data/spi-s3c64xx.h
index fb5625bcca9a..5c1e21c87270 100644
--- a/include/linux/platform_data/spi-s3c64xx.h
+++ b/include/linux/platform_data/spi-s3c64xx.h
@@ -38,6 +38,7 @@ struct s3c64xx_spi_csinfo {
struct s3c64xx_spi_info {
int src_clk_nr;
int num_cs;
+ bool no_cs;
int (*cfg_gpio)(void);
dma_filter_fn filter;
void *dma_tx;
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 1f03483f61e5..072cb2aa2413 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -312,8 +312,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @flags: other constraints relevant to this driver
* @max_transfer_size: function that returns the max transfer size for
* a &spi_device; may be %NULL, so the default %SIZE_MAX will be used.
+ * @io_mutex: mutex for physical bus access
* @bus_lock_spinlock: spinlock for SPI bus locking
- * @bus_lock_mutex: mutex for SPI bus locking
+ * @bus_lock_mutex: mutex for exclusion of multiple callers
* @bus_lock_flag: indicates that the SPI bus is locked for exclusive use
* @setup: updates the device mode and clocking records used by a
* device's SPI controller; protocol code may call this. This
@@ -446,6 +447,9 @@ struct spi_master {
*/
size_t (*max_transfer_size)(struct spi_device *spi);
+ /* I/O mutex */
+ struct mutex io_mutex;
+
/* lock and mutex for SPI bus locking */
spinlock_t bus_lock_spinlock;
struct mutex bus_lock_mutex;
@@ -1143,6 +1147,8 @@ static inline ssize_t spi_w8r16be(struct spi_device *spi, u8 cmd)
* @opcode_nbits: number of lines to send opcode
* @addr_nbits: number of lines to send address
* @data_nbits: number of lines for data
+ * @rx_sg: Scatterlist for receive data read from flash
+ * @cur_msg_mapped: message has been mapped for DMA
*/
struct spi_flash_read_message {
void *buf;
@@ -1155,6 +1161,8 @@ struct spi_flash_read_message {
u8 opcode_nbits;
u8 addr_nbits;
u8 data_nbits;
+ struct sg_table rx_sg;
+ bool cur_msg_mapped;
};
/* SPI core interface for flash read support */