summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-04-01 13:23:53 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-01 13:23:53 -0700
commitc12ac9f98ec08d6eb69f84e3f72241d56a8b0822 (patch)
tree8c749a097e54a93e22b0a099c38d60135022a221
parent3786075b5ebc8c4eaefd9e3ebf72883934fb64b3 (diff)
parent45b15d98a96ffdb3c608bdad952f51930c151420 (diff)
Merge tag 'spi-v3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi Updates from Mark Brown: "A busy release for both cleanups and new drivers this time along with further factoring out of replicated code into the core: - Provide support in the core for DMA mapping transfers - essentially all drivers weren't implementing this properly, now there's no excuse. - Dual and quad mode support for spidev. - Fix handling of cs_change in the generic implementation. - Remove the S3C_DMA code from the s3c64xx driver now that all the platforms using it have been converted to dmaengine. - Lots of improvements to the Renesas SPI controllers. - Drivers for Allwinner A10 and A31, Qualcomm QUP and Xylinx xtfpga. - Removal of the bitrotted ti-ssp driver" * tag 'spi-v3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (199 commits) spi: Fix handling of cs_change in core implementation spi: bitbang: Make spi_bitbang_stop() return void spi: mpc52xx: Convert to use bits_per_word_mask spi: omap-100k: Fix memory leak spi: dw: Don't call kfree for memory allocated by devm_kzalloc spi: fsl-dspi: Fix memory leak spi: omap-uwire: add missing iounmap spi: clps711x: Convert to use master->max_speed_hz spi: clps711x: Enable driver compilation with COMPILE_TEST spi: omap-uwire: Remove full duplex check spi: Do not require a completion spi: topcliff-pch: Transform noisy message to dev_vdbg spi: coldfire-qspi: Simplify the code to set register bits for transfer speed spi: bcm63xx: Remove unused define for PFX spi: efm32: use $vendor,$device scheme for compatible string spi: clps711x: Remove <mach/hardware.h> dependency spi: topcliff-pch: Properly unregister platform devices on probe() error paths spi: fsl-espi: Remove unused bits_per_word variable in fsl_espi_bufs spi: altera: Remove the code to get unused platform_data spi: fsl-lib: Fix memory leak of pinfo ...
-rw-r--r--Documentation/devicetree/bindings/spi/efm32-spi.txt8
-rw-r--r--Documentation/devicetree/bindings/spi/qcom,spi-qup.txt85
-rw-r--r--Documentation/devicetree/bindings/spi/sh-hspi.txt28
-rw-r--r--Documentation/devicetree/bindings/spi/sh-msiof.txt42
-rw-r--r--Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt2
-rw-r--r--Documentation/devicetree/bindings/spi/spi-rspi.txt61
-rw-r--r--Documentation/devicetree/bindings/spi/spi-sun4i.txt24
-rw-r--r--Documentation/devicetree/bindings/spi/spi-sun6i.txt24
-rw-r--r--Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt9
-rw-r--r--Documentation/spi/spidev6
-rw-r--r--Documentation/spi/spidev_fdx.c8
-rw-r--r--Documentation/spi/spidev_test.c45
-rw-r--r--MAINTAINERS6
-rw-r--r--drivers/spi/Kconfig55
-rw-r--r--drivers/spi/Makefile5
-rw-r--r--drivers/spi/spi-altera.c7
-rw-r--r--drivers/spi/spi-ath79.c1
-rw-r--r--drivers/spi/spi-atmel.c34
-rw-r--r--drivers/spi/spi-au1550.c30
-rw-r--r--drivers/spi/spi-bcm2835.c1
-rw-r--r--drivers/spi/spi-bcm63xx-hsspi.c8
-rw-r--r--drivers/spi/spi-bcm63xx.c6
-rw-r--r--drivers/spi/spi-bfin-sport.c1
-rw-r--r--drivers/spi/spi-bfin-v3.c3
-rw-r--r--drivers/spi/spi-bfin5xx.c8
-rw-r--r--drivers/spi/spi-bitbang.c5
-rw-r--r--drivers/spi/spi-butterfly.c3
-rw-r--r--drivers/spi/spi-clps711x.c227
-rw-r--r--drivers/spi/spi-coldfire-qspi.c112
-rw-r--r--drivers/spi/spi-davinci.c14
-rw-r--r--drivers/spi/spi-dw-mmio.c2
-rw-r--r--drivers/spi/spi-dw.c17
-rw-r--r--drivers/spi/spi-efm32.c46
-rw-r--r--drivers/spi/spi-ep93xx.c21
-rw-r--r--drivers/spi/spi-falcon.c5
-rw-r--r--drivers/spi/spi-fsl-dspi.c94
-rw-r--r--drivers/spi/spi-fsl-espi.c5
-rw-r--r--drivers/spi/spi-fsl-lib.c14
-rw-r--r--drivers/spi/spi-fsl-spi.c30
-rw-r--r--drivers/spi/spi-gpio.c8
-rw-r--r--drivers/spi/spi-imx.c7
-rw-r--r--drivers/spi/spi-mpc512x-psc.c17
-rw-r--r--drivers/spi/spi-mpc52xx-psc.c1
-rw-r--r--drivers/spi/spi-mpc52xx.c17
-rw-r--r--drivers/spi/spi-mxs.c7
-rw-r--r--drivers/spi/spi-nuc900.c28
-rw-r--r--drivers/spi/spi-oc-tiny.c3
-rw-r--r--drivers/spi/spi-octeon.c80
-rw-r--r--drivers/spi/spi-omap-100k.c52
-rw-r--r--drivers/spi/spi-omap-uwire.c34
-rw-r--r--drivers/spi/spi-omap2-mcspi.c65
-rw-r--r--drivers/spi/spi-orion.c80
-rw-r--r--drivers/spi/spi-pl022.c80
-rw-r--r--drivers/spi/spi-ppc4xx.c1
-rw-r--r--drivers/spi/spi-pxa2xx-dma.c1
-rw-r--r--drivers/spi/spi-pxa2xx-pxadma.c1
-rw-r--r--drivers/spi/spi-pxa2xx.c3
-rw-r--r--drivers/spi/spi-qup.c779
-rw-r--r--drivers/spi/spi-rspi.c842
-rw-r--r--drivers/spi/spi-s3c24xx.c19
-rw-r--r--drivers/spi/spi-s3c64xx.c424
-rw-r--r--drivers/spi/spi-sc18is602.c29
-rw-r--r--drivers/spi/spi-sh-hspi.c43
-rw-r--r--drivers/spi/spi-sh-msiof.c385
-rw-r--r--drivers/spi/spi-sh-sci.c8
-rw-r--r--drivers/spi/spi-sirf.c116
-rw-r--r--drivers/spi/spi-sun4i.c478
-rw-r--r--drivers/spi/spi-sun6i.c484
-rw-r--r--drivers/spi/spi-tegra114.c27
-rw-r--r--drivers/spi/spi-tegra20-sflash.c26
-rw-r--r--drivers/spi/spi-tegra20-slink.c20
-rw-r--r--drivers/spi/spi-ti-qspi.c5
-rw-r--r--drivers/spi/spi-ti-ssp.c378
-rw-r--r--drivers/spi/spi-topcliff-pch.c47
-rw-r--r--drivers/spi/spi-txx9.c25
-rw-r--r--drivers/spi/spi-xcomm.c13
-rw-r--r--drivers/spi/spi-xilinx.c27
-rw-r--r--drivers/spi/spi-xtensa-xtfpga.c170
-rw-r--r--drivers/spi/spi.c247
-rw-r--r--drivers/spi/spidev.c23
-rw-r--r--include/linux/platform_data/spi-s3c64xx.h9
-rw-r--r--include/linux/spi/spi.h31
-rw-r--r--include/linux/spi/spi_bitbang.h2
-rw-r--r--include/uapi/linux/spi/spidev.h14
84 files changed, 4001 insertions, 2257 deletions
diff --git a/Documentation/devicetree/bindings/spi/efm32-spi.txt b/Documentation/devicetree/bindings/spi/efm32-spi.txt
index a590ca51be7..8f081c96a4f 100644
--- a/Documentation/devicetree/bindings/spi/efm32-spi.txt
+++ b/Documentation/devicetree/bindings/spi/efm32-spi.txt
@@ -3,24 +3,24 @@
Required properties:
- #address-cells: see spi-bus.txt
- #size-cells: see spi-bus.txt
-- compatible: should be "efm32,spi"
+- compatible: should be "energymicro,efm32-spi"
- reg: Offset and length of the register set for the controller
- interrupts: pair specifying rx and tx irq
- clocks: phandle to the spi clock
- cs-gpios: see spi-bus.txt
-- location: Value to write to the ROUTE register's LOCATION bitfield to configure the pinmux for the device, see datasheet for values.
+- efm32,location: Value to write to the ROUTE register's LOCATION bitfield to configure the pinmux for the device, see datasheet for values.
Example:
spi1: spi@0x4000c400 { /* USART1 */
#address-cells = <1>;
#size-cells = <0>;
- compatible = "efm32,spi";
+ compatible = "energymicro,efm32-spi";
reg = <0x4000c400 0x400>;
interrupts = <15 16>;
clocks = <&cmu 20>;
cs-gpios = <&gpio 51 1>; // D3
- location = <1>;
+ efm32,location = <1>;
status = "ok";
ks8851@0 {
diff --git a/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt b/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt
new file mode 100644
index 00000000000..b82a268f1bd
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt
@@ -0,0 +1,85 @@
+Qualcomm Universal Peripheral (QUP) Serial Peripheral Interface (SPI)
+
+The QUP core is an AHB slave that provides a common data path (an output FIFO
+and an input FIFO) for serial peripheral interface (SPI) mini-core.
+
+SPI in master mode supports up to 50MHz, up to four chip selects, programmable
+data path from 4 bits to 32 bits and numerous protocol variants.
+
+Required properties:
+- compatible: Should contain "qcom,spi-qup-v2.1.1" or "qcom,spi-qup-v2.2.1"
+- reg: Should contain base register location and length
+- interrupts: Interrupt number used by this controller
+
+- clocks: Should contain the core clock and the AHB clock.
+- clock-names: Should be "core" for the core clock and "iface" for the
+ AHB clock.
+
+- #address-cells: Number of cells required to define a chip select
+ address on the SPI bus. Should be set to 1.
+- #size-cells: Should be zero.
+
+Optional properties:
+- spi-max-frequency: Specifies maximum SPI clock frequency,
+ Units - Hz. Definition as per
+ Documentation/devicetree/bindings/spi/spi-bus.txt
+
+SPI slave nodes must be children of the SPI master node and can contain
+properties described in Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Example:
+
+ spi_8: spi@f9964000 { /* BLSP2 QUP2 */
+
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xf9964000 0x1000>;
+ interrupts = <0 102 0>;
+ spi-max-frequency = <19200000>;
+
+ clocks = <&gcc GCC_BLSP2_QUP2_SPI_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
+ clock-names = "core", "iface";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi8_default>;
+
+ device@0 {
+ compatible = "arm,pl022-dummy";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <19200000>;
+ spi-cpol;
+ };
+
+ device@1 {
+ compatible = "arm,pl022-dummy";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <1>; /* Chip select 1 */
+ spi-max-frequency = <9600000>;
+ spi-cpha;
+ };
+
+ device@2 {
+ compatible = "arm,pl022-dummy";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <2>; /* Chip select 2 */
+ spi-max-frequency = <19200000>;
+ spi-cpol;
+ spi-cpha;
+ };
+
+ device@3 {
+ compatible = "arm,pl022-dummy";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <3>; /* Chip select 3 */
+ spi-max-frequency = <19200000>;
+ spi-cpol;
+ spi-cpha;
+ spi-cs-high;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/spi/sh-hspi.txt b/Documentation/devicetree/bindings/spi/sh-hspi.txt
index 30b57b1c8a1..319bad4af87 100644
--- a/Documentation/devicetree/bindings/spi/sh-hspi.txt
+++ b/Documentation/devicetree/bindings/spi/sh-hspi.txt
@@ -1,7 +1,29 @@
Renesas HSPI.
Required properties:
-- compatible : "renesas,hspi"
-- reg : Offset and length of the register set for the device
-- interrupts : interrupt line used by HSPI
+- compatible : "renesas,hspi-<soctype>", "renesas,hspi" as fallback.
+ Examples with soctypes are:
+ - "renesas,hspi-r8a7778" (R-Car M1)
+ - "renesas,hspi-r8a7779" (R-Car H1)
+- reg : Offset and length of the register set for the device
+- interrupt-parent : The phandle for the interrupt controller that
+ services interrupts for this device
+- interrupts : Interrupt specifier
+- #address-cells : Must be <1>
+- #size-cells : Must be <0>
+
+Pinctrl properties might be needed, too. See
+Documentation/devicetree/bindings/pinctrl/renesas,*.
+
+Example:
+
+ hspi0: spi@fffc7000 {
+ compatible = "renesas,hspi-r8a7778", "renesas,hspi";
+ reg = <0xfffc7000 0x18>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 63 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt
index e6222106ca3..f24baf3b6cc 100644
--- a/Documentation/devicetree/bindings/spi/sh-msiof.txt
+++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt
@@ -1,12 +1,40 @@
Renesas MSIOF spi controller
Required properties:
-- compatible : "renesas,sh-msiof" for SuperH or
- "renesas,sh-mobile-msiof" for SH Mobile series
-- reg : Offset and length of the register set for the device
-- interrupts : interrupt line used by MSIOF
+- compatible : "renesas,msiof-<soctype>" for SoCs,
+ "renesas,sh-msiof" for SuperH, or
+ "renesas,sh-mobile-msiof" for SH Mobile series.
+ Examples with soctypes are:
+ "renesas,msiof-r8a7790" (R-Car H2)
+ "renesas,msiof-r8a7791" (R-Car M2)
+- reg : Offset and length of the register set for the device
+- interrupt-parent : The phandle for the interrupt controller that
+ services interrupts for this device
+- interrupts : Interrupt specifier
+- #address-cells : Must be <1>
+- #size-cells : Must be <0>
Optional properties:
-- num-cs : total number of chip-selects
-- renesas,tx-fifo-size : Overrides the default tx fifo size given in words
-- renesas,rx-fifo-size : Overrides the default rx fifo size given in words
+- clocks : Must contain a reference to the functional clock.
+- num-cs : Total number of chip-selects (default is 1)
+
+Optional properties, deprecated for soctype-specific bindings:
+- renesas,tx-fifo-size : Overrides the default tx fifo size given in words
+ (default is 64)
+- renesas,rx-fifo-size : Overrides the default rx fifo size given in words
+ (default is 64, or 256 on R-Car H2 and M2)
+
+Pinctrl properties might be needed, too. See
+Documentation/devicetree/bindings/pinctrl/renesas,*.
+
+Example:
+
+ msiof0: spi@e6e20000 {
+ compatible = "renesas,msiof-r8a7791";
+ reg = <0 0xe6e20000 0 0x0064>;
+ interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
index a1fb3035a42..5376de40f10 100644
--- a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
+++ b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
@@ -10,6 +10,7 @@ Required properties:
- pinctrl-names: must contain a "default" entry.
- spi-num-chipselects : the number of the chipselect signals.
- bus-num : the slave chip chipselect signal number.
+- big-endian : if DSPI modudle is big endian, the bool will be set in node.
Example:
dspi0@4002c000 {
@@ -24,6 +25,7 @@ dspi0@4002c000 {
bus-num = <0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_dspi0_1>;
+ big-endian;
status = "okay";
sflash: at26df081a@0 {
diff --git a/Documentation/devicetree/bindings/spi/spi-rspi.txt b/Documentation/devicetree/bindings/spi/spi-rspi.txt
new file mode 100644
index 00000000000..d57d82a7405
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-rspi.txt
@@ -0,0 +1,61 @@
+Device tree configuration for Renesas RSPI/QSPI driver
+
+Required properties:
+- compatible : For Renesas Serial Peripheral Interface on legacy SH:
+ "renesas,rspi-<soctype>", "renesas,rspi" as fallback.
+ For Renesas Serial Peripheral Interface on RZ/A1H:
+ "renesas,rspi-<soctype>", "renesas,rspi-rz" as fallback.
+ For Quad Serial Peripheral Interface on R-Car Gen2:
+ "renesas,qspi-<soctype>", "renesas,qspi" as fallback.
+ Examples with soctypes are:
+ - "renesas,rspi-sh7757" (SH)
+ - "renesas,rspi-r7s72100" (RZ/A1H)
+ - "renesas,qspi-r8a7790" (R-Car H2)
+ - "renesas,qspi-r8a7791" (R-Car M2)
+- reg : Address start and address range size of the device
+- interrupts : A list of interrupt-specifiers, one for each entry in
+ interrupt-names.
+ If interrupt-names is not present, an interrupt specifier
+ for a single muxed interrupt.
+- interrupt-names : A list of interrupt names. Should contain (if present):
+ - "error" for SPEI,
+ - "rx" for SPRI,
+ - "tx" to SPTI,
+ - "mux" for a single muxed interrupt.
+- interrupt-parent : The phandle for the interrupt controller that
+ services interrupts for this device.
+- num-cs : Number of chip selects. Some RSPI cores have more than 1.
+- #address-cells : Must be <1>
+- #size-cells : Must be <0>
+
+Optional properties:
+- clocks : Must contain a reference to the functional clock.
+
+Pinctrl properties might be needed, too. See
+Documentation/devicetree/bindings/pinctrl/renesas,*.
+
+Examples:
+
+ spi0: spi@e800c800 {
+ compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
+ reg = <0xe800c800 0x24>;
+ interrupts = <0 238 IRQ_TYPE_LEVEL_HIGH>,
+ <0 239 IRQ_TYPE_LEVEL_HIGH>,
+ <0 240 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error", "rx", "tx";
+ interrupt-parent = <&gic>;
+ num-cs = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ spi: spi@e6b10000 {
+ compatible = "renesas,qspi-r8a7791", "renesas,qspi";
+ reg = <0 0xe6b10000 0 0x2c>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7791_CLK_QSPI_MOD>;
+ num-cs = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/spi/spi-sun4i.txt b/Documentation/devicetree/bindings/spi/spi-sun4i.txt
new file mode 100644
index 00000000000..de827f5a301
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-sun4i.txt
@@ -0,0 +1,24 @@
+Allwinner A10 SPI controller
+
+Required properties:
+- compatible: Should be "allwinner,sun4-a10-spi".
+- reg: Should contain register location and length.
+- interrupts: Should contain interrupt.
+- clocks: phandle to the clocks feeding the SPI controller. Two are
+ needed:
+ - "ahb": the gated AHB parent clock
+ - "mod": the parent module clock
+- clock-names: Must contain the clock names described just above
+
+Example:
+
+spi1: spi@01c06000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c06000 0x1000>;
+ interrupts = <11>;
+ clocks = <&ahb_gates 21>, <&spi1_clk>;
+ clock-names = "ahb", "mod";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/spi/spi-sun6i.txt b/Documentation/devicetree/bindings/spi/spi-sun6i.txt
new file mode 100644
index 00000000000..21de73db6a0
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-sun6i.txt
@@ -0,0 +1,24 @@
+Allwinner A31 SPI controller
+
+Required properties:
+- compatible: Should be "allwinner,sun6i-a31-spi".
+- reg: Should contain register location and length.
+- interrupts: Should contain interrupt.
+- clocks: phandle to the clocks feeding the SPI controller. Two are
+ needed:
+ - "ahb": the gated AHB parent clock
+ - "mod": the parent module clock
+- clock-names: Must contain the clock names described just above
+- resets: phandle to the reset controller asserting this device in
+ reset
+
+Example:
+
+spi1: spi@01c69000 {
+ compatible = "allwinner,sun6i-a31-spi";
+ reg = <0x01c69000 0x1000>;
+ interrupts = <0 66 4>;
+ clocks = <&ahb1_gates 21>, <&spi1_clk>;
+ clock-names = "ahb", "mod";
+ resets = <&ahb1_rst 21>;
+};
diff --git a/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt b/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt
new file mode 100644
index 00000000000..b6ebe2bc704
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt
@@ -0,0 +1,9 @@
+Cadence Xtensa XTFPGA platform SPI controller.
+
+This simple SPI master controller is built into xtfpga bitstreams and is used
+to control daughterboard audio codec.
+
+Required properties:
+- compatible: should be "cdns,xtfpga-spi".
+- reg: physical base address of the controller and length of memory mapped
+ region.
diff --git a/Documentation/spi/spidev b/Documentation/spi/spidev
index ed2da5e5b28..3d14035b176 100644
--- a/Documentation/spi/spidev
+++ b/Documentation/spi/spidev
@@ -85,6 +85,12 @@ settings for data transfer parameters:
SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL
(clock polarity, idle high iff this is set) or SPI_CPHA (clock phase,
sample on trailing edge iff this is set) flags.
+ Note that this request is limited to SPI mode flags that fit in a
+ single byte.
+
+ SPI_IOC_RD_MODE32, SPI_IOC_WR_MODE32 ... pass a pointer to a uin32_t
+ which will return (RD) or assign (WR) the full SPI transfer mode,
+ not limited to the bits that fit in one byte.
SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte
which will return (RD) or assign (WR) the bit justification used to
diff --git a/Documentation/spi/spidev_fdx.c b/Documentation/spi/spidev_fdx.c
index 36ec0774ca0..0ea3e51292f 100644
--- a/Documentation/spi/spidev_fdx.c
+++ b/Documentation/spi/spidev_fdx.c
@@ -78,10 +78,10 @@ static void do_msg(int fd, int len)
static void dumpstat(const char *name, int fd)
{
- __u8 mode, lsb, bits;
- __u32 speed;
+ __u8 lsb, bits;
+ __u32 mode, speed;
- if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) {
+ if (ioctl(fd, SPI_IOC_RD_MODE32, &mode) < 0) {
perror("SPI rd_mode");
return;
}
@@ -98,7 +98,7 @@ static void dumpstat(const char *name, int fd)
return;
}
- printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n",
+ printf("%s: spi mode 0x%x, %d bits %sper word, %d Hz max\n",
name, mode, bits, lsb ? "(lsb first) " : "", speed);
}
diff --git a/Documentation/spi/spidev_test.c b/Documentation/spi/spidev_test.c
index 16feda90146..3a2f9d59eda 100644
--- a/Documentation/spi/spidev_test.c
+++ b/Documentation/spi/spidev_test.c
@@ -30,7 +30,7 @@ static void pabort(const char *s)
}
static const char *device = "/dev/spidev1.1";
-static uint8_t mode;
+static uint32_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;
@@ -57,6 +57,21 @@ static void transfer(int fd)
.bits_per_word = bits,
};
+ if (mode & SPI_TX_QUAD)
+ tr.tx_nbits = 4;
+ else if (mode & SPI_TX_DUAL)
+ tr.tx_nbits = 2;
+ if (mode & SPI_RX_QUAD)
+ tr.rx_nbits = 4;
+ else if (mode & SPI_RX_DUAL)
+ tr.rx_nbits = 2;
+ if (!(mode & SPI_LOOP)) {
+ if (mode & (SPI_TX_QUAD | SPI_TX_DUAL))
+ tr.rx_buf = 0;
+ else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL))
+ tr.tx_buf = 0;
+ }
+
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message");
@@ -81,7 +96,11 @@ static void print_usage(const char *prog)
" -O --cpol clock polarity\n"
" -L --lsb least significant bit first\n"
" -C --cs-high chip select active high\n"
- " -3 --3wire SI/SO signals shared\n");
+ " -3 --3wire SI/SO signals shared\n"
+ " -N --no-cs no chip select\n"
+ " -R --ready slave pulls low to pause\n"
+ " -2 --dual dual transfer\n"
+ " -4 --quad quad transfer\n");
exit(1);
}
@@ -101,11 +120,13 @@ static void parse_opts(int argc, char *argv[])
{ "3wire", 0, 0, '3' },
{ "no-cs", 0, 0, 'N' },
{ "ready", 0, 0, 'R' },
+ { "dual", 0, 0, '2' },
+ { "quad", 0, 0, '4' },
{ NULL, 0, 0, 0 },
};
int c;
- c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);
+ c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24", lopts, NULL);
if (c == -1)
break;
@@ -147,11 +168,23 @@ static void parse_opts(int argc, char *argv[])
case 'R':
mode |= SPI_READY;
break;
+ case '2':
+ mode |= SPI_TX_DUAL;
+ break;
+ case '4':
+ mode |= SPI_TX_QUAD;
+ break;
default:
print_usage(argv[0]);
break;
}
}
+ if (mode & SPI_LOOP) {
+ if (mode & SPI_TX_DUAL)
+ mode |= SPI_RX_DUAL;
+ if (mode & SPI_TX_QUAD)
+ mode |= SPI_RX_QUAD;
+ }
}
int main(int argc, char *argv[])
@@ -168,11 +201,11 @@ int main(int argc, char *argv[])
/*
* spi mode
*/
- ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
+ ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
pabort("can't set spi mode");
- ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
+ ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
if (ret == -1)
pabort("can't get spi mode");
@@ -198,7 +231,7 @@ int main(int argc, char *argv[])
if (ret == -1)
pabort("can't get max speed hz");
- printf("spi mode: %d\n", mode);
+ printf("spi mode: 0x%x\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
diff --git a/MAINTAINERS b/MAINTAINERS
index eea871fdb8f..5fe2c0d6612 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9809,6 +9809,12 @@ L: linux-serial@vger.kernel.org
S: Maintained
F: drivers/tty/serial/uartlite.c
+XTENSA XTFPGA PLATFORM SUPPORT
+M: Max Filippov <jcmvbkbc@gmail.com>
+L: linux-xtensa@linux-xtensa.org
+S: Maintained
+F: drivers/spi/spi-xtensa-xtfpga.c
+
YAM DRIVER FOR AX.25
M: Jean-Paul Roubelat <jpr@f6fbb.org>
L: linux-hams@vger.kernel.org
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 581ee2a8856..efe1960af2b 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -150,7 +150,7 @@ config SPI_BUTTERFLY
config SPI_CLPS711X
tristate "CLPS711X host SPI controller"
- depends on ARCH_CLPS711X
+ depends on ARCH_CLPS711X || COMPILE_TEST
help
This enables dedicated general purpose SPI/Microwire1-compatible
master mode interface (SSI1) for CLPS711X-based CPUs.
@@ -212,7 +212,6 @@ config SPI_IMX
tristate "Freescale i.MX SPI controllers"
depends on ARCH_MXC || COMPILE_TEST
select SPI_BITBANG
- default m if IMX_HAVE_PLATFORM_SPI_IMX
help
This enables using the Freescale i.MX SPI controllers in master
mode.
@@ -270,6 +269,7 @@ config SPI_FSL_SPI
config SPI_FSL_DSPI
tristate "Freescale DSPI controller"
select SPI_BITBANG
+ select REGMAP_MMIO
depends on SOC_VF610 || COMPILE_TEST
help
This enables support for the Freescale DSPI controller in master
@@ -307,7 +307,7 @@ config SPI_OMAP_UWIRE
config SPI_OMAP24XX
tristate "McSPI driver for OMAP"
- depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SH
+ depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SUPERH
depends on ARCH_OMAP2PLUS || COMPILE_TEST
help
SPI master controller for OMAP24XX and later Multichannel SPI
@@ -381,6 +381,19 @@ config SPI_RSPI
help
SPI driver for Renesas RSPI and QSPI blocks.
+config SPI_QUP
+ tristate "Qualcomm SPI controller with QUP interface"
+ depends on ARCH_MSM_DT || (ARM && COMPILE_TEST)
+ help
+ Qualcomm Universal Peripheral (QUP) core is an AHB slave that
+ provides a common data path (an output FIFO and an input FIFO)
+ for serial peripheral interface (SPI) mini-core. SPI in master
+ mode supports up to 50MHz, up to four chip selects, programmable
+ data path from 4 bits to 32 bits and numerous protocol variants.
+
+ This driver can also be built as a module. If so, the module
+ will be called spi_qup.
+
config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI"
depends on ARCH_S3C24XX
@@ -416,7 +429,6 @@ config SPI_SH_MSIOF
tristate "SuperH MSIOF SPI controller"
depends on HAVE_CLK
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
- select SPI_BITBANG
help
SPI driver for SuperH and SH Mobile MSIOF blocks.
@@ -446,6 +458,19 @@ config SPI_SIRF
help
SPI driver for CSR SiRFprimaII SoCs
+config SPI_SUN4I
+ tristate "Allwinner A10 SoCs SPI controller"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ help
+ SPI driver for Allwinner sun4i, sun5i and sun7i SoCs
+
+config SPI_SUN6I
+ tristate "Allwinner A31 SPI controller"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ depends on RESET_CONTROLLER
+ help
+ This enables using the SPI controller on the Allwinner A31 SoCs.
+
config SPI_MXS
tristate "Freescale MXS SPI controller"
depends on ARCH_MXS
@@ -478,13 +503,6 @@ config SPI_TEGRA20_SLINK
help
SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
-config SPI_TI_SSP
- tristate "TI Sequencer Serial Port - SPI Support"
- depends on MFD_TI_SSP
- help
- This selects an SPI master implementation using a TI sequencer
- serial port.
-
config SPI_TOPCLIFF_PCH
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI"
depends on PCI
@@ -520,6 +538,19 @@ config SPI_XILINX
Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
+config SPI_XTENSA_XTFPGA
+ tristate "Xtensa SPI controller for xtfpga"
+ depends on (XTENSA && XTENSA_PLATFORM_XTFPGA) || COMPILE_TEST
+ select SPI_BITBANG
+ help
+ SPI driver for xtfpga SPI master controller.
+
+ This simple SPI master controller is built into xtfpga bitstreams
+ and is used to control daughterboard audio codec. It always transfers
+ 16 bit words in SPI mode 0, automatically asserting CS on transfer
+ start and deasserting on end.
+
+
config SPI_NUC900
tristate "Nuvoton NUC900 series SPI"
depends on ARCH_W90X900
@@ -546,7 +577,7 @@ config SPI_DW_MID_DMA
config SPI_DW_MMIO
tristate "Memory-mapped io interface driver for DW SPI core"
- depends on SPI_DESIGNWARE && HAVE_CLK
+ depends on SPI_DESIGNWARE
#
# There are lots of SPI device types, with sensors and memory
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 95af48d2d36..bd792669e56 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -59,6 +59,7 @@ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA) += spi-pxa2xx-pxadma.o
spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o
obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
+obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
spi-s3c24xx-hw-y := spi-s3c24xx.o
@@ -70,12 +71,14 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
+obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
+obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o
obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o
obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o
-obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o
obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
+obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o
diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c
index 5d7deaf6286..5b5709a5c95 100644
--- a/drivers/spi/spi-altera.c
+++ b/drivers/spi/spi-altera.c
@@ -13,7 +13,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/module.h>
@@ -200,7 +199,6 @@ static irqreturn_t altera_spi_irq(int irq, void *dev)
static int altera_spi_probe(struct platform_device *pdev)
{
- struct altera_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
struct altera_spi *hw;
struct spi_master *master;
struct resource *res;
@@ -214,6 +212,8 @@ static int altera_spi_probe(struct platform_device *pdev)
master->bus_num = pdev->id;
master->num_chipselect = 16;
master->mode_bits = SPI_CS_HIGH;
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
+ master->dev.of_node = pdev->dev.of_node;
hw = spi_master_get_devdata(master);
platform_set_drvdata(pdev, hw);
@@ -245,9 +245,6 @@ static int altera_spi_probe(struct platform_device *pdev)
if (err)
goto exit;
}
- /* find platform data */
- if (!platp)
- hw->bitbang.master->dev.of_node = pdev->dev.of_node;
/* register our spi controller */
err = spi_bitbang_start(&hw->bitbang);
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index c3b2fb9b671..3898b0b9ee7 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 5d7b07f0832..8005f986948 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -9,7 +9,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -26,6 +25,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
/* SPI register offsets */
#define SPI_CR 0x0000
@@ -993,13 +993,6 @@ static int atmel_spi_setup(struct spi_device *spi)
as = spi_master_get_devdata(spi->master);
- if (spi->chip_select > spi->master->num_chipselect) {
- dev_dbg(&spi->dev,
- "setup: invalid chipselect %u (%u defined)\n",
- spi->chip_select, spi->master->num_chipselect);
- return -EINVAL;
- }
-
/* see notes above re chipselect */
if (!atmel_spi_is_v2(as)
&& spi->chip_select == 0
@@ -1087,14 +1080,6 @@ static int atmel_spi_one_transfer(struct spi_master *master,
}
}
- if (xfer->bits_per_word > 8) {
- if (xfer->len % 2) {
- dev_dbg(&spi->dev,
- "buffer len should be 16 bits aligned\n");
- return -EINVAL;
- }
- }
-
/*
* DMA map early, for performance (empties dcache ASAP) and
* better fault reporting.
@@ -1221,9 +1206,6 @@ static int atmel_spi_transfer_one_message(struct spi_master *master,
dev_dbg(&spi->dev, "new message %p submitted for %s\n",
msg, dev_name(&spi->dev));
- if (unlikely(list_empty(&msg->transfers)))
- return -EINVAL;
-
atmel_spi_lock(as);
cs_activate(as, spi);
@@ -1244,10 +1226,10 @@ static int atmel_spi_transfer_one_message(struct spi_master *master,
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
dev_dbg(&spi->dev,
- " xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+ " xfer %p: len %u tx %p/%pad rx %p/%pad\n",
xfer, xfer->len,
- xfer->tx_buf, xfer->tx_dma,
- xfer->rx_buf, xfer->rx_dma);
+ xfer->tx_buf, &xfer->tx_dma,
+ xfer->rx_buf, &xfer->rx_dma);
}
msg_done:
@@ -1303,6 +1285,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
struct spi_master *master;
struct atmel_spi *as;
+ /* Select default pin state */
+ pinctrl_pm_select_default_state(&pdev->dev);
+
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
return -ENXIO;
@@ -1465,6 +1450,9 @@ static int atmel_spi_suspend(struct device *dev)
}
clk_disable_unprepare(as->clk);
+
+ pinctrl_pm_select_sleep_state(dev);
+
return 0;
}
@@ -1474,6 +1462,8 @@ static int atmel_spi_resume(struct device *dev)
struct atmel_spi *as = spi_master_get_devdata(master);
int ret;
+ pinctrl_pm_select_default_state(dev);
+
clk_prepare_enable(as->clk);
/* Start the queue running */
diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c
index c4141c92bcf..aafb812d7ea 100644
--- a/drivers/spi/spi-au1550.c
+++ b/drivers/spi/spi-au1550.c
@@ -55,8 +55,6 @@ struct au1550_spi {
volatile psc_spi_t __iomem *regs;
int irq;
- unsigned freq_max;
- unsigned freq_min;
unsigned len;
unsigned tx_count;
@@ -248,11 +246,8 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
hz = t->speed_hz;
}
- if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {
- dev_err(&spi->dev, "setupxfer: clock rate=%d out of range\n",
- hz);
+ if (!hz)
return -EINVAL;
- }
au1550_spi_bits_handlers_set(hw, spi->bits_per_word);
@@ -287,23 +282,6 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
return 0;
}
-static int au1550_spi_setup(struct spi_device *spi)
-{
- struct au1550_spi *hw = spi_master_get_devdata(spi->master);
-
- if (spi->max_speed_hz == 0)
- spi->max_speed_hz = hw->freq_max;
- if (spi->max_speed_hz > hw->freq_max
- || spi->max_speed_hz < hw->freq_min)
- return -EINVAL;
- /*
- * NOTE: cannot change speed and other hw settings immediately,
- * otherwise sharing of spi bus is not possible,
- * so do not call setupxfer(spi, NULL) here
- */
- return 0;
-}
-
/*
* for dma spi transfers, we have to setup rx channel, otherwise there is
* no reliable way how to recognize that spi transfer is done
@@ -838,7 +816,6 @@ static int au1550_spi_probe(struct platform_device *pdev)
hw->bitbang.master = hw->master;
hw->bitbang.setup_transfer = au1550_spi_setupxfer;
hw->bitbang.chipselect = au1550_spi_chipsel;
- hw->bitbang.master->setup = au1550_spi_setup;
hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs;
if (hw->usedma) {
@@ -909,8 +886,9 @@ static int au1550_spi_probe(struct platform_device *pdev)
{
int min_div = (2 << 0) * (2 * (4 + 1));
int max_div = (2 << 3) * (2 * (63 + 1));
- hw->freq_max = hw->pdata->mainclk_hz / min_div;
- hw->freq_min = hw->pdata->mainclk_hz / (max_div + 1) + 1;
+ master->max_speed_hz = hw->pdata->mainclk_hz / min_div;
+ master->min_speed_hz =
+ hw->pdata->mainclk_hz / (max_div + 1) + 1;
}
au1550_spi_setup_psc_as_spi(hw);
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 8a89dd1f265..69167456ec1 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -315,7 +315,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
master->mode_bits = BCM2835_SPI_MODE_BITS;
master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->bus_num = -1;
master->num_chipselect = 3;
master->transfer_one_message = bcm2835_spi_transfer_one;
master->dev.of_node = pdev->dev.of_node;
diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c
index b528f9fc8bc..5a211e98383 100644
--- a/drivers/spi/spi-bcm63xx-hsspi.c
+++ b/drivers/spi/spi-bcm63xx-hsspi.c
@@ -180,7 +180,7 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
while (pending > 0) {
int curr_step = min_t(int, step_size, pending);
- init_completion(&bs->done);
+ reinit_completion(&bs->done);
if (tx) {
memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, tx, curr_step);
tx += curr_step;
@@ -369,6 +369,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0));
mutex_init(&bs->bus_mutex);
+ init_completion(&bs->done);
master->bus_num = HSSPI_BUS_NUM;
master->num_chipselect = 8;
@@ -453,9 +454,8 @@ static int bcm63xx_hsspi_resume(struct device *dev)
}
#endif
-static const struct dev_pm_ops bcm63xx_hsspi_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(bcm63xx_hsspi_suspend, bcm63xx_hsspi_resume)
-};
+static SIMPLE_DEV_PM_OPS(bcm63xx_hsspi_pm_ops, bcm63xx_hsspi_suspend,
+ bcm63xx_hsspi_resume);
static struct platform_driver bcm63xx_hsspi_driver = {
.driver = {
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index 77286aef2ad..0250fa721ce 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -20,7 +20,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -35,8 +34,6 @@
#include <bcm63xx_dev_spi.h>
-#define PFX KBUILD_MODNAME
-
#define BCM63XX_SPI_MAX_PREPEND 15
struct bcm63xx_spi {
@@ -169,7 +166,7 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
transfer_list);
}
- init_completion(&bs->done);
+ reinit_completion(&bs->done);
/* Fill in the Message control register */
msg_ctl = (len << SPI_BYTE_CNT_SHIFT);
@@ -353,6 +350,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
}
bs = spi_master_get_devdata(master);
+ init_completion(&bs->done);
platform_set_drvdata(pdev, master);
bs->pdev = pdev;
diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c
index 38941e5920b..f515c5e9db5 100644
--- a/drivers/spi/spi-bfin-sport.c
+++ b/drivers/spi/spi-bfin-sport.c
@@ -8,7 +8,6 @@
* Licensed under the GPL-2 or later.
*/
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>
diff --git a/drivers/spi/spi-bfin-v3.c b/drivers/spi/spi-bfin-v3.c
index 8f8598834b3..4089d0e0d84 100644
--- a/drivers/spi/spi-bfin-v3.c
+++ b/drivers/spi/spi-bfin-v3.c
@@ -822,7 +822,8 @@ static int bfin_spi_probe(struct platform_device *pdev)
master->cleanup = bfin_spi_cleanup;
master->setup = bfin_spi_setup;
master->transfer_one_message = bfin_spi_transfer_one_message;
- master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1);
+ master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
+ SPI_BPW_MASK(8);
drv_data = spi_master_get_devdata(master);
drv_data->master = master;
diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c
index f0f195af75d..55e57c3eb9b 100644
--- a/drivers/spi/spi-bfin5xx.c
+++ b/drivers/spi/spi-bfin5xx.c
@@ -350,7 +350,6 @@ static void *bfin_spi_next_transfer(struct bfin_spi_master_data *drv_data)
static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data)
{
struct bfin_spi_slave_data *chip = drv_data->cur_chip;
- struct spi_transfer *last_transfer;
unsigned long flags;
struct spi_message *msg;
@@ -362,9 +361,6 @@ static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data)
queue_work(drv_data->workqueue, &drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags);
- last_transfer = list_entry(msg->transfers.prev,
- struct spi_transfer, transfer_list);
-
msg->state = NULL;
if (!drv_data->cs_change)
@@ -1030,10 +1026,6 @@ static int bfin_spi_setup(struct spi_device *spi)
}
/* translate common spi framework into our register */
- if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
- dev_err(&spi->dev, "unsupported spi modes detected\n");
- goto error;
- }
if (spi->mode & SPI_CPOL)
chip->ctl_reg |= BIT_CTL_CPOL;
if (spi->mode & SPI_CPHA)
diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c
index bd222f6b677..dc7d2c2d643 100644
--- a/drivers/spi/spi-bitbang.c
+++ b/drivers/spi/spi-bitbang.c
@@ -16,7 +16,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
@@ -467,11 +466,9 @@ EXPORT_SYMBOL_GPL(spi_bitbang_start);
/**
* spi_bitbang_stop - stops the task providing spi communication
*/
-int spi_bitbang_stop(struct spi_bitbang *bitbang)
+void spi_bitbang_stop(struct spi_bitbang *bitbang)
{
spi_unregister_master(bitbang->master);
-
- return 0;
}
EXPORT_SYMBOL_GPL(spi_bitbang_stop);
diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c
index 8081f96bd1d..ee4f91ccd8f 100644
--- a/drivers/spi/spi-butterfly.c
+++ b/drivers/spi/spi-butterfly.c
@@ -309,7 +309,6 @@ done:
static void butterfly_detach(struct parport *p)
{
struct butterfly *pp;
- int status;
/* FIXME this global is ugly ... but, how to quickly get from
* the parport to the "struct butterfly" associated with it?
@@ -321,7 +320,7 @@ static void butterfly_detach(struct parport *p)
butterfly = NULL;
/* stop() unregisters child devices too */
- status = spi_bitbang_stop(&pp->bitbang);
+ spi_bitbang_stop(&pp->bitbang);
/* turn off VCC */
parport_write_data(pp->port, 0);
diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c
index 374ba4a48a9..4cd62f63654 100644
--- a/drivers/spi/spi-clps711x.c
+++ b/drivers/spi/spi-clps711x.c
@@ -11,158 +11,125 @@
#include <linux/io.h>
#include <linux/clk.h>
-#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/clps711x.h>
#include <linux/spi/spi.h>
#include <linux/platform_data/spi-clps711x.h>
-#include <mach/hardware.h>
-
#define DRIVER_NAME "spi-clps711x"
-struct spi_clps711x_data {
- struct completion done;
+#define SYNCIO_FRMLEN(x) ((x) << 8)
+#define SYNCIO_TXFRMEN (1 << 14)
+struct spi_clps711x_data {
+ void __iomem *syncio;
+ struct regmap *syscon;
+ struct regmap *syscon1;
struct clk *spi_clk;
- u32 max_speed_hz;
u8 *tx_buf;
u8 *rx_buf;
- int count;
+ unsigned int bpw;
int len;
-
- int chipselect[0];
};
static int spi_clps711x_setup(struct spi_device *spi)
{
- struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
-
/* We are expect that SPI-device is not selected */
- gpio_direction_output(hw->chipselect[spi->chip_select],
- !(spi->mode & SPI_CS_HIGH));
+ gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
return 0;
}
-static void spi_clps711x_setup_mode(struct spi_device *spi)
-{
- /* Setup edge for transfer */
- if (spi->mode & SPI_CPHA)
- clps_writew(clps_readw(SYSCON3) | SYSCON3_ADCCKNSEN, SYSCON3);
- else
- clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCKNSEN, SYSCON3);
-}
-
-static int spi_clps711x_setup_xfer(struct spi_device *spi,
- struct spi_transfer *xfer)
+static void spi_clps711x_setup_xfer(struct spi_device *spi,
+ struct spi_transfer *xfer)
{
- u32 speed = xfer->speed_hz ? : spi->max_speed_hz;
- u8 bpw = xfer->bits_per_word;
- struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
-
- if (bpw != 8) {
- dev_err(&spi->dev, "Unsupported master bus width %i\n", bpw);
- return -EINVAL;
- }
+ struct spi_master *master = spi->master;
+ struct spi_clps711x_data *hw = spi_master_get_devdata(master);
/* Setup SPI frequency divider */
- if (!speed || (speed >= hw->max_speed_hz))
- clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
- SYSCON1_ADCKSEL(3), SYSCON1);
- else if (speed >= (hw->max_speed_hz / 2))
- clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
- SYSCON1_ADCKSEL(2), SYSCON1);
- else if (speed >= (hw->max_speed_hz / 8))
- clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
- SYSCON1_ADCKSEL(1), SYSCON1);
+ if (xfer->speed_hz >= master->max_speed_hz)
+ regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+ SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(3));
+ else if (xfer->speed_hz >= (master->max_speed_hz / 2))
+ regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+ SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(2));
+ else if (xfer->speed_hz >= (master->max_speed_hz / 8))
+ regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+ SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(1));
else
- clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
- SYSCON1_ADCKSEL(0), SYSCON1);
-
- return 0;
+ regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
+ SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(0));
}
-static int spi_clps711x_transfer_one_message(struct spi_master *master,
- struct spi_message *msg)
+static int spi_clps711x_prepare_message(struct spi_master *master,
+ struct spi_message *msg)
{
struct spi_clps711x_data *hw = spi_master_get_devdata(master);
- struct spi_transfer *xfer;
- int status = 0, cs = hw->chipselect[msg->spi->chip_select];
- u32 data;
-
- spi_clps711x_setup_mode(msg->spi);
-
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- if (spi_clps711x_setup_xfer(msg->spi, xfer)) {
- status = -EINVAL;
- goto out_xfr;
- }
+ struct spi_device *spi = msg->spi;
- gpio_set_value(cs, !!(msg->spi->mode & SPI_CS_HIGH));
-
- reinit_completion(&hw->done);
-
- hw->count = 0;
- hw->len = xfer->len;
- hw->tx_buf = (u8 *)xfer->tx_buf;
- hw->rx_buf = (u8 *)xfer->rx_buf;
-
- /* Initiate transfer */
- data = hw->tx_buf ? hw->tx_buf[hw->count] : 0;
- clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
-
- wait_for_completion(&hw->done);
+ /* Setup mode for transfer */
+ return regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCKNSEN,
+ (spi->mode & SPI_CPHA) ?
+ SYSCON3_ADCCKNSEN : 0);
+}
- if (xfer->delay_usecs)
- udelay(xfer->delay_usecs);
+static int spi_clps711x_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+ u8 data;
- if (xfer->cs_change ||
- list_is_last(&xfer->transfer_list, &msg->transfers))
- gpio_set_value(cs, !(msg->spi->mode & SPI_CS_HIGH));
+ spi_clps711x_setup_xfer(spi, xfer);
- msg->actual_length += xfer->len;
- }
+ hw->len = xfer->len;
+ hw->bpw = xfer->bits_per_word;
+ hw->tx_buf = (u8 *)xfer->tx_buf;
+ hw->rx_buf = (u8 *)xfer->rx_buf;
-out_xfr:
- msg->status = status;
- spi_finalize_current_message(master);
+ /* Initiate transfer */
+ data = hw->tx_buf ? *hw->tx_buf++ : 0;
+ writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, hw->syncio);
- return 0;
+ return 1;
}
static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
{
- struct spi_clps711x_data *hw = (struct spi_clps711x_data *)dev_id;
- u32 data;
+ struct spi_master *master = dev_id;
+ struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+ u8 data;
/* Handle RX */
- data = clps_readb(SYNCIO);
+ data = readb(hw->syncio);
if (hw->rx_buf)
- hw->rx_buf[hw->count] = (u8)data;
-
- hw->count++;
+ *hw->rx_buf++ = data;
/* Handle TX */
- if (hw->count < hw->len) {
- data = hw->tx_buf ? hw->tx_buf[hw->count] : 0;
- clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
+ if (--hw->len > 0) {
+ data = hw->tx_buf ? *hw->tx_buf++ : 0;
+ writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN,
+ hw->syncio);
} else
- complete(&hw->done);
+ spi_finalize_current_transfer(master);
return IRQ_HANDLED;
}
static int spi_clps711x_probe(struct platform_device *pdev)
{
- int i, ret;
- struct spi_master *master;
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");
@@ -174,33 +141,37 @@ static int spi_clps711x_probe(struct platform_device *pdev)
return -EINVAL;
}
- master = spi_alloc_master(&pdev->dev,
- sizeof(struct spi_clps711x_data) +
- sizeof(int) * pdata->num_chipselect);
- if (!master) {
- dev_err(&pdev->dev, "SPI allocating memory error\n");
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*hw));
+ 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->mode_bits = SPI_CPHA | SPI_CS_HIGH;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8);
master->num_chipselect = pdata->num_chipselect;
master->setup = spi_clps711x_setup;
- master->transfer_one_message = spi_clps711x_transfer_one_message;
+ 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++) {
- hw->chipselect[i] = pdata->chipselect[i];
- if (!gpio_is_valid(hw->chipselect[i])) {
- dev_err(&pdev->dev, "Invalid CS GPIO %i\n", i);
- ret = -EINVAL;
- goto err_out;
- }
- if (devm_gpio_request(&pdev->dev, hw->chipselect[i], NULL)) {
+ 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);
- ret = -EINVAL;
goto err_out;
}
}
@@ -211,29 +182,45 @@ static int spi_clps711x_probe(struct platform_device *pdev)
ret = PTR_ERR(hw->spi_clk);
goto err_out;
}
- hw->max_speed_hz = clk_get_rate(hw->spi_clk);
+ master->max_speed_hz = clk_get_rate(hw->spi_clk);
- init_completion(&hw->done);
platform_set_drvdata(pdev, master);
+ hw->syscon = syscon_regmap_lookup_by_pdevname("syscon.3");
+ if (IS_ERR(hw->syscon)) {
+ ret = PTR_ERR(hw->syscon);
+ goto err_out;
+ }
+
+ hw->syscon1 = syscon_regmap_lookup_by_pdevname("syscon.1");
+ if (IS_ERR(hw->syscon1)) {
+ ret = PTR_ERR(hw->syscon1);
+ goto err_out;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hw->syncio = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(hw->syncio)) {
+ ret = PTR_ERR(hw->syncio);
+ goto err_out;
+ }
+
/* Disable extended mode due hardware problems */
- clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCON, SYSCON3);
+ regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCON, 0);
/* Clear possible pending interrupt */
- clps_readl(SYNCIO);
+ readl(hw->syncio);
- ret = devm_request_irq(&pdev->dev, IRQ_SSEOTI, spi_clps711x_isr, 0,
- dev_name(&pdev->dev), hw);
- if (ret) {
- dev_err(&pdev->dev, "Can't request IRQ\n");
+ ret = devm_request_irq(&pdev->dev, irq, spi_clps711x_isr, 0,
+ dev_name(&pdev->dev), master);
+ if (ret)
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",
- hw->max_speed_hz);
+ master->max_speed_hz);
return 0;
}
diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c
index 28ae470397a..e2fa628e55e 100644
--- a/drivers/spi/spi-coldfire-qspi.c
+++ b/drivers/spi/spi-coldfire-qspi.c
@@ -77,8 +77,6 @@ struct mcfqspi {
struct mcfqspi_cs_control *cs_control;
wait_queue_head_t waitq;
-
- struct device *dev;
};
static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val)
@@ -135,13 +133,13 @@ static void mcfqspi_cs_deselect(struct mcfqspi *mcfqspi, u8 chip_select,
static int mcfqspi_cs_setup(struct mcfqspi *mcfqspi)
{
- return (mcfqspi->cs_control && mcfqspi->cs_control->setup) ?
+ return (mcfqspi->cs_control->setup) ?
mcfqspi->cs_control->setup(mcfqspi->cs_control) : 0;
}
static void mcfqspi_cs_teardown(struct mcfqspi *mcfqspi)
{
- if (mcfqspi->cs_control && mcfqspi->cs_control->teardown)
+ if (mcfqspi->cs_control->teardown)
mcfqspi->cs_control->teardown(mcfqspi->cs_control);
}
@@ -300,68 +298,45 @@ static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count,
}
}
-static int mcfqspi_transfer_one_message(struct spi_master *master,
- struct spi_message *msg)
+static void mcfqspi_set_cs(struct spi_device *spi, bool enable)
{
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
- struct spi_device *spi = msg->spi;
- struct spi_transfer *t;
- int status = 0;
-
- list_for_each_entry(t, &msg->transfers, transfer_list) {
- bool cs_high = spi->mode & SPI_CS_HIGH;
- u16 qmr = MCFQSPI_QMR_MSTR;
-
- qmr |= t->bits_per_word << 10;
- if (spi->mode & SPI_CPHA)
- qmr |= MCFQSPI_QMR_CPHA;
- if (spi->mode & SPI_CPOL)
- qmr |= MCFQSPI_QMR_CPOL;
- if (t->speed_hz)
- qmr |= mcfqspi_qmr_baud(t->speed_hz);
- else
- qmr |= mcfqspi_qmr_baud(spi->max_speed_hz);
- mcfqspi_wr_qmr(mcfqspi, qmr);
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(spi->master);
+ bool cs_high = spi->mode & SPI_CS_HIGH;
+ if (enable)
mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
+ else
+ mcfqspi_cs_deselect(mcfqspi, spi->chip_select, cs_high);
+}
- mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
- if (t->bits_per_word == 8)
- mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf,
- t->rx_buf);
- else
- mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf,
- t->rx_buf);
- mcfqspi_wr_qir(mcfqspi, 0);
-
- if (t->delay_usecs)
- udelay(t->delay_usecs);
- if (t->cs_change) {
- if (!list_is_last(&t->transfer_list, &msg->transfers))
- mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
- cs_high);
- } else {
- if (list_is_last(&t->transfer_list, &msg->transfers))
- mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
- cs_high);
- }
- msg->actual_length += t->len;
- }
- msg->status = status;
- spi_finalize_current_message(master);
-
- return status;
+static int mcfqspi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ u16 qmr = MCFQSPI_QMR_MSTR;
+
+ qmr |= t->bits_per_word << 10;
+ if (spi->mode & SPI_CPHA)
+ qmr |= MCFQSPI_QMR_CPHA;
+ if (spi->mode & SPI_CPOL)
+ qmr |= MCFQSPI_QMR_CPOL;
+ qmr |= mcfqspi_qmr_baud(t->speed_hz);
+ mcfqspi_wr_qmr(mcfqspi, qmr);
+
+ mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
+ if (t->bits_per_word == 8)
+ mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf, t->rx_buf);
+ else
+ mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf,
+ t->rx_buf);
+ mcfqspi_wr_qir(mcfqspi, 0);
+ return 0;
}
static int mcfqspi_setup(struct spi_device *spi)
{
- if (spi->chip_select >= spi->master->num_chipselect) {
- dev_dbg(&spi->dev, "%d chip select is out of range\n",
- spi->chip_select);
- return -EINVAL;
- }
-
mcfqspi_cs_deselect(spi_master_get_devdata(spi->master),
spi->chip_select, spi->mode & SPI_CS_HIGH);
@@ -388,6 +363,11 @@ static int mcfqspi_probe(struct platform_device *pdev)
return -ENOENT;
}
+ if (!pdata->cs_control) {
+ dev_dbg(&pdev->dev, "pdata->cs_control is NULL\n");
+ return -EINVAL;
+ }
+
master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi));
if (master == NULL) {
dev_dbg(&pdev->dev, "spi_alloc_master failed\n");
@@ -436,12 +416,12 @@ static int mcfqspi_probe(struct platform_device *pdev)
}
init_waitqueue_head(&mcfqspi->waitq);
- mcfqspi->dev = &pdev->dev;
master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
master->setup = mcfqspi_setup;
- master->transfer_one_message = mcfqspi_transfer_one_message;
+ master->set_cs = mcfqspi_set_cs;
+ master->transfer_one = mcfqspi_transfer_one;
master->auto_runtime_pm = true;
platform_set_drvdata(pdev, master);
@@ -451,7 +431,7 @@ static int mcfqspi_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "spi_register_master failed\n");
goto fail2;
}
- pm_runtime_enable(mcfqspi->dev);
+ pm_runtime_enable(&pdev->dev);
dev_info(&pdev->dev, "Coldfire QSPI bus driver\n");
@@ -473,9 +453,8 @@ static int mcfqspi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- pm_runtime_disable(mcfqspi->dev);
+ pm_runtime_disable(&pdev->dev);
/* disable the hardware (set the baud rate to 0) */
mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
@@ -490,8 +469,11 @@ static int mcfqspi_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ int ret;
- spi_master_suspend(master);
+ ret = spi_master_suspend(master);
+ if (ret)
+ return ret;
clk_disable(mcfqspi->clk);
@@ -503,11 +485,9 @@ static int mcfqspi_resume(struct device *dev)
struct spi_master *master = dev_get_drvdata(dev);
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
- spi_master_resume(master);
-
clk_enable(mcfqspi->clk);
- return 0;
+ return spi_master_resume(master);
}
#endif
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 5e7389faa2a..50f75098925 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -802,8 +802,7 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
pdata = &dspi->pdata;
pdata->version = SPI_VERSION_1;
- match = of_match_device(of_match_ptr(davinci_spi_of_match),
- &pdev->dev);
+ match = of_match_device(davinci_spi_of_match, &pdev->dev);
if (!match)
return -ENODEV;
@@ -824,7 +823,6 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
return 0;
}
#else
-#define davinci_spi_of_match NULL
static struct davinci_spi_platform_data
*spi_davinci_get_pdata(struct platform_device *pdev,
struct davinci_spi *dspi)
@@ -864,10 +862,6 @@ static int davinci_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
dspi = spi_master_get_devdata(master);
- if (dspi == NULL) {
- ret = -ENOENT;
- goto free_master;
- }
if (dev_get_platdata(&pdev->dev)) {
pdata = dev_get_platdata(&pdev->dev);
@@ -908,10 +902,6 @@ static int davinci_spi_probe(struct platform_device *pdev)
goto free_master;
dspi->bitbang.master = master;
- if (dspi->bitbang.master == NULL) {
- ret = -ENODEV;
- goto free_master;
- }
dspi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dspi->clk)) {
@@ -1040,7 +1030,7 @@ static struct platform_driver davinci_spi_driver = {
.driver = {
.name = "spi_davinci",
.owner = THIS_MODULE,
- .of_match_table = davinci_spi_of_match,
+ .of_match_table = of_match_ptr(davinci_spi_of_match),
},
.probe = davinci_spi_probe,
.remove = davinci_spi_remove,
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index 9af56cdf154..1492f5ee9aa 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -66,7 +66,7 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
if (ret)
return ret;
- dws->bus_num = 0;
+ dws->bus_num = pdev->id;
dws->num_cs = 4;
dws->max_freq = clk_get_rate(dwsmmio->clk);
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index bf98d63d92b..712ac5629cd 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -276,8 +276,7 @@ static void giveback(struct dw_spi *dws)
queue_work(dws->workqueue, &dws->pump_messages);
spin_unlock_irqrestore(&dws->lock, flags);
- last_transfer = list_entry(msg->transfers.prev,
- struct spi_transfer,
+ last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
transfer_list);
if (!last_transfer->cs_change && dws->cs_control)
@@ -439,12 +438,6 @@ static void pump_transfers(unsigned long data)
if (transfer->speed_hz != speed) {
speed = transfer->speed_hz;
- if (speed > dws->max_freq) {
- printk(KERN_ERR "MRST SPI0: unsupported"
- "freq: %dHz\n", speed);
- message->status = -EIO;
- goto early_exit;
- }
/* clk_div doesn't support odd number */
clk_div = dws->max_freq / speed;
@@ -671,12 +664,6 @@ static int dw_spi_setup(struct spi_device *spi)
return 0;
}
-static void dw_spi_cleanup(struct spi_device *spi)
-{
- struct chip_data *chip = spi_get_ctldata(spi);
- kfree(chip);
-}
-
static int init_queue(struct dw_spi *dws)
{
INIT_LIST_HEAD(&dws->queue);
@@ -806,9 +793,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
master->bus_num = dws->bus_num;
master->num_chipselect = dws->num_cs;
- master->cleanup = dw_spi_cleanup;
master->setup = dw_spi_setup;
master->transfer = dw_spi_transfer;
+ master->max_speed_hz = dws->max_freq;
/* Basic HW init */
spi_hw_init(dws);
diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c
index d4d3cc53479..be44a3eeb5e 100644
--- a/drivers/spi/spi-efm32.c
+++ b/drivers/spi/spi-efm32.c
@@ -198,7 +198,7 @@ static int efm32_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
efm32_spi_filltx(ddata);
- init_completion(&ddata->done);
+ reinit_completion(&ddata->done);
efm32_spi_write32(ddata, REG_IF_TXBL | REG_IF_RXDATAV, REG_IEN);
@@ -287,17 +287,17 @@ static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata)
return (reg & REG_ROUTE_LOCATION__MASK) >> __ffs(REG_ROUTE_LOCATION__MASK);
}
-static int efm32_spi_probe_dt(struct platform_device *pdev,
+static void efm32_spi_probe_dt(struct platform_device *pdev,
struct spi_master *master, struct efm32_spi_ddata *ddata)
{
struct device_node *np = pdev->dev.of_node;
u32 location;
int ret;
- if (!np)
- return 1;
-
- ret = of_property_read_u32(np, "location", &location);
+ ret = of_property_read_u32(np, "efm32,location", &location);
+ if (ret)
+ /* fall back to old and (wrongly) generic property "location" */
+ ret = of_property_read_u32(np, "location", &location);
if (!ret) {
dev_dbg(&pdev->dev, "using location %u\n", location);
} else {
@@ -308,11 +308,6 @@ static int efm32_spi_probe_dt(struct platform_device *pdev,
}
ddata->pdata.location = location;
-
- /* spi core takes care about the bus number using an alias */
- master->bus_num = -1;
-
- return 0;
}
static int efm32_spi_probe(struct platform_device *pdev)
@@ -322,9 +317,14 @@ static int efm32_spi_probe(struct platform_device *pdev)
int ret;
struct spi_master *master;
struct device_node *np = pdev->dev.of_node;
- unsigned int num_cs, i;
+ int num_cs, i;
+
+ if (!np)
+ return -EINVAL;
num_cs = of_gpio_named_count(np, "cs-gpios");
+ if (num_cs < 0)
+ return num_cs;
master = spi_alloc_master(&pdev->dev,
sizeof(*ddata) + num_cs * sizeof(unsigned));
@@ -349,6 +349,7 @@ static int efm32_spi_probe(struct platform_device *pdev)
ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs;
spin_lock_init(&ddata->lock);
+ init_completion(&ddata->done);
ddata->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(ddata->clk)) {
@@ -415,23 +416,7 @@ static int efm32_spi_probe(struct platform_device *pdev)
goto err;
}
- ret = efm32_spi_probe_dt(pdev, master, ddata);
- if (ret > 0) {
- /* not created by device tree */
- const struct efm32_spi_pdata *pdata =
- dev_get_platdata(&pdev->dev);
-
- if (pdata)
- ddata->pdata = *pdata;
- else
- ddata->pdata.location =
- efm32_spi_get_configured_location(ddata);
-
- master->bus_num = pdev->id;
-
- } else if (ret < 0) {
- goto err_disable_clk;
- }
+ efm32_spi_probe_dt(pdev, master, ddata);
efm32_spi_write32(ddata, 0, REG_IEN);
efm32_spi_write32(ddata, REG_ROUTE_TXPEN | REG_ROUTE_RXPEN |
@@ -487,6 +472,9 @@ static int efm32_spi_remove(struct platform_device *pdev)
static const struct of_device_id efm32_spi_dt_ids[] = {
{
+ .compatible = "energymicro,efm32-spi",
+ }, {
+ /* doesn't follow the "vendor,device" scheme, don't use */
.compatible = "efm32,spi",
}, {
/* sentinel */
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index 1bfaed6e407..2f675d32df0 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -73,8 +73,6 @@
* @clk: clock for the controller
* @regs_base: pointer to ioremap()'d registers
* @sspdr_phys: physical address of the SSPDR register
- * @min_rate: minimum clock rate (in Hz) supported by the controller
- * @max_rate: maximum clock rate (in Hz) supported by the controller
* @wait: wait here until given transfer is completed
* @current_msg: message that is currently processed (or %NULL if none)
* @tx: current byte in transfer to transmit
@@ -95,8 +93,6 @@ struct ep93xx_spi {
struct clk *clk;
void __iomem *regs_base;
unsigned long sspdr_phys;
- unsigned long min_rate;
- unsigned long max_rate;
struct completion wait;
struct spi_message *current_msg;
size_t tx;
@@ -199,9 +195,9 @@ static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)
* @div_scr: pointer to return the scr divider
*/
static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
- unsigned long rate,
- u8 *div_cpsr, u8 *div_scr)
+ u32 rate, u8 *div_cpsr, u8 *div_scr)
{
+ struct spi_master *master = platform_get_drvdata(espi->pdev);
unsigned long spi_clk_rate = clk_get_rate(espi->clk);
int cpsr, scr;
@@ -210,7 +206,7 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
* controller. Note that minimum value is already checked in
* ep93xx_spi_transfer_one_message().
*/
- rate = clamp(rate, espi->min_rate, espi->max_rate);
+ rate = clamp(rate, master->min_speed_hz, master->max_speed_hz);
/*
* Calculate divisors so that we can get speed according the
@@ -735,13 +731,6 @@ static int ep93xx_spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
struct ep93xx_spi *espi = spi_master_get_devdata(master);
- struct spi_transfer *t;
-
- /* first validate each transfer */
- list_for_each_entry(t, &msg->transfers, transfer_list) {
- if (t->speed_hz < espi->min_rate)
- return -EINVAL;
- }
msg->state = NULL;
msg->status = 0;
@@ -917,8 +906,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
* Calculate maximum and minimum supported clock rates
* for the controller.
*/
- espi->max_rate = clk_get_rate(espi->clk) / 2;
- espi->min_rate = clk_get_rate(espi->clk) / (254 * 256);
+ master->max_speed_hz = clk_get_rate(espi->clk) / 2;
+ master->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256);
espi->pdev = pdev;
espi->sspdr_phys = res->start + SSPDR;
diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c
index dd5bd468e96..09965f069a1 100644
--- a/drivers/spi/spi-falcon.c
+++ b/drivers/spi/spi-falcon.c
@@ -312,9 +312,6 @@ static int falcon_sflash_setup(struct spi_device *spi)
unsigned int i;
unsigned long flags;
- if (spi->chip_select > 0)
- return -ENODEV;
-
spin_lock_irqsave(&ebu_lock, flags);
if (spi->max_speed_hz >= CLOCK_100M) {
@@ -422,9 +419,7 @@ static int falcon_sflash_probe(struct platform_device *pdev)
priv->master = master;
master->mode_bits = SPI_MODE_3;
- master->num_chipselect = 1;
master->flags = SPI_MASTER_HALF_DUPLEX;
- master->bus_num = -1;
master->setup = falcon_sflash_setup;
master->prepare_transfer_hardware = falcon_sflash_prepare_xfer;
master->transfer_one_message = falcon_sflash_xfer_one;
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index a25392065d9..d565eeee3bd 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -18,6 +18,7 @@
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/io.h>
@@ -108,11 +109,11 @@ struct fsl_dspi {
struct spi_bitbang bitbang;
struct platform_device *pdev;
- void __iomem *base;
+ struct regmap *regmap;
int irq;
- struct clk *clk;
+ struct clk *clk;
- struct spi_transfer *cur_transfer;
+ struct spi_transfer *cur_transfer;
struct chip_data *cur_chip;
size_t len;
void *tx;
@@ -123,24 +124,17 @@ struct fsl_dspi {
u8 cs;
u16 void_write_data;
- wait_queue_head_t waitq;
- u32 waitflags;
+ wait_queue_head_t waitq;
+ u32 waitflags;
};
static inline int is_double_byte_mode(struct fsl_dspi *dspi)
{
- return ((readl(dspi->base + SPI_CTAR(dspi->cs)) & SPI_FRAME_BITS_MASK)
- == SPI_FRAME_BITS(8)) ? 0 : 1;
-}
+ unsigned int val;
-static void set_bit_mode(struct fsl_dspi *dspi, unsigned char bits)
-{
- u32 temp;
+ regmap_read(dspi->regmap, SPI_CTAR(dspi->cs), &val);
- temp = readl(dspi->base + SPI_CTAR(dspi->cs));
- temp &= ~SPI_FRAME_BITS_MASK;
- temp |= SPI_FRAME_BITS(bits);
- writel(temp, dspi->base + SPI_CTAR(dspi->cs));
+ return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
}
static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
@@ -188,7 +182,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi)
*/
if (tx_word && (dspi->len == 1)) {
dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
- set_bit_mode(dspi, 8);
+ regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
+ SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
tx_word = 0;
}
@@ -238,7 +233,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi)
dspi_pushr |= SPI_PUSHR_CTCNT; /* clear counter */
}
- writel(dspi_pushr, dspi->base + SPI_PUSHR);
+ regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
+
tx_count++;
}
@@ -253,17 +249,23 @@ static int dspi_transfer_read(struct fsl_dspi *dspi)
while ((dspi->rx < dspi->rx_end)
&& (rx_count < DSPI_FIFO_SIZE)) {
if (rx_word) {
+ unsigned int val;
+
if ((dspi->rx_end - dspi->rx) == 1)
break;
- d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
+ regmap_read(dspi->regmap, SPI_POPR, &val);
+ d = SPI_POPR_RXDATA(val);
if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
*(u16 *)dspi->rx = d;
dspi->rx += 2;
} else {
- d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
+ unsigned int val;
+
+ regmap_read(dspi->regmap, SPI_POPR, &val);
+ d = SPI_POPR_RXDATA(val);
if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
*(u8 *)dspi->rx = d;
dspi->rx++;
@@ -295,13 +297,13 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
if (!dspi->tx)
dspi->dataflags |= TRAN_STATE_TX_VOID;
- writel(dspi->cur_chip->mcr_val, dspi->base + SPI_MCR);
- writel(dspi->cur_chip->ctar_val, dspi->base + SPI_CTAR(dspi->cs));
- writel(SPI_RSER_EOQFE, dspi->base + SPI_RSER);
+ regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val);
+ regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), dspi->cur_chip->ctar_val);
+ regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE);
if (t->speed_hz)
- writel(dspi->cur_chip->ctar_val,
- dspi->base + SPI_CTAR(dspi->cs));
+ regmap_write(dspi->regmap, SPI_CTAR(dspi->cs),
+ dspi->cur_chip->ctar_val);
dspi_transfer_write(dspi);
@@ -315,7 +317,9 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
static void dspi_chipselect(struct spi_device *spi, int value)
{
struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
- u32 pushr = readl(dspi->base + SPI_PUSHR);
+ unsigned int pushr;
+
+ regmap_read(dspi->regmap, SPI_PUSHR, &pushr);
switch (value) {
case BITBANG_CS_ACTIVE:
@@ -326,7 +330,7 @@ static void dspi_chipselect(struct spi_device *spi, int value)
break;
}
- writel(pushr, dspi->base + SPI_PUSHR);
+ regmap_write(dspi->regmap, SPI_PUSHR, pushr);
}
static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
@@ -338,7 +342,8 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
/* Only alloc on first setup */
chip = spi_get_ctldata(spi);
if (chip == NULL) {
- chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL);
+ chip = devm_kzalloc(&spi->dev, sizeof(struct chip_data),
+ GFP_KERNEL);
if (!chip)
return -ENOMEM;
}
@@ -349,7 +354,6 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
fmsz = spi->bits_per_word - 1;
} else {
pr_err("Invalid wordsize\n");
- kfree(chip);
return -ENODEV;
}
@@ -382,13 +386,15 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
{
struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id;
- writel(SPI_SR_EOQF, dspi->base + SPI_SR);
+ regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF);
dspi_transfer_read(dspi);
if (!dspi->len) {
if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM)
- set_bit_mode(dspi, 16);
+ regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
+ SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16));
+
dspi->waitflags = 1;
wake_up_interruptible(&dspi->waitq);
} else {
@@ -430,8 +436,13 @@ static int dspi_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
-static const struct dev_pm_ops dspi_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(dspi_suspend, dspi_resume)
+static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume);
+
+static struct regmap_config dspi_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x88,
};
static int dspi_probe(struct platform_device *pdev)
@@ -440,6 +451,7 @@ static int dspi_probe(struct platform_device *pdev)
struct spi_master *master;
struct fsl_dspi *dspi;
struct resource *res;
+ void __iomem *base;
int ret = 0, cs_num, bus_num;
master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
@@ -474,12 +486,24 @@ static int dspi_probe(struct platform_device *pdev)
master->bus_num = bus_num;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dspi->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(dspi->base)) {
- ret = PTR_ERR(dspi->base);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base)) {
+ ret = PTR_ERR(base);
goto out_master_put;
}
+ dspi_regmap_config.lock_arg = dspi;
+ dspi_regmap_config.val_format_endian =
+ of_property_read_bool(np, "big-endian")
+ ? REGMAP_ENDIAN_BIG : REGMAP_ENDIAN_DEFAULT;
+ dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base,
+ &dspi_regmap_config);
+ if (IS_ERR(dspi->regmap)) {
+ dev_err(&pdev->dev, "failed to init regmap: %ld\n",
+ PTR_ERR(dspi->regmap));
+ return PTR_ERR(dspi->regmap);
+ }
+
dspi->irq = platform_get_irq(pdev, 0);
if (dspi->irq < 0) {
dev_err(&pdev->dev, "can't get platform irq\n");
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 428dc7a6b62..6fb2b75df82 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -219,13 +219,8 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base;
unsigned int len = t->len;
- u8 bits_per_word;
int ret;
- bits_per_word = spi->bits_per_word;
- if (t->bits_per_word)
- bits_per_word = t->bits_per_word;
-
mpc8xxx_spi->len = t->len;
len = roundup(len, 4) / 4;
diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c
index 0b75f26158a..e5d45fca355 100644
--- a/drivers/spi/spi-fsl-lib.c
+++ b/drivers/spi/spi-fsl-lib.c
@@ -200,7 +200,7 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
const void *prop;
int ret = -ENOMEM;
- pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
+ pinfo = devm_kzalloc(&ofdev->dev, sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
return -ENOMEM;
@@ -215,15 +215,13 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
pdata->sysclk = get_brgfreq();
if (pdata->sysclk == -1) {
pdata->sysclk = fsl_get_sys_freq();
- if (pdata->sysclk == -1) {
- ret = -ENODEV;
- goto err;
- }
+ if (pdata->sysclk == -1)
+ return -ENODEV;
}
#else
ret = of_property_read_u32(np, "clock-frequency", &pdata->sysclk);
if (ret)
- goto err;
+ return ret;
#endif
prop = of_get_property(np, "mode", NULL);
@@ -237,8 +235,4 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
pdata->flags = SPI_CPM_MODE | SPI_CPM1;
return 0;
-
-err:
- kfree(pinfo);
- return ret;
}
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index 119f7af9453..f35488ed62a 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -239,12 +239,6 @@ static int fsl_spi_setup_transfer(struct spi_device *spi,
if (!bits_per_word)
bits_per_word = spi->bits_per_word;
- /* Make sure its a bit width we support [4..16, 32] */
- if ((bits_per_word < 4)
- || ((bits_per_word > 16) && (bits_per_word != 32))
- || (bits_per_word > mpc8xxx_spi->max_bits_per_word))
- return -EINVAL;
-
if (!hz)
hz = spi->max_speed_hz;
@@ -362,18 +356,28 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
static void fsl_spi_do_one_msg(struct spi_message *m)
{
struct spi_device *spi = m->spi;
- struct spi_transfer *t;
+ struct spi_transfer *t, *first;
unsigned int cs_change;
const int nsecs = 50;
int status;
- cs_change = 1;
- status = 0;
+ /* Don't allow changes if CS is active */
+ first = list_first_entry(&m->transfers, struct spi_transfer,
+ transfer_list);
list_for_each_entry(t, &m->transfers, transfer_list) {
- if (t->bits_per_word || t->speed_hz) {
- /* Don't allow changes if CS is active */
+ if ((first->bits_per_word != t->bits_per_word) ||
+ (first->speed_hz != t->speed_hz)) {
status = -EINVAL;
+ dev_err(&spi->dev,
+ "bits_per_word/speed_hz should be same for the same SPI transfer\n");
+ return;
+ }
+ }
+ cs_change = 1;
+ status = -EINVAL;
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (t->bits_per_word || t->speed_hz) {
if (cs_change)
status = fsl_spi_setup_transfer(spi, t);
if (status < 0)
@@ -641,6 +645,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
if (mpc8xxx_spi->type == TYPE_GRLIB)
fsl_spi_grlib_probe(dev);
+ master->bits_per_word_mask =
+ (SPI_BPW_RANGE_MASK(4, 16) | SPI_BPW_MASK(32)) &
+ SPI_BPW_RANGE_MASK(1, mpc8xxx_spi->max_bits_per_word);
+
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
mpc8xxx_spi->set_shifts = fsl_spi_qe_cpu_set_shifts;
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index 7beeb29472a..09823076df8 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -19,7 +19,6 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of.h>
@@ -250,7 +249,7 @@ static int spi_gpio_setup(struct spi_device *spi)
/*
* ... otherwise, take it from spi->controller_data
*/
- cs = (unsigned int) spi->controller_data;
+ cs = (unsigned int)(uintptr_t) spi->controller_data;
}
if (!spi->controller_state) {
@@ -503,13 +502,12 @@ static int spi_gpio_remove(struct platform_device *pdev)
{
struct spi_gpio *spi_gpio;
struct spi_gpio_platform_data *pdata;
- int status;
spi_gpio = platform_get_drvdata(pdev);
pdata = dev_get_platdata(&pdev->dev);
/* stop() unregisters child devices too */
- status = spi_bitbang_stop(&spi_gpio->bitbang);
+ spi_bitbang_stop(&spi_gpio->bitbang);
if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
gpio_free(SPI_MISO_GPIO);
@@ -518,7 +516,7 @@ static int spi_gpio_remove(struct platform_device *pdev)
gpio_free(SPI_SCK_GPIO);
spi_master_put(spi_gpio->bitbang.master);
- return status;
+ return 0;
}
MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 47f15d97e7f..5daff2054ae 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -23,7 +23,6 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -741,7 +740,7 @@ static int spi_imx_transfer(struct spi_device *spi,
spi_imx->count = transfer->len;
spi_imx->txfifo = 0;
- init_completion(&spi_imx->xfer_done);
+ reinit_completion(&spi_imx->xfer_done);
spi_imx_push(spi_imx);
@@ -880,12 +879,12 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->irq = platform_get_irq(pdev, 0);
if (spi_imx->irq < 0) {
- ret = -EINVAL;
+ ret = spi_imx->irq;
goto out_master_put;
}
ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0,
- DRIVER_NAME, spi_imx);
+ dev_name(&pdev->dev), spi_imx);
if (ret) {
dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret);
goto out_master_put;
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index 5032141eeee..3822eef2ef9 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -16,7 +16,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/of_address.h>
@@ -466,10 +465,8 @@ static void mpc512x_spi_cs_control(struct spi_device *spi, bool onoff)
gpio_set_value(spi->cs_gpio, onoff);
}
-/* bus_num is used only for the case dev->platform_data == NULL */
static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
- u32 size, unsigned int irq,
- s16 bus_num)
+ u32 size, unsigned int irq)
{
struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct mpc512x_psc_spi *mps;
@@ -488,7 +485,6 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
if (pdata == NULL) {
mps->cs_control = mpc512x_spi_cs_control;
- master->bus_num = bus_num;
} else {
mps->cs_control = pdata->cs_control;
master->bus_num = pdata->bus_num;
@@ -574,7 +570,6 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *op)
{
const u32 *regaddr_p;
u64 regaddr64, size64;
- s16 id = -1;
regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL);
if (!regaddr_p) {
@@ -583,16 +578,8 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *op)
}
regaddr64 = of_translate_address(op->dev.of_node, regaddr_p);
- /* get PSC id (0..11, used by port_config) */
- id = of_alias_get_id(op->dev.of_node, "spi");
- if (id < 0) {
- dev_err(&op->dev, "no alias id for %s\n",
- op->dev.of_node->full_name);
- return id;
- }
-
return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64,
- irq_of_parse_and_map(op->dev.of_node, 0), id);
+ irq_of_parse_and_map(op->dev.of_node, 0));
}
static int mpc512x_psc_spi_of_remove(struct platform_device *op)
diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c
index 00ba910ab30..3d18d935118 100644
--- a/drivers/spi/spi-mpc52xx-psc.c
+++ b/drivers/spi/spi-mpc52xx-psc.c
@@ -12,7 +12,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c
index 7c675fe8310..aac2a5ddd96 100644
--- a/drivers/spi/spi-mpc52xx.c
+++ b/drivers/spi/spi-mpc52xx.c
@@ -12,7 +12,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/errno.h>
#include <linux/of_platform.h>
#include <linux/interrupt.h>
@@ -357,20 +356,6 @@ static void mpc52xx_spi_wq(struct work_struct *work)
* spi_master ops
*/
-static int mpc52xx_spi_setup(struct spi_device *spi)
-{
- if (spi->bits_per_word % 8)
- return -EINVAL;
-
- if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST))
- return -EINVAL;
-
- if (spi->chip_select >= spi->master->num_chipselect)
- return -EINVAL;
-
- return 0;
-}
-
static int mpc52xx_spi_transfer(struct spi_device *spi, struct spi_message *m)
{
struct mpc52xx_spi *ms = spi_master_get_devdata(spi->master);
@@ -433,9 +418,9 @@ static int mpc52xx_spi_probe(struct platform_device *op)
goto err_alloc;
}
- master->setup = mpc52xx_spi_setup;
master->transfer = mpc52xx_spi_transfer;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
master->dev.of_node = op->dev.of_node;
platform_set_drvdata(op, master);
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index 79e5aa2250c..2884f0c2f5f 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -29,7 +29,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -371,7 +370,7 @@ static int mxs_spi_transfer_one(struct spi_master *master,
{
struct mxs_spi *spi = spi_master_get_devdata(master);
struct mxs_ssp *ssp = &spi->ssp;
- struct spi_transfer *t, *tmp_t;
+ struct spi_transfer *t;
unsigned int flag;
int status = 0;
@@ -381,7 +380,7 @@ static int mxs_spi_transfer_one(struct spi_master *master,
writel(mxs_spi_cs_to_reg(m->spi->chip_select),
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
- list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) {
+ list_for_each_entry(t, &m->transfers, transfer_list) {
status = mxs_spi_setup_transfer(m->spi, t);
if (status)
@@ -473,7 +472,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq_err = platform_get_irq(pdev, 0);
if (irq_err < 0)
- return -EINVAL;
+ return irq_err;
base = devm_ioremap_resource(&pdev->dev, iores);
if (IS_ERR(base))
diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c
index bae97ffec4b..16e30de650b 100644
--- a/drivers/spi/spi-nuc900.c
+++ b/drivers/spi/spi-nuc900.c
@@ -9,7 +9,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
@@ -38,7 +37,9 @@
/* usi register bit */
#define ENINT (0x01 << 17)
#define ENFLG (0x01 << 16)
+#define SLEEP (0x0f << 12)
#define TXNUM (0x03 << 8)
+#define TXBITLEN (0x1f << 3)
#define TXNEG (0x01 << 2)
#define RXNEG (0x01 << 1)
#define LSB (0x01 << 10)
@@ -58,11 +59,8 @@ struct nuc900_spi {
unsigned char *rx;
struct clk *clk;
struct spi_master *master;
- struct spi_device *curdev;
- struct device *dev;
struct nuc900_spi_info *pdata;
spinlock_t lock;
- struct resource *res;
};
static inline struct nuc900_spi *to_hw(struct spi_device *sdev)
@@ -119,19 +117,16 @@ static void nuc900_spi_chipsel(struct spi_device *spi, int value)
}
}
-static void nuc900_spi_setup_txnum(struct nuc900_spi *hw,
- unsigned int txnum)
+static void nuc900_spi_setup_txnum(struct nuc900_spi *hw, unsigned int txnum)
{
unsigned int val;
unsigned long flags;
spin_lock_irqsave(&hw->lock, flags);
- val = __raw_readl(hw->regs + USI_CNT);
+ val = __raw_readl(hw->regs + USI_CNT) & ~TXNUM;
- if (!txnum)
- val &= ~TXNUM;
- else
+ if (txnum)
val |= txnum << 0x08;
__raw_writel(val, hw->regs + USI_CNT);
@@ -148,7 +143,7 @@ static void nuc900_spi_setup_txbitlen(struct nuc900_spi *hw,
spin_lock_irqsave(&hw->lock, flags);
- val = __raw_readl(hw->regs + USI_CNT);
+ val = __raw_readl(hw->regs + USI_CNT) & ~TXBITLEN;
val |= (txbitlen << 0x03);
@@ -287,12 +282,11 @@ static void nuc900_set_sleep(struct nuc900_spi *hw, unsigned int sleep)
spin_lock_irqsave(&hw->lock, flags);
- val = __raw_readl(hw->regs + USI_CNT);
+ val = __raw_readl(hw->regs + USI_CNT) & ~SLEEP;
if (sleep)
val |= (sleep << 12);
- else
- val &= ~(0x0f << 12);
+
__raw_writel(val, hw->regs + USI_CNT);
spin_unlock_irqrestore(&hw->lock, flags);
@@ -338,6 +332,7 @@ static int nuc900_spi_probe(struct platform_device *pdev)
{
struct nuc900_spi *hw;
struct spi_master *master;
+ struct resource *res;
int err = 0;
master = spi_alloc_master(&pdev->dev, sizeof(struct nuc900_spi));
@@ -349,7 +344,6 @@ static int nuc900_spi_probe(struct platform_device *pdev)
hw = spi_master_get_devdata(master);
hw->master = master;
hw->pdata = dev_get_platdata(&pdev->dev);
- hw->dev = &pdev->dev;
if (hw->pdata == NULL) {
dev_err(&pdev->dev, "No platform data supplied\n");
@@ -369,8 +363,8 @@ static int nuc900_spi_probe(struct platform_device *pdev)
hw->bitbang.chipselect = nuc900_spi_chipsel;
hw->bitbang.txrx_bufs = nuc900_spi_txrx;
- hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hw->regs = devm_ioremap_resource(&pdev->dev, hw->res);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hw->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hw->regs)) {
err = PTR_ERR(hw->regs);
goto err_pdata;
diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c
index f7c896e2981..8998d11c723 100644
--- a/drivers/spi/spi-oc-tiny.c
+++ b/drivers/spi/spi-oc-tiny.c
@@ -15,7 +15,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/module.h>
@@ -267,8 +266,6 @@ static int tiny_spi_probe(struct platform_device *pdev)
/* setup the state for the bitbang driver */
hw->bitbang.master = master;
- if (!hw->bitbang.master)
- return err;
hw->bitbang.setup_transfer = tiny_spi_setup_transfer;
hw->bitbang.chipselect = tiny_spi_chipselect;
hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs;
diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c
index 67249a48b39..c5e2f718eeb 100644
--- a/drivers/spi/spi-octeon.c
+++ b/drivers/spi/spi-octeon.c
@@ -11,7 +11,6 @@
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/of.h>
@@ -33,13 +32,6 @@ struct octeon_spi {
u64 cs_enax;
};
-struct octeon_spi_setup {
- u32 max_speed_hz;
- u8 chip_select;
- u8 mode;
- u8 bits_per_word;
-};
-
static void octeon_spi_wait_ready(struct octeon_spi *p)
{
union cvmx_mpi_sts mpi_sts;
@@ -57,6 +49,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
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;
@@ -68,18 +61,11 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
int len;
int i;
- struct octeon_spi_setup *msg_setup = spi_get_ctldata(msg->spi);
-
- speed_hz = msg_setup->max_speed_hz;
- mode = msg_setup->mode;
+ mode = spi->mode;
cpha = mode & SPI_CPHA;
cpol = mode & SPI_CPOL;
- if (xfer->speed_hz)
- speed_hz = xfer->speed_hz;
-
- if (speed_hz > OCTEON_SPI_MAX_CLOCK_HZ)
- speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
+ speed_hz = xfer->speed_hz ? : spi->max_speed_hz;
clkdiv = octeon_get_io_clock_rate() / (2 * speed_hz);
@@ -93,8 +79,8 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
mpi_cfg.s.cslate = cpha ? 1 : 0;
mpi_cfg.s.enable = 1;
- if (msg_setup->chip_select < 4)
- p->cs_enax |= 1ull << (12 + msg_setup->chip_select);
+ 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) {
@@ -114,7 +100,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d);
}
mpi_tx.u64 = 0;
- mpi_tx.s.csid = msg_setup->chip_select;
+ 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;
@@ -139,7 +125,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
}
mpi_tx.u64 = 0;
- mpi_tx.s.csid = msg_setup->chip_select;
+ mpi_tx.s.csid = spi->chip_select;
if (last_xfer)
mpi_tx.s.leavecs = xfer->cs_change;
else
@@ -169,17 +155,9 @@ static int octeon_spi_transfer_one_message(struct spi_master *master,
int status = 0;
struct spi_transfer *xfer;
- /*
- * We better have set the configuration via a call to .setup
- * before we get here.
- */
- if (spi_get_ctldata(msg->spi) == NULL) {
- status = -EINVAL;
- goto err;
- }
-
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- bool last_xfer = &xfer->transfer_list == msg->transfers.prev;
+ 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;
@@ -194,41 +172,6 @@ err:
return status;
}
-static struct octeon_spi_setup *octeon_spi_new_setup(struct spi_device *spi)
-{
- struct octeon_spi_setup *setup = kzalloc(sizeof(*setup), GFP_KERNEL);
- if (!setup)
- return NULL;
-
- setup->max_speed_hz = spi->max_speed_hz;
- setup->chip_select = spi->chip_select;
- setup->mode = spi->mode;
- setup->bits_per_word = spi->bits_per_word;
- return setup;
-}
-
-static int octeon_spi_setup(struct spi_device *spi)
-{
- struct octeon_spi_setup *new_setup;
- struct octeon_spi_setup *old_setup = spi_get_ctldata(spi);
-
- new_setup = octeon_spi_new_setup(spi);
- if (!new_setup)
- return -ENOMEM;
-
- spi_set_ctldata(spi, new_setup);
- kfree(old_setup);
-
- return 0;
-}
-
-static void octeon_spi_cleanup(struct spi_device *spi)
-{
- struct octeon_spi_setup *old_setup = spi_get_ctldata(spi);
- spi_set_ctldata(spi, NULL);
- kfree(old_setup);
-}
-
static int octeon_spi_probe(struct platform_device *pdev)
{
struct resource *res_mem;
@@ -257,8 +200,6 @@ static int octeon_spi_probe(struct platform_device *pdev)
p->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start,
resource_size(res_mem));
- /* Dynamic bus numbering */
- master->bus_num = -1;
master->num_chipselect = 4;
master->mode_bits = SPI_CPHA |
SPI_CPOL |
@@ -266,10 +207,9 @@ static int octeon_spi_probe(struct platform_device *pdev)
SPI_LSB_FIRST |
SPI_3WIRE;
- master->setup = octeon_spi_setup;
- master->cleanup = octeon_spi_cleanup;
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);
diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c
index 0d32054bfc0..e7ffcded4e1 100644
--- a/drivers/spi/spi-omap-100k.c
+++ b/drivers/spi/spi-omap-100k.c
@@ -83,15 +83,11 @@
#define SPI_SHUTDOWN 1
struct omap1_spi100k {
- struct spi_master *master;
struct clk *ick;
struct clk *fck;
/* Virtual base address of the controller */
void __iomem *base;
-
- /* State of the SPI */
- unsigned int state;
};
struct omap1_spi100k_cs {
@@ -99,13 +95,6 @@ struct omap1_spi100k_cs {
int word_len;
};
-#define MOD_REG_BIT(val, mask, set) do { \
- if (set) \
- val |= mask; \
- else \
- val &= ~mask; \
-} while (0)
-
static void spi100k_enable_clock(struct spi_master *master)
{
unsigned int val;
@@ -139,7 +128,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
}
spi100k_enable_clock(master);
- writew( data , spi100k->base + SPI_TX_MSB);
+ writew(data , spi100k->base + SPI_TX_MSB);
writew(SPI_CTRL_SEN(0) |
SPI_CTRL_WORD_SIZE(len) |
@@ -147,7 +136,8 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
spi100k->base + SPI_CTRL);
/* Wait for bit ack send change */
- while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE);
+ while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE)
+ ;
udelay(1000);
spi100k_disable_clock(master);
@@ -155,7 +145,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
static int spi100k_read_data(struct spi_master *master, int len)
{
- int dataH,dataL;
+ int dataH, dataL;
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
/* Always do at least 16 bits */
@@ -168,7 +158,8 @@ static int spi100k_read_data(struct spi_master *master, int len)
SPI_CTRL_RD,
spi100k->base + SPI_CTRL);
- while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD);
+ while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD)
+ ;
udelay(1000);
dataL = readw(spi100k->base + SPI_RX_LSB);
@@ -204,12 +195,10 @@ static void omap1_spi100k_force_cs(struct omap1_spi100k *spi100k, int enable)
static unsigned
omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
{
- struct omap1_spi100k *spi100k;
struct omap1_spi100k_cs *cs = spi->controller_state;
unsigned int count, c;
int word_len;
- spi100k = spi_master_get_devdata(spi->master);
count = xfer->len;
c = count;
word_len = cs->word_len;
@@ -221,12 +210,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
rx = xfer->rx_buf;
tx = xfer->tx_buf;
do {
- c-=1;
+ c -= 1;
if (xfer->tx_buf != NULL)
spi100k_write_data(spi->master, word_len, *tx++);
if (xfer->rx_buf != NULL)
*rx++ = spi100k_read_data(spi->master, word_len);
- } while(c);
+ } while (c);
} else if (word_len <= 16) {
u16 *rx;
const u16 *tx;
@@ -234,12 +223,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
rx = xfer->rx_buf;
tx = xfer->tx_buf;
do {
- c-=2;
+ c -= 2;
if (xfer->tx_buf != NULL)
- spi100k_write_data(spi->master,word_len, *tx++);
+ spi100k_write_data(spi->master, word_len, *tx++);
if (xfer->rx_buf != NULL)
- *rx++ = spi100k_read_data(spi->master,word_len);
- } while(c);
+ *rx++ = spi100k_read_data(spi->master, word_len);
+ } while (c);
} else if (word_len <= 32) {
u32 *rx;
const u32 *tx;
@@ -247,12 +236,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
rx = xfer->rx_buf;
tx = xfer->tx_buf;
do {
- c-=4;
+ c -= 4;
if (xfer->tx_buf != NULL)
- spi100k_write_data(spi->master,word_len, *tx);
+ spi100k_write_data(spi->master, word_len, *tx);
if (xfer->rx_buf != NULL)
- *rx = spi100k_read_data(spi->master,word_len);
- } while(c);
+ *rx = spi100k_read_data(spi->master, word_len);
+ } while (c);
}
return count - c;
}
@@ -294,7 +283,7 @@ static int omap1_spi100k_setup(struct spi_device *spi)
spi100k = spi_master_get_devdata(spi->master);
if (!cs) {
- cs = kzalloc(sizeof *cs, GFP_KERNEL);
+ cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL);
if (!cs)
return -ENOMEM;
cs->base = spi100k->base + spi->chip_select * 0x14;
@@ -411,14 +400,14 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
if (!pdev->id)
return -EINVAL;
- master = spi_alloc_master(&pdev->dev, sizeof *spi100k);
+ master = spi_alloc_master(&pdev->dev, sizeof(*spi100k));
if (master == NULL) {
dev_dbg(&pdev->dev, "master allocation failed\n");
return -ENOMEM;
}
if (pdev->id != -1)
- master->bus_num = pdev->id;
+ master->bus_num = pdev->id;
master->setup = omap1_spi100k_setup;
master->transfer_one_message = omap1_spi100k_transfer_one_message;
@@ -434,7 +423,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
spi100k = spi_master_get_devdata(master);
- spi100k->master = master;
/*
* The memory region base address is taken as the platform_data.
@@ -461,8 +449,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
if (status < 0)
goto err;
- spi100k->state = SPI_RUNNING;
-
return status;
err:
diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c
index 9313fd3b413..be2a2e108e2 100644
--- a/drivers/spi/spi-omap-uwire.c
+++ b/drivers/spi/spi-omap-uwire.c
@@ -99,7 +99,6 @@ struct uwire_spi {
};
struct uwire_state {
- unsigned bits_per_word;
unsigned div1_idx;
};
@@ -210,9 +209,8 @@ static void uwire_chipselect(struct spi_device *spi, int value)
static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
{
- struct uwire_state *ust = spi->controller_state;
unsigned len = t->len;
- unsigned bits = ust->bits_per_word;
+ unsigned bits = t->bits_per_word ? : spi->bits_per_word;
unsigned bytes;
u16 val, w;
int status = 0;
@@ -220,10 +218,6 @@ static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
if (!t->tx_buf && !t->rx_buf)
return 0;
- /* Microwire doesn't read and write concurrently */
- if (t->tx_buf && t->rx_buf)
- return -EPERM;
-
w = spi->chip_select << 10;
w |= CS_CMD;
@@ -322,7 +316,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
struct uwire_state *ust = spi->controller_state;
struct uwire_spi *uwire;
unsigned flags = 0;
- unsigned bits;
unsigned hz;
unsigned long rate;
int div1_idx;
@@ -332,23 +325,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
uwire = spi_master_get_devdata(spi->master);
- if (spi->chip_select > 3) {
- pr_debug("%s: cs%d?\n", dev_name(&spi->dev), spi->chip_select);
- status = -ENODEV;
- goto done;
- }
-
- bits = spi->bits_per_word;
- if (t != NULL && t->bits_per_word)
- bits = t->bits_per_word;
-
- if (bits > 16) {
- pr_debug("%s: wordsize %d?\n", dev_name(&spi->dev), bits);
- status = -ENODEV;
- goto done;
- }
- ust->bits_per_word = bits;
-
/* mode 0..3, clock inverted separately;
* standard nCS signaling;
* don't treat DI=high as "not ready"
@@ -502,6 +478,7 @@ static int uwire_probe(struct platform_device *pdev)
status = PTR_ERR(uwire->ck);
dev_dbg(&pdev->dev, "no functional clock?\n");
spi_master_put(master);
+ iounmap(uwire_base);
return status;
}
clk_enable(uwire->ck);
@@ -515,7 +492,7 @@ static int uwire_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
-
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
master->flags = SPI_MASTER_HALF_DUPLEX;
master->bus_num = 2; /* "official" */
@@ -539,14 +516,13 @@ static int uwire_probe(struct platform_device *pdev)
static int uwire_remove(struct platform_device *pdev)
{
struct uwire_spi *uwire = platform_get_drvdata(pdev);
- int status;
// FIXME remove all child devices, somewhere ...
- status = spi_bitbang_stop(&uwire->bitbang);
+ spi_bitbang_stop(&uwire->bitbang);
uwire_off(uwire);
iounmap(uwire_base);
- return status;
+ return 0;
}
/* work with hotplug and coldplug */
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index a72127f08e3..2941c5b96eb 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -22,7 +22,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/device.h>
@@ -45,6 +44,7 @@
#include <linux/platform_data/spi-omap2-mcspi.h>
#define OMAP2_MCSPI_MAX_FREQ 48000000
+#define OMAP2_MCSPI_MAX_DIVIDER 4096
#define OMAP2_MCSPI_MAX_FIFODEPTH 64
#define OMAP2_MCSPI_MAX_FIFOWCNT 0xFFFF
#define SPI_AUTOSUSPEND_TIMEOUT 2000
@@ -89,6 +89,7 @@
#define OMAP2_MCSPI_CHCONF_FORCE BIT(20)
#define OMAP2_MCSPI_CHCONF_FFET BIT(27)
#define OMAP2_MCSPI_CHCONF_FFER BIT(28)
+#define OMAP2_MCSPI_CHCONF_CLKG BIT(29)
#define OMAP2_MCSPI_CHSTAT_RXS BIT(0)
#define OMAP2_MCSPI_CHSTAT_TXS BIT(1)
@@ -96,6 +97,7 @@
#define OMAP2_MCSPI_CHSTAT_TXFFE BIT(3)
#define OMAP2_MCSPI_CHCTRL_EN BIT(0)
+#define OMAP2_MCSPI_CHCTRL_EXTCLK_MASK (0xff << 8)
#define OMAP2_MCSPI_WAKEUPENABLE_WKEN BIT(0)
@@ -149,7 +151,7 @@ struct omap2_mcspi_cs {
int word_len;
struct list_head node;
/* Context save and restore shadow register */
- u32 chconf0;
+ u32 chconf0, chctrl0;
};
static inline void mcspi_write_reg(struct spi_master *master,
@@ -230,10 +232,16 @@ static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
{
+ struct omap2_mcspi_cs *cs = spi->controller_state;
u32 l;
- l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0;
- mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
+ l = cs->chctrl0;
+ if (enable)
+ l |= OMAP2_MCSPI_CHCTRL_EN;
+ else
+ l &= ~OMAP2_MCSPI_CHCTRL_EN;
+ cs->chctrl0 = l;
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
/* Flash post-writes */
mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
}
@@ -840,7 +848,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
struct omap2_mcspi_cs *cs = spi->controller_state;
struct omap2_mcspi *mcspi;
struct spi_master *spi_cntrl;
- u32 l = 0, div = 0;
+ u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0;
u8 word_len = spi->bits_per_word;
u32 speed_hz = spi->max_speed_hz;
@@ -856,7 +864,17 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
speed_hz = t->speed_hz;
speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ);
- div = omap2_mcspi_calc_divisor(speed_hz);
+ if (speed_hz < (OMAP2_MCSPI_MAX_FREQ / OMAP2_MCSPI_MAX_DIVIDER)) {
+ clkd = omap2_mcspi_calc_divisor(speed_hz);
+ speed_hz = OMAP2_MCSPI_MAX_FREQ >> clkd;
+ clkg = 0;
+ } else {
+ div = (OMAP2_MCSPI_MAX_FREQ + speed_hz - 1) / speed_hz;
+ speed_hz = OMAP2_MCSPI_MAX_FREQ / div;
+ clkd = (div - 1) & 0xf;
+ extclk = (div - 1) >> 4;
+ clkg = OMAP2_MCSPI_CHCONF_CLKG;
+ }
l = mcspi_cached_chconf0(spi);
@@ -885,7 +903,16 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
/* set clock divisor */
l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK;
- l |= div << 2;
+ l |= clkd << 2;
+
+ /* set clock granularity */
+ l &= ~OMAP2_MCSPI_CHCONF_CLKG;
+ l |= clkg;
+ if (clkg) {
+ cs->chctrl0 &= ~OMAP2_MCSPI_CHCTRL_EXTCLK_MASK;
+ cs->chctrl0 |= extclk << 8;
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
+ }
/* set SPI mode 0..3 */
if (spi->mode & SPI_CPOL)
@@ -900,7 +927,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
mcspi_write_chconf0(spi, l);
dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n",
- OMAP2_MCSPI_MAX_FREQ >> div,
+ speed_hz,
(spi->mode & SPI_CPHA) ? "trailing" : "leading",
(spi->mode & SPI_CPOL) ? "inverted" : "normal");
@@ -972,6 +999,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
cs->base = mcspi->base + spi->chip_select * 0x14;
cs->phys = mcspi->phys + spi->chip_select * 0x14;
cs->chconf0 = 0;
+ cs->chctrl0 = 0;
spi->controller_state = cs;
/* Link this to context save list */
list_add_tail(&cs->node, &ctx->cs);
@@ -1057,12 +1085,15 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
status = -EINVAL;
break;
}
- if (par_override || t->speed_hz || t->bits_per_word) {
+ if (par_override ||
+ (t->speed_hz != spi->max_speed_hz) ||
+ (t->bits_per_word != spi->bits_per_word)) {
par_override = 1;
status = omap2_mcspi_setup_transfer(spi, t);
if (status < 0)
break;
- if (!t->speed_hz && !t->bits_per_word)
+ if (t->speed_hz == spi->max_speed_hz &&
+ t->bits_per_word == spi->bits_per_word)
par_override = 0;
}
if (cd && cd->cs_per_word) {
@@ -1176,16 +1207,12 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
m->actual_length = 0;
m->status = 0;
- /* reject invalid messages and transfers */
- if (list_empty(&m->transfers))
- return -EINVAL;
list_for_each_entry(t, &m->transfers, transfer_list) {
const void *tx_buf = t->tx_buf;
void *rx_buf = t->rx_buf;
unsigned len = t->len;
- if (t->speed_hz > OMAP2_MCSPI_MAX_FREQ
- || (len && !(rx_buf || tx_buf))) {
+ if ((len && !(rx_buf || tx_buf))) {
dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
t->speed_hz,
len,
@@ -1194,12 +1221,6 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
t->bits_per_word);
return -EINVAL;
}
- if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) {
- dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n",
- t->speed_hz,
- OMAP2_MCSPI_MAX_FREQ >> 15);
- return -EINVAL;
- }
if (m->is_dma_mapped || len < DMA_MIN_BYTES)
continue;
@@ -1311,6 +1332,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
master->transfer_one_message = omap2_mcspi_transfer_one_message;
master->cleanup = omap2_mcspi_cleanup;
master->dev.of_node = node;
+ master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;
+ master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15;
platform_set_drvdata(pdev, master);
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 7f2121fe262..d018a4aac3a 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -9,7 +9,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
@@ -43,8 +42,6 @@
struct orion_spi {
struct spi_master *master;
void __iomem *base;
- unsigned int max_speed;
- unsigned int min_speed;
struct clk *clk;
};
@@ -75,23 +72,6 @@ orion_spi_clrbits(struct orion_spi *orion_spi, u32 reg, u32 mask)
writel(val, reg_addr);
}
-static int orion_spi_set_transfer_size(struct orion_spi *orion_spi, int size)
-{
- if (size == 16) {
- orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
- ORION_SPI_IF_8_16_BIT_MODE);
- } else if (size == 8) {
- orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
- ORION_SPI_IF_8_16_BIT_MODE);
- } else {
- pr_debug("Bad bits per word value %d (only 8 or 16 are allowed).\n",
- size);
- return -EINVAL;
- }
-
- return 0;
-}
-
static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
{
u32 tclk_hz;
@@ -170,7 +150,14 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
if (rc)
return rc;
- return orion_spi_set_transfer_size(orion_spi, bits_per_word);
+ if (bits_per_word == 16)
+ orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
+ ORION_SPI_IF_8_16_BIT_MODE);
+ else
+ orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
+ ORION_SPI_IF_8_16_BIT_MODE);
+
+ return 0;
}
static void orion_spi_set_cs(struct orion_spi *orion_spi, int enable)
@@ -260,11 +247,9 @@ orion_spi_write_read_16bit(struct spi_device *spi,
static unsigned int
orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
{
- struct orion_spi *orion_spi;
unsigned int count;
int word_len;
- orion_spi = spi_master_get_devdata(spi->master);
word_len = spi->bits_per_word;
count = xfer->len;
@@ -310,27 +295,6 @@ static int orion_spi_transfer_one_message(struct spi_master *master,
goto msg_done;
list_for_each_entry(t, &m->transfers, transfer_list) {
- /* make sure buffer length is even when working in 16
- * bit mode*/
- if ((t->bits_per_word == 16) && (t->len & 1)) {
- dev_err(&spi->dev,
- "message rejected : "
- "odd data length %d while in 16 bit mode\n",
- t->len);
- status = -EIO;
- goto msg_done;
- }
-
- if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
- dev_err(&spi->dev,
- "message rejected : "
- "device min speed (%d Hz) exceeds "
- "required transfer speed (%d Hz)\n",
- orion_spi->min_speed, t->speed_hz);
- status = -EIO;
- goto msg_done;
- }
-
if (par_override || t->speed_hz || t->bits_per_word) {
par_override = 1;
status = orion_spi_setup_transfer(spi, t);
@@ -375,28 +339,6 @@ static int orion_spi_reset(struct orion_spi *orion_spi)
return 0;
}
-static int orion_spi_setup(struct spi_device *spi)
-{
- struct orion_spi *orion_spi;
-
- orion_spi = spi_master_get_devdata(spi->master);
-
- if ((spi->max_speed_hz == 0)
- || (spi->max_speed_hz > orion_spi->max_speed))
- spi->max_speed_hz = orion_spi->max_speed;
-
- if (spi->max_speed_hz < orion_spi->min_speed) {
- dev_err(&spi->dev, "setup: requested speed too low %d Hz\n",
- spi->max_speed_hz);
- return -EINVAL;
- }
-
- /*
- * baudrate & width will be set orion_spi_setup_transfer
- */
- return 0;
-}
-
static int orion_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
@@ -425,9 +367,9 @@ static int orion_spi_probe(struct platform_device *pdev)
/* we support only mode 0, and no options */
master->mode_bits = SPI_CPHA | SPI_CPOL;
- master->setup = orion_spi_setup;
master->transfer_one_message = orion_spi_transfer_one_message;
master->num_chipselect = ORION_NUM_CHIPSELECTS;
+ master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
platform_set_drvdata(pdev, master);
@@ -443,8 +385,8 @@ static int orion_spi_probe(struct platform_device *pdev)
clk_prepare(spi->clk);
clk_enable(spi->clk);
tclk_hz = clk_get_rate(spi->clk);
- spi->max_speed = DIV_ROUND_UP(tclk_hz, 4);
- spi->min_speed = DIV_ROUND_UP(tclk_hz, 30);
+ master->max_speed_hz = DIV_ROUND_UP(tclk_hz, 4);
+ master->min_speed_hz = DIV_ROUND_UP(tclk_hz, 30);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
spi->base = devm_ioremap_resource(&pdev->dev, r);
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 2789b452e71..51d99779682 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -459,9 +459,8 @@ static void giveback(struct pl022 *pl022)
struct spi_transfer *last_transfer;
pl022->next_msg_cs_active = false;
- last_transfer = list_entry(pl022->cur_msg->transfers.prev,
- struct spi_transfer,
- transfer_list);
+ last_transfer = list_last_entry(&pl022->cur_msg->transfers,
+ struct spi_transfer, transfer_list);
/* Delay if requested before any change in chip select */
if (last_transfer->delay_usecs)
@@ -2109,8 +2108,6 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int),
GFP_KERNEL);
- pinctrl_pm_select_default_state(dev);
-
/*
* Bus Number Which has been Assigned to this SSP controller
* on this board
@@ -2183,13 +2180,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
goto err_no_clk;
}
- status = clk_prepare(pl022->clk);
- if (status) {
- dev_err(&adev->dev, "could not prepare SSP/SPI bus clock\n");
- goto err_clk_prep;
- }
-
- status = clk_enable(pl022->clk);
+ status = clk_prepare_enable(pl022->clk);
if (status) {
dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n");
goto err_no_clk_en;
@@ -2250,10 +2241,8 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
if (platform_info->enable_dma)
pl022_dma_remove(pl022);
err_no_irq:
- clk_disable(pl022->clk);
+ clk_disable_unprepare(pl022->clk);
err_no_clk_en:
- clk_unprepare(pl022->clk);
- err_clk_prep:
err_no_clk:
err_no_ioremap:
amba_release_regions(adev);
@@ -2281,42 +2270,13 @@ pl022_remove(struct amba_device *adev)
if (pl022->master_info->enable_dma)
pl022_dma_remove(pl022);
- clk_disable(pl022->clk);
- clk_unprepare(pl022->clk);
+ clk_disable_unprepare(pl022->clk);
amba_release_regions(adev);
tasklet_disable(&pl022->pump_transfers);
return 0;
}
-#if defined(CONFIG_SUSPEND) || defined(CONFIG_PM_RUNTIME)
-/*
- * These two functions are used from both suspend/resume and
- * the runtime counterparts to handle external resources like
- * clocks, pins and regulators when going to sleep.
- */
-static void pl022_suspend_resources(struct pl022 *pl022, bool runtime)
-{
- clk_disable(pl022->clk);
-
- if (runtime)
- pinctrl_pm_select_idle_state(&pl022->adev->dev);
- else
- pinctrl_pm_select_sleep_state(&pl022->adev->dev);
-}
-
-static void pl022_resume_resources(struct pl022 *pl022, bool runtime)
-{
- /* First go to the default state */
- pinctrl_pm_select_default_state(&pl022->adev->dev);
- if (!runtime)
- /* Then let's idle the pins until the next transfer happens */
- pinctrl_pm_select_idle_state(&pl022->adev->dev);
-
- clk_enable(pl022->clk);
-}
-#endif
-
-#ifdef CONFIG_SUSPEND
+#ifdef CONFIG_PM_SLEEP
static int pl022_suspend(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
@@ -2328,8 +2288,13 @@ static int pl022_suspend(struct device *dev)
return ret;
}
- pm_runtime_get_sync(dev);
- pl022_suspend_resources(pl022, false);
+ ret = pm_runtime_force_suspend(dev);
+ if (ret) {
+ spi_master_resume(pl022->master);
+ return ret;
+ }
+
+ pinctrl_pm_select_sleep_state(dev);
dev_dbg(dev, "suspended\n");
return 0;
@@ -2340,8 +2305,9 @@ static int pl022_resume(struct device *dev)
struct pl022 *pl022 = dev_get_drvdata(dev);
int ret;
- pl022_resume_resources(pl022, false);
- pm_runtime_put(dev);
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ dev_err(dev, "problem resuming\n");
/* Start the queue running */
ret = spi_master_resume(pl022->master);
@@ -2352,14 +2318,16 @@ static int pl022_resume(struct device *dev)
return ret;
}
-#endif /* CONFIG_PM */
+#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int pl022_runtime_suspend(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
- pl022_suspend_resources(pl022, true);
+ clk_disable_unprepare(pl022->clk);
+ pinctrl_pm_select_idle_state(dev);
+
return 0;
}
@@ -2367,14 +2335,16 @@ static int pl022_runtime_resume(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
- pl022_resume_resources(pl022, true);
+ pinctrl_pm_select_default_state(dev);
+ clk_prepare_enable(pl022->clk);
+
return 0;
}
#endif
static const struct dev_pm_ops pl022_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume)
- SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
+ SET_PM_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
};
static struct vendor_data vendor_arm = {
diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c
index 5ee56726f8d..80b8408ac3e 100644
--- a/drivers/spi/spi-ppc4xx.c
+++ b/drivers/spi/spi-ppc4xx.c
@@ -24,7 +24,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c
index 3c0b55125f1..713af4806f2 100644
--- a/drivers/spi/spi-pxa2xx-dma.c
+++ b/drivers/spi/spi-pxa2xx-dma.c
@@ -9,7 +9,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
diff --git a/drivers/spi/spi-pxa2xx-pxadma.c b/drivers/spi/spi-pxa2xx-pxadma.c
index 2916efc7cfe..e8a26f25d5c 100644
--- a/drivers/spi/spi-pxa2xx-pxadma.c
+++ b/drivers/spi/spi-pxa2xx-pxadma.c
@@ -18,7 +18,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index c702fc536a7..41185d0557f 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -362,8 +362,7 @@ static void giveback(struct driver_data *drv_data)
drv_data->cur_msg = NULL;
drv_data->cur_transfer = NULL;
- last_transfer = list_entry(msg->transfers.prev,
- struct spi_transfer,
+ last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
transfer_list);
/* Delay if requested before any change in chip select */
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
new file mode 100644
index 00000000000..b032e8885e2
--- /dev/null
+++ b/drivers/spi/spi-qup.c
@@ -0,0 +1,779 @@
+/*
+ * Copyright (c) 2008-2014, The Linux foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License rev 2 and
+ * only rev 2 as published by the free Software foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or fITNESS fOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+
+#define QUP_CONFIG 0x0000
+#define QUP_STATE 0x0004
+#define QUP_IO_M_MODES 0x0008
+#define QUP_SW_RESET 0x000c
+#define QUP_OPERATIONAL 0x0018
+#define QUP_ERROR_FLAGS 0x001c
+#define QUP_ERROR_FLAGS_EN 0x0020
+#define QUP_OPERATIONAL_MASK 0x0028
+#define QUP_HW_VERSION 0x0030
+#define QUP_MX_OUTPUT_CNT 0x0100
+#define QUP_OUTPUT_FIFO 0x0110
+#define QUP_MX_WRITE_CNT 0x0150
+#define QUP_MX_INPUT_CNT 0x0200
+#define QUP_MX_READ_CNT 0x0208
+#define QUP_INPUT_FIFO 0x0218
+
+#define SPI_CONFIG 0x0300
+#define SPI_IO_CONTROL 0x0304
+#define SPI_ERROR_FLAGS 0x0308
+#define SPI_ERROR_FLAGS_EN 0x030c
+
+/* QUP_CONFIG fields */
+#define QUP_CONFIG_SPI_MODE (1 << 8)
+#define QUP_CONFIG_CLOCK_AUTO_GATE BIT(13)
+#define QUP_CONFIG_NO_INPUT BIT(7)
+#define QUP_CONFIG_NO_OUTPUT BIT(6)
+#define QUP_CONFIG_N 0x001f
+
+/* QUP_STATE fields */
+#define QUP_STATE_VALID BIT(2)
+#define QUP_STATE_RESET 0
+#define QUP_STATE_RUN 1
+#define QUP_STATE_PAUSE 3
+#define QUP_STATE_MASK 3
+#define QUP_STATE_CLEAR 2
+
+#define QUP_HW_VERSION_2_1_1 0x20010001
+
+/* QUP_IO_M_MODES fields */
+#define QUP_IO_M_PACK_EN BIT(15)
+#define QUP_IO_M_UNPACK_EN BIT(14)
+#define QUP_IO_M_INPUT_MODE_MASK_SHIFT 12
+#define QUP_IO_M_OUTPUT_MODE_MASK_SHIFT 10
+#define QUP_IO_M_INPUT_MODE_MASK (3 << QUP_IO_M_INPUT_MODE_MASK_SHIFT)
+#define QUP_IO_M_OUTPUT_MODE_MASK (3 << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT)
+
+#define QUP_IO_M_OUTPUT_BLOCK_SIZE(x) (((x) & (0x03 << 0)) >> 0)
+#define QUP_IO_M_OUTPUT_FIFO_SIZE(x) (((x) & (0x07 << 2)) >> 2)
+#define QUP_IO_M_INPUT_BLOCK_SIZE(x) (((x) & (0x03 << 5)) >> 5)
+#define QUP_IO_M_INPUT_FIFO_SIZE(x) (((x) & (0x07 << 7)) >> 7)
+
+#define QUP_IO_M_MODE_FIFO 0
+#define QUP_IO_M_MODE_BLOCK 1
+#define QUP_IO_M_MODE_DMOV 2
+#define QUP_IO_M_MODE_BAM 3
+
+/* QUP_OPERATIONAL fields */
+#define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11)
+#define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10)
+#define QUP_OP_IN_SERVICE_FLAG BIT(9)
+#define QUP_OP_OUT_SERVICE_FLAG BIT(8)
+#define QUP_OP_IN_FIFO_FULL BIT(7)
+#define QUP_OP_OUT_FIFO_FULL BIT(6)
+#define QUP_OP_IN_FIFO_NOT_EMPTY BIT(5)
+#define QUP_OP_OUT_FIFO_NOT_EMPTY BIT(4)
+
+/* QUP_ERROR_FLAGS and QUP_ERROR_FLAGS_EN fields */
+#define QUP_ERROR_OUTPUT_OVER_RUN BIT(5)
+#define QUP_ERROR_INPUT_UNDER_RUN BIT(4)
+#define QUP_ERROR_OUTPUT_UNDER_RUN BIT(3)
+#define QUP_ERROR_INPUT_OVER_RUN BIT(2)
+
+/* SPI_CONFIG fields */
+#define SPI_CONFIG_HS_MODE BIT(10)
+#define SPI_CONFIG_INPUT_FIRST BIT(9)
+#define SPI_CONFIG_LOOPBACK BIT(8)
+
+/* SPI_IO_CONTROL fields */
+#define SPI_IO_C_FORCE_CS BIT(11)
+#define SPI_IO_C_CLK_IDLE_HIGH BIT(10)
+#define SPI_IO_C_MX_CS_MODE BIT(8)
+#define SPI_IO_C_CS_N_POLARITY_0 BIT(4)
+#define SPI_IO_C_CS_SELECT(x) (((x) & 3) << 2)
+#define SPI_IO_C_CS_SELECT_MASK 0x000c
+#define SPI_IO_C_TRISTATE_CS BIT(1)
+#define SPI_IO_C_NO_TRI_STATE BIT(0)
+
+/* SPI_ERROR_FLAGS and SPI_ERROR_FLAGS_EN fields */
+#define SPI_ERROR_CLK_OVER_RUN BIT(1)
+#define SPI_ERROR_CLK_UNDER_RUN BIT(0)
+
+#define SPI_NUM_CHIPSELECTS 4
+
+/* high speed mode is when bus rate is greater then 26MHz */
+#define SPI_HS_MIN_RATE 26000000
+#define SPI_MAX_RATE 50000000
+
+#define SPI_DELAY_THRESHOLD 1
+#define SPI_DELAY_RETRY 10
+
+struct spi_qup {
+ void __iomem *base;
+ struct device *dev;
+ struct clk *cclk; /* core clock */
+ struct clk *iclk; /* interface clock */
+ int irq;
+ spinlock_t lock;
+
+ int in_fifo_sz;
+ int out_fifo_sz;
+ int in_blk_sz;
+ int out_blk_sz;
+
+ struct spi_transfer *xfer;
+ struct completion done;
+ int error;
+ int w_size; /* bytes per SPI word */
+ int tx_bytes;
+ int rx_bytes;
+};
+
+
+static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
+{
+ u32 opstate = readl_relaxed(controller->base + QUP_STATE);
+
+ return opstate & QUP_STATE_VALID;
+}
+
+static int spi_qup_set_state(struct spi_qup *controller, u32 state)
+{
+ unsigned long loop;
+ u32 cur_state;
+
+ loop = 0;
+ while (!spi_qup_is_valid_state(controller)) {
+
+ usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2);
+
+ if (++loop > SPI_DELAY_RETRY)
+ return -EIO;
+ }
+
+ if (loop)
+ dev_dbg(controller->dev, "invalid state for %ld,us %d\n",
+ loop, state);
+
+ cur_state = readl_relaxed(controller->base + QUP_STATE);
+ /*
+ * Per spec: for PAUSE_STATE to RESET_STATE, two writes
+ * of (b10) are required
+ */
+ if (((cur_state & QUP_STATE_MASK) == QUP_STATE_PAUSE) &&
+ (state == QUP_STATE_RESET)) {
+ writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE);
+ writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE);
+ } else {
+ cur_state &= ~QUP_STATE_MASK;
+ cur_state |= state;
+ writel_relaxed(cur_state, controller->base + QUP_STATE);
+ }
+
+ loop = 0;
+ while (!spi_qup_is_valid_state(controller)) {
+
+ usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2);
+
+ if (++loop > SPI_DELAY_RETRY)
+ return -EIO;
+ }
+
+ return 0;
+}
+
+
+static void spi_qup_fifo_read(struct spi_qup *controller,
+ struct spi_transfer *xfer)
+{
+ u8 *rx_buf = xfer->rx_buf;
+ u32 word, state;
+ int idx, shift, w_size;
+
+ w_size = controller->w_size;
+
+ while (controller->rx_bytes < xfer->len) {
+
+ state = readl_relaxed(controller->base + QUP_OPERATIONAL);
+ if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY))
+ break;
+
+ word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
+
+ if (!rx_buf) {
+ controller->rx_bytes += w_size;
+ continue;
+ }
+
+ for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) {
+ /*
+ * The data format depends on bytes per SPI word:
+ * 4 bytes: 0x12345678
+ * 2 bytes: 0x00001234
+ * 1 byte : 0x00000012
+ */
+ shift = BITS_PER_BYTE;
+ shift *= (w_size - idx - 1);
+ rx_buf[controller->rx_bytes] = word >> shift;
+ }
+ }
+}
+
+static void spi_qup_fifo_write(struct spi_qup *controller,
+ struct spi_transfer *xfer)
+{
+ const u8 *tx_buf = xfer->tx_buf;
+ u32 word, state, data;
+ int idx, w_size;
+
+ w_size = controller->w_size;
+
+ while (controller->tx_bytes < xfer->len) {
+
+ state = readl_relaxed(controller->base + QUP_OPERATIONAL);
+ if (state & QUP_OP_OUT_FIFO_FULL)
+ break;
+
+ word = 0;
+ for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) {
+
+ if (!tx_buf) {
+ controller->tx_bytes += w_size;
+ break;
+ }
+
+ data = tx_buf[controller->tx_bytes];
+ word |= data << (BITS_PER_BYTE * (3 - idx));
+ }
+
+ writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO);
+ }
+}
+
+static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
+{
+ struct spi_qup *controller = dev_id;
+ struct spi_transfer *xfer;
+ u32 opflags, qup_err, spi_err;
+ unsigned long flags;
+ int error = 0;
+
+ spin_lock_irqsave(&controller->lock, flags);
+ xfer = controller->xfer;
+ controller->xfer = NULL;
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+ qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS);
+ spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS);
+ opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
+
+ writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS);
+ writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS);
+ writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
+
+ if (!xfer) {
+ dev_err_ratelimited(controller->dev, "unexpected irq %x08 %x08 %x08\n",
+ qup_err, spi_err, opflags);
+ return IRQ_HANDLED;
+ }
+
+ if (qup_err) {
+ if (qup_err & QUP_ERROR_OUTPUT_OVER_RUN)
+ dev_warn(controller->dev, "OUTPUT_OVER_RUN\n");
+ if (qup_err & QUP_ERROR_INPUT_UNDER_RUN)
+ dev_warn(controller->dev, "INPUT_UNDER_RUN\n");
+ if (qup_err & QUP_ERROR_OUTPUT_UNDER_RUN)
+ dev_warn(controller->dev, "OUTPUT_UNDER_RUN\n");
+ if (qup_err & QUP_ERROR_INPUT_OVER_RUN)
+ dev_warn(controller->dev, "INPUT_OVER_RUN\n");
+
+ error = -EIO;
+ }
+
+ if (spi_err) {
+ if (spi_err & SPI_ERROR_CLK_OVER_RUN)
+ dev_warn(controller->dev, "CLK_OVER_RUN\n");
+ if (spi_err & SPI_ERROR_CLK_UNDER_RUN)
+ dev_warn(controller->dev, "CLK_UNDER_RUN\n");
+
+ error = -EIO;
+ }
+
+ if (opflags & QUP_OP_IN_SERVICE_FLAG)
+ spi_qup_fifo_read(controller, xfer);
+
+ if (opflags & QUP_OP_OUT_SERVICE_FLAG)
+ spi_qup_fifo_write(controller, xfer);
+
+ spin_lock_irqsave(&controller->lock, flags);
+ controller->error = error;
+ controller->xfer = xfer;
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+ if (controller->rx_bytes == xfer->len || error)
+ complete(&controller->done);
+
+ return IRQ_HANDLED;
+}
+
+
+/* set clock freq ... bits per word */
+static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
+{
+ struct spi_qup *controller = spi_master_get_devdata(spi->master);
+ u32 config, iomode, mode;
+ int ret, n_words, w_size;
+
+ if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
+ dev_err(controller->dev, "too big size for loopback %d > %d\n",
+ xfer->len, controller->in_fifo_sz);
+ return -EIO;
+ }
+
+ ret = clk_set_rate(controller->cclk, xfer->speed_hz);
+ if (ret) {
+ dev_err(controller->dev, "fail to set frequency %d",
+ xfer->speed_hz);
+ return -EIO;
+ }
+
+ if (spi_qup_set_state(controller, QUP_STATE_RESET)) {
+ dev_err(controller->dev, "cannot set RESET state\n");
+ return -EIO;
+ }
+
+ w_size = 4;
+ if (xfer->bits_per_word <= 8)
+ w_size = 1;
+ else if (xfer->bits_per_word <= 16)
+ w_size = 2;
+
+ n_words = xfer->len / w_size;
+ controller->w_size = w_size;
+
+ if (n_words <= controller->in_fifo_sz) {
+ mode = QUP_IO_M_MODE_FIFO;
+ writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
+ writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT);
+ /* must be zero for FIFO */
+ writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
+ writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
+ } else {
+ mode = QUP_IO_M_MODE_BLOCK;
+ writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
+ writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
+ /* must be zero for BLOCK and BAM */
+ writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
+ writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
+ }
+
+ iomode = readl_relaxed(controller->base + QUP_IO_M_MODES);
+ /* Set input and output transfer mode */
+ iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK);
+ iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
+ iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
+ iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
+
+ writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
+
+ config = readl_relaxed(controller->base + SPI_CONFIG);
+
+ if (spi->mode & SPI_LOOP)
+ config |= SPI_CONFIG_LOOPBACK;
+ else
+ config &= ~SPI_CONFIG_LOOPBACK;
+
+ if (spi->mode & SPI_CPHA)
+ config &= ~SPI_CONFIG_INPUT_FIRST;
+ else
+ config |= SPI_CONFIG_INPUT_FIRST;
+
+ /*
+ * HS_MODE improves signal stability for spi-clk high rates,
+ * but is invalid in loop back mode.
+ */
+ if ((xfer->speed_hz >= SPI_HS_MIN_RATE) && !(spi->mode & SPI_LOOP))
+ config |= SPI_CONFIG_HS_MODE;
+ else
+ config &= ~SPI_CONFIG_HS_MODE;
+
+ writel_relaxed(config, controller->base + SPI_CONFIG);
+
+ config = readl_relaxed(controller->base + QUP_CONFIG);
+ config &= ~(QUP_CONFIG_NO_INPUT | QUP_CONFIG_NO_OUTPUT | QUP_CONFIG_N);
+ config |= xfer->bits_per_word - 1;
+ config |= QUP_CONFIG_SPI_MODE;
+ writel_relaxed(config, controller->base + QUP_CONFIG);
+
+ writel_relaxed(0, controller->base + QUP_OPERATIONAL_MASK);
+ return 0;
+}
+
+static void spi_qup_set_cs(struct spi_device *spi, bool enable)
+{
+ struct spi_qup *controller = spi_master_get_devdata(spi->master);
+
+ u32 iocontol, mask;
+
+ iocontol = readl_relaxed(controller->base + SPI_IO_CONTROL);
+
+ /* Disable auto CS toggle and use manual */
+ iocontol &= ~SPI_IO_C_MX_CS_MODE;
+ iocontol |= SPI_IO_C_FORCE_CS;
+
+ iocontol &= ~SPI_IO_C_CS_SELECT_MASK;
+ iocontol |= SPI_IO_C_CS_SELECT(spi->chip_select);
+
+ mask = SPI_IO_C_CS_N_POLARITY_0 << spi->chip_select;
+
+ if (enable)
+ iocontol |= mask;
+ else
+ iocontol &= ~mask;
+
+ writel_relaxed(iocontol, controller->base + SPI_IO_CONTROL);
+}
+
+static int spi_qup_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ unsigned long timeout, flags;
+ int ret = -EIO;
+
+ ret = spi_qup_io_config(spi, xfer);
+ if (ret)
+ return ret;
+
+ timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
+ timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
+ timeout = 100 * msecs_to_jiffies(timeout);
+
+ reinit_completion(&controller->done);
+
+ spin_lock_irqsave(&controller->lock, flags);
+ controller->xfer = xfer;
+ controller->error = 0;
+ controller->rx_bytes = 0;
+ controller->tx_bytes = 0;
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+ if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
+ dev_warn(controller->dev, "cannot set RUN state\n");
+ goto exit;
+ }
+
+ if (spi_qup_set_state(controller, QUP_STATE_PAUSE)) {
+ dev_warn(controller->dev, "cannot set PAUSE state\n");
+ goto exit;
+ }
+
+ spi_qup_fifo_write(controller, xfer);
+
+ if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
+ dev_warn(controller->dev, "cannot set EXECUTE state\n");
+ goto exit;
+ }
+
+ if (!wait_for_completion_timeout(&controller->done, timeout))
+ ret = -ETIMEDOUT;
+exit:
+ spi_qup_set_state(controller, QUP_STATE_RESET);
+ spin_lock_irqsave(&controller->lock, flags);
+ controller->xfer = NULL;
+ if (!ret)
+ ret = controller->error;
+ spin_unlock_irqrestore(&controller->lock, flags);
+ return ret;
+}
+
+static int spi_qup_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct clk *iclk, *cclk;
+ struct spi_qup *controller;
+ struct resource *res;
+ struct device *dev;
+ void __iomem *base;
+ u32 data, max_freq, iomode;
+ int ret, irq, size;
+
+ dev = &pdev->dev;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ cclk = devm_clk_get(dev, "core");
+ if (IS_ERR(cclk))
+ return PTR_ERR(cclk);
+
+ iclk = devm_clk_get(dev, "iface");
+ if (IS_ERR(iclk))
+ return PTR_ERR(iclk);
+
+ /* This is optional parameter */
+ if (of_property_read_u32(dev->of_node, "spi-max-frequency", &max_freq))
+ max_freq = SPI_MAX_RATE;
+
+ if (!max_freq || max_freq > SPI_MAX_RATE) {
+ dev_err(dev, "invalid clock frequency %d\n", max_freq);
+ return -ENXIO;
+ }
+
+ ret = clk_prepare_enable(cclk);
+ if (ret) {
+ dev_err(dev, "cannot enable core clock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(iclk);
+ if (ret) {
+ clk_disable_unprepare(cclk);
+ dev_err(dev, "cannot enable iface clock\n");
+ return ret;
+ }
+
+ data = readl_relaxed(base + QUP_HW_VERSION);
+
+ if (data < QUP_HW_VERSION_2_1_1) {
+ clk_disable_unprepare(cclk);
+ clk_disable_unprepare(iclk);
+ dev_err(dev, "v.%08x is not supported\n", data);
+ return -ENXIO;
+ }
+
+ master = spi_alloc_master(dev, sizeof(struct spi_qup));
+ if (!master) {
+ clk_disable_unprepare(cclk);
+ clk_disable_unprepare(iclk);
+ dev_err(dev, "cannot allocate master\n");
+ return -ENOMEM;
+ }
+
+ master->bus_num = pdev->id;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
+ master->num_chipselect = SPI_NUM_CHIPSELECTS;
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ master->max_speed_hz = max_freq;
+ master->set_cs = spi_qup_set_cs;
+ master->transfer_one = spi_qup_transfer_one;
+ master->dev.of_node = pdev->dev.of_node;
+ master->auto_runtime_pm = true;
+
+ platform_set_drvdata(pdev, master);
+
+ controller = spi_master_get_devdata(master);
+
+ controller->dev = dev;
+ controller->base = base;
+ controller->iclk = iclk;
+ controller->cclk = cclk;
+ controller->irq = irq;
+
+ spin_lock_init(&controller->lock);
+ init_completion(&controller->done);
+
+ iomode = readl_relaxed(base + QUP_IO_M_MODES);
+
+ size = QUP_IO_M_OUTPUT_BLOCK_SIZE(iomode);
+ if (size)
+ controller->out_blk_sz = size * 16;
+ else
+ controller->out_blk_sz = 4;
+
+ size = QUP_IO_M_INPUT_BLOCK_SIZE(iomode);
+ if (size)
+ controller->in_blk_sz = size * 16;
+ else
+ controller->in_blk_sz = 4;
+
+ size = QUP_IO_M_OUTPUT_FIFO_SIZE(iomode);
+ controller->out_fifo_sz = controller->out_blk_sz * (2 << size);
+
+ size = QUP_IO_M_INPUT_FIFO_SIZE(iomode);
+ controller->in_fifo_sz = controller->in_blk_sz * (2 << size);
+
+ dev_info(dev, "v.%08x IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
+ data, controller->in_blk_sz, controller->in_fifo_sz,
+ controller->out_blk_sz, controller->out_fifo_sz);
+
+ writel_relaxed(1, base + QUP_SW_RESET);
+
+ ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+ if (ret) {
+ dev_err(dev, "cannot set RESET state\n");
+ goto error;
+ }
+
+ writel_relaxed(0, base + QUP_OPERATIONAL);
+ writel_relaxed(0, base + QUP_IO_M_MODES);
+ writel_relaxed(0, base + QUP_OPERATIONAL_MASK);
+ writel_relaxed(SPI_ERROR_CLK_UNDER_RUN | SPI_ERROR_CLK_OVER_RUN,
+ base + SPI_ERROR_FLAGS_EN);
+
+ writel_relaxed(0, base + SPI_CONFIG);
+ writel_relaxed(SPI_IO_C_NO_TRI_STATE, base + SPI_IO_CONTROL);
+
+ ret = devm_request_irq(dev, irq, spi_qup_qup_irq,
+ IRQF_TRIGGER_HIGH, pdev->name, controller);
+ if (ret)
+ goto error;
+
+ ret = devm_spi_register_master(dev, master);
+ if (ret)
+ goto error;
+
+ pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ return 0;
+
+error:
+ clk_disable_unprepare(cclk);
+ clk_disable_unprepare(iclk);
+ spi_master_put(master);
+ return ret;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int spi_qup_pm_suspend_runtime(struct device *device)
+{
+ struct spi_master *master = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ u32 config;
+
+ /* Enable clocks auto gaiting */
+ config = readl(controller->base + QUP_CONFIG);
+ config |= QUP_CONFIG_CLOCK_AUTO_GATE;
+ writel_relaxed(config, controller->base + QUP_CONFIG);
+ return 0;
+}
+
+static int spi_qup_pm_resume_runtime(struct device *device)
+{
+ struct spi_master *master = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ u32 config;
+
+ /* Disable clocks auto gaiting */
+ config = readl_relaxed(controller->base + QUP_CONFIG);
+ config &= ~QUP_CONFIG_CLOCK_AUTO_GATE;
+ writel_relaxed(config, controller->base + QUP_CONFIG);
+ return 0;
+}
+#endif /* CONFIG_PM_RUNTIME */
+
+#ifdef CONFIG_PM_SLEEP
+static int spi_qup_suspend(struct device *device)
+{
+ struct spi_master *master = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ int ret;
+
+ ret = spi_master_suspend(master);
+ if (ret)
+ return ret;
+
+ ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+ if (ret)
+ return ret;
+
+ clk_disable_unprepare(controller->cclk);
+ clk_disable_unprepare(controller->iclk);
+ return 0;
+}
+
+static int spi_qup_resume(struct device *device)
+{
+ struct spi_master *master = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(controller->iclk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(controller->cclk);
+ if (ret)
+ return ret;
+
+ ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+ if (ret)
+ return ret;
+
+ return spi_master_resume(master);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static int spi_qup_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = dev_get_drvdata(&pdev->dev);
+ struct spi_qup *controller = spi_master_get_devdata(master);
+ int ret;
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret)
+ return ret;
+
+ ret = spi_qup_set_state(controller, QUP_STATE_RESET);
+ if (ret)
+ return ret;
+
+ clk_disable_unprepare(controller->cclk);
+ clk_disable_unprepare(controller->iclk);
+
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
+static struct of_device_id spi_qup_dt_match[] = {
+ { .compatible = "qcom,spi-qup-v2.1.1", },
+ { .compatible = "qcom,spi-qup-v2.2.1", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, spi_qup_dt_match);
+
+static const struct dev_pm_ops spi_qup_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(spi_qup_suspend, spi_qup_resume)
+ SET_RUNTIME_PM_OPS(spi_qup_pm_suspend_runtime,
+ spi_qup_pm_resume_runtime,
+ NULL)
+};
+
+static struct platform_driver spi_qup_driver = {
+ .driver = {
+ .name = "spi_qup",
+ .owner = THIS_MODULE,
+ .pm = &spi_qup_dev_pm_ops,
+ .of_match_table = spi_qup_dt_match,
+ },
+ .probe = spi_qup_probe,
+ .remove = spi_qup_remove,
+};
+module_platform_driver(spi_qup_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:spi_qup");
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 28987d9fcfe..1fb0ad21332 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -1,7 +1,8 @@
/*
* SH RSPI driver
*
- * Copyright (C) 2012 Renesas Solutions Corp.
+ * Copyright (C) 2012, 2013 Renesas Solutions Corp.
+ * Copyright (C) 2014 Glider bvba
*
* Based on spi-sh.c:
* Copyright (C) 2011 Renesas Solutions Corp.
@@ -25,14 +26,14 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
#include <linux/sh_dma.h>
#include <linux/spi/spi.h>
#include <linux/spi/rspi.h>
@@ -49,7 +50,7 @@
#define RSPI_SPCKD 0x0c /* Clock Delay Register */
#define RSPI_SSLND 0x0d /* Slave Select Negation Delay Register */
#define RSPI_SPND 0x0e /* Next-Access Delay Register */
-#define RSPI_SPCR2 0x0f /* Control Register 2 */
+#define RSPI_SPCR2 0x0f /* Control Register 2 (SH only) */
#define RSPI_SPCMD0 0x10 /* Command Register 0 */
#define RSPI_SPCMD1 0x12 /* Command Register 1 */
#define RSPI_SPCMD2 0x14 /* Command Register 2 */
@@ -58,16 +59,23 @@
#define RSPI_SPCMD5 0x1a /* Command Register 5 */
#define RSPI_SPCMD6 0x1c /* Command Register 6 */
#define RSPI_SPCMD7 0x1e /* Command Register 7 */
+#define RSPI_SPCMD(i) (RSPI_SPCMD0 + (i) * 2)
+#define RSPI_NUM_SPCMD 8
+#define RSPI_RZ_NUM_SPCMD 4
+#define QSPI_NUM_SPCMD 4
+
+/* RSPI on RZ only */
#define RSPI_SPBFCR 0x20 /* Buffer Control Register */
#define RSPI_SPBFDR 0x22 /* Buffer Data Count Setting Register */
-/*qspi only */
+/* QSPI only */
#define QSPI_SPBFCR 0x18 /* Buffer Control Register */
#define QSPI_SPBDCR 0x1a /* Buffer Data Count Register */
#define QSPI_SPBMUL0 0x1c /* Transfer Data Length Multiplier Setting Register 0 */
#define QSPI_SPBMUL1 0x20 /* Transfer Data Length Multiplier Setting Register 1 */
#define QSPI_SPBMUL2 0x24 /* Transfer Data Length Multiplier Setting Register 2 */
#define QSPI_SPBMUL3 0x28 /* Transfer Data Length Multiplier Setting Register 3 */
+#define QSPI_SPBMUL(i) (QSPI_SPBMUL0 + (i) * 4)
/* SPCR - Control Register */
#define SPCR_SPRIE 0x80 /* Receive Interrupt Enable */
@@ -104,7 +112,7 @@
#define SPSR_PERF 0x08 /* Parity Error Flag */
#define SPSR_MODF 0x04 /* Mode Fault Error Flag */
#define SPSR_IDLNF 0x02 /* RSPI Idle Flag */
-#define SPSR_OVRF 0x01 /* Overrun Error Flag */
+#define SPSR_OVRF 0x01 /* Overrun Error Flag (RSPI only) */
/* SPSCR - Sequence Control Register */
#define SPSCR_SPSLN_MASK 0x07 /* Sequence Length Specification */
@@ -121,13 +129,13 @@
#define SPDCR_SPLWORD SPDCR_SPLW1
#define SPDCR_SPLBYTE SPDCR_SPLW0
#define SPDCR_SPLW 0x20 /* Access Width Specification (SH) */
-#define SPDCR_SPRDTD 0x10 /* Receive Transmit Data Select */
+#define SPDCR_SPRDTD 0x10 /* Receive Transmit Data Select (SH) */
#define SPDCR_SLSEL1 0x08
#define SPDCR_SLSEL0 0x04
-#define SPDCR_SLSEL_MASK 0x0c /* SSL1 Output Select */
+#define SPDCR_SLSEL_MASK 0x0c /* SSL1 Output Select (SH) */
#define SPDCR_SPFC1 0x02
#define SPDCR_SPFC0 0x01
-#define SPDCR_SPFC_MASK 0x03 /* Frame Count Setting (1-4) */
+#define SPDCR_SPFC_MASK 0x03 /* Frame Count Setting (1-4) (SH) */
/* SPCKD - Clock Delay Register */
#define SPCKD_SCKDL_MASK 0x07 /* Clock Delay Setting (1-8) */
@@ -151,7 +159,7 @@
#define SPCMD_LSBF 0x1000 /* LSB First */
#define SPCMD_SPB_MASK 0x0f00 /* Data Length Setting */
#define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK)
-#define SPCMD_SPB_8BIT 0x0000 /* qspi only */
+#define SPCMD_SPB_8BIT 0x0000 /* QSPI only */
#define SPCMD_SPB_16BIT 0x0100
#define SPCMD_SPB_20BIT 0x0000
#define SPCMD_SPB_24BIT 0x0100
@@ -170,8 +178,8 @@
#define SPCMD_CPHA 0x0001 /* Clock Phase Setting */
/* SPBFCR - Buffer Control Register */
-#define SPBFCR_TXRST 0x80 /* Transmit Buffer Data Reset (qspi only) */
-#define SPBFCR_RXRST 0x40 /* Receive Buffer Data Reset (qspi only) */
+#define SPBFCR_TXRST 0x80 /* Transmit Buffer Data Reset */
+#define SPBFCR_RXRST 0x40 /* Receive Buffer Data Reset */
#define SPBFCR_TXTRG_MASK 0x30 /* Transmit Buffer Data Triggering Number */
#define SPBFCR_RXTRG_MASK 0x07 /* Receive Buffer Data Triggering Number */
@@ -181,22 +189,21 @@ struct rspi_data {
void __iomem *addr;
u32 max_speed_hz;
struct spi_master *master;
- struct list_head queue;
- struct work_struct ws;
wait_queue_head_t wait;
- spinlock_t lock;
struct clk *clk;
- u8 spsr;
u16 spcmd;
+ u8 spsr;
+ u8 sppcr;
+ int rx_irq, tx_irq;
const struct spi_ops *ops;
/* for dmaengine */
struct dma_chan *chan_tx;
struct dma_chan *chan_rx;
- int irq;
unsigned dma_width_16bit:1;
unsigned dma_callbacked:1;
+ unsigned byte_access:1;
};
static void rspi_write8(const struct rspi_data *rspi, u8 data, u16 offset)
@@ -224,34 +231,47 @@ static u16 rspi_read16(const struct rspi_data *rspi, u16 offset)
return ioread16(rspi->addr + offset);
}
+static void rspi_write_data(const struct rspi_data *rspi, u16 data)
+{
+ if (rspi->byte_access)
+ rspi_write8(rspi, data, RSPI_SPDR);
+ else /* 16 bit */
+ rspi_write16(rspi, data, RSPI_SPDR);
+}
+
+static u16 rspi_read_data(const struct rspi_data *rspi)
+{
+ if (rspi->byte_access)
+ return rspi_read8(rspi, RSPI_SPDR);
+ else /* 16 bit */
+ return rspi_read16(rspi, RSPI_SPDR);
+}
+
/* optional functions */
struct spi_ops {
- int (*set_config_register)(const struct rspi_data *rspi,
- int access_size);
- int (*send_pio)(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t);
- int (*receive_pio)(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t);
-
+ int (*set_config_register)(struct rspi_data *rspi, int access_size);
+ int (*transfer_one)(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *xfer);
+ u16 mode_bits;
};
/*
- * functions for RSPI
+ * functions for RSPI on legacy SH
*/
-static int rspi_set_config_register(const struct rspi_data *rspi,
- int access_size)
+static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
{
int spbr;
- /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
- rspi_write8(rspi, 0x00, RSPI_SPPCR);
+ /* Sets output mode, MOSI signal, and (optionally) loopback */
+ rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
/* Sets transfer bit rate */
spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
- /* Sets number of frames to be used: 1 frame */
- rspi_write8(rspi, 0x00, RSPI_SPDCR);
+ /* Disable dummy transmission, set 16-bit word access, 1 frame */
+ rspi_write8(rspi, 0, RSPI_SPDCR);
+ rspi->byte_access = 0;
/* Sets RSPCK, SSL, next-access delay value */
rspi_write8(rspi, 0x00, RSPI_SPCKD);
@@ -262,8 +282,41 @@ static int rspi_set_config_register(const struct rspi_data *rspi,
rspi_write8(rspi, 0x00, RSPI_SPCR2);
/* Sets SPCMD */
- rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | rspi->spcmd,
- RSPI_SPCMD0);
+ rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
+
+ /* Sets RSPI mode */
+ rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
+
+ return 0;
+}
+
+/*
+ * functions for RSPI on RZ
+ */
+static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size)
+{
+ int spbr;
+
+ /* Sets output mode, MOSI signal, and (optionally) loopback */
+ rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
+
+ /* Sets transfer bit rate */
+ spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
+ rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
+
+ /* Disable dummy transmission, set byte access */
+ rspi_write8(rspi, SPDCR_SPLBYTE, RSPI_SPDCR);
+ rspi->byte_access = 1;
+
+ /* Sets RSPCK, SSL, next-access delay value */
+ rspi_write8(rspi, 0x00, RSPI_SPCKD);
+ rspi_write8(rspi, 0x00, RSPI_SSLND);
+ rspi_write8(rspi, 0x00, RSPI_SPND);
+
+ /* Sets SPCMD */
+ rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
/* Sets RSPI mode */
rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
@@ -274,21 +327,20 @@ static int rspi_set_config_register(const struct rspi_data *rspi,
/*
* functions for QSPI
*/
-static int qspi_set_config_register(const struct rspi_data *rspi,
- int access_size)
+static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
{
- u16 spcmd;
int spbr;
- /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
- rspi_write8(rspi, 0x00, RSPI_SPPCR);
+ /* Sets output mode, MOSI signal, and (optionally) loopback */
+ rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
/* Sets transfer bit rate */
spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz);
rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
- /* Sets number of frames to be used: 1 frame */
- rspi_write8(rspi, 0x00, RSPI_SPDCR);
+ /* Disable dummy transmission, set byte access */
+ rspi_write8(rspi, 0, RSPI_SPDCR);
+ rspi->byte_access = 1;
/* Sets RSPCK, SSL, next-access delay value */
rspi_write8(rspi, 0x00, RSPI_SPCKD);
@@ -297,13 +349,13 @@ static int qspi_set_config_register(const struct rspi_data *rspi,
/* Data Length Setting */
if (access_size == 8)
- spcmd = SPCMD_SPB_8BIT;
+ rspi->spcmd |= SPCMD_SPB_8BIT;
else if (access_size == 16)
- spcmd = SPCMD_SPB_16BIT;
+ rspi->spcmd |= SPCMD_SPB_16BIT;
else
- spcmd = SPCMD_SPB_32BIT;
+ rspi->spcmd |= SPCMD_SPB_32BIT;
- spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | rspi->spcmd | SPCMD_SPNDEN;
+ rspi->spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | SPCMD_SPNDEN;
/* Resets transfer data length */
rspi_write32(rspi, 0, QSPI_SPBMUL0);
@@ -314,9 +366,9 @@ static int qspi_set_config_register(const struct rspi_data *rspi,
rspi_write8(rspi, 0x00, QSPI_SPBFCR);
/* Sets SPCMD */
- rspi_write16(rspi, spcmd, RSPI_SPCMD0);
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
- /* Enables SPI function in a master mode */
+ /* Enables SPI function in master mode */
rspi_write8(rspi, SPCR_SPE | SPCR_MSTR, RSPI_SPCR);
return 0;
@@ -340,6 +392,9 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask,
int ret;
rspi->spsr = rspi_read8(rspi, RSPI_SPSR);
+ if (rspi->spsr & wait_mask)
+ return 0;
+
rspi_enable_irq(rspi, enable_bit);
ret = wait_event_timeout(rspi->wait, rspi->spsr & wait_mask, HZ);
if (ret == 0 && !(rspi->spsr & wait_mask))
@@ -348,78 +403,39 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask,
return 0;
}
-static void rspi_assert_ssl(const struct rspi_data *rspi)
-{
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR);
-}
-
-static void rspi_negate_ssl(const struct rspi_data *rspi)
+static int rspi_data_out(struct rspi_data *rspi, u8 data)
{
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
+ if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
+ dev_err(&rspi->master->dev, "transmit timeout\n");
+ return -ETIMEDOUT;
+ }
+ rspi_write_data(rspi, data);
+ return 0;
}
-static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
+static int rspi_data_in(struct rspi_data *rspi)
{
- int remain = t->len;
- const u8 *data = t->tx_buf;
- while (remain > 0) {
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD,
- RSPI_SPCR);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
+ u8 data;
- rspi_write16(rspi, *data, RSPI_SPDR);
- data++;
- remain--;
+ if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
+ dev_err(&rspi->master->dev, "receive timeout\n");
+ return -ETIMEDOUT;
}
-
- /* Waiting for the last transmission */
- rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
-
- return 0;
+ data = rspi_read_data(rspi);
+ return data;
}
-static int qspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
+static int rspi_data_out_in(struct rspi_data *rspi, u8 data)
{
- int remain = t->len;
- const u8 *data = t->tx_buf;
-
- rspi_write8(rspi, SPBFCR_TXRST, QSPI_SPBFCR);
- rspi_write8(rspi, 0x00, QSPI_SPBFCR);
-
- while (remain > 0) {
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
- rspi_write8(rspi, *data++, RSPI_SPDR);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: receive timeout\n", __func__);
- return -ETIMEDOUT;
- }
- rspi_read8(rspi, RSPI_SPDR);
-
- remain--;
- }
+ int ret;
- /* Waiting for the last transmission */
- rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+ ret = rspi_data_out(rspi, data);
+ if (ret < 0)
+ return ret;
- return 0;
+ return rspi_data_in(rspi);
}
-#define send_pio(spi, mesg, t) spi->ops->send_pio(spi, mesg, t)
-
static void rspi_dma_complete(void *arg)
{
struct rspi_data *rspi = arg;
@@ -471,7 +487,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
struct scatterlist sg;
const void *buf = NULL;
struct dma_async_tx_descriptor *desc;
- unsigned len;
+ unsigned int len;
int ret = 0;
if (rspi->dma_width_16bit) {
@@ -509,7 +525,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
* DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be
* called. So, this driver disables the IRQ while DMA transfer.
*/
- disable_irq(rspi->irq);
+ disable_irq(rspi->tx_irq);
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, RSPI_SPCR);
rspi_enable_irq(rspi, SPCR_SPTIE);
@@ -528,7 +544,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
ret = -ETIMEDOUT;
rspi_disable_irq(rspi, SPCR_SPTIE);
- enable_irq(rspi->irq);
+ enable_irq(rspi->tx_irq);
end:
rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE);
@@ -545,46 +561,17 @@ static void rspi_receive_init(const struct rspi_data *rspi)
spsr = rspi_read8(rspi, RSPI_SPSR);
if (spsr & SPSR_SPRF)
- rspi_read16(rspi, RSPI_SPDR); /* dummy read */
+ rspi_read_data(rspi); /* dummy read */
if (spsr & SPSR_OVRF)
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPSR) & ~SPSR_OVRF,
RSPI_SPSR);
}
-static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
+static void rspi_rz_receive_init(const struct rspi_data *rspi)
{
- int remain = t->len;
- u8 *data;
-
rspi_receive_init(rspi);
-
- data = t->rx_buf;
- while (remain > 0) {
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD,
- RSPI_SPCR);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
- /* dummy write for generate clock */
- rspi_write16(rspi, DUMMY_DATA, RSPI_SPDR);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: receive timeout\n", __func__);
- return -ETIMEDOUT;
- }
- /* SPDR allows 16 or 32-bit access only */
- *data = (u8)rspi_read16(rspi, RSPI_SPDR);
-
- data++;
- remain--;
- }
-
- return 0;
+ rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, RSPI_SPBFCR);
+ rspi_write8(rspi, 0, RSPI_SPBFCR);
}
static void qspi_receive_init(const struct rspi_data *rspi)
@@ -593,51 +580,17 @@ static void qspi_receive_init(const struct rspi_data *rspi)
spsr = rspi_read8(rspi, RSPI_SPSR);
if (spsr & SPSR_SPRF)
- rspi_read8(rspi, RSPI_SPDR); /* dummy read */
+ rspi_read_data(rspi); /* dummy read */
rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR);
- rspi_write8(rspi, 0x00, QSPI_SPBFCR);
+ rspi_write8(rspi, 0, QSPI_SPBFCR);
}
-static int qspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
-{
- int remain = t->len;
- u8 *data;
-
- qspi_receive_init(rspi);
-
- data = t->rx_buf;
- while (remain > 0) {
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
- /* dummy write for generate clock */
- rspi_write8(rspi, DUMMY_DATA, RSPI_SPDR);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: receive timeout\n", __func__);
- return -ETIMEDOUT;
- }
- /* SPDR allows 8, 16 or 32-bit access */
- *data++ = rspi_read8(rspi, RSPI_SPDR);
- remain--;
- }
-
- return 0;
-}
-
-#define receive_pio(spi, mesg, t) spi->ops->receive_pio(spi, mesg, t)
-
static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
{
struct scatterlist sg, sg_dummy;
void *dummy = NULL, *rx_buf = NULL;
struct dma_async_tx_descriptor *desc, *desc_dummy;
- unsigned len;
+ unsigned int len;
int ret = 0;
if (rspi->dma_width_16bit) {
@@ -695,7 +648,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
* DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be
* called. So, this driver disables the IRQ while DMA transfer.
*/
- disable_irq(rspi->irq);
+ disable_irq(rspi->tx_irq);
+ if (rspi->rx_irq != rspi->tx_irq)
+ disable_irq(rspi->rx_irq);
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, RSPI_SPCR);
rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
@@ -718,7 +673,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
ret = -ETIMEDOUT;
rspi_disable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
- enable_irq(rspi->irq);
+ enable_irq(rspi->tx_irq);
+ if (rspi->rx_irq != rspi->tx_irq)
+ enable_irq(rspi->rx_irq);
end:
rspi_dma_unmap_sg(&sg, rspi->chan_rx, DMA_FROM_DEVICE);
@@ -746,56 +703,175 @@ static int rspi_is_dma(const struct rspi_data *rspi, struct spi_transfer *t)
return 0;
}
-static void rspi_work(struct work_struct *work)
+static int rspi_transfer_out_in(struct rspi_data *rspi,
+ struct spi_transfer *xfer)
{
- struct rspi_data *rspi = container_of(work, struct rspi_data, ws);
- struct spi_message *mesg;
- struct spi_transfer *t;
- unsigned long flags;
- int ret;
+ int remain = xfer->len, ret;
+ const u8 *tx_buf = xfer->tx_buf;
+ u8 *rx_buf = xfer->rx_buf;
+ u8 spcr, data;
- while (1) {
- spin_lock_irqsave(&rspi->lock, flags);
- if (list_empty(&rspi->queue)) {
- spin_unlock_irqrestore(&rspi->lock, flags);
- break;
- }
- mesg = list_entry(rspi->queue.next, struct spi_message, queue);
- list_del_init(&mesg->queue);
- spin_unlock_irqrestore(&rspi->lock, flags);
-
- rspi_assert_ssl(rspi);
-
- list_for_each_entry(t, &mesg->transfers, transfer_list) {
- if (t->tx_buf) {
- if (rspi_is_dma(rspi, t))
- ret = rspi_send_dma(rspi, t);
- else
- ret = send_pio(rspi, mesg, t);
- if (ret < 0)
- goto error;
- }
- if (t->rx_buf) {
- if (rspi_is_dma(rspi, t))
- ret = rspi_receive_dma(rspi, t);
- else
- ret = receive_pio(rspi, mesg, t);
- if (ret < 0)
- goto error;
- }
- mesg->actual_length += t->len;
+ rspi_receive_init(rspi);
+
+ spcr = rspi_read8(rspi, RSPI_SPCR);
+ if (rx_buf)
+ spcr &= ~SPCR_TXMD;
+ else
+ spcr |= SPCR_TXMD;
+ rspi_write8(rspi, spcr, RSPI_SPCR);
+
+ while (remain > 0) {
+ data = tx_buf ? *tx_buf++ : DUMMY_DATA;
+ ret = rspi_data_out(rspi, data);
+ if (ret < 0)
+ return ret;
+ if (rx_buf) {
+ ret = rspi_data_in(rspi);
+ if (ret < 0)
+ return ret;
+ *rx_buf++ = ret;
}
- rspi_negate_ssl(rspi);
+ remain--;
+ }
+
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+ return 0;
+}
+
+static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+ int ret;
+
+ if (!rspi_is_dma(rspi, xfer))
+ return rspi_transfer_out_in(rspi, xfer);
+
+ if (xfer->tx_buf) {
+ ret = rspi_send_dma(rspi, xfer);
+ if (ret < 0)
+ return ret;
+ }
+ if (xfer->rx_buf)
+ return rspi_receive_dma(rspi, xfer);
+
+ return 0;
+}
+
+static int rspi_rz_transfer_out_in(struct rspi_data *rspi,
+ struct spi_transfer *xfer)
+{
+ int remain = xfer->len, ret;
+ const u8 *tx_buf = xfer->tx_buf;
+ u8 *rx_buf = xfer->rx_buf;
+ u8 data;
+
+ rspi_rz_receive_init(rspi);
+
+ while (remain > 0) {
+ data = tx_buf ? *tx_buf++ : DUMMY_DATA;
+ ret = rspi_data_out_in(rspi, data);
+ if (ret < 0)
+ return ret;
+ if (rx_buf)
+ *rx_buf++ = ret;
+ remain--;
+ }
+
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+ return 0;
+}
+
+static int rspi_rz_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+
+ return rspi_rz_transfer_out_in(rspi, xfer);
+}
+
+static int qspi_transfer_out_in(struct rspi_data *rspi,
+ struct spi_transfer *xfer)
+{
+ int remain = xfer->len, ret;
+ const u8 *tx_buf = xfer->tx_buf;
+ u8 *rx_buf = xfer->rx_buf;
+ u8 data;
- mesg->status = 0;
- mesg->complete(mesg->context);
+ qspi_receive_init(rspi);
+
+ while (remain > 0) {
+ data = tx_buf ? *tx_buf++ : DUMMY_DATA;
+ ret = rspi_data_out_in(rspi, data);
+ if (ret < 0)
+ return ret;
+ if (rx_buf)
+ *rx_buf++ = ret;
+ remain--;
+ }
+
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+ return 0;
+}
+
+static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer)
+{
+ const u8 *buf = xfer->tx_buf;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < xfer->len; i++) {
+ ret = rspi_data_out(rspi, *buf++);
+ if (ret < 0)
+ return ret;
}
- return;
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
-error:
- mesg->status = ret;
- mesg->complete(mesg->context);
+ return 0;
+}
+
+static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer)
+{
+ u8 *buf = xfer->rx_buf;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < xfer->len; i++) {
+ ret = rspi_data_in(rspi);
+ if (ret < 0)
+ return ret;
+ *buf++ = ret;
+ }
+
+ return 0;
+}
+
+static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+
+ if (spi->mode & SPI_LOOP) {
+ return qspi_transfer_out_in(rspi, xfer);
+ } else if (xfer->tx_buf && xfer->tx_nbits > SPI_NBITS_SINGLE) {
+ /* Quad or Dual SPI Write */
+ return qspi_transfer_out(rspi, xfer);
+ } else if (xfer->rx_buf && xfer->rx_nbits > SPI_NBITS_SINGLE) {
+ /* Quad or Dual SPI Read */
+ return qspi_transfer_in(rspi, xfer);
+ } else {
+ /* Single SPI Transfer */
+ return qspi_transfer_out_in(rspi, xfer);
+ }
}
static int rspi_setup(struct spi_device *spi)
@@ -810,32 +886,115 @@ static int rspi_setup(struct spi_device *spi)
if (spi->mode & SPI_CPHA)
rspi->spcmd |= SPCMD_CPHA;
+ /* CMOS output mode and MOSI signal from previous transfer */
+ rspi->sppcr = 0;
+ if (spi->mode & SPI_LOOP)
+ rspi->sppcr |= SPPCR_SPLP;
+
set_config_register(rspi, 8);
return 0;
}
-static int rspi_transfer(struct spi_device *spi, struct spi_message *mesg)
+static u16 qspi_transfer_mode(const struct spi_transfer *xfer)
{
- struct rspi_data *rspi = spi_master_get_devdata(spi->master);
- unsigned long flags;
+ if (xfer->tx_buf)
+ switch (xfer->tx_nbits) {
+ case SPI_NBITS_QUAD:
+ return SPCMD_SPIMOD_QUAD;
+ case SPI_NBITS_DUAL:
+ return SPCMD_SPIMOD_DUAL;
+ default:
+ return 0;
+ }
+ if (xfer->rx_buf)
+ switch (xfer->rx_nbits) {
+ case SPI_NBITS_QUAD:
+ return SPCMD_SPIMOD_QUAD | SPCMD_SPRW;
+ case SPI_NBITS_DUAL:
+ return SPCMD_SPIMOD_DUAL | SPCMD_SPRW;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
- mesg->actual_length = 0;
- mesg->status = -EINPROGRESS;
+static int qspi_setup_sequencer(struct rspi_data *rspi,
+ const struct spi_message *msg)
+{
+ const struct spi_transfer *xfer;
+ unsigned int i = 0, len = 0;
+ u16 current_mode = 0xffff, mode;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ mode = qspi_transfer_mode(xfer);
+ if (mode == current_mode) {
+ len += xfer->len;
+ continue;
+ }
+
+ /* Transfer mode change */
+ if (i) {
+ /* Set transfer data length of previous transfer */
+ rspi_write32(rspi, len, QSPI_SPBMUL(i - 1));
+ }
- spin_lock_irqsave(&rspi->lock, flags);
- list_add_tail(&mesg->queue, &rspi->queue);
- schedule_work(&rspi->ws);
- spin_unlock_irqrestore(&rspi->lock, flags);
+ if (i >= QSPI_NUM_SPCMD) {
+ dev_err(&msg->spi->dev,
+ "Too many different transfer modes");
+ return -EINVAL;
+ }
+
+ /* Program transfer mode for this transfer */
+ rspi_write16(rspi, rspi->spcmd | mode, RSPI_SPCMD(i));
+ current_mode = mode;
+ len = xfer->len;
+ i++;
+ }
+ if (i) {
+ /* Set final transfer data length and sequence length */
+ rspi_write32(rspi, len, QSPI_SPBMUL(i - 1));
+ rspi_write8(rspi, i - 1, RSPI_SPSCR);
+ }
return 0;
}
-static void rspi_cleanup(struct spi_device *spi)
+static int rspi_prepare_message(struct spi_master *master,
+ struct spi_message *msg)
{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+ int ret;
+
+ if (msg->spi->mode &
+ (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)) {
+ /* Setup sequencer for messages with multiple transfer modes */
+ ret = qspi_setup_sequencer(rspi, msg);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Enable SPI function in master mode */
+ rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR);
+ return 0;
}
-static irqreturn_t rspi_irq(int irq, void *_sr)
+static int rspi_unprepare_message(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+
+ /* Disable SPI function */
+ rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
+
+ /* Reset sequencer for Single SPI Transfers */
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
+ rspi_write8(rspi, 0, RSPI_SPSCR);
+ return 0;
+}
+
+static irqreturn_t rspi_irq_mux(int irq, void *_sr)
{
struct rspi_data *rspi = _sr;
u8 spsr;
@@ -857,6 +1016,36 @@ static irqreturn_t rspi_irq(int irq, void *_sr)
return ret;
}
+static irqreturn_t rspi_irq_rx(int irq, void *_sr)
+{
+ struct rspi_data *rspi = _sr;
+ u8 spsr;
+
+ rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR);
+ if (spsr & SPSR_SPRF) {
+ rspi_disable_irq(rspi, SPCR_SPRIE);
+ wake_up(&rspi->wait);
+ return IRQ_HANDLED;
+ }
+
+ return 0;
+}
+
+static irqreturn_t rspi_irq_tx(int irq, void *_sr)
+{
+ struct rspi_data *rspi = _sr;
+ u8 spsr;
+
+ rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR);
+ if (spsr & SPSR_SPTEF) {
+ rspi_disable_irq(rspi, SPCR_SPTIE);
+ wake_up(&rspi->wait);
+ return IRQ_HANDLED;
+ }
+
+ return 0;
+}
+
static int rspi_request_dma(struct rspi_data *rspi,
struct platform_device *pdev)
{
@@ -923,34 +1112,89 @@ static int rspi_remove(struct platform_device *pdev)
struct rspi_data *rspi = platform_get_drvdata(pdev);
rspi_release_dma(rspi);
- clk_disable(rspi->clk);
+ pm_runtime_disable(&pdev->dev);
return 0;
}
+static const struct spi_ops rspi_ops = {
+ .set_config_register = rspi_set_config_register,
+ .transfer_one = rspi_transfer_one,
+ .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP,
+};
+
+static const struct spi_ops rspi_rz_ops = {
+ .set_config_register = rspi_rz_set_config_register,
+ .transfer_one = rspi_rz_transfer_one,
+ .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP,
+};
+
+static const struct spi_ops qspi_ops = {
+ .set_config_register = qspi_set_config_register,
+ .transfer_one = qspi_transfer_one,
+ .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP |
+ SPI_TX_DUAL | SPI_TX_QUAD |
+ SPI_RX_DUAL | SPI_RX_QUAD,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id rspi_of_match[] = {
+ /* RSPI on legacy SH */
+ { .compatible = "renesas,rspi", .data = &rspi_ops },
+ /* RSPI on RZ/A1H */
+ { .compatible = "renesas,rspi-rz", .data = &rspi_rz_ops },
+ /* QSPI on R-Car Gen2 */
+ { .compatible = "renesas,qspi", .data = &qspi_ops },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, rspi_of_match);
+
+static int rspi_parse_dt(struct device *dev, struct spi_master *master)
+{
+ u32 num_cs;
+ int error;
+
+ /* Parse DT properties */
+ error = of_property_read_u32(dev->of_node, "num-cs", &num_cs);
+ if (error) {
+ dev_err(dev, "of_property_read_u32 num-cs failed %d\n", error);
+ return error;
+ }
+
+ master->num_chipselect = num_cs;
+ return 0;
+}
+#else
+#define rspi_of_match NULL
+static inline int rspi_parse_dt(struct device *dev, struct spi_master *master)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_OF */
+
+static int rspi_request_irq(struct device *dev, unsigned int irq,
+ irq_handler_t handler, const char *suffix,
+ void *dev_id)
+{
+ const char *base = dev_name(dev);
+ size_t len = strlen(base) + strlen(suffix) + 2;
+ char *name = devm_kzalloc(dev, len, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+ snprintf(name, len, "%s:%s", base, suffix);
+ return devm_request_irq(dev, irq, handler, 0, name, dev_id);
+}
+
static int rspi_probe(struct platform_device *pdev)
{
struct resource *res;
struct spi_master *master;
struct rspi_data *rspi;
- int ret, irq;
- char clk_name[16];
- const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev);
+ int ret;
+ const struct of_device_id *of_id;
+ const struct rspi_plat_data *rspi_pd;
const struct spi_ops *ops;
- const struct platform_device_id *id_entry = pdev->id_entry;
-
- ops = (struct spi_ops *)id_entry->driver_data;
- /* ops parameter check */
- if (!ops->set_config_register) {
- dev_err(&pdev->dev, "there is no set_config_register\n");
- return -ENODEV;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "platform_get_irq error\n");
- return -ENODEV;
- }
master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data));
if (master == NULL) {
@@ -958,6 +1202,28 @@ static int rspi_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ of_id = of_match_device(rspi_of_match, &pdev->dev);
+ if (of_id) {
+ ops = of_id->data;
+ ret = rspi_parse_dt(&pdev->dev, master);
+ if (ret)
+ goto error1;
+ } else {
+ ops = (struct spi_ops *)pdev->id_entry->driver_data;
+ rspi_pd = dev_get_platdata(&pdev->dev);
+ if (rspi_pd && rspi_pd->num_chipselect)
+ master->num_chipselect = rspi_pd->num_chipselect;
+ else
+ master->num_chipselect = 2; /* default */
+ };
+
+ /* ops parameter check */
+ if (!ops->set_config_register) {
+ dev_err(&pdev->dev, "there is no set_config_register\n");
+ ret = -ENODEV;
+ goto error1;
+ }
+
rspi = spi_master_get_devdata(master);
platform_set_drvdata(pdev, rspi);
rspi->ops = ops;
@@ -970,39 +1236,61 @@ static int rspi_probe(struct platform_device *pdev)
goto error1;
}
- snprintf(clk_name, sizeof(clk_name), "%s%d", id_entry->name, pdev->id);
- rspi->clk = devm_clk_get(&pdev->dev, clk_name);
+ rspi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(rspi->clk)) {
dev_err(&pdev->dev, "cannot get clock\n");
ret = PTR_ERR(rspi->clk);
goto error1;
}
- clk_enable(rspi->clk);
- INIT_LIST_HEAD(&rspi->queue);
- spin_lock_init(&rspi->lock);
- INIT_WORK(&rspi->ws, rspi_work);
- init_waitqueue_head(&rspi->wait);
+ pm_runtime_enable(&pdev->dev);
- if (rspi_pd && rspi_pd->num_chipselect)
- master->num_chipselect = rspi_pd->num_chipselect;
- else
- master->num_chipselect = 2; /* default */
+ init_waitqueue_head(&rspi->wait);
master->bus_num = pdev->id;
master->setup = rspi_setup;
- master->transfer = rspi_transfer;
- master->cleanup = rspi_cleanup;
- master->mode_bits = SPI_CPHA | SPI_CPOL;
+ master->auto_runtime_pm = true;
+ master->transfer_one = ops->transfer_one;
+ master->prepare_message = rspi_prepare_message;
+ master->unprepare_message = rspi_unprepare_message;
+ master->mode_bits = ops->mode_bits;
+ master->dev.of_node = pdev->dev.of_node;
+
+ ret = platform_get_irq_byname(pdev, "rx");
+ if (ret < 0) {
+ ret = platform_get_irq_byname(pdev, "mux");
+ if (ret < 0)
+ ret = platform_get_irq(pdev, 0);
+ if (ret >= 0)
+ rspi->rx_irq = rspi->tx_irq = ret;
+ } else {
+ rspi->rx_irq = ret;
+ ret = platform_get_irq_byname(pdev, "tx");
+ if (ret >= 0)
+ rspi->tx_irq = ret;
+ }
+ if (ret < 0) {
+ dev_err(&pdev->dev, "platform_get_irq error\n");
+ goto error2;
+ }
- ret = devm_request_irq(&pdev->dev, irq, rspi_irq, 0,
- dev_name(&pdev->dev), rspi);
+ if (rspi->rx_irq == rspi->tx_irq) {
+ /* Single multiplexed interrupt */
+ ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_mux,
+ "mux", rspi);
+ } else {
+ /* Multi-interrupt mode, only SPRI and SPTI are used */
+ ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_rx,
+ "rx", rspi);
+ if (!ret)
+ ret = rspi_request_irq(&pdev->dev, rspi->tx_irq,
+ rspi_irq_tx, "tx", rspi);
+ }
if (ret < 0) {
dev_err(&pdev->dev, "request_irq error\n");
goto error2;
}
- rspi->irq = irq;
ret = rspi_request_dma(rspi, pdev);
if (ret < 0) {
dev_err(&pdev->dev, "rspi_request_dma failed.\n");
@@ -1022,27 +1310,16 @@ static int rspi_probe(struct platform_device *pdev)
error3:
rspi_release_dma(rspi);
error2:
- clk_disable(rspi->clk);
+ pm_runtime_disable(&pdev->dev);
error1:
spi_master_put(master);
return ret;
}
-static struct spi_ops rspi_ops = {
- .set_config_register = rspi_set_config_register,
- .send_pio = rspi_send_pio,
- .receive_pio = rspi_receive_pio,
-};
-
-static struct spi_ops qspi_ops = {
- .set_config_register = qspi_set_config_register,
- .send_pio = qspi_send_pio,
- .receive_pio = qspi_receive_pio,
-};
-
static struct platform_device_id spi_driver_ids[] = {
{ "rspi", (kernel_ulong_t)&rspi_ops },
+ { "rspi-rz", (kernel_ulong_t)&rspi_rz_ops },
{ "qspi", (kernel_ulong_t)&qspi_ops },
{},
};
@@ -1056,6 +1333,7 @@ static struct platform_driver rspi_driver = {
.driver = {
.name = "renesas_spi",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rspi_of_match),
},
};
module_platform_driver(rspi_driver);
diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c
index 746424aa535..bed23384dfa 100644
--- a/drivers/spi/spi-s3c24xx.c
+++ b/drivers/spi/spi-s3c24xx.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
@@ -123,25 +122,15 @@ static int s3c24xx_spi_update_state(struct spi_device *spi,
{
struct s3c24xx_spi *hw = to_hw(spi);
struct s3c24xx_spi_devstate *cs = spi->controller_state;
- unsigned int bpw;
unsigned int hz;
unsigned int div;
unsigned long clk;
- bpw = t ? t->bits_per_word : spi->bits_per_word;
hz = t ? t->speed_hz : spi->max_speed_hz;
- if (!bpw)
- bpw = 8;
-
if (!hz)
hz = spi->max_speed_hz;
- if (bpw != 8) {
- dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
- return -EINVAL;
- }
-
if (spi->mode != cs->mode) {
u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK;
@@ -544,6 +533,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
master->num_chipselect = hw->pdata->num_cs;
master->bus_num = pdata->bus_num;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
/* setup the state for the bitbang driver */
@@ -643,6 +633,11 @@ static int s3c24xx_spi_remove(struct platform_device *dev)
static int s3c24xx_spi_suspend(struct device *dev)
{
struct s3c24xx_spi *hw = dev_get_drvdata(dev);
+ int ret;
+
+ ret = spi_master_suspend(hw->master);
+ if (ret)
+ return ret;
if (hw->pdata && hw->pdata->gpio_setup)
hw->pdata->gpio_setup(hw->pdata, 0);
@@ -656,7 +651,7 @@ static int s3c24xx_spi_resume(struct device *dev)
struct s3c24xx_spi *hw = dev_get_drvdata(dev);
s3c24xx_spi_initialsetup(hw);
- return 0;
+ return spi_master_resume(hw->master);
}
static const struct dev_pm_ops s3c24xx_spi_pmops = {
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index ae907dde137..f19cd97855e 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -34,10 +34,6 @@
#include <linux/platform_data/spi-s3c64xx.h>
-#ifdef CONFIG_S3C_DMA
-#include <mach/dma.h>
-#endif
-
#define MAX_SPI_PORTS 3
#define S3C64XX_SPI_QUIRK_POLL (1 << 0)
@@ -200,9 +196,6 @@ struct s3c64xx_spi_driver_data {
unsigned cur_speed;
struct s3c64xx_spi_dma_data rx_dma;
struct s3c64xx_spi_dma_data tx_dma;
-#ifdef CONFIG_S3C_DMA
- struct samsung_dma_ops *ops;
-#endif
struct s3c64xx_spi_port_config *port_conf;
unsigned int port_id;
bool cs_gpio;
@@ -284,104 +277,8 @@ static void s3c64xx_spi_dmacb(void *data)
spin_unlock_irqrestore(&sdd->lock, flags);
}
-#ifdef CONFIG_S3C_DMA
-/* FIXME: remove this section once arch/arm/mach-s3c64xx uses dmaengine */
-
-static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
- .name = "samsung-spi-dma",
-};
-
-static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
- unsigned len, dma_addr_t buf)
-{
- struct s3c64xx_spi_driver_data *sdd;
- struct samsung_dma_prep info;
- struct samsung_dma_config config;
-
- if (dma->direction == DMA_DEV_TO_MEM) {
- sdd = container_of((void *)dma,
- struct s3c64xx_spi_driver_data, rx_dma);
- config.direction = sdd->rx_dma.direction;
- config.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
- config.width = sdd->cur_bpw / 8;
- sdd->ops->config((enum dma_ch)sdd->rx_dma.ch, &config);
- } else {
- sdd = container_of((void *)dma,
- struct s3c64xx_spi_driver_data, tx_dma);
- config.direction = sdd->tx_dma.direction;
- config.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
- config.width = sdd->cur_bpw / 8;
- sdd->ops->config((enum dma_ch)sdd->tx_dma.ch, &config);
- }
-
- info.cap = DMA_SLAVE;
- info.len = len;
- info.fp = s3c64xx_spi_dmacb;
- info.fp_param = dma;
- info.direction = dma->direction;
- info.buf = buf;
-
- sdd->ops->prepare((enum dma_ch)dma->ch, &info);
- sdd->ops->trigger((enum dma_ch)dma->ch);
-}
-
-static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
-{
- struct samsung_dma_req req;
- struct device *dev = &sdd->pdev->dev;
-
- sdd->ops = samsung_dma_get_ops();
-
- req.cap = DMA_SLAVE;
- req.client = &s3c64xx_spi_dma_client;
-
- sdd->rx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
- sdd->rx_dma.dmach, &req, dev, "rx");
- sdd->tx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
- sdd->tx_dma.dmach, &req, dev, "tx");
-
- return 1;
-}
-
-static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
-{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
-
- /*
- * If DMA resource was not available during
- * probe, no need to continue with dma requests
- * else Acquire DMA channels
- */
- while (!is_polling(sdd) && !acquire_dma(sdd))
- usleep_range(10000, 11000);
-
- return 0;
-}
-
-static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
-{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
-
- /* Free DMA channels */
- if (!is_polling(sdd)) {
- sdd->ops->release((enum dma_ch)sdd->rx_dma.ch,
- &s3c64xx_spi_dma_client);
- sdd->ops->release((enum dma_ch)sdd->tx_dma.ch,
- &s3c64xx_spi_dma_client);
- }
-
- return 0;
-}
-
-static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd,
- struct s3c64xx_spi_dma_data *dma)
-{
- sdd->ops->stop((enum dma_ch)dma->ch);
-}
-#else
-
static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
- unsigned len, dma_addr_t buf)
+ struct sg_table *sgt)
{
struct s3c64xx_spi_driver_data *sdd;
struct dma_slave_config config;
@@ -407,8 +304,8 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
dmaengine_slave_config(dma->ch, &config);
}
- desc = dmaengine_prep_slave_single(dma->ch, buf, len,
- dma->direction, DMA_PREP_INTERRUPT);
+ desc = dmaengine_prep_slave_sg(dma->ch, sgt->sgl, sgt->nents,
+ dma->direction, DMA_PREP_INTERRUPT);
desc->callback = s3c64xx_spi_dmacb;
desc->callback_param = dma;
@@ -437,6 +334,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
ret = -EBUSY;
goto out;
}
+ spi->dma_rx = sdd->rx_dma.ch;
sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
(void *)sdd->tx_dma.dmach, dev, "tx");
@@ -445,6 +343,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
ret = -EBUSY;
goto out_rx;
}
+ spi->dma_tx = sdd->tx_dma.ch;
}
ret = pm_runtime_get_sync(&sdd->pdev->dev);
@@ -477,12 +376,14 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
return 0;
}
-static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd,
- struct s3c64xx_spi_dma_data *dma)
+static bool s3c64xx_spi_can_dma(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
{
- dmaengine_terminate_all(dma->ch);
+ struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+
+ return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1;
}
-#endif
static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
struct spi_device *spi,
@@ -515,7 +416,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
chcfg |= S3C64XX_SPI_CH_TXCH_ON;
if (dma_mode) {
modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
- prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma);
+ prepare_dma(&sdd->tx_dma, &xfer->tx_sg);
} else {
switch (sdd->cur_bpw) {
case 32:
@@ -547,7 +448,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
| S3C64XX_SPI_PACKET_CNT_EN,
regs + S3C64XX_SPI_PACKET_CNT);
- prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma);
+ prepare_dma(&sdd->rx_dma, &xfer->rx_sg);
}
}
@@ -555,23 +456,6 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
writel(chcfg, regs + S3C64XX_SPI_CH_CFG);
}
-static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
- struct spi_device *spi)
-{
- if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */
- if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
- /* Deselect the last toggled device */
- if (spi->cs_gpio >= 0)
- gpio_set_value(spi->cs_gpio,
- spi->mode & SPI_CS_HIGH ? 0 : 1);
- }
- sdd->tgl_spi = NULL;
- }
-
- if (spi->cs_gpio >= 0)
- gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 1 : 0);
-}
-
static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
int timeout_ms)
{
@@ -593,112 +477,111 @@ static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
return RX_FIFO_LVL(status, sdd);
}
-static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
- struct spi_transfer *xfer, int dma_mode)
+static int wait_for_dma(struct s3c64xx_spi_driver_data *sdd,
+ struct spi_transfer *xfer)
{
void __iomem *regs = sdd->regs;
unsigned long val;
+ u32 status;
int ms;
/* millisecs to xfer 'len' bytes @ 'cur_speed' */
ms = xfer->len * 8 * 1000 / sdd->cur_speed;
ms += 10; /* some tolerance */
- if (dma_mode) {
- val = msecs_to_jiffies(ms) + 10;
- val = wait_for_completion_timeout(&sdd->xfer_completion, val);
- } else {
- u32 status;
- val = msecs_to_loops(ms);
- do {
+ val = msecs_to_jiffies(ms) + 10;
+ val = wait_for_completion_timeout(&sdd->xfer_completion, val);
+
+ /*
+ * If the previous xfer was completed within timeout, then
+ * proceed further else return -EIO.
+ * DmaTx returns after simply writing data in the FIFO,
+ * w/o waiting for real transmission on the bus to finish.
+ * DmaRx returns only after Dma read data from FIFO which
+ * needs bus transmission to finish, so we don't worry if
+ * Xfer involved Rx(with or without Tx).
+ */
+ if (val && !xfer->rx_buf) {
+ val = msecs_to_loops(10);
+ status = readl(regs + S3C64XX_SPI_STATUS);
+ while ((TX_FIFO_LVL(status, sdd)
+ || !S3C64XX_SPI_ST_TX_DONE(status, sdd))
+ && --val) {
+ cpu_relax();
status = readl(regs + S3C64XX_SPI_STATUS);
- } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
+ }
+
}
- if (dma_mode) {
- u32 status;
-
- /*
- * If the previous xfer was completed within timeout, then
- * proceed further else return -EIO.
- * DmaTx returns after simply writing data in the FIFO,
- * w/o waiting for real transmission on the bus to finish.
- * DmaRx returns only after Dma read data from FIFO which
- * needs bus transmission to finish, so we don't worry if
- * Xfer involved Rx(with or without Tx).
- */
- if (val && !xfer->rx_buf) {
- val = msecs_to_loops(10);
- status = readl(regs + S3C64XX_SPI_STATUS);
- while ((TX_FIFO_LVL(status, sdd)
- || !S3C64XX_SPI_ST_TX_DONE(status, sdd))
- && --val) {
- cpu_relax();
- status = readl(regs + S3C64XX_SPI_STATUS);
- }
+ /* If timed out while checking rx/tx status return error */
+ if (!val)
+ return -EIO;
- }
+ return 0;
+}
- /* If timed out while checking rx/tx status return error */
- if (!val)
- return -EIO;
- } else {
- int loops;
- u32 cpy_len;
- u8 *buf;
-
- /* If it was only Tx */
- if (!xfer->rx_buf) {
- sdd->state &= ~TXBUSY;
- return 0;
- }
+static int wait_for_pio(struct s3c64xx_spi_driver_data *sdd,
+ struct spi_transfer *xfer)
+{
+ void __iomem *regs = sdd->regs;
+ unsigned long val;
+ u32 status;
+ int loops;
+ u32 cpy_len;
+ u8 *buf;
+ int ms;
- /*
- * If the receive length is bigger than the controller fifo
- * size, calculate the loops and read the fifo as many times.
- * loops = length / max fifo size (calculated by using the
- * fifo mask).
- * For any size less than the fifo size the below code is
- * executed atleast once.
- */
- loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1);
- buf = xfer->rx_buf;
- do {
- /* wait for data to be received in the fifo */
- cpy_len = s3c64xx_spi_wait_for_timeout(sdd,
- (loops ? ms : 0));
+ /* millisecs to xfer 'len' bytes @ 'cur_speed' */
+ ms = xfer->len * 8 * 1000 / sdd->cur_speed;
+ ms += 10; /* some tolerance */
- switch (sdd->cur_bpw) {
- case 32:
- ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
- buf, cpy_len / 4);
- break;
- case 16:
- ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
- buf, cpy_len / 2);
- break;
- default:
- ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
- buf, cpy_len);
- break;
- }
+ val = msecs_to_loops(ms);
+ do {
+ status = readl(regs + S3C64XX_SPI_STATUS);
+ } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
- buf = buf + cpy_len;
- } while (loops--);
- sdd->state &= ~RXBUSY;
+
+ /* If it was only Tx */
+ if (!xfer->rx_buf) {
+ sdd->state &= ~TXBUSY;
+ return 0;
}
- return 0;
-}
+ /*
+ * If the receive length is bigger than the controller fifo
+ * size, calculate the loops and read the fifo as many times.
+ * loops = length / max fifo size (calculated by using the
+ * fifo mask).
+ * For any size less than the fifo size the below code is
+ * executed atleast once.
+ */
+ loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1);
+ buf = xfer->rx_buf;
+ do {
+ /* wait for data to be received in the fifo */
+ cpy_len = s3c64xx_spi_wait_for_timeout(sdd,
+ (loops ? ms : 0));
+
+ switch (sdd->cur_bpw) {
+ case 32:
+ ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
+ buf, cpy_len / 4);
+ break;
+ case 16:
+ ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
+ buf, cpy_len / 2);
+ break;
+ default:
+ ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
+ buf, cpy_len);
+ break;
+ }
-static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
- struct spi_device *spi)
-{
- if (sdd->tgl_spi == spi)
- sdd->tgl_spi = NULL;
+ buf = buf + cpy_len;
+ } while (loops--);
+ sdd->state &= ~RXBUSY;
- if (spi->cs_gpio >= 0)
- gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1);
+ return 0;
}
static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
@@ -774,81 +657,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
#define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
-static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
- struct spi_message *msg)
-{
- struct device *dev = &sdd->pdev->dev;
- struct spi_transfer *xfer;
-
- if (is_polling(sdd) || msg->is_dma_mapped)
- return 0;
-
- /* First mark all xfer unmapped */
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- xfer->rx_dma = XFER_DMAADDR_INVALID;
- xfer->tx_dma = XFER_DMAADDR_INVALID;
- }
-
- /* Map until end or first fail */
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-
- if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
- continue;
-
- if (xfer->tx_buf != NULL) {
- xfer->tx_dma = dma_map_single(dev,
- (void *)xfer->tx_buf, xfer->len,
- DMA_TO_DEVICE);
- if (dma_mapping_error(dev, xfer->tx_dma)) {
- dev_err(dev, "dma_map_single Tx failed\n");
- xfer->tx_dma = XFER_DMAADDR_INVALID;
- return -ENOMEM;
- }
- }
-
- if (xfer->rx_buf != NULL) {
- xfer->rx_dma = dma_map_single(dev, xfer->rx_buf,
- xfer->len, DMA_FROM_DEVICE);
- if (dma_mapping_error(dev, xfer->rx_dma)) {
- dev_err(dev, "dma_map_single Rx failed\n");
- dma_unmap_single(dev, xfer->tx_dma,
- xfer->len, DMA_TO_DEVICE);
- xfer->tx_dma = XFER_DMAADDR_INVALID;
- xfer->rx_dma = XFER_DMAADDR_INVALID;
- return -ENOMEM;
- }
- }
- }
-
- return 0;
-}
-
-static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
- struct spi_message *msg)
-{
- struct device *dev = &sdd->pdev->dev;
- struct spi_transfer *xfer;
-
- if (is_polling(sdd) || msg->is_dma_mapped)
- return;
-
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-
- if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
- continue;
-
- if (xfer->rx_buf != NULL
- && xfer->rx_dma != XFER_DMAADDR_INVALID)
- dma_unmap_single(dev, xfer->rx_dma,
- xfer->len, DMA_FROM_DEVICE);
-
- if (xfer->tx_buf != NULL
- && xfer->tx_dma != XFER_DMAADDR_INVALID)
- dma_unmap_single(dev, xfer->tx_dma,
- xfer->len, DMA_TO_DEVICE);
- }
-}
-
static int s3c64xx_spi_prepare_message(struct spi_master *master,
struct spi_message *msg)
{
@@ -866,13 +674,6 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master,
s3c64xx_spi_config(sdd);
}
- /* Map all the transfers if needed */
- if (s3c64xx_spi_map_mssg(sdd, msg)) {
- dev_err(&spi->dev,
- "Xfer: Unable to map message buffers!\n");
- return -ENOMEM;
- }
-
/* Configure feedback delay */
writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
@@ -896,13 +697,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
bpw = xfer->bits_per_word;
speed = xfer->speed_hz ? : spi->max_speed_hz;
- if (xfer->len % (bpw / 8)) {
- dev_err(&spi->dev,
- "Xfer length(%u) not a multiple of word size(%u)\n",
- xfer->len, bpw / 8);
- return -EIO;
- }
-
if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
sdd->cur_bpw = bpw;
sdd->cur_speed = speed;
@@ -929,7 +723,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
spin_unlock_irqrestore(&sdd->lock, flags);
- status = wait_for_xfer(sdd, xfer, use_dma);
+ if (use_dma)
+ status = wait_for_dma(sdd, xfer);
+ else
+ status = wait_for_pio(sdd, xfer);
if (status) {
dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
@@ -941,10 +738,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
if (use_dma) {
if (xfer->tx_buf != NULL
&& (sdd->state & TXBUSY))
- s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma);
+ dmaengine_terminate_all(sdd->tx_dma.ch);
if (xfer->rx_buf != NULL
&& (sdd->state & RXBUSY))
- s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma);
+ dmaengine_terminate_all(sdd->rx_dma.ch);
}
} else {
flush_fifo(sdd);
@@ -953,16 +750,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
return status;
}
-static int s3c64xx_spi_unprepare_message(struct spi_master *master,
- struct spi_message *msg)
-{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
-
- s3c64xx_spi_unmap_mssg(sdd, msg);
-
- return 0;
-}
-
static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
struct spi_device *spi)
{
@@ -1092,14 +879,12 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
pm_runtime_put(&sdd->pdev->dev);
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
- disable_cs(sdd, spi);
return 0;
setup_exit:
pm_runtime_put(&sdd->pdev->dev);
/* setup() returns with device de-selected */
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
- disable_cs(sdd, spi);
gpio_free(cs->line);
spi_set_ctldata(spi, NULL);
@@ -1338,7 +1123,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
master->prepare_message = s3c64xx_spi_prepare_message;
master->transfer_one = s3c64xx_spi_transfer_one;
- master->unprepare_message = s3c64xx_spi_unprepare_message;
master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
master->num_chipselect = sci->num_cs;
master->dma_alignment = 8;
@@ -1347,6 +1131,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->auto_runtime_pm = true;
+ if (!is_polling(sdd))
+ master->can_dma = s3c64xx_spi_can_dma;
sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(sdd->regs)) {
diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c
index 121c2e1dea3..237f2e7a717 100644
--- a/drivers/spi/spi-sc18is602.c
+++ b/drivers/spi/spi-sc18is602.c
@@ -183,17 +183,9 @@ static int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode)
static int sc18is602_check_transfer(struct spi_device *spi,
struct spi_transfer *t, int tlen)
{
- uint32_t hz;
-
if (t && t->len + tlen > SC18IS602_BUFSIZ)
return -EINVAL;
- hz = spi->max_speed_hz;
- if (t && t->speed_hz)
- hz = t->speed_hz;
- if (hz == 0)
- return -EINVAL;
-
return 0;
}
@@ -205,22 +197,15 @@ static int sc18is602_transfer_one(struct spi_master *master,
struct spi_transfer *t;
int status = 0;
- /* SC18IS602 does not support CS2 */
- if (hw->id == sc18is602 && spi->chip_select == 2) {
- status = -ENXIO;
- goto error;
- }
-
hw->tlen = 0;
list_for_each_entry(t, &m->transfers, transfer_list) {
- u32 hz = t->speed_hz ? : spi->max_speed_hz;
bool do_transfer;
status = sc18is602_check_transfer(spi, t, hw->tlen);
if (status < 0)
break;
- status = sc18is602_setup_transfer(hw, hz, spi->mode);
+ status = sc18is602_setup_transfer(hw, t->speed_hz, spi->mode);
if (status < 0)
break;
@@ -238,7 +223,6 @@ static int sc18is602_transfer_one(struct spi_master *master,
if (t->delay_usecs)
udelay(t->delay_usecs);
}
-error:
m->status = status;
spi_finalize_current_message(master);
@@ -247,10 +231,13 @@ error:
static int sc18is602_setup(struct spi_device *spi)
{
- if (spi->mode & ~(SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST))
- return -EINVAL;
+ struct sc18is602 *hw = spi_master_get_devdata(spi->master);
- return sc18is602_check_transfer(spi, NULL, 0);
+ /* SC18IS602 does not support CS2 */
+ if (hw->id == sc18is602 && spi->chip_select == 2)
+ return -ENXIO;
+
+ return 0;
}
static int sc18is602_probe(struct i2c_client *client,
@@ -309,6 +296,8 @@ static int sc18is602_probe(struct i2c_client *client,
master->setup = sc18is602_setup;
master->transfer_one_message = sc18is602_transfer_one;
master->dev.of_node = np;
+ master->min_speed_hz = hw->freq / 128;
+ master->max_speed_hz = hw->freq / 4;
error = devm_spi_register_master(dev, master);
if (error)
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c
index 82d2f922ffa..9009456bdf4 100644
--- a/drivers/spi/spi-sh-hspi.c
+++ b/drivers/spi/spi-sh-hspi.c
@@ -46,8 +46,6 @@
/* SPSR */
#define RXFL (1 << 2)
-#define hspi2info(h) (h->dev->platform_data)
-
struct hspi_priv {
void __iomem *addr;
struct spi_master *master;
@@ -113,14 +111,9 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
{
struct spi_device *spi = msg->spi;
struct device *dev = hspi->dev;
- u32 target_rate;
u32 spcr, idiv_clk;
u32 rate, best_rate, min, tmp;
- target_rate = t ? t->speed_hz : 0;
- if (!target_rate)
- target_rate = spi->max_speed_hz;
-
/*
* find best IDIV/CLKCx settings
*/
@@ -140,7 +133,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
rate /= (((idiv_clk & 0x1F) + 1) * 2);
/* save best settings */
- tmp = abs(target_rate - rate);
+ tmp = abs(t->speed_hz - rate);
if (tmp < min) {
min = tmp;
spcr = idiv_clk;
@@ -153,7 +146,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
if (spi->mode & SPI_CPOL)
spcr |= 1 << 6;
- dev_dbg(dev, "speed %d/%d\n", target_rate, best_rate);
+ dev_dbg(dev, "speed %d/%d\n", t->speed_hz, best_rate);
hspi_write(hspi, SPCR, spcr);
hspi_write(hspi, SPSR, 0x0);
@@ -230,29 +223,6 @@ static int hspi_transfer_one_message(struct spi_master *master,
return ret;
}
-static int hspi_setup(struct spi_device *spi)
-{
- struct hspi_priv *hspi = spi_master_get_devdata(spi->master);
- struct device *dev = hspi->dev;
-
- if (8 != spi->bits_per_word) {
- dev_err(dev, "bits_per_word should be 8\n");
- return -EIO;
- }
-
- dev_dbg(dev, "%s setup\n", spi->modalias);
-
- return 0;
-}
-
-static void hspi_cleanup(struct spi_device *spi)
-{
- struct hspi_priv *hspi = spi_master_get_devdata(spi->master);
- struct device *dev = hspi->dev;
-
- dev_dbg(dev, "%s cleanup\n", spi->modalias);
-}
-
static int hspi_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -298,22 +268,23 @@ static int hspi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
- master->num_chipselect = 1;
master->bus_num = pdev->id;
- master->setup = hspi_setup;
- master->cleanup = hspi_cleanup;
master->mode_bits = SPI_CPOL | SPI_CPHA;
master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true;
master->transfer_one_message = hspi_transfer_one_message;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+
ret = devm_spi_register_master(&pdev->dev, master);
if (ret < 0) {
dev_err(&pdev->dev, "spi_register_master error.\n");
- goto error1;
+ goto error2;
}
return 0;
+ error2:
+ pm_runtime_disable(&pdev->dev);
error1:
clk_put(clk);
error0:
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 81cc02f5f9b..e850d03e719 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -15,59 +15,108 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/sh_msiof.h>
#include <linux/spi/spi.h>
-#include <linux/spi/spi_bitbang.h>
#include <asm/unaligned.h>
+
+struct sh_msiof_chipdata {
+ u16 tx_fifo_size;
+ u16 rx_fifo_size;
+ u16 master_flags;
+};
+
struct sh_msiof_spi_priv {
- struct spi_bitbang bitbang; /* must be first for spi_bitbang.c */
void __iomem *mapbase;
struct clk *clk;
struct platform_device *pdev;
+ const struct sh_msiof_chipdata *chipdata;
struct sh_msiof_spi_info *info;
struct completion done;
- unsigned long flags;
int tx_fifo_size;
int rx_fifo_size;
};
-#define TMDR1 0x00
-#define TMDR2 0x04
-#define TMDR3 0x08
-#define RMDR1 0x10
-#define RMDR2 0x14
-#define RMDR3 0x18
-#define TSCR 0x20
-#define RSCR 0x22
-#define CTR 0x28
-#define FCTR 0x30
-#define STR 0x40
-#define IER 0x44
-#define TDR1 0x48
-#define TDR2 0x4c
-#define TFDR 0x50
-#define RDR1 0x58
-#define RDR2 0x5c
-#define RFDR 0x60
-
-#define CTR_TSCKE (1 << 15)
-#define CTR_TFSE (1 << 14)
-#define CTR_TXE (1 << 9)
-#define CTR_RXE (1 << 8)
-
-#define STR_TEOF (1 << 23)
-#define STR_REOF (1 << 7)
+#define TMDR1 0x00 /* Transmit Mode Register 1 */
+#define TMDR2 0x04 /* Transmit Mode Register 2 */
+#define TMDR3 0x08 /* Transmit Mode Register 3 */
+#define RMDR1 0x10 /* Receive Mode Register 1 */
+#define RMDR2 0x14 /* Receive Mode Register 2 */
+#define RMDR3 0x18 /* Receive Mode Register 3 */
+#define TSCR 0x20 /* Transmit Clock Select Register */
+#define RSCR 0x22 /* Receive Clock Select Register (SH, A1, APE6) */
+#define CTR 0x28 /* Control Register */
+#define FCTR 0x30 /* FIFO Control Register */
+#define STR 0x40 /* Status Register */
+#define IER 0x44 /* Interrupt Enable Register */
+#define TDR1 0x48 /* Transmit Control Data Register 1 (SH, A1) */
+#define TDR2 0x4c /* Transmit Control Data Register 2 (SH, A1) */
+#define TFDR 0x50 /* Transmit FIFO Data Register */
+#define RDR1 0x58 /* Receive Control Data Register 1 (SH, A1) */
+#define RDR2 0x5c /* Receive Control Data Register 2 (SH, A1) */
+#define RFDR 0x60 /* Receive FIFO Data Register */
+
+/* TMDR1 and RMDR1 */
+#define MDR1_TRMD 0x80000000 /* Transfer Mode (1 = Master mode) */
+#define MDR1_SYNCMD_MASK 0x30000000 /* SYNC Mode */
+#define MDR1_SYNCMD_SPI 0x20000000 /* Level mode/SPI */
+#define MDR1_SYNCMD_LR 0x30000000 /* L/R mode */
+#define MDR1_SYNCAC_SHIFT 25 /* Sync Polarity (1 = Active-low) */
+#define MDR1_BITLSB_SHIFT 24 /* MSB/LSB First (1 = LSB first) */
+#define MDR1_FLD_MASK 0x000000c0 /* Frame Sync Signal Interval (0-3) */
+#define MDR1_FLD_SHIFT 2
+#define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */
+/* TMDR1 */
+#define TMDR1_PCON 0x40000000 /* Transfer Signal Connection */
+
+/* TMDR2 and RMDR2 */
+#define MDR2_BITLEN1(i) (((i) - 1) << 24) /* Data Size (8-32 bits) */
+#define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */
+#define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */
+
+/* TSCR and RSCR */
+#define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */
+#define SCR_BRPS(i) (((i) - 1) << 8)
+#define SCR_BRDV_MASK 0x0007 /* Baud Rate Generator's Division Ratio */
+#define SCR_BRDV_DIV_2 0x0000
+#define SCR_BRDV_DIV_4 0x0001
+#define SCR_BRDV_DIV_8 0x0002
+#define SCR_BRDV_DIV_16 0x0003
+#define SCR_BRDV_DIV_32 0x0004
+#define SCR_BRDV_DIV_1 0x0007
+
+/* CTR */
+#define CTR_TSCKIZ_MASK 0xc0000000 /* Transmit Clock I/O Polarity Select */
+#define CTR_TSCKIZ_SCK 0x80000000 /* Disable SCK when TX disabled */
+#define CTR_TSCKIZ_POL_SHIFT 30 /* Transmit Clock Polarity */
+#define CTR_RSCKIZ_MASK 0x30000000 /* Receive Clock Polarity Select */
+#define CTR_RSCKIZ_SCK 0x20000000 /* Must match CTR_TSCKIZ_SCK */
+#define CTR_RSCKIZ_POL_SHIFT 28 /* Receive Clock Polarity */
+#define CTR_TEDG_SHIFT 27 /* Transmit Timing (1 = falling edge) */
+#define CTR_REDG_SHIFT 26 /* Receive Timing (1 = falling edge) */
+#define CTR_TXDIZ_MASK 0x00c00000 /* Pin Output When TX is Disabled */
+#define CTR_TXDIZ_LOW 0x00000000 /* 0 */
+#define CTR_TXDIZ_HIGH 0x00400000 /* 1 */
+#define CTR_TXDIZ_HIZ 0x00800000 /* High-impedance */
+#define CTR_TSCKE 0x00008000 /* Transmit Serial Clock Output Enable */
+#define CTR_TFSE 0x00004000 /* Transmit Frame Sync Signal Output Enable */
+#define CTR_TXE 0x00000200 /* Transmit Enable */
+#define CTR_RXE 0x00000100 /* Receive Enable */
+
+/* STR and IER */
+#define STR_TEOF 0x00800000 /* Frame Transmission End */
+#define STR_REOF 0x00000080 /* Frame Reception End */
+
static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs)
{
@@ -131,22 +180,21 @@ static struct {
unsigned short div;
unsigned short scr;
} const sh_msiof_spi_clk_table[] = {
- { 1, 0x0007 },
- { 2, 0x0000 },
- { 4, 0x0001 },
- { 8, 0x0002 },
- { 16, 0x0003 },
- { 32, 0x0004 },
- { 64, 0x1f00 },
- { 128, 0x1f01 },
- { 256, 0x1f02 },
- { 512, 0x1f03 },
- { 1024, 0x1f04 },
+ { 1, SCR_BRPS( 1) | SCR_BRDV_DIV_1 },
+ { 2, SCR_BRPS( 1) | SCR_BRDV_DIV_2 },
+ { 4, SCR_BRPS( 1) | SCR_BRDV_DIV_4 },
+ { 8, SCR_BRPS( 1) | SCR_BRDV_DIV_8 },
+ { 16, SCR_BRPS( 1) | SCR_BRDV_DIV_16 },
+ { 32, SCR_BRPS( 1) | SCR_BRDV_DIV_32 },
+ { 64, SCR_BRPS(32) | SCR_BRDV_DIV_2 },
+ { 128, SCR_BRPS(32) | SCR_BRDV_DIV_4 },
+ { 256, SCR_BRPS(32) | SCR_BRDV_DIV_8 },
+ { 512, SCR_BRPS(32) | SCR_BRDV_DIV_16 },
+ { 1024, SCR_BRPS(32) | SCR_BRDV_DIV_32 },
};
static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
- unsigned long parent_rate,
- unsigned long spi_hz)
+ unsigned long parent_rate, u32 spi_hz)
{
unsigned long div = 1024;
size_t k;
@@ -164,7 +212,8 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_clk_table) - 1);
sh_msiof_write(p, TSCR, sh_msiof_spi_clk_table[k].scr);
- sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr);
+ if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX))
+ sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr);
}
static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
@@ -183,21 +232,25 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
*/
sh_msiof_write(p, FCTR, 0);
- tmp = 0;
- tmp |= !cs_high << 25;
- tmp |= lsb_first << 24;
- sh_msiof_write(p, TMDR1, 0xe0000005 | tmp);
- sh_msiof_write(p, RMDR1, 0x20000005 | tmp);
+ tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP;
+ tmp |= !cs_high << MDR1_SYNCAC_SHIFT;
+ tmp |= lsb_first << MDR1_BITLSB_SHIFT;
+ sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
+ if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) {
+ /* These bits are reserved if RX needs TX */
+ tmp &= ~0x0000ffff;
+ }
+ sh_msiof_write(p, RMDR1, tmp);
- tmp = 0xa0000000;
- tmp |= cpol << 30; /* TSCKIZ */
- tmp |= cpol << 28; /* RSCKIZ */
+ tmp = 0;
+ tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT;
+ tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT;
edge = cpol ^ !cpha;
- tmp |= edge << 27; /* TEDG */
- tmp |= edge << 26; /* REDG */
- tmp |= (tx_hi_z ? 2 : 0) << 22; /* TXDIZ */
+ tmp |= edge << CTR_TEDG_SHIFT;
+ tmp |= edge << CTR_REDG_SHIFT;
+ tmp |= tx_hi_z ? CTR_TXDIZ_HIZ : CTR_TXDIZ_LOW;
sh_msiof_write(p, CTR, tmp);
}
@@ -205,12 +258,12 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p,
const void *tx_buf, void *rx_buf,
u32 bits, u32 words)
{
- u32 dr2 = ((bits - 1) << 24) | ((words - 1) << 16);
+ u32 dr2 = MDR2_BITLEN1(bits) | MDR2_WDLEN1(words);
- if (tx_buf)
+ if (tx_buf || (p->chipdata->master_flags & SPI_MASTER_MUST_TX))
sh_msiof_write(p, TMDR2, dr2);
else
- sh_msiof_write(p, TMDR2, dr2 | 1);
+ sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1);
if (rx_buf)
sh_msiof_write(p, RMDR2, dr2);
@@ -363,77 +416,45 @@ static void sh_msiof_spi_read_fifo_s32u(struct sh_msiof_spi_priv *p,
put_unaligned(swab32(sh_msiof_read(p, RFDR) >> fs), &buf_32[k]);
}
-static int sh_msiof_spi_bits(struct spi_device *spi, struct spi_transfer *t)
+static int sh_msiof_spi_setup(struct spi_device *spi)
{
- int bits;
-
- bits = t ? t->bits_per_word : 0;
- if (!bits)
- bits = spi->bits_per_word;
- return bits;
-}
-
-static unsigned long sh_msiof_spi_hz(struct spi_device *spi,
- struct spi_transfer *t)
-{
- unsigned long hz;
-
- hz = t ? t->speed_hz : 0;
- if (!hz)
- hz = spi->max_speed_hz;
- return hz;
-}
+ struct device_node *np = spi->master->dev.of_node;
+ struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
-static int sh_msiof_spi_setup_transfer(struct spi_device *spi,
- struct spi_transfer *t)
-{
- int bits;
+ if (!np) {
+ /*
+ * Use spi->controller_data for CS (same strategy as spi_gpio),
+ * if any. otherwise let HW control CS
+ */
+ spi->cs_gpio = (uintptr_t)spi->controller_data;
+ }
- /* noting to check hz values against since parent clock is disabled */
+ /* Configure pins before deasserting CS */
+ sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
+ !!(spi->mode & SPI_CPHA),
+ !!(spi->mode & SPI_3WIRE),
+ !!(spi->mode & SPI_LSB_FIRST),
+ !!(spi->mode & SPI_CS_HIGH));
- bits = sh_msiof_spi_bits(spi, t);
- if (bits < 8)
- return -EINVAL;
- if (bits > 32)
- return -EINVAL;
+ if (spi->cs_gpio >= 0)
+ gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
- return spi_bitbang_setup_transfer(spi, t);
+ return 0;
}
-static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on)
+static int sh_msiof_prepare_message(struct spi_master *master,
+ struct spi_message *msg)
{
- struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
- int value;
-
- /* chip select is active low unless SPI_CS_HIGH is set */
- if (spi->mode & SPI_CS_HIGH)
- value = (is_on == BITBANG_CS_ACTIVE) ? 1 : 0;
- else
- value = (is_on == BITBANG_CS_ACTIVE) ? 0 : 1;
-
- if (is_on == BITBANG_CS_ACTIVE) {
- if (!test_and_set_bit(0, &p->flags)) {
- pm_runtime_get_sync(&p->pdev->dev);
- clk_enable(p->clk);
- }
-
- /* Configure pins before asserting CS */
- sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
- !!(spi->mode & SPI_CPHA),
- !!(spi->mode & SPI_3WIRE),
- !!(spi->mode & SPI_LSB_FIRST),
- !!(spi->mode & SPI_CS_HIGH));
- }
+ struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
+ const struct spi_device *spi = msg->spi;
- /* use spi->controller data for CS (same strategy as spi_gpio) */
- gpio_set_value((uintptr_t)spi->controller_data, value);
-
- if (is_on == BITBANG_CS_INACTIVE) {
- if (test_and_clear_bit(0, &p->flags)) {
- clk_disable(p->clk);
- pm_runtime_put(&p->pdev->dev);
- }
- }
+ /* Configure pins before asserting CS */
+ sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
+ !!(spi->mode & SPI_CPHA),
+ !!(spi->mode & SPI_3WIRE),
+ !!(spi->mode & SPI_LSB_FIRST),
+ !!(spi->mode & SPI_CS_HIGH));
+ return 0;
}
static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
@@ -487,7 +508,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
/* clear status bits */
sh_msiof_reset_str(p);
- /* shut down frame, tx/tx and clock signals */
+ /* shut down frame, rx/tx and clock signals */
ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0);
ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TXE, 0);
if (rx_buf)
@@ -505,9 +526,11 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
return ret;
}
-static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
+static int sh_msiof_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *t)
{
- struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
+ struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int);
void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int);
int bits;
@@ -517,7 +540,7 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
int n;
bool swab;
- bits = sh_msiof_spi_bits(spi, t);
+ bits = t->bits_per_word;
if (bits <= 8 && t->len > 15 && !(t->len & 3)) {
bits = 32;
@@ -567,8 +590,7 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
}
/* setup clocks (clock already enabled in chipselect()) */
- sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk),
- sh_msiof_spi_hz(spi, t));
+ sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz);
/* transfer in fifo sized chunks */
words = t->len / bytes_per_word;
@@ -588,22 +610,36 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
words -= n;
}
- return bytes_done;
-}
-
-static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
- u32 word, u8 bits)
-{
- BUG(); /* unused but needed by bitbang code */
return 0;
}
+static const struct sh_msiof_chipdata sh_data = {
+ .tx_fifo_size = 64,
+ .rx_fifo_size = 64,
+ .master_flags = 0,
+};
+
+static const struct sh_msiof_chipdata r8a779x_data = {
+ .tx_fifo_size = 64,
+ .rx_fifo_size = 256,
+ .master_flags = SPI_MASTER_MUST_TX,
+};
+
+static const struct of_device_id sh_msiof_match[] = {
+ { .compatible = "renesas,sh-msiof", .data = &sh_data },
+ { .compatible = "renesas,sh-mobile-msiof", .data = &sh_data },
+ { .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data },
+ { .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sh_msiof_match);
+
#ifdef CONFIG_OF
static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
{
struct sh_msiof_spi_info *info;
struct device_node *np = dev->of_node;
- u32 num_cs = 0;
+ u32 num_cs = 1;
info = devm_kzalloc(dev, sizeof(struct sh_msiof_spi_info), GFP_KERNEL);
if (!info) {
@@ -633,6 +669,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
{
struct resource *r;
struct spi_master *master;
+ const struct of_device_id *of_id;
struct sh_msiof_spi_priv *p;
int i;
int ret;
@@ -646,10 +683,15 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
p = spi_master_get_devdata(master);
platform_set_drvdata(pdev, p);
- if (pdev->dev.of_node)
+
+ of_id = of_match_device(sh_msiof_match, &pdev->dev);
+ if (of_id) {
+ p->chipdata = of_id->data;
p->info = sh_msiof_spi_parse_dt(&pdev->dev);
- else
+ } else {
+ p->chipdata = (const void *)pdev->id_entry->driver_data;
p->info = dev_get_platdata(&pdev->dev);
+ }
if (!p->info) {
dev_err(&pdev->dev, "failed to obtain device info\n");
@@ -687,49 +729,40 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
goto err1;
}
- ret = clk_prepare(p->clk);
- if (ret < 0) {
- dev_err(&pdev->dev, "unable to prepare clock\n");
- goto err1;
- }
-
p->pdev = pdev;
pm_runtime_enable(&pdev->dev);
- /* The standard version of MSIOF use 64 word FIFOs */
- p->tx_fifo_size = 64;
- p->rx_fifo_size = 64;
-
/* Platform data may override FIFO sizes */
+ p->tx_fifo_size = p->chipdata->tx_fifo_size;
+ p->rx_fifo_size = p->chipdata->rx_fifo_size;
if (p->info->tx_fifo_override)
p->tx_fifo_size = p->info->tx_fifo_override;
if (p->info->rx_fifo_override)
p->rx_fifo_size = p->info->rx_fifo_override;
- /* init master and bitbang code */
+ /* init master code */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE;
- master->flags = 0;
+ master->flags = p->chipdata->master_flags;
master->bus_num = pdev->id;
+ master->dev.of_node = pdev->dev.of_node;
master->num_chipselect = p->info->num_chipselect;
- master->setup = spi_bitbang_setup;
- master->cleanup = spi_bitbang_cleanup;
-
- p->bitbang.master = master;
- p->bitbang.chipselect = sh_msiof_spi_chipselect;
- p->bitbang.setup_transfer = sh_msiof_spi_setup_transfer;
- p->bitbang.txrx_bufs = sh_msiof_spi_txrx;
- p->bitbang.txrx_word[SPI_MODE_0] = sh_msiof_spi_txrx_word;
- p->bitbang.txrx_word[SPI_MODE_1] = sh_msiof_spi_txrx_word;
- p->bitbang.txrx_word[SPI_MODE_2] = sh_msiof_spi_txrx_word;
- p->bitbang.txrx_word[SPI_MODE_3] = sh_msiof_spi_txrx_word;
-
- ret = spi_bitbang_start(&p->bitbang);
- if (ret == 0)
- return 0;
+ master->setup = sh_msiof_spi_setup;
+ master->prepare_message = sh_msiof_prepare_message;
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
+ master->auto_runtime_pm = true;
+ master->transfer_one = sh_msiof_transfer_one;
+
+ ret = devm_spi_register_master(&pdev->dev, master);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "spi_register_master error.\n");
+ goto err2;
+ }
+ return 0;
+
+ err2:
pm_runtime_disable(&pdev->dev);
- clk_unprepare(p->clk);
err1:
spi_master_put(master);
return ret;
@@ -737,30 +770,22 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
static int sh_msiof_spi_remove(struct platform_device *pdev)
{
- struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev);
- int ret;
-
- ret = spi_bitbang_stop(&p->bitbang);
- if (!ret) {
- pm_runtime_disable(&pdev->dev);
- clk_unprepare(p->clk);
- spi_master_put(p->bitbang.master);
- }
- return ret;
+ pm_runtime_disable(&pdev->dev);
+ return 0;
}
-#ifdef CONFIG_OF
-static const struct of_device_id sh_msiof_match[] = {
- { .compatible = "renesas,sh-msiof", },
- { .compatible = "renesas,sh-mobile-msiof", },
+static struct platform_device_id spi_driver_ids[] = {
+ { "spi_sh_msiof", (kernel_ulong_t)&sh_data },
+ { "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data },
+ { "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data },
{},
};
-MODULE_DEVICE_TABLE(of, sh_msiof_match);
-#endif
+MODULE_DEVICE_TABLE(platform, spi_driver_ids);
static struct platform_driver sh_msiof_spi_drv = {
.probe = sh_msiof_spi_probe,
.remove = sh_msiof_spi_remove,
+ .id_table = spi_driver_ids,
.driver = {
.name = "spi_sh_msiof",
.owner = THIS_MODULE,
diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c
index 38eb24df796..8b44b71f502 100644
--- a/drivers/spi/spi-sh-sci.c
+++ b/drivers/spi/spi-sh-sci.c
@@ -14,7 +14,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
@@ -109,7 +108,7 @@ static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
{
struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
- if (sp->info && sp->info->chip_select)
+ if (sp->info->chip_select)
(sp->info->chip_select)(sp->info, dev->chip_select, value);
}
@@ -131,6 +130,11 @@ static int sh_sci_spi_probe(struct platform_device *dev)
platform_set_drvdata(dev, sp);
sp->info = dev_get_platdata(&dev->dev);
+ if (!sp->info) {
+ dev_err(&dev->dev, "platform data is missing\n");
+ ret = -ENOENT;
+ goto err1;
+ }
/* setup spi bitbang adaptor */
sp->bitbang.master = master;
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
index e430689c383..1a77ad52812 100644
--- a/drivers/spi/spi-sirf.c
+++ b/drivers/spi/spi-sirf.c
@@ -22,7 +22,6 @@
#include <linux/dmaengine.h>
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
-#include <linux/sirfsoc_dma.h>
#define DRIVER_NAME "sirfsoc_spi"
@@ -132,6 +131,8 @@
#define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \
ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE))
+#define SIRFSOC_MAX_CMD_BYTES 4
+
struct sirfsoc_spi {
struct spi_bitbang bitbang;
struct completion rx_done;
@@ -162,6 +163,12 @@ struct sirfsoc_spi {
void *dummypage;
int word_width; /* in bytes */
+ /*
+ * if tx size is not more than 4 and rx size is NULL, use
+ * command model
+ */
+ bool tx_by_cmd;
+
int chipselect[0];
};
@@ -260,6 +267,12 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS);
+ if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) {
+ complete(&sspi->tx_done);
+ writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
+ return IRQ_HANDLED;
+ }
+
/* Error Conditions */
if (spi_stat & SIRFSOC_SPI_RX_OFLOW ||
spi_stat & SIRFSOC_SPI_TX_UFLOW) {
@@ -310,6 +323,34 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)
writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS);
+ /*
+ * fill tx_buf into command register and wait for its completion
+ */
+ if (sspi->tx_by_cmd) {
+ u32 cmd;
+ memcpy(&cmd, sspi->tx, t->len);
+
+ if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST))
+ cmd = cpu_to_be32(cmd) >>
+ ((SIRFSOC_MAX_CMD_BYTES - t->len) * 8);
+ if (sspi->word_width == 2 && t->len == 4 &&
+ (!(spi->mode & SPI_LSB_FIRST)))
+ cmd = ((cmd & 0xffff) << 16) | (cmd >> 16);
+
+ writel(cmd, sspi->base + SIRFSOC_SPI_CMD);
+ writel(SIRFSOC_SPI_FRM_END_INT_EN,
+ sspi->base + SIRFSOC_SPI_INT_EN);
+ writel(SIRFSOC_SPI_CMD_TX_EN,
+ sspi->base + SIRFSOC_SPI_TX_RX_EN);
+
+ if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) {
+ dev_err(&spi->dev, "transfer timeout\n");
+ return 0;
+ }
+
+ return t->len;
+ }
+
if (sspi->left_tx_word == 1) {
writel(readl(sspi->base + SIRFSOC_SPI_CTRL) |
SIRFSOC_SPI_ENA_AUTO_CLR,
@@ -459,11 +500,6 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_8;
sspi->rx_word = spi_sirfsoc_rx_word_u8;
sspi->tx_word = spi_sirfsoc_tx_word_u8;
- txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_BYTE;
- rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_BYTE;
- sspi->word_width = 1;
break;
case 12:
case 16:
@@ -471,26 +507,22 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
SIRFSOC_SPI_TRAN_DAT_FORMAT_16;
sspi->rx_word = spi_sirfsoc_rx_word_u16;
sspi->tx_word = spi_sirfsoc_tx_word_u16;
- txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_WORD;
- rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_WORD;
- sspi->word_width = 2;
break;
case 32:
regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_32;
sspi->rx_word = spi_sirfsoc_rx_word_u32;
sspi->tx_word = spi_sirfsoc_tx_word_u32;
- txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_DWORD;
- rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
- SIRFSOC_SPI_FIFO_WIDTH_DWORD;
- sspi->word_width = 4;
break;
default:
BUG();
}
+ sspi->word_width = DIV_ROUND_UP(bits_per_word, 8);
+ txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
+ sspi->word_width;
+ rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
+ sspi->word_width;
+
if (!(spi->mode & SPI_CS_HIGH))
regval |= SIRFSOC_SPI_CS_IDLE_STAT;
if (!(spi->mode & SPI_LSB_FIRST))
@@ -519,6 +551,14 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
writel(txfifo_ctrl, sspi->base + SIRFSOC_SPI_TXFIFO_CTRL);
writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL);
+ if (t && t->tx_buf && !t->rx_buf && (t->len <= SIRFSOC_MAX_CMD_BYTES)) {
+ regval |= (SIRFSOC_SPI_CMD_BYTE_NUM((t->len - 1)) |
+ SIRFSOC_SPI_CMD_MODE);
+ sspi->tx_by_cmd = true;
+ } else {
+ regval &= ~SIRFSOC_SPI_CMD_MODE;
+ sspi->tx_by_cmd = false;
+ }
writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
if (IS_DMA_VALID(t)) {
@@ -548,8 +588,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
struct spi_master *master;
struct resource *mem_res;
int num_cs, cs_gpio, irq;
- u32 rx_dma_ch, tx_dma_ch;
- dma_cap_mask_t dma_cap_mask;
int i;
int ret;
@@ -560,20 +598,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
goto err_cs;
}
- ret = of_property_read_u32(pdev->dev.of_node,
- "sirf,spi-dma-rx-channel", &rx_dma_ch);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unable to get rx dma channel\n");
- goto err_cs;
- }
-
- ret = of_property_read_u32(pdev->dev.of_node,
- "sirf,spi-dma-tx-channel", &tx_dma_ch);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unable to get tx dma channel\n");
- goto err_cs;
- }
-
master = spi_alloc_master(&pdev->dev, sizeof(*sspi) + sizeof(int) * num_cs);
if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI master\n");
@@ -637,18 +661,13 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
sspi->bitbang.master->dev.of_node = pdev->dev.of_node;
/* request DMA channels */
- dma_cap_zero(dma_cap_mask);
- dma_cap_set(DMA_INTERLEAVE, dma_cap_mask);
-
- sspi->rx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id,
- (void *)rx_dma_ch);
+ sspi->rx_chan = dma_request_slave_channel(&pdev->dev, "rx");
if (!sspi->rx_chan) {
dev_err(&pdev->dev, "can not allocate rx dma channel\n");
ret = -ENODEV;
goto free_master;
}
- sspi->tx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id,
- (void *)tx_dma_ch);
+ sspi->tx_chan = dma_request_slave_channel(&pdev->dev, "tx");
if (!sspi->tx_chan) {
dev_err(&pdev->dev, "can not allocate tx dma channel\n");
ret = -ENODEV;
@@ -724,11 +743,16 @@ static int spi_sirfsoc_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int spi_sirfsoc_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct sirfsoc_spi *sspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = spi_master_suspend(master);
+ if (ret)
+ return ret;
clk_disable(sspi->clk);
return 0;
@@ -745,15 +769,13 @@ static int spi_sirfsoc_resume(struct device *dev)
writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
- return 0;
+ return spi_master_resume(master);
}
-
-static const struct dev_pm_ops spi_sirfsoc_pm_ops = {
- .suspend = spi_sirfsoc_suspend,
- .resume = spi_sirfsoc_resume,
-};
#endif
+static SIMPLE_DEV_PM_OPS(spi_sirfsoc_pm_ops, spi_sirfsoc_suspend,
+ spi_sirfsoc_resume);
+
static const struct of_device_id spi_sirfsoc_of_match[] = {
{ .compatible = "sirf,prima2-spi", },
{ .compatible = "sirf,marco-spi", },
@@ -765,9 +787,7 @@ static struct platform_driver spi_sirfsoc_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &spi_sirfsoc_pm_ops,
-#endif
.of_match_table = spi_sirfsoc_of_match,
},
.probe = spi_sirfsoc_probe,
diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
new file mode 100644
index 00000000000..d266a870206
--- /dev/null
+++ b/drivers/spi/spi-sun4i.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2012 - 2014 Allwinner Tech
+ * Pan Nan <pannan@allwinnertech.com>
+ *
+ * Copyright (C) 2014 Maxime Ripard
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/workqueue.h>
+
+#include <linux/spi/spi.h>
+
+#define SUN4I_FIFO_DEPTH 64
+
+#define SUN4I_RXDATA_REG 0x00
+
+#define SUN4I_TXDATA_REG 0x04
+
+#define SUN4I_CTL_REG 0x08
+#define SUN4I_CTL_ENABLE BIT(0)
+#define SUN4I_CTL_MASTER BIT(1)
+#define SUN4I_CTL_CPHA BIT(2)
+#define SUN4I_CTL_CPOL BIT(3)
+#define SUN4I_CTL_CS_ACTIVE_LOW BIT(4)
+#define SUN4I_CTL_LMTF BIT(6)
+#define SUN4I_CTL_TF_RST BIT(8)
+#define SUN4I_CTL_RF_RST BIT(9)
+#define SUN4I_CTL_XCH BIT(10)
+#define SUN4I_CTL_CS_MASK 0x3000
+#define SUN4I_CTL_CS(cs) (((cs) << 12) & SUN4I_CTL_CS_MASK)
+#define SUN4I_CTL_DHB BIT(15)
+#define SUN4I_CTL_CS_MANUAL BIT(16)
+#define SUN4I_CTL_CS_LEVEL BIT(17)
+#define SUN4I_CTL_TP BIT(18)
+
+#define SUN4I_INT_CTL_REG 0x0c
+#define SUN4I_INT_CTL_TC BIT(16)
+
+#define SUN4I_INT_STA_REG 0x10
+
+#define SUN4I_DMA_CTL_REG 0x14
+
+#define SUN4I_WAIT_REG 0x18
+
+#define SUN4I_CLK_CTL_REG 0x1c
+#define SUN4I_CLK_CTL_CDR2_MASK 0xff
+#define SUN4I_CLK_CTL_CDR2(div) ((div) & SUN4I_CLK_CTL_CDR2_MASK)
+#define SUN4I_CLK_CTL_CDR1_MASK 0xf
+#define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8)
+#define SUN4I_CLK_CTL_DRS BIT(12)
+
+#define SUN4I_BURST_CNT_REG 0x20
+#define SUN4I_BURST_CNT(cnt) ((cnt) & 0xffffff)
+
+#define SUN4I_XMIT_CNT_REG 0x24
+#define SUN4I_XMIT_CNT(cnt) ((cnt) & 0xffffff)
+
+#define SUN4I_FIFO_STA_REG 0x28
+#define SUN4I_FIFO_STA_RF_CNT_MASK 0x7f
+#define SUN4I_FIFO_STA_RF_CNT_BITS 0
+#define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f
+#define SUN4I_FIFO_STA_TF_CNT_BITS 16
+
+struct sun4i_spi {
+ struct spi_master *master;
+ void __iomem *base_addr;
+ struct clk *hclk;
+ struct clk *mclk;
+
+ struct completion done;
+
+ const u8 *tx_buf;
+ u8 *rx_buf;
+ int len;
+};
+
+static inline u32 sun4i_spi_read(struct sun4i_spi *sspi, u32 reg)
+{
+ return readl(sspi->base_addr + reg);
+}
+
+static inline void sun4i_spi_write(struct sun4i_spi *sspi, u32 reg, u32 value)
+{
+ writel(value, sspi->base_addr + reg);
+}
+
+static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len)
+{
+ u32 reg, cnt;
+ u8 byte;
+
+ /* See how much data is available */
+ reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG);
+ reg &= SUN4I_FIFO_STA_RF_CNT_MASK;
+ cnt = reg >> SUN4I_FIFO_STA_RF_CNT_BITS;
+
+ if (len > cnt)
+ len = cnt;
+
+ while (len--) {
+ byte = readb(sspi->base_addr + SUN4I_RXDATA_REG);
+ if (sspi->rx_buf)
+ *sspi->rx_buf++ = byte;
+ }
+}
+
+static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len)
+{
+ u8 byte;
+
+ if (len > sspi->len)
+ len = sspi->len;
+
+ while (len--) {
+ byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
+ writeb(byte, sspi->base_addr + SUN4I_TXDATA_REG);
+ sspi->len--;
+ }
+}
+
+static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct sun4i_spi *sspi = spi_master_get_devdata(spi->master);
+ u32 reg;
+
+ reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+
+ reg &= ~SUN4I_CTL_CS_MASK;
+ reg |= SUN4I_CTL_CS(spi->chip_select);
+
+ if (enable)
+ reg |= SUN4I_CTL_CS_LEVEL;
+ else
+ reg &= ~SUN4I_CTL_CS_LEVEL;
+
+ /*
+ * Even though this looks irrelevant since we are supposed to
+ * be controlling the chip select manually, this bit also
+ * controls the levels of the chip select for inactive
+ * devices.
+ *
+ * If we don't set it, the chip select level will go low by
+ * default when the device is idle, which is not really
+ * expected in the common case where the chip select is active
+ * low.
+ */
+ if (spi->mode & SPI_CS_HIGH)
+ reg &= ~SUN4I_CTL_CS_ACTIVE_LOW;
+ else
+ reg |= SUN4I_CTL_CS_ACTIVE_LOW;
+
+ sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
+}
+
+static int sun4i_spi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ struct sun4i_spi *sspi = spi_master_get_devdata(master);
+ unsigned int mclk_rate, div, timeout;
+ unsigned int tx_len = 0;
+ int ret = 0;
+ u32 reg;
+
+ /* We don't support transfer larger than the FIFO */
+ if (tfr->len > SUN4I_FIFO_DEPTH)
+ return -EINVAL;
+
+ reinit_completion(&sspi->done);
+ sspi->tx_buf = tfr->tx_buf;
+ sspi->rx_buf = tfr->rx_buf;
+ sspi->len = tfr->len;
+
+ /* Clear pending interrupts */
+ sun4i_spi_write(sspi, SUN4I_INT_STA_REG, ~0);
+
+
+ reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+
+ /* Reset FIFOs */
+ sun4i_spi_write(sspi, SUN4I_CTL_REG,
+ reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST);
+
+ /*
+ * Setup the transfer control register: Chip Select,
+ * polarities, etc.
+ */
+ if (spi->mode & SPI_CPOL)
+ reg |= SUN4I_CTL_CPOL;
+ else
+ reg &= ~SUN4I_CTL_CPOL;
+
+ if (spi->mode & SPI_CPHA)
+ reg |= SUN4I_CTL_CPHA;
+ else
+ reg &= ~SUN4I_CTL_CPHA;
+
+ if (spi->mode & SPI_LSB_FIRST)
+ reg |= SUN4I_CTL_LMTF;
+ else
+ reg &= ~SUN4I_CTL_LMTF;
+
+
+ /*
+ * If it's a TX only transfer, we don't want to fill the RX
+ * FIFO with bogus data
+ */
+ if (sspi->rx_buf)
+ reg &= ~SUN4I_CTL_DHB;
+ else
+ reg |= SUN4I_CTL_DHB;
+
+ /* We want to control the chip select manually */
+ reg |= SUN4I_CTL_CS_MANUAL;
+
+ sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
+
+ /* Ensure that we have a parent clock fast enough */
+ mclk_rate = clk_get_rate(sspi->mclk);
+ if (mclk_rate < (2 * spi->max_speed_hz)) {
+ clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
+ mclk_rate = clk_get_rate(sspi->mclk);
+ }
+
+ /*
+ * Setup clock divider.
+ *
+ * We have two choices there. Either we can use the clock
+ * divide rate 1, which is calculated thanks to this formula:
+ * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
+ * Or we can use CDR2, which is calculated with the formula:
+ * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
+ * Wether we use the former or the latter is set through the
+ * DRS bit.
+ *
+ * First try CDR2, and if we can't reach the expected
+ * frequency, fall back to CDR1.
+ */
+ div = mclk_rate / (2 * spi->max_speed_hz);
+ if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
+ if (div > 0)
+ div--;
+
+ reg = SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
+ } else {
+ div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
+ reg = SUN4I_CLK_CTL_CDR1(div);
+ }
+
+ sun4i_spi_write(sspi, SUN4I_CLK_CTL_REG, reg);
+
+ /* Setup the transfer now... */
+ if (sspi->tx_buf)
+ tx_len = tfr->len;
+
+ /* Setup the counters */
+ sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len));
+ sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len));
+
+ /* Fill the TX FIFO */
+ sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
+
+ /* Enable the interrupts */
+ sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC);
+
+ /* Start the transfer */
+ reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
+ sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
+
+ timeout = wait_for_completion_timeout(&sspi->done,
+ msecs_to_jiffies(1000));
+ if (!timeout) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
+
+out:
+ sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0);
+
+ return ret;
+}
+
+static irqreturn_t sun4i_spi_handler(int irq, void *dev_id)
+{
+ struct sun4i_spi *sspi = dev_id;
+ u32 status = sun4i_spi_read(sspi, SUN4I_INT_STA_REG);
+
+ /* Transfer complete */
+ if (status & SUN4I_INT_CTL_TC) {
+ sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC);
+ complete(&sspi->done);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int sun4i_spi_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct sun4i_spi *sspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(sspi->hclk);
+ if (ret) {
+ dev_err(dev, "Couldn't enable AHB clock\n");
+ goto out;
+ }
+
+ ret = clk_prepare_enable(sspi->mclk);
+ if (ret) {
+ dev_err(dev, "Couldn't enable module clock\n");
+ goto err;
+ }
+
+ sun4i_spi_write(sspi, SUN4I_CTL_REG,
+ SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP);
+
+ return 0;
+
+err:
+ clk_disable_unprepare(sspi->hclk);
+out:
+ return ret;
+}
+
+static int sun4i_spi_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct sun4i_spi *sspi = spi_master_get_devdata(master);
+
+ clk_disable_unprepare(sspi->mclk);
+ clk_disable_unprepare(sspi->hclk);
+
+ return 0;
+}
+
+static int sun4i_spi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct sun4i_spi *sspi;
+ struct resource *res;
+ int ret = 0, irq;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi));
+ if (!master) {
+ dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, master);
+ sspi = spi_master_get_devdata(master);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sspi->base_addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(sspi->base_addr)) {
+ ret = PTR_ERR(sspi->base_addr);
+ goto err_free_master;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "No spi IRQ specified\n");
+ ret = -ENXIO;
+ goto err_free_master;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler,
+ 0, "sun4i-spi", sspi);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot request IRQ\n");
+ goto err_free_master;
+ }
+
+ sspi->master = master;
+ master->set_cs = sun4i_spi_set_cs;
+ master->transfer_one = sun4i_spi_transfer_one;
+ master->num_chipselect = 4;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->dev.of_node = pdev->dev.of_node;
+ master->auto_runtime_pm = true;
+
+ sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
+ if (IS_ERR(sspi->hclk)) {
+ dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
+ ret = PTR_ERR(sspi->hclk);
+ goto err_free_master;
+ }
+
+ sspi->mclk = devm_clk_get(&pdev->dev, "mod");
+ if (IS_ERR(sspi->mclk)) {
+ dev_err(&pdev->dev, "Unable to acquire module clock\n");
+ ret = PTR_ERR(sspi->mclk);
+ goto err_free_master;
+ }
+
+ init_completion(&sspi->done);
+
+ /*
+ * This wake-up/shutdown pattern is to be able to have the
+ * device woken up, even if runtime_pm is disabled
+ */
+ ret = sun4i_spi_runtime_resume(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't resume the device\n");
+ goto err_free_master;
+ }
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_idle(&pdev->dev);
+
+ ret = devm_spi_register_master(&pdev->dev, master);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot register SPI master\n");
+ goto err_pm_disable;
+ }
+
+ return 0;
+
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+ sun4i_spi_runtime_suspend(&pdev->dev);
+err_free_master:
+ spi_master_put(master);
+ return ret;
+}
+
+static int sun4i_spi_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id sun4i_spi_match[] = {
+ { .compatible = "allwinner,sun4i-a10-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun4i_spi_match);
+
+static const struct dev_pm_ops sun4i_spi_pm_ops = {
+ .runtime_resume = sun4i_spi_runtime_resume,
+ .runtime_suspend = sun4i_spi_runtime_suspend,
+};
+
+static struct platform_driver sun4i_spi_driver = {
+ .probe = sun4i_spi_probe,
+ .remove = sun4i_spi_remove,
+ .driver = {
+ .name = "sun4i-spi",
+ .owner = THIS_MODULE,
+ .of_match_table = sun4i_spi_match,
+ .pm = &sun4i_spi_pm_ops,
+ },
+};
+module_platform_driver(sun4i_spi_driver);
+
+MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A1X/A20 SPI controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
new file mode 100644
index 00000000000..b3e3498a7e6
--- /dev/null
+++ b/drivers/spi/spi-sun6i.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2012 - 2014 Allwinner Tech
+ * Pan Nan <pannan@allwinnertech.com>
+ *
+ * Copyright (C) 2014 Maxime Ripard
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/workqueue.h>
+
+#include <linux/spi/spi.h>
+
+#define SUN6I_FIFO_DEPTH 128
+
+#define SUN6I_GBL_CTL_REG 0x04
+#define SUN6I_GBL_CTL_BUS_ENABLE BIT(0)
+#define SUN6I_GBL_CTL_MASTER BIT(1)
+#define SUN6I_GBL_CTL_TP BIT(7)
+#define SUN6I_GBL_CTL_RST BIT(31)
+
+#define SUN6I_TFR_CTL_REG 0x08
+#define SUN6I_TFR_CTL_CPHA BIT(0)
+#define SUN6I_TFR_CTL_CPOL BIT(1)
+#define SUN6I_TFR_CTL_SPOL BIT(2)
+#define SUN6I_TFR_CTL_CS_MASK 0x30
+#define SUN6I_TFR_CTL_CS(cs) (((cs) << 4) & SUN6I_TFR_CTL_CS_MASK)
+#define SUN6I_TFR_CTL_CS_MANUAL BIT(6)
+#define SUN6I_TFR_CTL_CS_LEVEL BIT(7)
+#define SUN6I_TFR_CTL_DHB BIT(8)
+#define SUN6I_TFR_CTL_FBS BIT(12)
+#define SUN6I_TFR_CTL_XCH BIT(31)
+
+#define SUN6I_INT_CTL_REG 0x10
+#define SUN6I_INT_CTL_RF_OVF BIT(8)
+#define SUN6I_INT_CTL_TC BIT(12)
+
+#define SUN6I_INT_STA_REG 0x14
+
+#define SUN6I_FIFO_CTL_REG 0x18
+#define SUN6I_FIFO_CTL_RF_RST BIT(15)
+#define SUN6I_FIFO_CTL_TF_RST BIT(31)
+
+#define SUN6I_FIFO_STA_REG 0x1c
+#define SUN6I_FIFO_STA_RF_CNT_MASK 0x7f
+#define SUN6I_FIFO_STA_RF_CNT_BITS 0
+#define SUN6I_FIFO_STA_TF_CNT_MASK 0x7f
+#define SUN6I_FIFO_STA_TF_CNT_BITS 16
+
+#define SUN6I_CLK_CTL_REG 0x24
+#define SUN6I_CLK_CTL_CDR2_MASK 0xff
+#define SUN6I_CLK_CTL_CDR2(div) (((div) & SUN6I_CLK_CTL_CDR2_MASK) << 0)
+#define SUN6I_CLK_CTL_CDR1_MASK 0xf
+#define SUN6I_CLK_CTL_CDR1(div) (((div) & SUN6I_CLK_CTL_CDR1_MASK) << 8)
+#define SUN6I_CLK_CTL_DRS BIT(12)
+
+#define SUN6I_BURST_CNT_REG 0x30
+#define SUN6I_BURST_CNT(cnt) ((cnt) & 0xffffff)
+
+#define SUN6I_XMIT_CNT_REG 0x34
+#define SUN6I_XMIT_CNT(cnt) ((cnt) & 0xffffff)
+
+#define SUN6I_BURST_CTL_CNT_REG 0x38
+#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & 0xffffff)
+
+#define SUN6I_TXDATA_REG 0x200
+#define SUN6I_RXDATA_REG 0x300
+
+struct sun6i_spi {
+ struct spi_master *master;
+ void __iomem *base_addr;
+ struct clk *hclk;
+ struct clk *mclk;
+ struct reset_control *rstc;
+
+ struct completion done;
+
+ const u8 *tx_buf;
+ u8 *rx_buf;
+ int len;
+};
+
+static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg)
+{
+ return readl(sspi->base_addr + reg);
+}
+
+static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value)
+{
+ writel(value, sspi->base_addr + reg);
+}
+
+static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
+{
+ u32 reg, cnt;
+ u8 byte;
+
+ /* See how much data is available */
+ reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
+ reg &= SUN6I_FIFO_STA_RF_CNT_MASK;
+ cnt = reg >> SUN6I_FIFO_STA_RF_CNT_BITS;
+
+ if (len > cnt)
+ len = cnt;
+
+ while (len--) {
+ byte = readb(sspi->base_addr + SUN6I_RXDATA_REG);
+ if (sspi->rx_buf)
+ *sspi->rx_buf++ = byte;
+ }
+}
+
+static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len)
+{
+ u8 byte;
+
+ if (len > sspi->len)
+ len = sspi->len;
+
+ while (len--) {
+ byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
+ writeb(byte, sspi->base_addr + SUN6I_TXDATA_REG);
+ sspi->len--;
+ }
+}
+
+static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
+ u32 reg;
+
+ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+ reg &= ~SUN6I_TFR_CTL_CS_MASK;
+ reg |= SUN6I_TFR_CTL_CS(spi->chip_select);
+
+ if (enable)
+ reg |= SUN6I_TFR_CTL_CS_LEVEL;
+ else
+ reg &= ~SUN6I_TFR_CTL_CS_LEVEL;
+
+ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+}
+
+
+static int sun6i_spi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ unsigned int mclk_rate, div, timeout;
+ unsigned int tx_len = 0;
+ int ret = 0;
+ u32 reg;
+
+ /* We don't support transfer larger than the FIFO */
+ if (tfr->len > SUN6I_FIFO_DEPTH)
+ return -EINVAL;
+
+ reinit_completion(&sspi->done);
+ sspi->tx_buf = tfr->tx_buf;
+ sspi->rx_buf = tfr->rx_buf;
+ sspi->len = tfr->len;
+
+ /* Clear pending interrupts */
+ sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0);
+
+ /* Reset FIFO */
+ sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
+ SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
+
+ /*
+ * Setup the transfer control register: Chip Select,
+ * polarities, etc.
+ */
+ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+
+ if (spi->mode & SPI_CPOL)
+ reg |= SUN6I_TFR_CTL_CPOL;
+ else
+ reg &= ~SUN6I_TFR_CTL_CPOL;
+
+ if (spi->mode & SPI_CPHA)
+ reg |= SUN6I_TFR_CTL_CPHA;
+ else
+ reg &= ~SUN6I_TFR_CTL_CPHA;
+
+ if (spi->mode & SPI_LSB_FIRST)
+ reg |= SUN6I_TFR_CTL_FBS;
+ else
+ reg &= ~SUN6I_TFR_CTL_FBS;
+
+ /*
+ * If it's a TX only transfer, we don't want to fill the RX
+ * FIFO with bogus data
+ */
+ if (sspi->rx_buf)
+ reg &= ~SUN6I_TFR_CTL_DHB;
+ else
+ reg |= SUN6I_TFR_CTL_DHB;
+
+ /* We want to control the chip select manually */
+ reg |= SUN6I_TFR_CTL_CS_MANUAL;
+
+ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+
+ /* Ensure that we have a parent clock fast enough */
+ mclk_rate = clk_get_rate(sspi->mclk);
+ if (mclk_rate < (2 * spi->max_speed_hz)) {
+ clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
+ mclk_rate = clk_get_rate(sspi->mclk);
+ }
+
+ /*
+ * Setup clock divider.
+ *
+ * We have two choices there. Either we can use the clock
+ * divide rate 1, which is calculated thanks to this formula:
+ * SPI_CLK = MOD_CLK / (2 ^ cdr)
+ * Or we can use CDR2, which is calculated with the formula:
+ * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
+ * Wether we use the former or the latter is set through the
+ * DRS bit.
+ *
+ * First try CDR2, and if we can't reach the expected
+ * frequency, fall back to CDR1.
+ */
+ div = mclk_rate / (2 * spi->max_speed_hz);
+ if (div <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
+ if (div > 0)
+ div--;
+
+ reg = SUN6I_CLK_CTL_CDR2(div) | SUN6I_CLK_CTL_DRS;
+ } else {
+ div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
+ reg = SUN6I_CLK_CTL_CDR1(div);
+ }
+
+ sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
+
+ /* Setup the transfer now... */
+ if (sspi->tx_buf)
+ tx_len = tfr->len;
+
+ /* Setup the counters */
+ sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, SUN6I_BURST_CNT(tfr->len));
+ sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, SUN6I_XMIT_CNT(tx_len));
+ sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG,
+ SUN6I_BURST_CTL_CNT_STC(tx_len));
+
+ /* Fill the TX FIFO */
+ sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH);
+
+ /* Enable the interrupts */
+ sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
+
+ /* Start the transfer */
+ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
+
+ timeout = wait_for_completion_timeout(&sspi->done,
+ msecs_to_jiffies(1000));
+ if (!timeout) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
+
+out:
+ sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
+
+ return ret;
+}
+
+static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
+{
+ struct sun6i_spi *sspi = dev_id;
+ u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
+
+ /* Transfer complete */
+ if (status & SUN6I_INT_CTL_TC) {
+ sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC);
+ complete(&sspi->done);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int sun6i_spi_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(sspi->hclk);
+ if (ret) {
+ dev_err(dev, "Couldn't enable AHB clock\n");
+ goto out;
+ }
+
+ ret = clk_prepare_enable(sspi->mclk);
+ if (ret) {
+ dev_err(dev, "Couldn't enable module clock\n");
+ goto err;
+ }
+
+ ret = reset_control_deassert(sspi->rstc);
+ if (ret) {
+ dev_err(dev, "Couldn't deassert the device from reset\n");
+ goto err2;
+ }
+
+ sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG,
+ SUN6I_GBL_CTL_BUS_ENABLE | SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP);
+
+ return 0;
+
+err2:
+ clk_disable_unprepare(sspi->mclk);
+err:
+ clk_disable_unprepare(sspi->hclk);
+out:
+ return ret;
+}
+
+static int sun6i_spi_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct sun6i_spi *sspi = spi_master_get_devdata(master);
+
+ reset_control_assert(sspi->rstc);
+ clk_disable_unprepare(sspi->mclk);
+ clk_disable_unprepare(sspi->hclk);
+
+ return 0;
+}
+
+static int sun6i_spi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct sun6i_spi *sspi;
+ struct resource *res;
+ int ret = 0, irq;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
+ if (!master) {
+ dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, master);
+ sspi = spi_master_get_devdata(master);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sspi->base_addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(sspi->base_addr)) {
+ ret = PTR_ERR(sspi->base_addr);
+ goto err_free_master;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "No spi IRQ specified\n");
+ ret = -ENXIO;
+ goto err_free_master;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler,
+ 0, "sun6i-spi", sspi);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot request IRQ\n");
+ goto err_free_master;
+ }
+
+ sspi->master = master;
+ master->set_cs = sun6i_spi_set_cs;
+ master->transfer_one = sun6i_spi_transfer_one;
+ master->num_chipselect = 4;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->dev.of_node = pdev->dev.of_node;
+ master->auto_runtime_pm = true;
+
+ sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
+ if (IS_ERR(sspi->hclk)) {
+ dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
+ ret = PTR_ERR(sspi->hclk);
+ goto err_free_master;
+ }
+
+ sspi->mclk = devm_clk_get(&pdev->dev, "mod");
+ if (IS_ERR(sspi->mclk)) {
+ dev_err(&pdev->dev, "Unable to acquire module clock\n");
+ ret = PTR_ERR(sspi->mclk);
+ goto err_free_master;
+ }
+
+ init_completion(&sspi->done);
+
+ sspi->rstc = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(sspi->rstc)) {
+ dev_err(&pdev->dev, "Couldn't get reset controller\n");
+ ret = PTR_ERR(sspi->rstc);
+ goto err_free_master;
+ }
+
+ /*
+ * This wake-up/shutdown pattern is to be able to have the
+ * device woken up, even if runtime_pm is disabled
+ */
+ ret = sun6i_spi_runtime_resume(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't resume the device\n");
+ goto err_free_master;
+ }
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_idle(&pdev->dev);
+
+ ret = devm_spi_register_master(&pdev->dev, master);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot register SPI master\n");
+ goto err_pm_disable;
+ }
+
+ return 0;
+
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+ sun6i_spi_runtime_suspend(&pdev->dev);
+err_free_master:
+ spi_master_put(master);
+ return ret;
+}
+
+static int sun6i_spi_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id sun6i_spi_match[] = {
+ { .compatible = "allwinner,sun6i-a31-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun6i_spi_match);
+
+static const struct dev_pm_ops sun6i_spi_pm_ops = {
+ .runtime_resume = sun6i_spi_runtime_resume,
+ .runtime_suspend = sun6i_spi_runtime_suspend,
+};
+
+static struct platform_driver sun6i_spi_driver = {
+ .probe = sun6i_spi_probe,
+ .remove = sun6i_spi_remove,
+ .driver = {
+ .name = "sun6i-spi",
+ .owner = THIS_MODULE,
+ .of_match_table = sun6i_spi_match,
+ .pm = &sun6i_spi_pm_ops,
+ },
+};
+module_platform_driver(sun6i_spi_driver);
+
+MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A31 SPI controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 413c7184349..40064959550 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -23,7 +23,6 @@
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/err.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -172,7 +171,6 @@ struct tegra_spi_data {
void __iomem *base;
phys_addr_t phys;
unsigned irq;
- u32 spi_max_frequency;
u32 cur_speed;
struct spi_device *cur_spi;
@@ -761,11 +759,6 @@ static int tegra_spi_setup(struct spi_device *spi)
spi->mode & SPI_CPHA ? "" : "~",
spi->max_speed_hz);
- BUG_ON(spi->chip_select >= MAX_CHIP_SELECT);
-
- /* Set speed to the spi max fequency if spi device has not set */
- spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency;
-
ret = pm_runtime_get_sync(tspi->dev);
if (ret < 0) {
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
@@ -853,8 +846,8 @@ complete_xfer:
SPI_COMMAND1);
tegra_spi_transfer_delay(xfer->delay_usecs);
goto exit;
- } else if (msg->transfers.prev == &xfer->transfer_list) {
- /* This is the last transfer in message */
+ } else if (list_is_last(&xfer->transfer_list,
+ &msg->transfers)) {
if (xfer->cs_change)
tspi->cs_control = spi;
else {
@@ -1019,16 +1012,6 @@ static irqreturn_t tegra_spi_isr(int irq, void *context_data)
return IRQ_WAKE_THREAD;
}
-static void tegra_spi_parse_dt(struct platform_device *pdev,
- struct tegra_spi_data *tspi)
-{
- struct device_node *np = pdev->dev.of_node;
-
- if (of_property_read_u32(np, "spi-max-frequency",
- &tspi->spi_max_frequency))
- tspi->spi_max_frequency = 25000000; /* 25MHz */
-}
-
static struct of_device_id tegra_spi_of_match[] = {
{ .compatible = "nvidia,tegra114-spi", },
{}
@@ -1050,15 +1033,15 @@ static int tegra_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
tspi = spi_master_get_devdata(master);
- /* Parse DT */
- tegra_spi_parse_dt(pdev, tspi);
+ if (of_property_read_u32(pdev->dev.of_node, "spi-max-frequency",
+ &master->max_speed_hz))
+ master->max_speed_hz = 25000000; /* 25MHz */
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->setup = tegra_spi_setup;
master->transfer_one_message = tegra_spi_transfer_one_message;
master->num_chipselect = MAX_CHIP_SELECT;
- master->bus_num = -1;
master->auto_runtime_pm = true;
tspi->master = master;
diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c
index 08794977f21..47869ea636e 100644
--- a/drivers/spi/spi-tegra20-sflash.c
+++ b/drivers/spi/spi-tegra20-sflash.c
@@ -22,7 +22,6 @@
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -121,7 +120,6 @@ struct tegra_sflash_data {
struct reset_control *rst;
void __iomem *base;
unsigned irq;
- u32 spi_max_frequency;
u32 cur_speed;
struct spi_device *cur_spi;
@@ -315,15 +313,6 @@ static int tegra_sflash_start_transfer_one(struct spi_device *spi,
return tegra_sflash_start_cpu_based_transfer(tsd, t);
}
-static int tegra_sflash_setup(struct spi_device *spi)
-{
- struct tegra_sflash_data *tsd = spi_master_get_devdata(spi->master);
-
- /* Set speed to the spi max fequency if spi device has not set */
- spi->max_speed_hz = spi->max_speed_hz ? : tsd->spi_max_frequency;
- return 0;
-}
-
static int tegra_sflash_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
@@ -430,15 +419,6 @@ static irqreturn_t tegra_sflash_isr(int irq, void *context_data)
return handle_cpu_based_xfer(tsd);
}
-static void tegra_sflash_parse_dt(struct tegra_sflash_data *tsd)
-{
- struct device_node *np = tsd->dev->of_node;
-
- if (of_property_read_u32(np, "spi-max-frequency",
- &tsd->spi_max_frequency))
- tsd->spi_max_frequency = 25000000; /* 25MHz */
-}
-
static struct of_device_id tegra_sflash_of_match[] = {
{ .compatible = "nvidia,tegra20-sflash", },
{}
@@ -467,11 +447,9 @@ static int tegra_sflash_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA;
- master->setup = tegra_sflash_setup;
master->transfer_one_message = tegra_sflash_transfer_one_message;
master->auto_runtime_pm = true;
master->num_chipselect = MAX_CHIP_SELECT;
- master->bus_num = -1;
platform_set_drvdata(pdev, master);
tsd = spi_master_get_devdata(master);
@@ -479,7 +457,9 @@ static int tegra_sflash_probe(struct platform_device *pdev)
tsd->dev = &pdev->dev;
spin_lock_init(&tsd->lock);
- tegra_sflash_parse_dt(tsd);
+ if (of_property_read_u32(tsd->dev->of_node, "spi-max-frequency",
+ &master->max_speed_hz))
+ master->max_speed_hz = 25000000; /* 25MHz */
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
tsd->base = devm_ioremap_resource(&pdev->dev, r);
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c
index be3a069879c..e3c1b93e45d 100644
--- a/drivers/spi/spi-tegra20-slink.c
+++ b/drivers/spi/spi-tegra20-slink.c
@@ -23,7 +23,6 @@
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/err.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -171,7 +170,6 @@ struct tegra_slink_data {
void __iomem *base;
phys_addr_t phys;
unsigned irq;
- u32 spi_max_frequency;
u32 cur_speed;
struct spi_device *cur_spi;
@@ -761,10 +759,6 @@ static int tegra_slink_setup(struct spi_device *spi)
spi->mode & SPI_CPHA ? "" : "~",
spi->max_speed_hz);
- BUG_ON(spi->chip_select >= MAX_CHIP_SELECT);
-
- /* Set speed to the spi max fequency if spi device has not set */
- spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency;
ret = pm_runtime_get_sync(tspi->dev);
if (ret < 0) {
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
@@ -999,15 +993,6 @@ static irqreturn_t tegra_slink_isr(int irq, void *context_data)
return IRQ_WAKE_THREAD;
}
-static void tegra_slink_parse_dt(struct tegra_slink_data *tspi)
-{
- struct device_node *np = tspi->dev->of_node;
-
- if (of_property_read_u32(np, "spi-max-frequency",
- &tspi->spi_max_frequency))
- tspi->spi_max_frequency = 25000000; /* 25MHz */
-}
-
static const struct tegra_slink_chip_data tegra30_spi_cdata = {
.cs_hold_time = true,
};
@@ -1053,7 +1038,6 @@ static int tegra_slink_probe(struct platform_device *pdev)
master->unprepare_message = tegra_slink_unprepare_message;
master->auto_runtime_pm = true;
master->num_chipselect = MAX_CHIP_SELECT;
- master->bus_num = -1;
platform_set_drvdata(pdev, master);
tspi = spi_master_get_devdata(master);
@@ -1062,7 +1046,9 @@ static int tegra_slink_probe(struct platform_device *pdev)
tspi->chip_data = cdata;
spin_lock_init(&tspi->lock);
- tegra_slink_parse_dt(tspi);
+ if (of_property_read_u32(tspi->dev->of_node, "spi-max-frequency",
+ &master->max_speed_hz))
+ master->max_speed_hz = 25000000; /* 25MHz */
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
index 3d09265b513..6c211d1910b 100644
--- a/drivers/spi/spi-ti-qspi.c
+++ b/drivers/spi/spi-ti-qspi.c
@@ -429,13 +429,13 @@ static int ti_qspi_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD;
- master->bus_num = -1;
master->flags = SPI_MASTER_HALF_DUPLEX;
master->setup = ti_qspi_setup;
master->auto_runtime_pm = true;
master->transfer_one_message = ti_qspi_start_transfer_one;
master->dev.of_node = pdev->dev.of_node;
- master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1);
+ master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
+ SPI_BPW_MASK(8);
if (!of_property_read_u32(np, "num-cs", &num_cs))
master->num_chipselect = num_cs;
@@ -461,7 +461,6 @@ static int ti_qspi_probe(struct platform_device *pdev)
if (res_mmap == NULL) {
dev_err(&pdev->dev,
"memory mapped resource not required\n");
- return -ENODEV;
}
}
diff --git a/drivers/spi/spi-ti-ssp.c b/drivers/spi/spi-ti-ssp.c
deleted file mode 100644
index 7d20e121e4c..00000000000
--- a/drivers/spi/spi-ti-ssp.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Sequencer Serial Port (SSP) based SPI master driver
- *
- * Copyright (C) 2010 Texas Instruments Inc
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/mfd/ti_ssp.h>
-
-#define MODE_BITS (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
-
-struct ti_ssp_spi {
- struct spi_master *master;
- struct device *dev;
- spinlock_t lock;
- struct list_head msg_queue;
- struct completion complete;
- bool shutdown;
- struct workqueue_struct *workqueue;
- struct work_struct work;
- u8 mode, bpw;
- int cs_active;
- u32 pc_en, pc_dis, pc_wr, pc_rd;
- void (*select)(int cs);
-};
-
-static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw)
-{
- u32 ret;
-
- ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret);
- return ret;
-}
-
-static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data)
-{
- ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL);
-}
-
-static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg,
- struct spi_transfer *t)
-{
- int count;
-
- if (hw->bpw <= 8) {
- u8 *rx = t->rx_buf;
- const u8 *tx = t->tx_buf;
-
- for (count = 0; count < t->len; count += 1) {
- if (t->tx_buf)
- ti_ssp_spi_tx(hw, *tx++);
- if (t->rx_buf)
- *rx++ = ti_ssp_spi_rx(hw);
- }
- } else if (hw->bpw <= 16) {
- u16 *rx = t->rx_buf;
- const u16 *tx = t->tx_buf;
-
- for (count = 0; count < t->len; count += 2) {
- if (t->tx_buf)
- ti_ssp_spi_tx(hw, *tx++);
- if (t->rx_buf)
- *rx++ = ti_ssp_spi_rx(hw);
- }
- } else {
- u32 *rx = t->rx_buf;
- const u32 *tx = t->tx_buf;
-
- for (count = 0; count < t->len; count += 4) {
- if (t->tx_buf)
- ti_ssp_spi_tx(hw, *tx++);
- if (t->rx_buf)
- *rx++ = ti_ssp_spi_rx(hw);
- }
- }
-
- msg->actual_length += count; /* bytes transferred */
-
- dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n",
- t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len,
- hw->bpw, count, (count < t->len) ? " (under)" : "");
-
- return (count < t->len) ? -EIO : 0; /* left over data */
-}
-
-static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active)
-{
- cs_active = !!cs_active;
- if (cs_active == hw->cs_active)
- return;
- ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL);
- hw->cs_active = cs_active;
-}
-
-#define __SHIFT_OUT(bits) (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \
- cs_en | clk | SSP_COUNT((bits) * 2 - 1))
-#define __SHIFT_IN(bits) (SSP_OPCODE_SHIFT | SSP_IN_MODE | \
- cs_en | clk | SSP_COUNT((bits) * 2 - 1))
-
-static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode)
-{
- int error, idx = 0;
- u32 seqram[16];
- u32 cs_en, cs_dis, clk;
- u32 topbits, botbits;
-
- mode &= MODE_BITS;
- if (mode == hw->mode && bpw == hw->bpw)
- return 0;
-
- cs_en = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW;
- cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW : SSP_CS_HIGH;
- clk = (mode & SPI_CPOL) ? SSP_CLK_HIGH : SSP_CLK_LOW;
-
- /* Construct instructions */
-
- /* Disable Chip Select */
- hw->pc_dis = idx;
- seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk;
- seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_dis | clk;
-
- /* Enable Chip Select */
- hw->pc_en = idx;
- seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk;
- seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
-
- /* Reads and writes need to be split for bpw > 16 */
- topbits = (bpw > 16) ? 16 : bpw;
- botbits = bpw - topbits;
-
- /* Write */
- hw->pc_wr = idx;
- seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG;
- if (botbits)
- seqram[idx++] = __SHIFT_OUT(botbits) | SSP_DATA_REG;
- seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
-
- /* Read */
- hw->pc_rd = idx;
- if (botbits)
- seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG;
- seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG;
- seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
-
- error = ti_ssp_load(hw->dev, 0, seqram, idx);
- if (error < 0)
- return error;
-
- error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ?
- 0 : SSP_EARLY_DIN));
- if (error < 0)
- return error;
-
- hw->bpw = bpw;
- hw->mode = mode;
-
- return error;
-}
-
-static void ti_ssp_spi_work(struct work_struct *work)
-{
- struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work);
-
- spin_lock(&hw->lock);
-
- while (!list_empty(&hw->msg_queue)) {
- struct spi_message *m;
- struct spi_device *spi;
- struct spi_transfer *t = NULL;
- int status = 0;
-
- m = container_of(hw->msg_queue.next, struct spi_message,
- queue);
-
- list_del_init(&m->queue);
-
- spin_unlock(&hw->lock);
-
- spi = m->spi;
-
- if (hw->select)
- hw->select(spi->chip_select);
-
- list_for_each_entry(t, &m->transfers, transfer_list) {
- int bpw = spi->bits_per_word;
- int xfer_status;
-
- if (t->bits_per_word)
- bpw = t->bits_per_word;
-
- if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0)
- break;
-
- ti_ssp_spi_chip_select(hw, 1);
-
- xfer_status = ti_ssp_spi_txrx(hw, m, t);
- if (xfer_status < 0)
- status = xfer_status;
-
- if (t->delay_usecs)
- udelay(t->delay_usecs);
-
- if (t->cs_change)
- ti_ssp_spi_chip_select(hw, 0);
- }
-
- ti_ssp_spi_chip_select(hw, 0);
- m->status = status;
- m->complete(m->context);
-
- spin_lock(&hw->lock);
- }
-
- if (hw->shutdown)
- complete(&hw->complete);
-
- spin_unlock(&hw->lock);
-}
-
-static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
-{
- struct ti_ssp_spi *hw;
- struct spi_transfer *t;
- int error = 0;
-
- m->actual_length = 0;
- m->status = -EINPROGRESS;
-
- hw = spi_master_get_devdata(spi->master);
-
- if (list_empty(&m->transfers) || !m->complete)
- return -EINVAL;
-
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if (t->len && !(t->rx_buf || t->tx_buf)) {
- dev_err(&spi->dev, "invalid xfer, no buffer\n");
- return -EINVAL;
- }
-
- if (t->len && t->rx_buf && t->tx_buf) {
- dev_err(&spi->dev, "invalid xfer, full duplex\n");
- return -EINVAL;
- }
- }
-
- spin_lock(&hw->lock);
- if (hw->shutdown) {
- error = -ESHUTDOWN;
- goto error_unlock;
- }
- list_add_tail(&m->queue, &hw->msg_queue);
- queue_work(hw->workqueue, &hw->work);
-error_unlock:
- spin_unlock(&hw->lock);
- return error;
-}
-
-static int ti_ssp_spi_probe(struct platform_device *pdev)
-{
- const struct ti_ssp_spi_data *pdata;
- struct ti_ssp_spi *hw;
- struct spi_master *master;
- struct device *dev = &pdev->dev;
- int error = 0;
-
- pdata = dev_get_platdata(dev);
- if (!pdata) {
- dev_err(dev, "platform data not found\n");
- return -EINVAL;
- }
-
- master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi));
- if (!master) {
- dev_err(dev, "cannot allocate SPI master\n");
- return -ENOMEM;
- }
-
- hw = spi_master_get_devdata(master);
- platform_set_drvdata(pdev, hw);
-
- hw->master = master;
- hw->dev = dev;
- hw->select = pdata->select;
-
- spin_lock_init(&hw->lock);
- init_completion(&hw->complete);
- INIT_LIST_HEAD(&hw->msg_queue);
- INIT_WORK(&hw->work, ti_ssp_spi_work);
-
- hw->workqueue = create_singlethread_workqueue(dev_name(dev));
- if (!hw->workqueue) {
- error = -ENOMEM;
- dev_err(dev, "work queue creation failed\n");
- goto error_wq;
- }
-
- error = ti_ssp_set_iosel(hw->dev, pdata->iosel);
- if (error < 0) {
- dev_err(dev, "io setup failed\n");
- goto error_iosel;
- }
-
- master->bus_num = pdev->id;
- master->num_chipselect = pdata->num_cs;
- master->mode_bits = MODE_BITS;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->transfer = ti_ssp_spi_transfer;
-
- error = spi_register_master(master);
- if (error) {
- dev_err(dev, "master registration failed\n");
- goto error_reg;
- }
-
- return 0;
-
-error_reg:
-error_iosel:
- destroy_workqueue(hw->workqueue);
-error_wq:
- spi_master_put(master);
- return error;
-}
-
-static int ti_ssp_spi_remove(struct platform_device *pdev)
-{
- struct ti_ssp_spi *hw = platform_get_drvdata(pdev);
- int error;
-
- hw->shutdown = 1;
- while (!list_empty(&hw->msg_queue)) {
- error = wait_for_completion_interruptible(&hw->complete);
- if (error < 0) {
- hw->shutdown = 0;
- return error;
- }
- }
- destroy_workqueue(hw->workqueue);
- spi_unregister_master(hw->master);
-
- return 0;
-}
-
-static struct platform_driver ti_ssp_spi_driver = {
- .probe = ti_ssp_spi_probe,
- .remove = ti_ssp_spi_remove,
- .driver = {
- .name = "ti-ssp-spi",
- .owner = THIS_MODULE,
- },
-};
-module_platform_driver(ti_ssp_spi_driver);
-
-MODULE_DESCRIPTION("SSP SPI Master");
-MODULE_AUTHOR("Cyril Chemparathy");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:ti-ssp-spi");
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index 88eb57e858b..f406b30af96 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -332,7 +332,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
data->transfer_active = false;
wake_up(&data->wait);
} else {
- dev_err(&data->master->dev,
+ dev_vdbg(&data->master->dev,
"%s : Transfer is not completed",
__func__);
}
@@ -464,20 +464,6 @@ static void pch_spi_reset(struct spi_master *master)
pch_spi_writereg(master, PCH_SRST, 0x0);
}
-static int pch_spi_setup(struct spi_device *pspi)
-{
- /* Check baud rate setting */
- /* if baud rate of chip is greater than
- max we can support,return error */
- if ((pspi->max_speed_hz) > PCH_MAX_BAUDRATE)
- pspi->max_speed_hz = PCH_MAX_BAUDRATE;
-
- dev_dbg(&pspi->dev, "%s MODE = %x\n", __func__,
- (pspi->mode) & (SPI_CPOL | SPI_CPHA));
-
- return 0;
-}
-
static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
{
@@ -486,23 +472,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
int retval;
unsigned long flags;
- /* validate spi message and baud rate */
- if (unlikely(list_empty(&pmsg->transfers) == 1)) {
- dev_err(&pspi->dev, "%s list empty\n", __func__);
- retval = -EINVAL;
- goto err_out;
- }
-
- if (unlikely(pspi->max_speed_hz == 0)) {
- dev_err(&pspi->dev, "%s pch_spi_transfer maxspeed=%d\n",
- __func__, pspi->max_speed_hz);
- retval = -EINVAL;
- goto err_out;
- }
-
- dev_dbg(&pspi->dev,
- "%s Transfer List not empty. Transfer Speed is set.\n", __func__);
-
spin_lock_irqsave(&data->lock, flags);
/* validate Tx/Rx buffers and Transfer length */
list_for_each_entry(transfer, &pmsg->transfers, transfer_list) {
@@ -523,10 +492,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
dev_dbg(&pspi->dev,
"%s Tx/Rx buffer valid. Transfer length valid\n",
__func__);
-
- /* if baud rate has been specified validate the same */
- if (transfer->speed_hz > PCH_MAX_BAUDRATE)
- transfer->speed_hz = PCH_MAX_BAUDRATE;
}
spin_unlock_irqrestore(&data->lock, flags);
@@ -1151,8 +1116,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
dma->nent = num;
dma->desc_tx = desc_tx;
- dev_dbg(&data->master->dev, "\n%s:Pulling down SSN low - writing "
- "0x2 to SSNXCR\n", __func__);
+ dev_dbg(&data->master->dev, "%s:Pulling down SSN low - writing 0x2 to SSNXCR\n", __func__);
spin_lock_irqsave(&data->lock, flags);
pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW);
@@ -1418,10 +1382,10 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
/* initialize members of SPI master */
master->num_chipselect = PCH_MAX_CS;
- master->setup = pch_spi_setup;
master->transfer = pch_spi_transfer;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
+ master->max_speed_hz = PCH_MAX_BAUDRATE;
data->board_dat = board_dat;
data->plat_dev = plat_dev;
@@ -1605,8 +1569,7 @@ static struct platform_driver pch_spi_pd_driver = {
.resume = pch_spi_pd_resume
};
-static int pch_spi_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
+static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct pch_spi_board_data *board_dat;
struct platform_device *pd_dev = NULL;
@@ -1676,6 +1639,8 @@ static int pch_spi_probe(struct pci_dev *pdev,
return 0;
err_platform_device:
+ while (--i >= 0)
+ platform_device_unregister(pd_dev_save->pd_save[i]);
pci_disable_device(pdev);
pci_enable_device:
pci_release_regions(pdev);
diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c
index 6191ced514b..820b499816f 100644
--- a/drivers/spi/spi-txx9.c
+++ b/drivers/spi/spi-txx9.c
@@ -80,7 +80,6 @@ struct txx9spi {
void __iomem *membase;
int baseclk;
struct clk *clk;
- u32 max_speed_hz, min_speed_hz;
int last_chipselect;
int last_chipselect_val;
};
@@ -117,9 +116,7 @@ static int txx9spi_setup(struct spi_device *spi)
{
struct txx9spi *c = spi_master_get_devdata(spi->master);
- if (!spi->max_speed_hz
- || spi->max_speed_hz > c->max_speed_hz
- || spi->max_speed_hz < c->min_speed_hz)
+ if (!spi->max_speed_hz)
return -EINVAL;
if (gpio_direction_output(spi->chip_select,
@@ -309,15 +306,8 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
/* check each transfer's parameters */
list_for_each_entry(t, &m->transfers, transfer_list) {
- u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
- u8 bits_per_word = t->bits_per_word;
-
if (!t->tx_buf && !t->rx_buf && t->len)
return -EINVAL;
- if (t->len & ((bits_per_word >> 3) - 1))
- return -EINVAL;
- if (speed_hz < c->min_speed_hz || speed_hz > c->max_speed_hz)
- return -EINVAL;
}
spin_lock_irqsave(&c->lock, flags);
@@ -360,17 +350,12 @@ static int txx9spi_probe(struct platform_device *dev)
goto exit;
}
c->baseclk = clk_get_rate(c->clk);
- c->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1);
- c->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1);
+ master->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1);
+ master->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1);
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!res)
- goto exit_busy;
- if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res),
- "spi_txx9"))
- goto exit_busy;
- c->membase = devm_ioremap(&dev->dev, res->start, resource_size(res));
- if (!c->membase)
+ c->membase = devm_ioremap_resource(&dev->dev, res);
+ if (IS_ERR(c->membase))
goto exit_busy;
/* enter config mode */
diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c
index 24c40b13dab..bb478dccf1d 100644
--- a/drivers/spi/spi-xcomm.c
+++ b/drivers/spi/spi-xcomm.c
@@ -8,7 +8,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -74,15 +73,13 @@ static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm,
static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
struct spi_device *spi, struct spi_transfer *t, unsigned int *settings)
{
- unsigned int speed;
-
if (t->len > 62)
return -EINVAL;
- speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
+ if (t->speed_hz != spi_xcomm->current_speed) {
+ unsigned int divider;
- if (speed != spi_xcomm->current_speed) {
- unsigned int divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, speed);
+ divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, t->speed_hz);
if (divider >= 64)
*settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_64;
else if (divider >= 16)
@@ -90,7 +87,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
else
*settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_4;
- spi_xcomm->current_speed = speed;
+ spi_xcomm->current_speed = t->speed_hz;
}
if (spi->mode & SPI_CPOL)
@@ -148,8 +145,6 @@ static int spi_xcomm_transfer_one(struct spi_master *master,
int status = 0;
bool is_last;
- is_first = true;
-
spi_xcomm_chipselect(spi_xcomm, spi, true);
list_for_each_entry(t, &msg->transfers, transfer_list) {
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 6d4ce461516..a3b0b9944bf 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -14,7 +14,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -88,10 +87,10 @@ struct xilinx_spi {
const u8 *tx_ptr; /* pointer in the Rx buffer */
int remaining_bytes; /* the number of bytes left to transfer */
u8 bits_per_word;
- unsigned int (*read_fn) (void __iomem *);
- void (*write_fn) (u32, void __iomem *);
- void (*tx_fn) (struct xilinx_spi *);
- void (*rx_fn) (struct xilinx_spi *);
+ unsigned int (*read_fn)(void __iomem *);
+ void (*write_fn)(u32, void __iomem *);
+ void (*tx_fn)(struct xilinx_spi *);
+ void (*rx_fn)(struct xilinx_spi *);
};
static void xspi_write32(u32 val, void __iomem *addr)
@@ -209,26 +208,11 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
}
/* spi_bitbang requires custom setup_transfer() to be defined if there is a
- * custom txrx_bufs(). We have nothing to setup here as the SPI IP block
- * supports 8 or 16 bits per word which cannot be changed in software.
- * SPI clock can't be changed in software either.
- * Check for correct bits per word. Chip select delay calculations could be
- * added here as soon as bitbang_work() can be made aware of the delay value.
+ * custom txrx_bufs().
*/
static int xilinx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
- struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
- u8 bits_per_word;
-
- bits_per_word = (t && t->bits_per_word)
- ? t->bits_per_word : spi->bits_per_word;
- if (bits_per_word != xspi->bits_per_word) {
- dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
- __func__, bits_per_word);
- return -EINVAL;
- }
-
return 0;
}
@@ -407,6 +391,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
xspi->write_fn = xspi_write32_be;
}
+ master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word);
xspi->bits_per_word = bits_per_word;
if (xspi->bits_per_word == 8) {
xspi->tx_fn = xspi_tx8;
diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c
new file mode 100644
index 00000000000..41e158187f9
--- /dev/null
+++ b/drivers/spi/spi-xtensa-xtfpga.c
@@ -0,0 +1,170 @@
+/*
+ * Xtensa xtfpga SPI controller driver
+ *
+ * Copyright (c) 2014 Cadence Design Systems Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#define XTFPGA_SPI_NAME "xtfpga_spi"
+
+#define XTFPGA_SPI_START 0x0
+#define XTFPGA_SPI_BUSY 0x4
+#define XTFPGA_SPI_DATA 0x8
+
+#define BUSY_WAIT_US 100
+
+struct xtfpga_spi {
+ struct spi_bitbang bitbang;
+ void __iomem *regs;
+ u32 data;
+ unsigned data_sz;
+};
+
+static inline void xtfpga_spi_write32(const struct xtfpga_spi *spi,
+ unsigned addr, u32 val)
+{
+ iowrite32(val, spi->regs + addr);
+}
+
+static inline unsigned int xtfpga_spi_read32(const struct xtfpga_spi *spi,
+ unsigned addr)
+{
+ return ioread32(spi->regs + addr);
+}
+
+static inline void xtfpga_spi_wait_busy(struct xtfpga_spi *xspi)
+{
+ unsigned i;
+ for (i = 0; xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY) &&
+ i < BUSY_WAIT_US; ++i)
+ udelay(1);
+ WARN_ON_ONCE(i == BUSY_WAIT_US);
+}
+
+static u32 xtfpga_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
+ u32 v, u8 bits)
+{
+ struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master);
+
+ xspi->data = (xspi->data << bits) | (v & GENMASK(bits - 1, 0));
+ xspi->data_sz += bits;
+ if (xspi->data_sz >= 16) {
+ xtfpga_spi_write32(xspi, XTFPGA_SPI_DATA,
+ xspi->data >> (xspi->data_sz - 16));
+ xspi->data_sz -= 16;
+ xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 1);
+ xtfpga_spi_wait_busy(xspi);
+ xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0);
+ }
+
+ return 0;
+}
+
+static void xtfpga_spi_chipselect(struct spi_device *spi, int is_on)
+{
+ struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master);
+
+ WARN_ON(xspi->data_sz != 0);
+ xspi->data_sz = 0;
+}
+
+static int xtfpga_spi_probe(struct platform_device *pdev)
+{
+ struct xtfpga_spi *xspi;
+ struct resource *mem;
+ int ret;
+ struct spi_master *master;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct xtfpga_spi));
+ if (!master)
+ return -ENOMEM;
+
+ master->flags = SPI_MASTER_NO_RX;
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
+ master->bus_num = pdev->dev.id;
+ master->dev.of_node = pdev->dev.of_node;
+
+ xspi = spi_master_get_devdata(master);
+ xspi->bitbang.master = master;
+ xspi->bitbang.chipselect = xtfpga_spi_chipselect;
+ xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "No memory resource\n");
+ ret = -ENODEV;
+ goto err;
+ }
+ xspi->regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(xspi->regs)) {
+ ret = PTR_ERR(xspi->regs);
+ goto err;
+ }
+
+ xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0);
+ usleep_range(1000, 2000);
+ if (xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY)) {
+ dev_err(&pdev->dev, "Device stuck in busy state\n");
+ ret = -EBUSY;
+ goto err;
+ }
+
+ ret = spi_bitbang_start(&xspi->bitbang);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "spi_bitbang_start failed\n");
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, master);
+ return 0;
+err:
+ spi_master_put(master);
+ return ret;
+}
+
+static int xtfpga_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct xtfpga_spi *xspi = spi_master_get_devdata(master);
+
+ spi_bitbang_stop(&xspi->bitbang);
+ spi_master_put(master);
+
+ return 0;
+}
+
+MODULE_ALIAS("platform:" XTFPGA_SPI_NAME);
+
+#ifdef CONFIG_OF
+static const struct of_device_id xtfpga_spi_of_match[] = {
+ { .compatible = "cdns,xtfpga-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, xtfpga_spi_of_match);
+#endif
+
+static struct platform_driver xtfpga_spi_driver = {
+ .probe = xtfpga_spi_probe,
+ .remove = xtfpga_spi_remove,
+ .driver = {
+ .name = XTFPGA_SPI_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(xtfpga_spi_of_match),
+ },
+};
+module_platform_driver(xtfpga_spi_driver);
+
+MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");
+MODULE_DESCRIPTION("xtensa xtfpga SPI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index d0b28bba38b..4eb9bf02996 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -24,6 +24,8 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/cache.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
@@ -255,13 +257,12 @@ EXPORT_SYMBOL_GPL(spi_bus_type);
static int spi_drv_probe(struct device *dev)
{
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
- struct spi_device *spi = to_spi_device(dev);
int ret;
- acpi_dev_pm_attach(&spi->dev, true);
- ret = sdrv->probe(spi);
+ acpi_dev_pm_attach(dev, true);
+ ret = sdrv->probe(to_spi_device(dev));
if (ret)
- acpi_dev_pm_detach(&spi->dev, true);
+ acpi_dev_pm_detach(dev, true);
return ret;
}
@@ -269,11 +270,10 @@ static int spi_drv_probe(struct device *dev)
static int spi_drv_remove(struct device *dev)
{
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
- struct spi_device *spi = to_spi_device(dev);
int ret;
- ret = sdrv->remove(spi);
- acpi_dev_pm_detach(&spi->dev, true);
+ ret = sdrv->remove(to_spi_device(dev));
+ acpi_dev_pm_detach(dev, true);
return ret;
}
@@ -580,6 +580,169 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
spi->master->set_cs(spi, !enable);
}
+static 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)
+{
+ const bool vmalloced_buf = is_vmalloc_addr(buf);
+ const int desc_len = vmalloced_buf ? PAGE_SIZE : master->max_dma_len;
+ const int sgs = DIV_ROUND_UP(len, desc_len);
+ struct page *vm_page;
+ void *sg_buf;
+ size_t min;
+ int i, ret;
+
+ ret = sg_alloc_table(sgt, sgs, GFP_KERNEL);
+ if (ret != 0)
+ return ret;
+
+ for (i = 0; i < sgs; i++) {
+ min = min_t(size_t, len, desc_len);
+
+ if (vmalloced_buf) {
+ vm_page = vmalloc_to_page(buf);
+ if (!vm_page) {
+ sg_free_table(sgt);
+ return -ENOMEM;
+ }
+ sg_buf = page_address(vm_page) +
+ ((size_t)buf & ~PAGE_MASK);
+ } else {
+ sg_buf = buf;
+ }
+
+ sg_set_buf(&sgt->sgl[i], sg_buf, min);
+
+ buf += min;
+ len -= min;
+ }
+
+ ret = dma_map_sg(dev, sgt->sgl, sgt->nents, dir);
+ if (ret < 0) {
+ sg_free_table(sgt);
+ return ret;
+ }
+
+ sgt->nents = ret;
+
+ return 0;
+}
+
+static void spi_unmap_buf(struct spi_master *master, struct device *dev,
+ struct sg_table *sgt, enum dma_data_direction dir)
+{
+ if (sgt->orig_nents) {
+ dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir);
+ sg_free_table(sgt);
+ }
+}
+
+static int spi_map_msg(struct spi_master *master, struct spi_message *msg)
+{
+ struct device *tx_dev, *rx_dev;
+ struct spi_transfer *xfer;
+ void *tmp;
+ unsigned int max_tx, max_rx;
+ int ret;
+
+ if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) {
+ max_tx = 0;
+ max_rx = 0;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if ((master->flags & SPI_MASTER_MUST_TX) &&
+ !xfer->tx_buf)
+ max_tx = max(xfer->len, max_tx);
+ if ((master->flags & SPI_MASTER_MUST_RX) &&
+ !xfer->rx_buf)
+ max_rx = max(xfer->len, max_rx);
+ }
+
+ if (max_tx) {
+ tmp = krealloc(master->dummy_tx, max_tx,
+ GFP_KERNEL | GFP_DMA);
+ if (!tmp)
+ return -ENOMEM;
+ master->dummy_tx = tmp;
+ memset(tmp, 0, max_tx);
+ }
+
+ if (max_rx) {
+ tmp = krealloc(master->dummy_rx, max_rx,
+ GFP_KERNEL | GFP_DMA);
+ if (!tmp)
+ return -ENOMEM;
+ master->dummy_rx = tmp;
+ }
+
+ if (max_tx || max_rx) {
+ list_for_each_entry(xfer, &msg->transfers,
+ transfer_list) {
+ if (!xfer->tx_buf)
+ xfer->tx_buf = master->dummy_tx;
+ if (!xfer->rx_buf)
+ xfer->rx_buf = master->dummy_rx;
+ }
+ }
+ }
+
+ if (!master->can_dma)
+ return 0;
+
+ tx_dev = &master->dma_tx->dev->device;
+ rx_dev = &master->dma_rx->dev->device;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if (!master->can_dma(master, msg->spi, xfer))
+ continue;
+
+ if (xfer->tx_buf != NULL) {
+ ret = spi_map_buf(master, tx_dev, &xfer->tx_sg,
+ (void *)xfer->tx_buf, xfer->len,
+ DMA_TO_DEVICE);
+ if (ret != 0)
+ return ret;
+ }
+
+ if (xfer->rx_buf != NULL) {
+ ret = spi_map_buf(master, rx_dev, &xfer->rx_sg,
+ xfer->rx_buf, xfer->len,
+ DMA_FROM_DEVICE);
+ if (ret != 0) {
+ spi_unmap_buf(master, tx_dev, &xfer->tx_sg,
+ DMA_TO_DEVICE);
+ return ret;
+ }
+ }
+ }
+
+ master->cur_msg_mapped = true;
+
+ return 0;
+}
+
+static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
+{
+ struct spi_transfer *xfer;
+ struct device *tx_dev, *rx_dev;
+
+ if (!master->cur_msg_mapped || !master->can_dma)
+ return 0;
+
+ tx_dev = &master->dma_tx->dev->device;
+ rx_dev = &master->dma_rx->dev->device;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if (!master->can_dma(master, msg->spi, xfer))
+ continue;
+
+ spi_unmap_buf(master, rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
+ spi_unmap_buf(master, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
+ }
+
+ return 0;
+}
+
/*
* spi_transfer_one_message - Default implementation of transfer_one_message()
*
@@ -591,9 +754,9 @@ static int spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
struct spi_transfer *xfer;
- bool cur_cs = true;
bool keep_cs = false;
int ret = 0;
+ int ms = 1;
spi_set_cs(msg->spi, true);
@@ -611,7 +774,16 @@ static int spi_transfer_one_message(struct spi_master *master,
if (ret > 0) {
ret = 0;
- wait_for_completion(&master->xfer_completion);
+ ms = xfer->len * 8 * 1000 / xfer->speed_hz;
+ ms += 10; /* some tolerance */
+
+ ms = wait_for_completion_timeout(&master->xfer_completion,
+ msecs_to_jiffies(ms));
+ }
+
+ if (ms == 0) {
+ dev_err(&msg->spi->dev, "SPI transfer timed out\n");
+ msg->status = -ETIMEDOUT;
}
trace_spi_transfer_stop(msg, xfer);
@@ -627,8 +799,9 @@ static int spi_transfer_one_message(struct spi_master *master,
&msg->transfers)) {
keep_cs = true;
} else {
- cur_cs = !cur_cs;
- spi_set_cs(msg->spi, cur_cs);
+ spi_set_cs(msg->spi, false);
+ udelay(10);
+ spi_set_cs(msg->spi, true);
}
}
@@ -686,6 +859,10 @@ static void spi_pump_messages(struct kthread_work *work)
}
master->busy = false;
spin_unlock_irqrestore(&master->queue_lock, flags);
+ kfree(master->dummy_rx);
+ master->dummy_rx = NULL;
+ kfree(master->dummy_tx);
+ master->dummy_tx = NULL;
if (master->unprepare_transfer_hardware &&
master->unprepare_transfer_hardware(master))
dev_err(&master->dev,
@@ -752,6 +929,13 @@ static void spi_pump_messages(struct kthread_work *work)
master->cur_msg_prepared = true;
}
+ ret = spi_map_msg(master, master->cur_msg);
+ if (ret) {
+ master->cur_msg->status = ret;
+ spi_finalize_current_message(master);
+ return;
+ }
+
ret = master->transfer_one_message(master, master->cur_msg);
if (ret) {
dev_err(&master->dev,
@@ -839,6 +1023,8 @@ void spi_finalize_current_message(struct spi_master *master)
queue_kthread_work(&master->kworker, &master->pump_messages);
spin_unlock_irqrestore(&master->queue_lock, flags);
+ spi_unmap_msg(master, mesg);
+
if (master->cur_msg_prepared && master->unprepare_message) {
ret = master->unprepare_message(master, mesg);
if (ret) {
@@ -892,7 +1078,7 @@ static int spi_stop_queue(struct spi_master *master)
*/
while ((!list_empty(&master->queue) || master->busy) && limit--) {
spin_unlock_irqrestore(&master->queue_lock, flags);
- msleep(10);
+ usleep_range(10000, 11000);
spin_lock_irqsave(&master->queue_lock, flags);
}
@@ -1372,6 +1558,8 @@ int spi_register_master(struct spi_master *master)
mutex_init(&master->bus_lock_mutex);
master->bus_lock_flag = 0;
init_completion(&master->xfer_completion);
+ if (!master->max_dma_len)
+ master->max_dma_len = INT_MAX;
/* register the device, then userspace will see it.
* registration fails if the bus ID is in use.
@@ -1597,6 +1785,9 @@ int spi_setup(struct spi_device *spi)
if (!spi->bits_per_word)
spi->bits_per_word = 8;
+ if (!spi->max_speed_hz)
+ spi->max_speed_hz = spi->master->max_speed_hz;
+
if (spi->master->setup)
status = spi->master->setup(spi);
@@ -1617,11 +1808,10 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
{
struct spi_master *master = spi->master;
struct spi_transfer *xfer;
+ int w_size;
if (list_empty(&message->transfers))
return -EINVAL;
- if (!message->complete)
- return -EINVAL;
/* Half-duplex links include original MicroWire, and ones with
* only one data pin like SPI_3WIRE (switches direction) or where
@@ -1652,12 +1842,13 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
message->frame_length += xfer->len;
if (!xfer->bits_per_word)
xfer->bits_per_word = spi->bits_per_word;
- if (!xfer->speed_hz) {
+
+ if (!xfer->speed_hz)
xfer->speed_hz = spi->max_speed_hz;
- if (master->max_speed_hz &&
- xfer->speed_hz > master->max_speed_hz)
- xfer->speed_hz = master->max_speed_hz;
- }
+
+ if (master->max_speed_hz &&
+ xfer->speed_hz > master->max_speed_hz)
+ xfer->speed_hz = master->max_speed_hz;
if (master->bits_per_word_mask) {
/* Only 32 bits fit in the mask */
@@ -1668,12 +1859,24 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
return -EINVAL;
}
+ /*
+ * SPI transfer length should be multiple of SPI word size
+ * where SPI word size should be power-of-two multiple
+ */
+ if (xfer->bits_per_word <= 8)
+ w_size = 1;
+ else if (xfer->bits_per_word <= 16)
+ w_size = 2;
+ else
+ w_size = 4;
+
+ /* No partial transfers accepted */
+ if (xfer->len % w_size)
+ return -EINVAL;
+
if (xfer->speed_hz && master->min_speed_hz &&
xfer->speed_hz < master->min_speed_hz)
return -EINVAL;
- if (xfer->speed_hz && master->max_speed_hz &&
- xfer->speed_hz > master->max_speed_hz)
- return -EINVAL;
if (xfer->tx_buf && !xfer->tx_nbits)
xfer->tx_nbits = SPI_NBITS_SINGLE;
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index d7c6e36021e..e3bc23bb588 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -73,7 +73,8 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS);
*/
#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
| SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
- | SPI_NO_CS | SPI_READY)
+ | SPI_NO_CS | SPI_READY | SPI_TX_DUAL \
+ | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)
struct spidev_data {
dev_t devt;
@@ -265,6 +266,8 @@ static int spidev_message(struct spidev_data *spidev,
buf += k_tmp->len;
k_tmp->cs_change = !!u_tmp->cs_change;
+ k_tmp->tx_nbits = u_tmp->tx_nbits;
+ k_tmp->rx_nbits = u_tmp->rx_nbits;
k_tmp->bits_per_word = u_tmp->bits_per_word;
k_tmp->delay_usecs = u_tmp->delay_usecs;
k_tmp->speed_hz = u_tmp->speed_hz;
@@ -359,6 +362,10 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = __put_user(spi->mode & SPI_MODE_MASK,
(__u8 __user *)arg);
break;
+ case SPI_IOC_RD_MODE32:
+ retval = __put_user(spi->mode & SPI_MODE_MASK,
+ (__u32 __user *)arg);
+ break;
case SPI_IOC_RD_LSB_FIRST:
retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0,
(__u8 __user *)arg);
@@ -372,9 +379,13 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
/* write requests */
case SPI_IOC_WR_MODE:
- retval = __get_user(tmp, (u8 __user *)arg);
+ case SPI_IOC_WR_MODE32:
+ if (cmd == SPI_IOC_WR_MODE)
+ retval = __get_user(tmp, (u8 __user *)arg);
+ else
+ retval = __get_user(tmp, (u32 __user *)arg);
if (retval == 0) {
- u8 save = spi->mode;
+ u32 save = spi->mode;
if (tmp & ~SPI_MODE_MASK) {
retval = -EINVAL;
@@ -382,18 +393,18 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
tmp |= spi->mode & ~SPI_MODE_MASK;
- spi->mode = (u8)tmp;
+ spi->mode = (u16)tmp;
retval = spi_setup(spi);
if (retval < 0)
spi->mode = save;
else
- dev_dbg(&spi->dev, "spi mode %02x\n", tmp);
+ dev_dbg(&spi->dev, "spi mode %x\n", tmp);
}
break;
case SPI_IOC_WR_LSB_FIRST:
retval = __get_user(tmp, (__u8 __user *)arg);
if (retval == 0) {
- u8 save = spi->mode;
+ u32 save = spi->mode;
if (tmp)
spi->mode |= SPI_LSB_FIRST;
diff --git a/include/linux/platform_data/spi-s3c64xx.h b/include/linux/platform_data/spi-s3c64xx.h
index 8447f634c7f..d3889b98a1a 100644
--- a/include/linux/platform_data/spi-s3c64xx.h
+++ b/include/linux/platform_data/spi-s3c64xx.h
@@ -1,5 +1,4 @@
-/* linux/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
- *
+/*
* Copyright (C) 2009 Samsung Electronics Ltd.
* Jaswinder Singh <jassi.brar@samsung.com>
*
@@ -8,8 +7,8 @@
* published by the Free Software Foundation.
*/
-#ifndef __S3C64XX_PLAT_SPI_H
-#define __S3C64XX_PLAT_SPI_H
+#ifndef __SPI_S3C64XX_H
+#define __SPI_S3C64XX_H
#include <linux/dmaengine.h>
@@ -68,4 +67,4 @@ extern int s3c64xx_spi2_cfg_gpio(void);
extern struct s3c64xx_spi_info s3c64xx_spi0_pdata;
extern struct s3c64xx_spi_info s3c64xx_spi1_pdata;
extern struct s3c64xx_spi_info s3c64xx_spi2_pdata;
-#endif /* __S3C64XX_PLAT_SPI_H */
+#endif /*__SPI_S3C64XX_H */
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 4203c66d880..36c86ef51ff 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -24,6 +24,9 @@
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/completion.h>
+#include <linux/scatterlist.h>
+
+struct dma_chan;
/*
* INTERFACES between SPI master-side drivers and SPI infrastructure.
@@ -266,6 +269,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @auto_runtime_pm: the core should ensure a runtime PM reference is held
* while the hardware is prepared, using the parent
* device for the spidev
+ * @max_dma_len: Maximum length of a DMA transfer for the device.
* @prepare_transfer_hardware: a message will soon arrive from the queue
* so the subsystem requests the driver to prepare the transfer hardware
* by issuing this call
@@ -348,6 +352,8 @@ struct spi_master {
#define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */
#define SPI_MASTER_NO_RX BIT(1) /* can't do buffer read */
#define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */
+#define SPI_MASTER_MUST_RX BIT(3) /* requires rx */
+#define SPI_MASTER_MUST_TX BIT(4) /* requires tx */
/* lock and mutex for SPI bus locking */
spinlock_t bus_lock_spinlock;
@@ -390,6 +396,17 @@ struct spi_master {
void (*cleanup)(struct spi_device *spi);
/*
+ * Used to enable core support for DMA handling, if can_dma()
+ * exists and returns true then the transfer will be mapped
+ * prior to transfer_one() being called. The driver should
+ * not modify or store xfer and dma_tx and dma_rx must be set
+ * while the device is prepared.
+ */
+ bool (*can_dma)(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer);
+
+ /*
* These hooks are for drivers that want to use the generic
* master transfer queueing mechanism. If these are used, the
* transfer() function above must NOT be specified by the driver.
@@ -407,7 +424,9 @@ struct spi_master {
bool rt;
bool auto_runtime_pm;
bool cur_msg_prepared;
+ bool cur_msg_mapped;
struct completion xfer_completion;
+ size_t max_dma_len;
int (*prepare_transfer_hardware)(struct spi_master *master);
int (*transfer_one_message)(struct spi_master *master,
@@ -428,6 +447,14 @@ struct spi_master {
/* gpio chip select */
int *cs_gpios;
+
+ /* DMA channels for use with core dmaengine helpers */
+ struct dma_chan *dma_tx;
+ struct dma_chan *dma_rx;
+
+ /* dummy data for full duplex devices */
+ void *dummy_rx;
+ void *dummy_tx;
};
static inline void *spi_master_get_devdata(struct spi_master *master)
@@ -512,6 +539,8 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum);
* (optionally) changing the chipselect status, then starting
* the next transfer or completing this @spi_message.
* @transfer_list: transfers are sequenced through @spi_message.transfers
+ * @tx_sg: Scatterlist for transmit, currently not for client use
+ * @rx_sg: Scatterlist for receive, currently not for client use
*
* SPI transfers always write the same number of bytes as they read.
* Protocol drivers should always provide @rx_buf and/or @tx_buf.
@@ -579,6 +608,8 @@ struct spi_transfer {
dma_addr_t tx_dma;
dma_addr_t rx_dma;
+ struct sg_table tx_sg;
+ struct sg_table rx_sg;
unsigned cs_change:1;
unsigned tx_nbits:3;
diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h
index daebaba886a..85578d4be03 100644
--- a/include/linux/spi/spi_bitbang.h
+++ b/include/linux/spi/spi_bitbang.h
@@ -42,6 +42,6 @@ extern int spi_bitbang_setup_transfer(struct spi_device *spi,
/* start or stop queue processing */
extern int spi_bitbang_start(struct spi_bitbang *spi);
-extern int spi_bitbang_stop(struct spi_bitbang *spi);
+extern void spi_bitbang_stop(struct spi_bitbang *spi);
#endif /* __SPI_BITBANG_H */
diff --git a/include/uapi/linux/spi/spidev.h b/include/uapi/linux/spi/spidev.h
index 52d9ed01855..dd5f21e7580 100644
--- a/include/uapi/linux/spi/spidev.h
+++ b/include/uapi/linux/spi/spidev.h
@@ -42,6 +42,10 @@
#define SPI_LOOP 0x20
#define SPI_NO_CS 0x40
#define SPI_READY 0x80
+#define SPI_TX_DUAL 0x100
+#define SPI_TX_QUAD 0x200
+#define SPI_RX_DUAL 0x400
+#define SPI_RX_QUAD 0x800
/*---------------------------------------------------------------------------*/
@@ -92,7 +96,9 @@ struct spi_ioc_transfer {
__u16 delay_usecs;
__u8 bits_per_word;
__u8 cs_change;
- __u32 pad;
+ __u8 tx_nbits;
+ __u8 rx_nbits;
+ __u16 pad;
/* If the contents of 'struct spi_ioc_transfer' ever change
* incompatibly, then the ioctl number (currently 0) must change;
@@ -110,7 +116,7 @@ struct spi_ioc_transfer {
#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
-/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */
+/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) (limited to 8 bits) */
#define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8)
#define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, __u8)
@@ -126,6 +132,10 @@ struct spi_ioc_transfer {
#define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32)
#define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32)
+/* Read / Write of the SPI mode field */
+#define SPI_IOC_RD_MODE32 _IOR(SPI_IOC_MAGIC, 5, __u32)
+#define SPI_IOC_WR_MODE32 _IOW(SPI_IOC_MAGIC, 5, __u32)
+
#endif /* SPIDEV_H */