Merge tag 'v5.2-rc4' into spi-5.3
authorMark Brown <broonie@kernel.org>
Mon, 10 Jun 2019 17:52:53 +0000 (18:52 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 10 Jun 2019 17:52:53 +0000 (18:52 +0100)
Linux 5.2-rc4

31 files changed:
Documentation/devicetree/bindings/mfd/atmel-usart.txt
Documentation/devicetree/bindings/spi/allwinner,sun4i-a10-spi.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-bus.txt
Documentation/devicetree/bindings/spi/spi-controller.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-gpio.txt [deleted file]
Documentation/devicetree/bindings/spi/spi-gpio.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-pl022.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-sun4i.txt [deleted file]
Documentation/devicetree/bindings/spi/spi-sun6i.txt [deleted file]
Documentation/devicetree/bindings/spi/spi-synquacer.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi_pl022.txt [deleted file]
MAINTAINERS
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/spi-at91-usart.c
drivers/spi/spi-bcm2835.c
drivers/spi/spi-bcm2835aux.c
drivers/spi/spi-bitbang.c
drivers/spi/spi-fsl-spi.c
drivers/spi/spi-meson-spifc.c
drivers/spi/spi-mt65xx.c
drivers/spi/spi-qup.c
drivers/spi/spi-rockchip.c
drivers/spi/spi-sh-msiof.c
drivers/spi/spi-synquacer.c [new file with mode: 0644]
drivers/spi/spi-tegra114.c
drivers/spi/spi.c
drivers/spi/spidev.c
include/linux/platform_data/spi-mt65xx.h
include/linux/spi/spi.h

index 7f0cd72..699fd3c 100644 (file)
@@ -17,17 +17,24 @@ Required properties for USART in SPI mode:
 - cs-gpios: chipselects (internal cs not supported)
 - atmel,usart-mode : Must be <AT91_USART_MODE_SPI> (found in dt-bindings/mfd/at91-usart.h)
 
+Optional properties in serial and SPI mode:
+- dma bindings for dma transfer:
+       - dmas: DMA specifier, consisting of a phandle to DMA controller node,
+               memory peripheral interface and USART DMA channel ID, FIFO configuration.
+               The order of DMA channels is fixed. The first DMA channel must be TX
+               associated channel and the second one must be RX associated channel.
+               Refer to dma.txt and atmel-dma.txt for details.
+       - dma-names: "tx" for TX channel.
+                    "rx" for RX channel.
+                    The order of dma-names is also fixed. The first name must be "tx"
+                    and the second one must be "rx" as in the examples below.
+
 Optional properties in serial mode:
 - atmel,use-dma-rx: use of PDC or DMA for receiving data
 - atmel,use-dma-tx: use of PDC or DMA for transmitting data
 - {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD line respectively.
   It will use specified PIO instead of the peripheral function pin for the USART feature.
   If unsure, don't specify this property.
-- add dma bindings for dma transfer:
-       - dmas: DMA specifier, consisting of a phandle to DMA controller node,
-               memory peripheral interface and USART DMA channel ID, FIFO configuration.
-               Refer to dma.txt and atmel-dma.txt for details.
-       - dma-names: "rx" for RX channel, "tx" for TX channel.
 - atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO
   capable USARTs.
 - rs485-rts-delay, rs485-rx-during-tx, linux,rs485-enabled-at-boot-time: see rs485.txt
@@ -81,5 +88,8 @@ Example:
                interrupts = <12 IRQ_TYPE_LEVEL_HIGH 5>;
                clocks = <&usart0_clk>;
                clock-names = "usart";
+               dmas = <&dma0 2 AT91_DMA_CFG_PER_ID(3)>,
+                      <&dma0 2 (AT91_DMA_CFG_PER_ID(4) | AT91_DMA_CFG_FIFOCFG_ASAP)>;
+               dma-names = "tx", "rx";
                cs-gpios = <&pioB 3 0>;
        };
diff --git a/Documentation/devicetree/bindings/spi/allwinner,sun4i-a10-spi.yaml b/Documentation/devicetree/bindings/spi/allwinner,sun4i-a10-spi.yaml
new file mode 100644 (file)
index 0000000..c374fd4
--- /dev/null
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/allwinner,sun4i-a10-spi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A10 SPI Controller Device Tree Bindings
+
+allOf:
+  - $ref: "spi-controller.yaml"
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  "#address-cells": true
+  "#size-cells": true
+
+  compatible:
+    const: allwinner,sun4i-a10-spi
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Bus Clock
+      - description: Module Clock
+
+  clock-names:
+    items:
+      - const: ahb
+      - const: mod
+
+  dmas:
+    items:
+      - description: RX DMA Channel
+      - description: TX DMA Channel
+
+  dma-names:
+    items:
+      - const: rx
+      - const: tx
+
+  num-cs: true
+
+patternProperties:
+  "^.*@[0-9a-f]+":
+    properties:
+      reg:
+        items:
+          minimum: 0
+          maximum: 4
+
+      spi-rx-bus-width:
+        const: 1
+
+      spi-tx-bus-width:
+        const: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    spi1: spi@1c06000 {
+        compatible = "allwinner,sun4i-a10-spi";
+        reg = <0x01c06000 0x1000>;
+        interrupts = <11>;
+        clocks = <&ahb_gates 21>, <&spi1_clk>;
+        clock-names = "ahb", "mod";
+        #address-cells = <1>;
+        #size-cells = <0>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
new file mode 100644 (file)
index 0000000..bda7a5b
--- /dev/null
@@ -0,0 +1,106 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/allwinner,sun6i-a31-spi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A31 SPI Controller Device Tree Bindings
+
+allOf:
+  - $ref: "spi-controller.yaml"
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+properties:
+  "#address-cells": true
+  "#size-cells": true
+
+  compatible:
+    enum:
+      - allwinner,sun6i-a31-spi
+      - allwinner,sun8i-h3-spi
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Bus Clock
+      - description: Module Clock
+
+  clock-names:
+    items:
+      - const: ahb
+      - const: mod
+
+  resets:
+    maxItems: 1
+
+  dmas:
+    items:
+      - description: RX DMA Channel
+      - description: TX DMA Channel
+
+  dma-names:
+    items:
+      - const: rx
+      - const: tx
+
+  num-cs: true
+
+patternProperties:
+  "^.*@[0-9a-f]+":
+    properties:
+      reg:
+        items:
+          minimum: 0
+          maximum: 4
+
+      spi-rx-bus-width:
+        const: 1
+
+      spi-tx-bus-width:
+        const: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    spi1: spi@1c69000 {
+        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>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+    };
+
+  - |
+    spi0: spi@1c68000 {
+        compatible = "allwinner,sun8i-h3-spi";
+        reg = <0x01c68000 0x1000>;
+        interrupts = <0 65 4>;
+        clocks = <&ccu 30>, <&ccu 82>;
+        clock-names = "ahb", "mod";
+        dmas = <&dma 23>, <&dma 23>;
+        dma-names = "rx", "tx";
+        resets = <&ccu 15>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+    };
+
+...
index 1f6e86f..e077835 100644 (file)
@@ -1,111 +1 @@
-SPI (Serial Peripheral Interface) busses
-
-SPI busses can be described with a node for the SPI controller device
-and a set of child nodes for each SPI slave on the bus.  The system's SPI
-controller may be described for use in SPI master mode or in SPI slave mode,
-but not for both at the same time.
-
-The SPI controller node requires the following properties:
-- compatible      - Name of SPI bus controller following generic names
-                   recommended practice.
-
-In master mode, the SPI controller node requires the following additional
-properties:
-- #address-cells  - number of cells required to define a chip select
-               address on the SPI bus.
-- #size-cells     - should be zero.
-
-In slave mode, the SPI controller node requires one additional property:
-- spi-slave       - Empty property.
-
-No other properties are required in the SPI bus node.  It is assumed
-that a driver for an SPI bus device will understand that it is an SPI bus.
-However, the binding does not attempt to define the specific method for
-assigning chip select numbers.  Since SPI chip select configuration is
-flexible and non-standardized, it is left out of this binding with the
-assumption that board specific platform code will be used to manage
-chip selects.  Individual drivers can define additional properties to
-support describing the chip select layout.
-
-Optional properties (master mode only):
-- cs-gpios       - gpios chip select.
-- num-cs         - total number of chipselects.
-
-If cs-gpios is used the number of chip selects will be increased automatically
-with max(cs-gpios > hw cs).
-
-So if for example the controller has 2 CS lines, and the cs-gpios
-property looks like this:
-
-cs-gpios = <&gpio1 0 0>, <0>, <&gpio1 1 0>, <&gpio1 2 0>;
-
-Then it should be configured so that num_chipselect = 4 with the
-following mapping:
-
-cs0 : &gpio1 0 0
-cs1 : native
-cs2 : &gpio1 1 0
-cs3 : &gpio1 2 0
-
-
-SPI slave nodes must be children of the SPI controller node.
-
-In master mode, one or more slave nodes (up to the number of chip selects) can
-be present.  Required properties are:
-- compatible      - Name of SPI device following generic names recommended
-                   practice.
-- reg             - Chip select address of device.
-- spi-max-frequency - Maximum SPI clocking speed of device in Hz.
-
-In slave mode, the (single) slave node is optional.
-If present, it must be called "slave".  Required properties are:
-- compatible      - Name of SPI device following generic names recommended
-                   practice.
-
-All slave nodes can contain the following optional properties:
-- spi-cpol        - Empty property indicating device requires inverse clock
-                   polarity (CPOL) mode.
-- spi-cpha        - Empty property indicating device requires shifted clock
-                   phase (CPHA) mode.
-- spi-cs-high     - Empty property indicating device requires chip select
-                   active high.
-- spi-3wire       - Empty property indicating device requires 3-wire mode.
-- spi-lsb-first   - Empty property indicating device requires LSB first mode.
-- spi-tx-bus-width - The bus width (number of data wires) that is used for MOSI.
-                   Defaults to 1 if not present.
-- spi-rx-bus-width - The bus width (number of data wires) that is used for MISO.
-                   Defaults to 1 if not present.
-- spi-rx-delay-us - Microsecond delay after a read transfer.
-- spi-tx-delay-us - Microsecond delay after a write transfer.
-
-Some SPI controllers and devices support Dual and Quad SPI transfer mode.
-It allows data in the SPI system to be transferred using 2 wires (DUAL) or 4
-wires (QUAD).
-Now the value that spi-tx-bus-width and spi-rx-bus-width can receive is
-only 1 (SINGLE), 2 (DUAL) and 4 (QUAD).
-Dual/Quad mode is not allowed when 3-wire mode is used.
-
-If a gpio chipselect is used for the SPI slave the gpio number will be passed
-via the SPI master node cs-gpios property.
-
-SPI example for an MPC5200 SPI bus:
-       spi@f00 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
-               reg = <0xf00 0x20>;
-               interrupts = <2 13 0 2 14 0>;
-               interrupt-parent = <&mpc5200_pic>;
-
-               ethernet-switch@0 {
-                       compatible = "micrel,ks8995m";
-                       spi-max-frequency = <1000000>;
-                       reg = <0>;
-               };
-
-               codec@1 {
-                       compatible = "ti,tlv320aic26";
-                       spi-max-frequency = <100000>;
-                       reg = <1>;
-               };
-       };
+This file has moved to spi-controller.yaml.
diff --git a/Documentation/devicetree/bindings/spi/spi-controller.yaml b/Documentation/devicetree/bindings/spi/spi-controller.yaml
new file mode 100644 (file)
index 0000000..876c062
--- /dev/null
@@ -0,0 +1,161 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/spi-controller.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SPI Controller Generic Binding
+
+maintainers:
+  - Mark Brown <broonie@kernel.org>
+
+description: |
+  SPI busses can be described with a node for the SPI controller device
+  and a set of child nodes for each SPI slave on the bus. The system SPI
+  controller may be described for use in SPI master mode or in SPI slave mode,
+  but not for both at the same time.
+
+properties:
+  $nodename:
+    pattern: "^spi(@.*|-[0-9a-f])*$"
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  cs-gpios:
+    description: |
+      GPIOs used as chip selects.
+      If that property is used, the number of chip selects will be
+      increased automatically with max(cs-gpios, hardware chip selects).
+
+      So if, for example, the controller has 2 CS lines, and the
+      cs-gpios looks like this
+        cs-gpios = <&gpio1 0 0>, <0>, <&gpio1 1 0>, <&gpio1 2 0>;
+
+      Then it should be configured so that num_chipselect = 4, with
+      the following mapping
+        cs0 : &gpio1 0 0
+        cs1 : native
+        cs2 : &gpio1 1 0
+        cs3 : &gpio1 2 0
+
+  num-cs:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Total number of chip selects.
+
+  spi-slave:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      The SPI controller acts as a slave, instead of a master.
+
+patternProperties:
+  "^slave$":
+    type: object
+
+    properties:
+      compatible:
+        description:
+          Compatible of the SPI device.
+
+    required:
+      - compatible
+
+  "^.*@[0-9a-f]+$":
+    type: object
+
+    properties:
+      compatible:
+        description:
+          Compatible of the SPI device.
+
+      reg:
+        maxItems: 1
+        minimum: 0
+        maximum: 256
+        description:
+          Chip select used by the device.
+
+      spi-3wire:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The device requires 3-wire mode.
+
+      spi-cpha:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The device requires shifted clock phase (CPHA) mode.
+
+      spi-cpol:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The device requires inverse clock polarity (CPOL) mode.
+
+      spi-cs-high:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The device requires the chip select active high.
+
+      spi-lsb-first:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The device requires the LSB first mode.
+
+      spi-max-frequency:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description:
+          Maximum SPI clocking speed of the device in Hz.
+
+      spi-rx-bus-width:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32
+          - enum: [ 1, 2, 4 ]
+          - default: 1
+        description:
+          Bus width to the SPI bus used for MISO.
+
+      spi-rx-delay-us:
+        description:
+          Delay, in microseconds, after a read transfer.
+
+      spi-tx-bus-width:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32
+          - enum: [ 1, 2, 4 ]
+          - default: 1
+        description:
+          Bus width to the SPI bus used for MOSI.
+
+      spi-tx-delay-us:
+        description:
+          Delay, in microseconds, after a write transfer.
+
+    required:
+      - compatible
+      - reg
+
+examples:
+  - |
+    spi@f00 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
+        reg = <0xf00 0x20>;
+        interrupts = <2 13 0 2 14 0>;
+        interrupt-parent = <&mpc5200_pic>;
+
+        ethernet-switch@0 {
+            compatible = "micrel,ks8995m";
+            spi-max-frequency = <1000000>;
+            reg = <0>;
+        };
+
+        codec@1 {
+            compatible = "ti,tlv320aic26";
+            spi-max-frequency = <100000>;
+            reg = <1>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/spi/spi-gpio.txt b/Documentation/devicetree/bindings/spi/spi-gpio.txt
deleted file mode 100644 (file)
index 52db562..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-SPI-GPIO devicetree bindings
-
-This represents a group of 3-n GPIO lines used for bit-banged SPI on dedicated
-GPIO lines.
-
-Required properties:
-
- - compatible: should be set to "spi-gpio"
- - #address-cells: should be set to <0x1>
- - ranges
- - sck-gpios: GPIO spec for the SCK line to use
- - miso-gpios: GPIO spec for the MISO line to use
- - mosi-gpios: GPIO spec for the MOSI line to use
- - cs-gpios: GPIOs to use for chipselect lines.
-             Not needed if num-chipselects = <0>.
- - num-chipselects: Number of chipselect lines. Should be <0> if a single device
-                    with no chip select is connected.
-
-Deprecated bindings:
-
-These legacy GPIO line bindings can alternatively be used to define the
-GPIO lines used, they should not be used in new device trees.
-
- - gpio-sck: GPIO spec for the SCK line to use
- - gpio-miso: GPIO spec for the MISO line to use
- - gpio-mosi: GPIO spec for the MOSI line to use
-
-Example:
-
-       spi {
-               compatible = "spi-gpio";
-               #address-cells = <0x1>;
-               ranges;
-
-               sck-gpios = <&gpio 95 0>;
-               miso-gpios = <&gpio 98 0>;
-               mosi-gpios = <&gpio 97 0>;
-               cs-gpios = <&gpio 125 0>;
-               num-chipselects = <1>;
-
-               /* clients */
-       };
-
diff --git a/Documentation/devicetree/bindings/spi/spi-gpio.yaml b/Documentation/devicetree/bindings/spi/spi-gpio.yaml
new file mode 100644 (file)
index 0000000..55c4f17
--- /dev/null
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/spi-gpio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SPI-GPIO devicetree bindings
+
+maintainers:
+  - Rob Herring <robh@kernel.org>
+
+description:
+  This represents a group of 3-n GPIO lines used for bit-banged SPI on
+  dedicated GPIO lines.
+
+allOf:
+  - $ref: "/schemas/spi/spi-controller.yaml#"
+
+properties:
+  compatible:
+    const: spi-gpio
+
+  sck-gpios:
+    description: GPIO spec for the SCK line to use
+    maxItems: 1
+
+  miso-gpios:
+    description: GPIO spec for the MISO line to use
+    maxItems: 1
+
+  mosi-gpios:
+    description: GPIO spec for the MOSI line to use
+    maxItems: 1
+
+  cs-gpios:
+    description: GPIOs to use for chipselect lines.
+      Not needed if num-chipselects = <0>.
+    minItems: 1
+    maxItems: 1024
+
+  num-chipselects:
+    description: Number of chipselect lines. Should be <0> if a single device
+      with no chip select is connected.
+    $ref: "/schemas/types.yaml#/definitions/uint32"
+
+  # Deprecated properties
+  gpio-sck: false
+  gpio-miso: false
+  gpio-mosi: false
+
+required:
+  - compatible
+  - num-chipselects
+  - sck-gpios
+
+examples:
+  - |
+    spi {
+      compatible = "spi-gpio";
+      #address-cells = <0x1>;
+      #size-cells = <0x0>;
+
+      sck-gpios = <&gpio 95 0>;
+      miso-gpios = <&gpio 98 0>;
+      mosi-gpios = <&gpio 97 0>;
+      cs-gpios = <&gpio 125 0>;
+      num-chipselects = <1>;
+
+      /* clients */
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/spi/spi-pl022.yaml b/Documentation/devicetree/bindings/spi/spi-pl022.yaml
new file mode 100644 (file)
index 0000000..dfb697c
--- /dev/null
@@ -0,0 +1,165 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/spi-pl022.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ARM PL022 SPI controller
+
+maintainers:
+  - Linus Walleij <linus.walleij@linaro.org>
+
+allOf:
+  - $ref: "spi-controller.yaml#"
+
+# We need a select here so we don't match all nodes with 'arm,primecell'
+select:
+  properties:
+    compatible:
+      contains:
+        const: arm,pl022
+  required:
+    - compatible
+
+properties:
+  compatible:
+    items:
+      - const: arm,pl022
+      - const: arm,primecell
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 2
+
+  clock-names:
+    items:
+      - enum:
+          - SSPCLK
+          - sspclk
+      - const: apb_pclk
+
+  pl022,autosuspend-delay:
+    description: delay in ms following transfer completion before the
+      runtime power management system suspends the device. A setting of 0
+      indicates no delay and the device will be suspended immediately.
+    $ref: "/schemas/types.yaml#/definitions/uint32"
+
+  pl022,rt:
+    description: indicates the controller should run the message pump with realtime
+               priority to minimise the transfer latency on the bus (boolean)
+    type: boolean
+
+  dmas:
+    description:
+      Two or more DMA channel specifiers following the convention outlined
+      in bindings/dma/dma.txt
+    minItems: 2
+    maxItems: 32
+
+  dma-names:
+    description:
+      There must be at least one channel named "tx" for transmit and named "rx"
+      for receive.
+    minItems: 2
+    maxItems: 32
+    additionalItems: true
+    items:
+      - const: rx
+      - const: tx
+
+patternProperties:
+  "^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-f]+$":
+    type: object
+    # SPI slave nodes must be children of the SPI master node and can
+    # contain the following properties.
+    properties:
+      pl022,interface:
+        description: SPI interface type
+        allOf:
+          - $ref: "/schemas/types.yaml#/definitions/uint32"
+          - enum:
+              - 0  # SPI
+              - 1  # Texas Instruments Synchronous Serial Frame Format
+              - 2  # Microwire (Half Duplex)
+
+      pl022,com-mode:
+        description: Specifies the transfer mode
+        allOf:
+          - $ref: "/schemas/types.yaml#/definitions/uint32"
+          - enum:
+              - 0  # interrupt mode
+              - 1  # polling mode
+              - 2  # DMA mode
+            default: 1
+
+      pl022,rx-level-trig:
+        description: Rx FIFO watermark level
+        allOf:
+          - $ref: "/schemas/types.yaml#/definitions/uint32"
+          - minimum: 0
+            maximum: 4
+
+      pl022,tx-level-trig:
+        description: Tx FIFO watermark level
+        allOf:
+          - $ref: "/schemas/types.yaml#/definitions/uint32"
+          - minimum: 0
+            maximum: 4
+
+      pl022,ctrl-len:
+        description: Microwire interface - Control length
+        allOf:
+          - $ref: "/schemas/types.yaml#/definitions/uint32"
+          - minimum: 0x03
+            maximum: 0x1f
+
+      pl022,wait-state:
+        description: Microwire interface - Wait state
+        allOf:
+          - $ref: "/schemas/types.yaml#/definitions/uint32"
+          - enum: [ 0, 1 ]
+
+      pl022,duplex:
+        description: Microwire interface - Full/Half duplex
+        allOf:
+          - $ref: "/schemas/types.yaml#/definitions/uint32"
+          - enum: [ 0, 1 ]
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+examples:
+  - |
+    spi@e0100000 {
+      compatible = "arm,pl022", "arm,primecell";
+      reg = <0xe0100000 0x1000>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+      interrupts = <0 31 0x4>;
+      dmas = <&dma_controller 23 1>,
+        <&dma_controller 24 0>;
+      dma-names = "rx", "tx";
+
+      m25p80@1 {
+        compatible = "st,m25p80";
+        reg = <1>;
+        spi-max-frequency = <12000000>;
+        spi-cpol;
+        spi-cpha;
+        pl022,interface = <0>;
+        pl022,com-mode = <0x2>;
+        pl022,rx-level-trig = <0>;
+        pl022,tx-level-trig = <0>;
+        pl022,ctrl-len = <0x11>;
+        pl022,wait-state = <0>;
+        pl022,duplex = <0>;
+      };
+    };
+...
diff --git a/Documentation/devicetree/bindings/spi/spi-sun4i.txt b/Documentation/devicetree/bindings/spi/spi-sun4i.txt
deleted file mode 100644 (file)
index c75d604..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-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@1c06000 {
-       compatible = "allwinner,sun4i-a10-spi";
-       reg = <0x01c06000 0x1000>;
-       interrupts = <11>;
-       clocks = <&ahb_gates 21>, <&spi1_clk>;
-       clock-names = "ahb", "mod";
-       #address-cells = <1>;
-       #size-cells = <0>;
-};
diff --git a/Documentation/devicetree/bindings/spi/spi-sun6i.txt b/Documentation/devicetree/bindings/spi/spi-sun6i.txt
deleted file mode 100644 (file)
index 435a8e0..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-Allwinner A31/H3 SPI controller
-
-Required properties:
-- compatible: Should be "allwinner,sun6i-a31-spi" or "allwinner,sun8i-h3-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
-
-Optional properties:
-- dmas: DMA specifiers for rx and tx dma. See the DMA client binding,
-       Documentation/devicetree/bindings/dma/dma.txt
-- dma-names: DMA request names should include "rx" and "tx" if present.
-
-Example:
-
-spi1: spi@1c69000 {
-       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>;
-};
-
-spi0: spi@1c68000 {
-       compatible = "allwinner,sun8i-h3-spi";
-       reg = <0x01c68000 0x1000>;
-       interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
-       clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
-       clock-names = "ahb", "mod";
-       dmas = <&dma 23>, <&dma 23>;
-       dma-names = "rx", "tx";
-       pinctrl-names = "default";
-       pinctrl-0 = <&spi0_pins>;
-       resets = <&ccu RST_BUS_SPI0>;
-       #address-cells = <1>;
-       #size-cells = <0>;
-};
diff --git a/Documentation/devicetree/bindings/spi/spi-synquacer.txt b/Documentation/devicetree/bindings/spi/spi-synquacer.txt
new file mode 100644 (file)
index 0000000..291dfa6
--- /dev/null
@@ -0,0 +1,27 @@
+* Socionext Synquacer HS-SPI bindings
+
+Required Properties:
+- compatible: should be "socionext,synquacer-spi"
+- reg: physical base address of the controller and length of memory mapped
+       region.
+- interrupts: should contain the "spi_rx", "spi_tx" and "spi_fault" interrupts.
+- clocks: core clock iHCLK. Optional rate clock iPCLK (default is iHCLK)
+- clock-names: Shall be "iHCLK" and "iPCLK" respectively
+
+Optional Properties:
+- socionext,use-rtm: boolean, if required to use "retimed clock" for RX
+- socionext,set-aces: boolean, if same active clock edges field to be set.
+
+Example:
+
+       spi0: spi@ff110000 {
+               compatible = "socionext,synquacer-spi";
+               reg = <0xff110000 0x1000>;
+               interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_hsspi>;
+               clock-names = "iHCLK";
+               socionext,use-rtm;
+               socionext,set-aces;
+       };
diff --git a/Documentation/devicetree/bindings/spi/spi_pl022.txt b/Documentation/devicetree/bindings/spi/spi_pl022.txt
deleted file mode 100644 (file)
index 7638b49..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-ARM PL022 SPI controller
-
-Required properties:
-- compatible : "arm,pl022", "arm,primecell"
-- reg : Offset and length of the register set for the device
-- interrupts : Should contain SPI controller interrupt
-- num-cs : total number of chipselects
-
-Optional properties:
-- cs-gpios : should specify GPIOs used for chipselects.
-  The gpios will be referred to as reg = <index> in the SPI child nodes.
-  If unspecified, a single SPI device without a chip select can be used.
-- pl022,autosuspend-delay : delay in ms following transfer completion before
-                           the runtime power management system suspends the
-                           device. A setting of 0 indicates no delay and the
-                            device will be suspended immediately
-- pl022,rt : indicates the controller should run the message pump with realtime
-             priority to minimise the transfer latency on the bus (boolean)
-- dmas : Two or more DMA channel specifiers following the convention outlined
-         in bindings/dma/dma.txt
-- dma-names: Names for the dma channels, if present. There must be at
-            least one channel named "tx" for transmit and named "rx" for
-             receive.
-
-
-SPI slave nodes must be children of the SPI master node and can
-contain the following properties.
-
-- pl022,interface : interface type:
-       0: SPI
-       1: Texas Instruments Synchronous Serial Frame Format
-       2: Microwire (Half Duplex)
-- pl022,com-mode : specifies the transfer mode:
-       0: interrupt mode
-       1: polling mode (default mode if property not present)
-       2: DMA mode
-- pl022,rx-level-trig : Rx FIFO watermark level
-- pl022,tx-level-trig : Tx FIFO watermark level
-- pl022,ctrl-len : Microwire interface: Control length
-- pl022,wait-state : Microwire interface: Wait state
-- pl022,duplex : Microwire interface: Full/Half duplex
-
-
-Example:
-
-       spi@e0100000 {
-               compatible = "arm,pl022", "arm,primecell";
-               reg = <0xe0100000 0x1000>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-               interrupts = <0 31 0x4>;
-               dmas = <&dma-controller 23 1>,
-                       <&dma-controller 24 0>;
-               dma-names = "rx", "tx";
-
-               m25p80@1 {
-                       compatible = "st,m25p80";
-                       reg = <1>;
-                       spi-max-frequency = <12000000>;
-                       spi-cpol;
-                       spi-cpha;
-                       pl022,interface = <0>;
-                       pl022,com-mode = <0x2>;
-                       pl022,rx-level-trig = <0>;
-                       pl022,tx-level-trig = <0>;
-                       pl022,ctrl-len = <0x11>;
-                       pl022,wait-state = <0>;
-                       pl022,duplex = <0>;
-               };
-       };
index 57f496c..f6f0f8b 100644 (file)
@@ -14612,6 +14612,14 @@ S:     Maintained
 F:     drivers/net/ethernet/socionext/netsec.c
 F:     Documentation/devicetree/bindings/net/socionext-netsec.txt
 
+SOCIONEXT (SNI) Synquacer SPI DRIVER
+M:     Masahisa Kojima <masahisa.kojima@linaro.org>
+M:     Jassi Brar <jaswinder.singh@linaro.org>
+L:     linux-spi@vger.kernel.org
+S:     Maintained
+F:     drivers/spi/spi-synquacer.c
+F:     Documentation/devicetree/bindings/spi/spi-synquacer.txt
+
 SOLIDRUN CLEARFOG SUPPORT
 M:     Russell King <linux@armlinux.org.uk>
 S:     Maintained
index 30a4028..3a1d8f1 100644 (file)
@@ -120,7 +120,7 @@ config SPI_AXI_SPI_ENGINE
 config SPI_BCM2835
        tristate "BCM2835 SPI controller"
        depends on GPIOLIB
-       depends on ARCH_BCM2835 || COMPILE_TEST
+       depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
        help
          This selects a driver for the Broadcom BCM2835 SPI master.
 
@@ -131,7 +131,7 @@ config SPI_BCM2835
 
 config SPI_BCM2835AUX
        tristate "BCM2835 SPI auxiliary controller"
-       depends on (ARCH_BCM2835 && GPIOLIB) || COMPILE_TEST
+       depends on ((ARCH_BCM2835 || ARCH_BRCMSTB) && GPIOLIB) || COMPILE_TEST
        help
          This selects a driver for the Broadcom BCM2835 SPI aux master.
 
@@ -733,6 +733,16 @@ config SPI_SUN6I
        help
          This enables using the SPI controller on the Allwinner A31 SoCs.
 
+config SPI_SYNQUACER
+       tristate "Socionext's SynQuacer HighSpeed SPI controller"
+       depends on ARCH_SYNQUACER || COMPILE_TEST
+       help
+         SPI driver for Socionext's High speed SPI controller which provides
+         various operating modes for interfacing to serial peripheral devices
+         that use the de-facto standard SPI protocol.
+
+         It also supports the new dual-bit and quad-bit SPI protocol.
+
 config SPI_MXIC
         tristate "Macronix MX25F0A SPI controller"
         depends on SPI_MASTER
index f2f78d0..63dcab5 100644 (file)
@@ -106,6 +106,7 @@ obj-$(CONFIG_SPI_STM32_QSPI)                += spi-stm32-qspi.o
 obj-$(CONFIG_SPI_ST_SSC4)              += spi-st-ssc4.o
 obj-$(CONFIG_SPI_SUN4I)                        += spi-sun4i.o
 obj-$(CONFIG_SPI_SUN6I)                        += spi-sun6i.o
+obj-$(CONFIG_SPI_SYNQUACER)            += spi-synquacer.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
index f763e14..a40bb2e 100644 (file)
@@ -8,9 +8,12 @@
 
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-direction.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of_platform.h>
 #include <linux/of_gpio.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
@@ -59,6 +62,8 @@
 
 #define US_INIT \
        (US_MR_SPI_MASTER | US_MR_CHRL | US_MR_CLKO | US_MR_WRDBT)
+#define US_DMA_MIN_BYTES       16
+#define US_DMA_TIMEOUT         (msecs_to_jiffies(1000))
 
 /* Register access macros */
 #define at91_usart_spi_readl(port, reg) \
        writeb_relaxed((value), (port)->regs + US_##reg)
 
 struct at91_usart_spi {
+       struct platform_device  *mpdev;
        struct spi_transfer     *current_transfer;
        void __iomem            *regs;
        struct device           *dev;
        struct clk              *clk;
 
+       struct completion       xfer_completion;
+
        /*used in interrupt to protect data reading*/
        spinlock_t              lock;
 
+       phys_addr_t             phybase;
+
        int                     irq;
        unsigned int            current_tx_remaining_bytes;
        unsigned int            current_rx_remaining_bytes;
@@ -88,8 +98,182 @@ struct at91_usart_spi {
        u32                     status;
 
        bool                    xfer_failed;
+       bool                    use_dma;
 };
 
+static void dma_callback(void *data)
+{
+       struct spi_controller   *ctlr = data;
+       struct at91_usart_spi   *aus = spi_master_get_devdata(ctlr);
+
+       at91_usart_spi_writel(aus, IER, US_IR_RXRDY);
+       aus->current_rx_remaining_bytes = 0;
+       complete(&aus->xfer_completion);
+}
+
+static bool at91_usart_spi_can_dma(struct spi_controller *ctrl,
+                                  struct spi_device *spi,
+                                  struct spi_transfer *xfer)
+{
+       struct at91_usart_spi *aus = spi_master_get_devdata(ctrl);
+
+       return aus->use_dma && xfer->len >= US_DMA_MIN_BYTES;
+}
+
+static int at91_usart_spi_configure_dma(struct spi_controller *ctlr,
+                                       struct at91_usart_spi *aus)
+{
+       struct dma_slave_config slave_config;
+       struct device *dev = &aus->mpdev->dev;
+       phys_addr_t phybase = aus->phybase;
+       dma_cap_mask_t mask;
+       int err = 0;
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       ctlr->dma_tx = dma_request_slave_channel_reason(dev, "tx");
+       if (IS_ERR_OR_NULL(ctlr->dma_tx)) {
+               if (IS_ERR(ctlr->dma_tx)) {
+                       err = PTR_ERR(ctlr->dma_tx);
+                       goto at91_usart_spi_error_clear;
+               }
+
+               dev_dbg(dev,
+                       "DMA TX channel not available, SPI unable to use DMA\n");
+               err = -EBUSY;
+               goto at91_usart_spi_error_clear;
+       }
+
+       ctlr->dma_rx = dma_request_slave_channel_reason(dev, "rx");
+       if (IS_ERR_OR_NULL(ctlr->dma_rx)) {
+               if (IS_ERR(ctlr->dma_rx)) {
+                       err = PTR_ERR(ctlr->dma_rx);
+                       goto at91_usart_spi_error;
+               }
+
+               dev_dbg(dev,
+                       "DMA RX channel not available, SPI unable to use DMA\n");
+               err = -EBUSY;
+               goto at91_usart_spi_error;
+       }
+
+       slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       slave_config.dst_addr = (dma_addr_t)phybase + US_THR;
+       slave_config.src_addr = (dma_addr_t)phybase + US_RHR;
+       slave_config.src_maxburst = 1;
+       slave_config.dst_maxburst = 1;
+       slave_config.device_fc = false;
+
+       slave_config.direction = DMA_DEV_TO_MEM;
+       if (dmaengine_slave_config(ctlr->dma_rx, &slave_config)) {
+               dev_err(&ctlr->dev,
+                       "failed to configure rx dma channel\n");
+               err = -EINVAL;
+               goto at91_usart_spi_error;
+       }
+
+       slave_config.direction = DMA_MEM_TO_DEV;
+       if (dmaengine_slave_config(ctlr->dma_tx, &slave_config)) {
+               dev_err(&ctlr->dev,
+                       "failed to configure tx dma channel\n");
+               err = -EINVAL;
+               goto at91_usart_spi_error;
+       }
+
+       aus->use_dma = true;
+       return 0;
+
+at91_usart_spi_error:
+       if (!IS_ERR_OR_NULL(ctlr->dma_tx))
+               dma_release_channel(ctlr->dma_tx);
+       if (!IS_ERR_OR_NULL(ctlr->dma_rx))
+               dma_release_channel(ctlr->dma_rx);
+       ctlr->dma_tx = NULL;
+       ctlr->dma_rx = NULL;
+
+at91_usart_spi_error_clear:
+       return err;
+}
+
+static void at91_usart_spi_release_dma(struct spi_controller *ctlr)
+{
+       if (ctlr->dma_rx)
+               dma_release_channel(ctlr->dma_rx);
+       if (ctlr->dma_tx)
+               dma_release_channel(ctlr->dma_tx);
+}
+
+static void at91_usart_spi_stop_dma(struct spi_controller *ctlr)
+{
+       if (ctlr->dma_rx)
+               dmaengine_terminate_all(ctlr->dma_rx);
+       if (ctlr->dma_tx)
+               dmaengine_terminate_all(ctlr->dma_tx);
+}
+
+static int at91_usart_spi_dma_transfer(struct spi_controller *ctlr,
+                                      struct spi_transfer *xfer)
+{
+       struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+       struct dma_chan  *rxchan = ctlr->dma_rx;
+       struct dma_chan *txchan = ctlr->dma_tx;
+       struct dma_async_tx_descriptor *rxdesc;
+       struct dma_async_tx_descriptor *txdesc;
+       dma_cookie_t cookie;
+
+       /* Disable RX interrupt */
+       at91_usart_spi_writel(aus, IDR, US_IR_RXRDY);
+
+       rxdesc = dmaengine_prep_slave_sg(rxchan,
+                                        xfer->rx_sg.sgl,
+                                        xfer->rx_sg.nents,
+                                        DMA_DEV_TO_MEM,
+                                        DMA_PREP_INTERRUPT |
+                                        DMA_CTRL_ACK);
+       if (!rxdesc)
+               goto at91_usart_spi_err_dma;
+
+       txdesc = dmaengine_prep_slave_sg(txchan,
+                                        xfer->tx_sg.sgl,
+                                        xfer->tx_sg.nents,
+                                        DMA_MEM_TO_DEV,
+                                        DMA_PREP_INTERRUPT |
+                                        DMA_CTRL_ACK);
+       if (!txdesc)
+               goto at91_usart_spi_err_dma;
+
+       rxdesc->callback = dma_callback;
+       rxdesc->callback_param = ctlr;
+
+       cookie = rxdesc->tx_submit(rxdesc);
+       if (dma_submit_error(cookie))
+               goto at91_usart_spi_err_dma;
+
+       cookie = txdesc->tx_submit(txdesc);
+       if (dma_submit_error(cookie))
+               goto at91_usart_spi_err_dma;
+
+       rxchan->device->device_issue_pending(rxchan);
+       txchan->device->device_issue_pending(txchan);
+
+       return 0;
+
+at91_usart_spi_err_dma:
+       /* Enable RX interrupt if something fails and fallback to PIO */
+       at91_usart_spi_writel(aus, IER, US_IR_RXRDY);
+       at91_usart_spi_stop_dma(ctlr);
+
+       return -ENOMEM;
+}
+
+static unsigned long at91_usart_spi_dma_timeout(struct at91_usart_spi *aus)
+{
+       return wait_for_completion_timeout(&aus->xfer_completion,
+                                          US_DMA_TIMEOUT);
+}
+
 static inline u32 at91_usart_spi_tx_ready(struct at91_usart_spi *aus)
 {
        return aus->status & US_IR_TXRDY;
@@ -216,6 +400,8 @@ static int at91_usart_spi_transfer_one(struct spi_controller *ctlr,
                                       struct spi_transfer *xfer)
 {
        struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+       unsigned long dma_timeout = 0;
+       int ret = 0;
 
        at91_usart_spi_set_xfer_speed(aus, xfer);
        aus->xfer_failed = false;
@@ -225,8 +411,25 @@ static int at91_usart_spi_transfer_one(struct spi_controller *ctlr,
 
        while ((aus->current_tx_remaining_bytes ||
                aus->current_rx_remaining_bytes) && !aus->xfer_failed) {
-               at91_usart_spi_read_status(aus);
-               at91_usart_spi_tx(aus);
+               reinit_completion(&aus->xfer_completion);
+               if (at91_usart_spi_can_dma(ctlr, spi, xfer) &&
+                   !ret) {
+                       ret = at91_usart_spi_dma_transfer(ctlr, xfer);
+                       if (ret)
+                               continue;
+
+                       dma_timeout = at91_usart_spi_dma_timeout(aus);
+
+                       if (WARN_ON(dma_timeout == 0)) {
+                               dev_err(&spi->dev, "DMA transfer timeout\n");
+                               return -EIO;
+                       }
+                       aus->current_tx_remaining_bytes = 0;
+               } else {
+                       at91_usart_spi_read_status(aus);
+                       at91_usart_spi_tx(aus);
+               }
+
                cpu_relax();
        }
 
@@ -345,6 +548,7 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
        controller->transfer_one = at91_usart_spi_transfer_one;
        controller->prepare_message = at91_usart_spi_prepare_message;
        controller->unprepare_message = at91_usart_spi_unprepare_message;
+       controller->can_dma = at91_usart_spi_can_dma;
        controller->cleanup = at91_usart_spi_cleanup;
        controller->max_speed_hz = DIV_ROUND_UP(clk_get_rate(clk),
                                                US_MIN_CLK_DIV);
@@ -376,7 +580,17 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
        aus->spi_clk = clk_get_rate(clk);
        at91_usart_spi_init(aus);
 
+       aus->phybase = regs->start;
+
+       aus->mpdev = to_platform_device(pdev->dev.parent);
+
+       ret = at91_usart_spi_configure_dma(controller, aus);
+       if (ret)
+               goto at91_usart_fail_dma;
+
        spin_lock_init(&aus->lock);
+       init_completion(&aus->xfer_completion);
+
        ret = devm_spi_register_master(&pdev->dev, controller);
        if (ret)
                goto at91_usart_fail_register_master;
@@ -389,6 +603,8 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
        return 0;
 
 at91_usart_fail_register_master:
+       at91_usart_spi_release_dma(controller);
+at91_usart_fail_dma:
        clk_disable_unprepare(clk);
 at91_usart_spi_probe_fail:
        spi_master_put(controller);
@@ -453,6 +669,7 @@ static int at91_usart_spi_remove(struct platform_device *pdev)
        struct spi_controller *ctlr = platform_get_drvdata(pdev);
        struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
 
+       at91_usart_spi_release_dma(ctlr);
        clk_disable_unprepare(aus->clk);
 
        return 0;
index 402c1ef..6f243a9 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/clk.h>
 #include <linux/completion.h>
+#include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
 
 #define BCM2835_SPI_FIFO_SIZE          64
 #define BCM2835_SPI_FIFO_SIZE_3_4      48
-#define BCM2835_SPI_POLLING_LIMIT_US   30
-#define BCM2835_SPI_POLLING_JIFFIES    2
 #define BCM2835_SPI_DMA_MIN_LENGTH     96
 #define BCM2835_SPI_MODE_BITS  (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
                                | SPI_NO_CS | SPI_3WIRE)
 
 #define DRV_NAME       "spi-bcm2835"
 
+/* define polling limits */
+unsigned int polling_limit_us = 30;
+module_param(polling_limit_us, uint, 0664);
+MODULE_PARM_DESC(polling_limit_us,
+                "time in us to run a transfer in polling mode\n");
+
 /**
  * struct bcm2835_spi - BCM2835 SPI controller
  * @regs: base address of register map
  *     length is not a multiple of 4 (to overcome hardware limitation)
  * @tx_spillover: whether @tx_prologue spills over to second TX sglist entry
  * @dma_pending: whether a DMA transfer is in progress
+ * @debugfs_dir: the debugfs directory - neede to remove debugfs when
+ *      unloading the module
+ * @count_transfer_polling: count of how often polling mode is used
+ * @count_transfer_irq: count of how often interrupt mode is used
+ * @count_transfer_irq_after_polling: count of how often we fall back to
+ *      interrupt mode after starting in polling mode.
+ *      These are counted as well in @count_transfer_polling and
+ *      @count_transfer_irq
+ * @count_transfer_dma: count how often dma mode is used
  */
 struct bcm2835_spi {
        void __iomem *regs;
@@ -102,8 +116,55 @@ struct bcm2835_spi {
        int rx_prologue;
        unsigned int tx_spillover;
        unsigned int dma_pending;
+
+       struct dentry *debugfs_dir;
+       u64 count_transfer_polling;
+       u64 count_transfer_irq;
+       u64 count_transfer_irq_after_polling;
+       u64 count_transfer_dma;
 };
 
+#if defined(CONFIG_DEBUG_FS)
+static void bcm2835_debugfs_create(struct bcm2835_spi *bs,
+                                  const char *dname)
+{
+       char name[64];
+       struct dentry *dir;
+
+       /* get full name */
+       snprintf(name, sizeof(name), "spi-bcm2835-%s", dname);
+
+       /* the base directory */
+       dir = debugfs_create_dir(name, NULL);
+       bs->debugfs_dir = dir;
+
+       /* the counters */
+       debugfs_create_u64("count_transfer_polling", 0444, dir,
+                          &bs->count_transfer_polling);
+       debugfs_create_u64("count_transfer_irq", 0444, dir,
+                          &bs->count_transfer_irq);
+       debugfs_create_u64("count_transfer_irq_after_polling", 0444, dir,
+                          &bs->count_transfer_irq_after_polling);
+       debugfs_create_u64("count_transfer_dma", 0444, dir,
+                          &bs->count_transfer_dma);
+}
+
+static void bcm2835_debugfs_remove(struct bcm2835_spi *bs)
+{
+       debugfs_remove_recursive(bs->debugfs_dir);
+       bs->debugfs_dir = NULL;
+}
+#else
+static void bcm2835_debugfs_create(struct bcm2835_spi *bs,
+                                  const char *dname)
+{
+}
+
+static void bcm2835_debugfs_remove(struct bcm2835_spi *bs)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
 static inline u32 bcm2835_rd(struct bcm2835_spi *bs, unsigned reg)
 {
        return readl(bs->regs + reg);
@@ -248,9 +309,9 @@ static inline void bcm2835_wr_fifo_blind(struct bcm2835_spi *bs, int count)
        }
 }
 
-static void bcm2835_spi_reset_hw(struct spi_master *master)
+static void bcm2835_spi_reset_hw(struct spi_controller *ctlr)
 {
-       struct bcm2835_spi *bs = spi_master_get_devdata(master);
+       struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
        u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
 
        /* Disable SPI interrupts and transfer */
@@ -269,8 +330,8 @@ static void bcm2835_spi_reset_hw(struct spi_master *master)
 
 static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
 {
-       struct spi_master *master = dev_id;
-       struct bcm2835_spi *bs = spi_master_get_devdata(master);
+       struct spi_controller *ctlr = dev_id;
+       struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
        u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
 
        /*
@@ -292,20 +353,23 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
 
        if (!bs->rx_len) {
                /* Transfer complete - reset SPI HW */
-               bcm2835_spi_reset_hw(master);
+               bcm2835_spi_reset_hw(ctlr);
                /* wake up the framework */
-               complete(&master->xfer_completion);
+               complete(&ctlr->xfer_completion);
        }
 
        return IRQ_HANDLED;
 }
 
-static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
+static int bcm2835_spi_transfer_one_irq(struct spi_controller *ctlr,
                                        struct spi_device *spi,
                                        struct spi_transfer *tfr,
                                        u32 cs, bool fifo_empty)
 {
-       struct bcm2835_spi *bs = spi_master_get_devdata(master);
+       struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+
+       /* update usage statistics */
+       bs->count_transfer_irq++;
 
        /*
         * Enable HW block, but with interrupts still disabled.
@@ -328,7 +392,7 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
 
 /**
  * bcm2835_spi_transfer_prologue() - transfer first few bytes without DMA
- * @master: SPI master
+ * @ctlr: SPI master controller
  * @tfr: SPI transfer
  * @bs: BCM2835 SPI controller
  * @cs: CS register
@@ -372,7 +436,7 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
  * be transmitted in 32-bit width to ensure that the following DMA transfer can
  * pick up the residue in the RX FIFO in ungarbled form.
  */
-static void bcm2835_spi_transfer_prologue(struct spi_master *master,
+static void bcm2835_spi_transfer_prologue(struct spi_controller *ctlr,
                                          struct spi_transfer *tfr,
                                          struct bcm2835_spi *bs,
                                          u32 cs)
@@ -413,9 +477,9 @@ static void bcm2835_spi_transfer_prologue(struct spi_master *master,
                bcm2835_wr_fifo_count(bs, bs->rx_prologue);
                bcm2835_wait_tx_fifo_empty(bs);
                bcm2835_rd_fifo_count(bs, bs->rx_prologue);
-               bcm2835_spi_reset_hw(master);
+               bcm2835_spi_reset_hw(ctlr);
 
-               dma_sync_single_for_device(master->dma_rx->device->dev,
+               dma_sync_single_for_device(ctlr->dma_rx->device->dev,
                                           sg_dma_address(&tfr->rx_sg.sgl[0]),
                                           bs->rx_prologue, DMA_FROM_DEVICE);
 
@@ -479,11 +543,11 @@ static void bcm2835_spi_undo_prologue(struct bcm2835_spi *bs)
 
 static void bcm2835_spi_dma_done(void *data)
 {
-       struct spi_master *master = data;
-       struct bcm2835_spi *bs = spi_master_get_devdata(master);
+       struct spi_controller *ctlr = data;
+       struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
 
        /* reset fifo and HW */
-       bcm2835_spi_reset_hw(master);
+       bcm2835_spi_reset_hw(ctlr);
 
        /* and terminate tx-dma as we do not have an irq for it
         * because when the rx dma will terminate and this callback
@@ -491,15 +555,15 @@ static void bcm2835_spi_dma_done(void *data)
         * situation otherwise...
         */
        if (cmpxchg(&bs->dma_pending, true, false)) {
-               dmaengine_terminate_async(master->dma_tx);
+               dmaengine_terminate_async(ctlr->dma_tx);
                bcm2835_spi_undo_prologue(bs);
        }
 
        /* and mark as completed */;
-       complete(&master->xfer_completion);
+       complete(&ctlr->xfer_completion);
 }
 
-static int bcm2835_spi_prepare_sg(struct spi_master *master,
+static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
                                  struct spi_transfer *tfr,
                                  bool is_tx)
 {
@@ -514,14 +578,14 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master,
 
        if (is_tx) {
                dir   = DMA_MEM_TO_DEV;
-               chan  = master->dma_tx;
+               chan  = ctlr->dma_tx;
                nents = tfr->tx_sg.nents;
                sgl   = tfr->tx_sg.sgl;
                flags = 0 /* no  tx interrupt */;
 
        } else {
                dir   = DMA_DEV_TO_MEM;
-               chan  = master->dma_rx;
+               chan  = ctlr->dma_rx;
                nents = tfr->rx_sg.nents;
                sgl   = tfr->rx_sg.sgl;
                flags = DMA_PREP_INTERRUPT;
@@ -534,7 +598,7 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master,
        /* set callback for rx */
        if (!is_tx) {
                desc->callback = bcm2835_spi_dma_done;
-               desc->callback_param = master;
+               desc->callback_param = ctlr;
        }
 
        /* submit it to DMA-engine */
@@ -543,27 +607,30 @@ static int bcm2835_spi_prepare_sg(struct spi_master *master,
        return dma_submit_error(cookie);
 }
 
-static int bcm2835_spi_transfer_one_dma(struct spi_master *master,
+static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
                                        struct spi_device *spi,
                                        struct spi_transfer *tfr,
                                        u32 cs)
 {
-       struct bcm2835_spi *bs = spi_master_get_devdata(master);
+       struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
        int ret;
 
+       /* update usage statistics */
+       bs->count_transfer_dma++;
+
        /*
         * Transfer first few bytes without DMA if length of first TX or RX
         * sglist entry is not a multiple of 4 bytes (hardware limitation).
         */
-       bcm2835_spi_transfer_prologue(master, tfr, bs, cs);
+       bcm2835_spi_transfer_prologue(ctlr, tfr, bs, cs);
 
        /* setup tx-DMA */
-       ret = bcm2835_spi_prepare_sg(master, tfr, true);
+       ret = bcm2835_spi_prepare_sg(ctlr, tfr, true);
        if (ret)
                goto err_reset_hw;
 
        /* start TX early */
-       dma_async_issue_pending(master->dma_tx);
+       dma_async_issue_pending(ctlr->dma_tx);
 
        /* mark as dma pending */
        bs->dma_pending = 1;
@@ -579,27 +646,27 @@ static int bcm2835_spi_transfer_one_dma(struct spi_master *master,
         * mapping of the rx buffers still takes place
         * this saves 10us or more.
         */
-       ret = bcm2835_spi_prepare_sg(master, tfr, false);
+       ret = bcm2835_spi_prepare_sg(ctlr, tfr, false);
        if (ret) {
                /* need to reset on errors */
-               dmaengine_terminate_sync(master->dma_tx);
+               dmaengine_terminate_sync(ctlr->dma_tx);
                bs->dma_pending = false;
                goto err_reset_hw;
        }
 
        /* start rx dma late */
-       dma_async_issue_pending(master->dma_rx);
+       dma_async_issue_pending(ctlr->dma_rx);
 
        /* wait for wakeup in framework */
        return 1;
 
 err_reset_hw:
-       bcm2835_spi_reset_hw(master);
+       bcm2835_spi_reset_hw(ctlr);
        bcm2835_spi_undo_prologue(bs);
        return ret;
 }
 
-static bool bcm2835_spi_can_dma(struct spi_master *master,
+static bool bcm2835_spi_can_dma(struct spi_controller *ctlr,
                                struct spi_device *spi,
                                struct spi_transfer *tfr)
 {
@@ -611,21 +678,21 @@ static bool bcm2835_spi_can_dma(struct spi_master *master,
        return true;
 }
 
-static void bcm2835_dma_release(struct spi_master *master)
+static void bcm2835_dma_release(struct spi_controller *ctlr)
 {
-       if (master->dma_tx) {
-               dmaengine_terminate_sync(master->dma_tx);
-               dma_release_channel(master->dma_tx);
-               master->dma_tx = NULL;
+       if (ctlr->dma_tx) {
+               dmaengine_terminate_sync(ctlr->dma_tx);
+               dma_release_channel(ctlr->dma_tx);
+               ctlr->dma_tx = NULL;
        }
-       if (master->dma_rx) {
-               dmaengine_terminate_sync(master->dma_rx);
-               dma_release_channel(master->dma_rx);
-               master->dma_rx = NULL;
+       if (ctlr->dma_rx) {
+               dmaengine_terminate_sync(ctlr->dma_rx);
+               dma_release_channel(ctlr->dma_rx);
+               ctlr->dma_rx = NULL;
        }
 }
 
-static void bcm2835_dma_init(struct spi_master *master, struct device *dev)
+static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev)
 {
        struct dma_slave_config slave_config;
        const __be32 *addr;
@@ -633,7 +700,7 @@ static void bcm2835_dma_init(struct spi_master *master, struct device *dev)
        int ret;
 
        /* base address in dma-space */
-       addr = of_get_address(master->dev.of_node, 0, NULL, NULL);
+       addr = of_get_address(ctlr->dev.of_node, 0, NULL, NULL);
        if (!addr) {
                dev_err(dev, "could not get DMA-register address - not using dma mode\n");
                goto err;
@@ -641,38 +708,36 @@ static void bcm2835_dma_init(struct spi_master *master, struct device *dev)
        dma_reg_base = be32_to_cpup(addr);
 
        /* get tx/rx dma */
-       master->dma_tx = dma_request_slave_channel(dev, "tx");
-       if (!master->dma_tx) {
+       ctlr->dma_tx = dma_request_slave_channel(dev, "tx");
+       if (!ctlr->dma_tx) {
                dev_err(dev, "no tx-dma configuration found - not using dma mode\n");
                goto err;
        }
-       master->dma_rx = dma_request_slave_channel(dev, "rx");
-       if (!master->dma_rx) {
+       ctlr->dma_rx = dma_request_slave_channel(dev, "rx");
+       if (!ctlr->dma_rx) {
                dev_err(dev, "no rx-dma configuration found - not using dma mode\n");
                goto err_release;
        }
 
        /* configure DMAs */
-       slave_config.direction = DMA_MEM_TO_DEV;
        slave_config.dst_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO);
        slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 
-       ret = dmaengine_slave_config(master->dma_tx, &slave_config);
+       ret = dmaengine_slave_config(ctlr->dma_tx, &slave_config);
        if (ret)
                goto err_config;
 
-       slave_config.direction = DMA_DEV_TO_MEM;
        slave_config.src_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO);
        slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 
-       ret = dmaengine_slave_config(master->dma_rx, &slave_config);
+       ret = dmaengine_slave_config(ctlr->dma_rx, &slave_config);
        if (ret)
                goto err_config;
 
        /* all went well, so set can_dma */
-       master->can_dma = bcm2835_spi_can_dma;
+       ctlr->can_dma = bcm2835_spi_can_dma;
        /* need to do TX AND RX DMA, so we need dummy buffers */
-       master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX;
+       ctlr->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
 
        return;
 
@@ -680,20 +745,22 @@ err_config:
        dev_err(dev, "issue configuring dma: %d - not using DMA mode\n",
                ret);
 err_release:
-       bcm2835_dma_release(master);
+       bcm2835_dma_release(ctlr);
 err:
        return;
 }
 
-static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
+static int bcm2835_spi_transfer_one_poll(struct spi_controller *ctlr,
                                         struct spi_device *spi,
                                         struct spi_transfer *tfr,
-                                        u32 cs,
-                                        unsigned long long xfer_time_us)
+                                        u32 cs)
 {
-       struct bcm2835_spi *bs = spi_master_get_devdata(master);
+       struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
        unsigned long timeout;
 
+       /* update usage statistics */
+       bs->count_transfer_polling++;
+
        /* enable HW block without interrupts */
        bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA);
 
@@ -703,8 +770,8 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
         */
        bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE);
 
-       /* set the timeout */
-       timeout = jiffies + BCM2835_SPI_POLLING_JIFFIES;
+       /* set the timeout to at least 2 jiffies */
+       timeout = jiffies + 2 + HZ * polling_limit_us / 1000000;
 
        /* loop until finished the transfer */
        while (bs->rx_len) {
@@ -723,25 +790,28 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
                                            jiffies - timeout,
                                            bs->tx_len, bs->rx_len);
                        /* fall back to interrupt mode */
-                       return bcm2835_spi_transfer_one_irq(master, spi,
+
+                       /* update usage statistics */
+                       bs->count_transfer_irq_after_polling++;
+
+                       return bcm2835_spi_transfer_one_irq(ctlr, spi,
                                                            tfr, cs, false);
                }
        }
 
        /* Transfer complete - reset SPI HW */
-       bcm2835_spi_reset_hw(master);
+       bcm2835_spi_reset_hw(ctlr);
        /* and return without waiting for completion */
        return 0;
 }
 
-static int bcm2835_spi_transfer_one(struct spi_master *master,
+static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
                                    struct spi_device *spi,
                                    struct spi_transfer *tfr)
 {
-       struct bcm2835_spi *bs = spi_master_get_devdata(master);
-       unsigned long spi_hz, clk_hz, cdiv;
-       unsigned long spi_used_hz;
-       unsigned long long xfer_time_us;
+       struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+       unsigned long spi_hz, clk_hz, cdiv, spi_used_hz;
+       unsigned long hz_per_byte, byte_limit;
        u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
 
        /* set clock */
@@ -782,42 +852,49 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
        bs->tx_len = tfr->len;
        bs->rx_len = tfr->len;
 
-       /* calculate the estimated time in us the transfer runs */
-       xfer_time_us = (unsigned long long)tfr->len
-               * 9 /* clocks/byte - SPI-HW waits 1 clock after each byte */
-               * 1000000;
-       do_div(xfer_time_us, spi_used_hz);
+       /* Calculate the estimated time in us the transfer runs.  Note that
+        * there is 1 idle clocks cycles after each byte getting transferred
+        * so we have 9 cycles/byte.  This is used to find the number of Hz
+        * per byte per polling limit.  E.g., we can transfer 1 byte in 30 us
+        * per 300,000 Hz of bus clock.
+        */
+       hz_per_byte = polling_limit_us ? (9 * 1000000) / polling_limit_us : 0;
+       byte_limit = hz_per_byte ? spi_used_hz / hz_per_byte : 1;
 
-       /* for short requests run polling*/
-       if (xfer_time_us <= BCM2835_SPI_POLLING_LIMIT_US)
-               return bcm2835_spi_transfer_one_poll(master, spi, tfr,
-                                                    cs, xfer_time_us);
+       /* run in polling mode for short transfers */
+       if (tfr->len < byte_limit)
+               return bcm2835_spi_transfer_one_poll(ctlr, spi, tfr, cs);
 
-       /* run in dma mode if conditions are right */
-       if (master->can_dma && bcm2835_spi_can_dma(master, spi, tfr))
-               return bcm2835_spi_transfer_one_dma(master, spi, tfr, cs);
+       /* run in dma mode if conditions are right
+        * Note that unlike poll or interrupt mode DMA mode does not have
+        * this 1 idle clock cycle pattern but runs the spi clock without gaps
+        */
+       if (ctlr->can_dma && bcm2835_spi_can_dma(ctlr, spi, tfr))
+               return bcm2835_spi_transfer_one_dma(ctlr, spi, tfr, cs);
 
        /* run in interrupt-mode */
-       return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs, true);
+       return bcm2835_spi_transfer_one_irq(ctlr, spi, tfr, cs, true);
 }
 
-static int bcm2835_spi_prepare_message(struct spi_master *master,
+static int bcm2835_spi_prepare_message(struct spi_controller *ctlr,
                                       struct spi_message *msg)
 {
        struct spi_device *spi = msg->spi;
-       struct bcm2835_spi *bs = spi_master_get_devdata(master);
+       struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
        u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
        int ret;
 
-       /*
-        * DMA transfers are limited to 16 bit (0 to 65535 bytes) by the SPI HW
-        * due to DLEN. Split up transfers (32-bit FIFO aligned) if the limit is
-        * exceeded.
-        */
-       ret = spi_split_transfers_maxsize(master, msg, 65532,
-                                         GFP_KERNEL | GFP_DMA);
-       if (ret)
-               return ret;
+       if (ctlr->can_dma) {
+               /*
+                * DMA transfers are limited to 16 bit (0 to 65535 bytes) by
+                * the SPI HW due to DLEN. Split up transfers (32-bit FIFO
+                * aligned) if the limit is exceeded.
+                */
+               ret = spi_split_transfers_maxsize(ctlr, msg, 65532,
+                                                 GFP_KERNEL | GFP_DMA);
+               if (ret)
+                       return ret;
+       }
 
        cs &= ~(BCM2835_SPI_CS_CPOL | BCM2835_SPI_CS_CPHA);
 
@@ -831,19 +908,19 @@ static int bcm2835_spi_prepare_message(struct spi_master *master,
        return 0;
 }
 
-static void bcm2835_spi_handle_err(struct spi_master *master,
+static void bcm2835_spi_handle_err(struct spi_controller *ctlr,
                                   struct spi_message *msg)
 {
-       struct bcm2835_spi *bs = spi_master_get_devdata(master);
+       struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
 
        /* if an error occurred and we have an active dma, then terminate */
        if (cmpxchg(&bs->dma_pending, true, false)) {
-               dmaengine_terminate_sync(master->dma_tx);
-               dmaengine_terminate_sync(master->dma_rx);
+               dmaengine_terminate_sync(ctlr->dma_tx);
+               dmaengine_terminate_sync(ctlr->dma_rx);
                bcm2835_spi_undo_prologue(bs);
        }
        /* and reset */
-       bcm2835_spi_reset_hw(master);
+       bcm2835_spi_reset_hw(ctlr);
 }
 
 static int chip_match_name(struct gpio_chip *chip, void *data)
@@ -900,85 +977,88 @@ static int bcm2835_spi_setup(struct spi_device *spi)
 
 static int bcm2835_spi_probe(struct platform_device *pdev)
 {
-       struct spi_master *master;
+       struct spi_controller *ctlr;
        struct bcm2835_spi *bs;
        struct resource *res;
        int err;
 
-       master = spi_alloc_master(&pdev->dev, sizeof(*bs));
-       if (!master) {
-               dev_err(&pdev->dev, "spi_alloc_master() failed\n");
+       ctlr = spi_alloc_master(&pdev->dev, sizeof(*bs));
+       if (!ctlr)
                return -ENOMEM;
-       }
 
-       platform_set_drvdata(pdev, master);
+       platform_set_drvdata(pdev, ctlr);
 
-       master->mode_bits = BCM2835_SPI_MODE_BITS;
-       master->bits_per_word_mask = SPI_BPW_MASK(8);
-       master->num_chipselect = 3;
-       master->setup = bcm2835_spi_setup;
-       master->transfer_one = bcm2835_spi_transfer_one;
-       master->handle_err = bcm2835_spi_handle_err;
-       master->prepare_message = bcm2835_spi_prepare_message;
-       master->dev.of_node = pdev->dev.of_node;
+       ctlr->mode_bits = BCM2835_SPI_MODE_BITS;
+       ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
+       ctlr->num_chipselect = 3;
+       ctlr->setup = bcm2835_spi_setup;
+       ctlr->transfer_one = bcm2835_spi_transfer_one;
+       ctlr->handle_err = bcm2835_spi_handle_err;
+       ctlr->prepare_message = bcm2835_spi_prepare_message;
+       ctlr->dev.of_node = pdev->dev.of_node;
 
-       bs = spi_master_get_devdata(master);
+       bs = spi_controller_get_devdata(ctlr);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        bs->regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(bs->regs)) {
                err = PTR_ERR(bs->regs);
-               goto out_master_put;
+               goto out_controller_put;
        }
 
        bs->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(bs->clk)) {
                err = PTR_ERR(bs->clk);
                dev_err(&pdev->dev, "could not get clk: %d\n", err);
-               goto out_master_put;
+               goto out_controller_put;
        }
 
        bs->irq = platform_get_irq(pdev, 0);
        if (bs->irq <= 0) {
                dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq);
                err = bs->irq ? bs->irq : -ENODEV;
-               goto out_master_put;
+               goto out_controller_put;
        }
 
        clk_prepare_enable(bs->clk);
 
-       bcm2835_dma_init(master, &pdev->dev);
+       bcm2835_dma_init(ctlr, &pdev->dev);
 
        /* initialise the hardware with the default polarities */
        bcm2835_wr(bs, BCM2835_SPI_CS,
                   BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
 
        err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0,
-                              dev_name(&pdev->dev), master);
+                              dev_name(&pdev->dev), ctlr);
        if (err) {
                dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
                goto out_clk_disable;
        }
 
-       err = devm_spi_register_master(&pdev->dev, master);
+       err = devm_spi_register_controller(&pdev->dev, ctlr);
        if (err) {
-               dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
+               dev_err(&pdev->dev, "could not register SPI controller: %d\n",
+                       err);
                goto out_clk_disable;
        }
 
+       bcm2835_debugfs_create(bs, dev_name(&pdev->dev));
+
        return 0;
 
 out_clk_disable:
        clk_disable_unprepare(bs->clk);
-out_master_put:
-       spi_master_put(master);
+out_controller_put:
+       spi_controller_put(ctlr);
        return err;
 }
 
 static int bcm2835_spi_remove(struct platform_device *pdev)
 {
-       struct spi_master *master = platform_get_drvdata(pdev);
-       struct bcm2835_spi *bs = spi_master_get_devdata(master);
+       struct spi_controller *ctlr = platform_get_drvdata(pdev);
+       struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+
+       bcm2835_debugfs_remove(bs);
 
        /* Clear FIFOs, and disable the HW block */
        bcm2835_wr(bs, BCM2835_SPI_CS,
@@ -986,7 +1066,7 @@ static int bcm2835_spi_remove(struct platform_device *pdev)
 
        clk_disable_unprepare(bs->clk);
 
-       bcm2835_dma_release(master);
+       bcm2835_dma_release(ctlr);
 
        return 0;
 }
index 40dfb7f..bb57035 100644 (file)
@@ -496,10 +496,8 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
        int err;
 
        master = spi_alloc_master(&pdev->dev, sizeof(*bs));
-       if (!master) {
-               dev_err(&pdev->dev, "spi_alloc_master() failed\n");
+       if (!master)
                return -ENOMEM;
-       }
 
        platform_set_drvdata(pdev, master);
        master->mode_bits = (SPI_CPOL | SPI_CS_HIGH | SPI_NO_CS);
index dad566b..d84e22d 100644 (file)
@@ -406,7 +406,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
        if (ret)
                spi_master_put(master);
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(spi_bitbang_start);
 
index 4c71df9..1d9b33a 100644 (file)
@@ -428,7 +428,6 @@ static int fsl_spi_do_one_msg(struct spi_master *master,
        }
 
        m->status = status;
-       spi_finalize_current_message(master);
 
        if (status || !cs_change) {
                ndelay(nsecs);
@@ -436,6 +435,7 @@ static int fsl_spi_do_one_msg(struct spi_master *master,
        }
 
        fsl_spi_setup_transfer(spi, NULL);
+       spi_finalize_current_message(master);
        return 0;
 }
 
index ea4b1bf..f7fe9b1 100644 (file)
@@ -1,9 +1,9 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Driver for Amlogic Meson SPI flash controller (SPIFC)
- *
- * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Driver for Amlogic Meson SPI flash controller (SPIFC)
+//
+// Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
+//
 
 #include <linux/clk.h>
 #include <linux/delay.h>
index 10041ea..45d8a70 100644 (file)
@@ -123,8 +123,6 @@ static const struct mtk_spi_compatible mt8183_compat = {
  * supplies it.
  */
 static const struct mtk_chip_config mtk_default_chip_info = {
-       .rx_mlsb = 1,
-       .tx_mlsb = 1,
        .cs_pol = 0,
        .sample_sel = 0,
 };
@@ -195,14 +193,13 @@ static int mtk_spi_prepare_message(struct spi_master *master,
                reg_val &= ~SPI_CMD_CPOL;
 
        /* set the mlsbx and mlsbtx */
-       if (chip_config->tx_mlsb)
-               reg_val |= SPI_CMD_TXMSBF;
-       else
+       if (spi->mode & SPI_LSB_FIRST) {
                reg_val &= ~SPI_CMD_TXMSBF;
-       if (chip_config->rx_mlsb)
-               reg_val |= SPI_CMD_RXMSBF;
-       else
                reg_val &= ~SPI_CMD_RXMSBF;
+       } else {
+               reg_val |= SPI_CMD_TXMSBF;
+               reg_val |= SPI_CMD_RXMSBF;
+       }
 
        /* set the tx/rx endian */
 #ifdef __LITTLE_ENDIAN
@@ -599,7 +596,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
 
        master->auto_runtime_pm = true;
        master->dev.of_node = pdev->dev.of_node;
-       master->mode_bits = SPI_CPOL | SPI_CPHA;
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
 
        master->set_cs = mtk_spi_set_cs;
        master->prepare_message = mtk_spi_prepare_message;
index f22dbb4..4ca0a62 100644 (file)
@@ -834,10 +834,6 @@ static int spi_qup_transfer_one(struct spi_master *master,
        else
                ret = spi_qup_do_pio(spi, xfer, timeout);
 
-       if (ret)
-               goto exit;
-
-exit:
        spi_qup_set_state(controller, QUP_STATE_RESET);
        spin_lock_irqsave(&controller->lock, flags);
        if (!ret)
index 9b91188..2cc6d99 100644 (file)
@@ -417,7 +417,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
                        .direction = DMA_MEM_TO_DEV,
                        .dst_addr = rs->dma_addr_tx,
                        .dst_addr_width = rs->n_bytes,
-                       .dst_maxburst = rs->fifo_len / 2,
+                       .dst_maxburst = rs->fifo_len / 4,
                };
 
                dmaengine_slave_config(master->dma_tx, &txconf);
@@ -518,7 +518,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
        else
                writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
 
-       writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);
+       writel_relaxed(rs->fifo_len / 2, rs->regs + ROCKCHIP_SPI_DMATDLR);
        writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR);
        writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR);
 
index 6aab7b2..b50bdbc 100644 (file)
@@ -229,7 +229,7 @@ static int sh_msiof_modify_ctr_wait(struct sh_msiof_spi_priv *p,
        sh_msiof_write(p, CTR, data);
 
        return readl_poll_timeout_atomic(p->mapbase + CTR, data,
-                                        (data & mask) == set, 10, 1000);
+                                        (data & mask) == set, 1, 100);
 }
 
 static irqreturn_t sh_msiof_spi_irq(int irq, void *data)
diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c
new file mode 100644 (file)
index 0000000..c8c8d9c
--- /dev/null
@@ -0,0 +1,822 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Synquacer HSSPI controller driver
+//
+// Copyright (c) 2015-2018 Socionext Inc.
+// Copyright (c) 2018-2019 Linaro Ltd.
+//
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+
+/* HSSPI register address definitions */
+#define SYNQUACER_HSSPI_REG_MCTRL      0x00
+#define SYNQUACER_HSSPI_REG_PCC0       0x04
+#define SYNQUACER_HSSPI_REG_PCC(n)     (SYNQUACER_HSSPI_REG_PCC0 + (n) * 4)
+#define SYNQUACER_HSSPI_REG_TXF                0x14
+#define SYNQUACER_HSSPI_REG_TXE                0x18
+#define SYNQUACER_HSSPI_REG_TXC                0x1C
+#define SYNQUACER_HSSPI_REG_RXF                0x20
+#define SYNQUACER_HSSPI_REG_RXE                0x24
+#define SYNQUACER_HSSPI_REG_RXC                0x28
+#define SYNQUACER_HSSPI_REG_FAULTF     0x2C
+#define SYNQUACER_HSSPI_REG_FAULTC     0x30
+#define SYNQUACER_HSSPI_REG_DMCFG      0x34
+#define SYNQUACER_HSSPI_REG_DMSTART    0x38
+#define SYNQUACER_HSSPI_REG_DMBCC      0x3C
+#define SYNQUACER_HSSPI_REG_DMSTATUS   0x40
+#define SYNQUACER_HSSPI_REG_FIFOCFG    0x4C
+#define SYNQUACER_HSSPI_REG_TX_FIFO    0x50
+#define SYNQUACER_HSSPI_REG_RX_FIFO    0x90
+#define SYNQUACER_HSSPI_REG_MID                0xFC
+
+/* HSSPI register bit definitions */
+#define SYNQUACER_HSSPI_MCTRL_MEN                      BIT(0)
+#define SYNQUACER_HSSPI_MCTRL_COMMAND_SEQUENCE_EN      BIT(1)
+#define SYNQUACER_HSSPI_MCTRL_CDSS                     BIT(3)
+#define SYNQUACER_HSSPI_MCTRL_MES                      BIT(4)
+#define SYNQUACER_HSSPI_MCTRL_SYNCON                   BIT(5)
+
+#define SYNQUACER_HSSPI_PCC_CPHA               BIT(0)
+#define SYNQUACER_HSSPI_PCC_CPOL               BIT(1)
+#define SYNQUACER_HSSPI_PCC_ACES               BIT(2)
+#define SYNQUACER_HSSPI_PCC_RTM                        BIT(3)
+#define SYNQUACER_HSSPI_PCC_SSPOL              BIT(4)
+#define SYNQUACER_HSSPI_PCC_SDIR               BIT(7)
+#define SYNQUACER_HSSPI_PCC_SENDIAN            BIT(8)
+#define SYNQUACER_HSSPI_PCC_SAFESYNC           BIT(16)
+#define SYNQUACER_HSSPI_PCC_SS2CD_SHIFT                5U
+#define SYNQUACER_HSSPI_PCC_CDRS_MASK          0x7f
+#define SYNQUACER_HSSPI_PCC_CDRS_SHIFT         9U
+
+#define SYNQUACER_HSSPI_TXF_FIFO_FULL          BIT(0)
+#define SYNQUACER_HSSPI_TXF_FIFO_EMPTY         BIT(1)
+#define SYNQUACER_HSSPI_TXF_SLAVE_RELEASED     BIT(6)
+
+#define SYNQUACER_HSSPI_TXE_FIFO_FULL          BIT(0)
+#define SYNQUACER_HSSPI_TXE_FIFO_EMPTY         BIT(1)
+#define SYNQUACER_HSSPI_TXE_SLAVE_RELEASED     BIT(6)
+
+#define SYNQUACER_HSSPI_RXF_FIFO_MORE_THAN_THRESHOLD           BIT(5)
+#define SYNQUACER_HSSPI_RXF_SLAVE_RELEASED                     BIT(6)
+
+#define SYNQUACER_HSSPI_RXE_FIFO_MORE_THAN_THRESHOLD           BIT(5)
+#define SYNQUACER_HSSPI_RXE_SLAVE_RELEASED                     BIT(6)
+
+#define SYNQUACER_HSSPI_DMCFG_SSDC             BIT(1)
+#define SYNQUACER_HSSPI_DMCFG_MSTARTEN         BIT(2)
+
+#define SYNQUACER_HSSPI_DMSTART_START          BIT(0)
+#define SYNQUACER_HSSPI_DMSTOP_STOP            BIT(8)
+#define SYNQUACER_HSSPI_DMPSEL_CS_MASK         0x3
+#define SYNQUACER_HSSPI_DMPSEL_CS_SHIFT                16U
+#define SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT  24U
+#define SYNQUACER_HSSPI_DMTRP_DATA_MASK                0x3
+#define SYNQUACER_HSSPI_DMTRP_DATA_SHIFT       26U
+#define SYNQUACER_HSSPI_DMTRP_DATA_TXRX                0
+#define SYNQUACER_HSSPI_DMTRP_DATA_RX          1
+#define SYNQUACER_HSSPI_DMTRP_DATA_TX          2
+
+#define SYNQUACER_HSSPI_DMSTATUS_RX_DATA_MASK  0x1f
+#define SYNQUACER_HSSPI_DMSTATUS_RX_DATA_SHIFT 8U
+#define SYNQUACER_HSSPI_DMSTATUS_TX_DATA_MASK  0x1f
+#define SYNQUACER_HSSPI_DMSTATUS_TX_DATA_SHIFT 16U
+
+#define SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_MASK      0xf
+#define SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT     0U
+#define SYNQUACER_HSSPI_FIFOCFG_TX_THRESHOLD_MASK      0xf
+#define SYNQUACER_HSSPI_FIFOCFG_TX_THRESHOLD_SHIFT     4U
+#define SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_MASK                0x3
+#define SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT       8U
+#define SYNQUACER_HSSPI_FIFOCFG_RX_FLUSH               BIT(11)
+#define SYNQUACER_HSSPI_FIFOCFG_TX_FLUSH               BIT(12)
+
+#define SYNQUACER_HSSPI_FIFO_DEPTH             16U
+#define SYNQUACER_HSSPI_FIFO_TX_THRESHOLD      4U
+#define SYNQUACER_HSSPI_FIFO_RX_THRESHOLD \
+       (SYNQUACER_HSSPI_FIFO_DEPTH - SYNQUACER_HSSPI_FIFO_TX_THRESHOLD)
+
+#define SYNQUACER_HSSPI_TRANSFER_MODE_TX       BIT(1)
+#define SYNQUACER_HSSPI_TRANSFER_MODE_RX       BIT(2)
+#define SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC    2000U
+#define SYNQUACER_HSSPI_ENABLE_TMOUT_MSEC      1000U
+
+#define SYNQUACER_HSSPI_CLOCK_SRC_IHCLK                0
+#define SYNQUACER_HSSPI_CLOCK_SRC_IPCLK                1
+
+#define SYNQUACER_HSSPI_NUM_CHIP_SELECT                4U
+#define SYNQUACER_HSSPI_IRQ_NAME_MAX           32U
+
+struct synquacer_spi {
+       struct device *dev;
+       struct completion transfer_done;
+       unsigned int cs;
+       unsigned int bpw;
+       unsigned int mode;
+       unsigned int speed;
+       bool aces, rtm;
+       void *rx_buf;
+       const void *tx_buf;
+       struct clk *clk;
+       int clk_src_type;
+       void __iomem *regs;
+       u32 tx_words, rx_words;
+       unsigned int bus_width;
+       unsigned int transfer_mode;
+       char rx_irq_name[SYNQUACER_HSSPI_IRQ_NAME_MAX];
+       char tx_irq_name[SYNQUACER_HSSPI_IRQ_NAME_MAX];
+};
+
+static int read_fifo(struct synquacer_spi *sspi)
+{
+       u32 len = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTATUS);
+
+       len = (len >> SYNQUACER_HSSPI_DMSTATUS_RX_DATA_SHIFT) &
+              SYNQUACER_HSSPI_DMSTATUS_RX_DATA_MASK;
+       len = min(len, sspi->rx_words);
+
+       switch (sspi->bpw) {
+       case 8: {
+               u8 *buf = sspi->rx_buf;
+
+               readsb(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO, buf, len);
+               sspi->rx_buf = buf + len;
+               break;
+       }
+       case 16: {
+               u16 *buf = sspi->rx_buf;
+
+               readsw(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO, buf, len);
+               sspi->rx_buf = buf + len;
+               break;
+       }
+       case 24:
+               /* fallthrough, should use 32-bits access */
+       case 32: {
+               u32 *buf = sspi->rx_buf;
+
+               readsl(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO, buf, len);
+               sspi->rx_buf = buf + len;
+               break;
+       }
+       default:
+               return -EINVAL;
+       }
+
+       sspi->rx_words -= len;
+       return 0;
+}
+
+static int write_fifo(struct synquacer_spi *sspi)
+{
+       u32 len = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTATUS);
+
+       len = (len >> SYNQUACER_HSSPI_DMSTATUS_TX_DATA_SHIFT) &
+              SYNQUACER_HSSPI_DMSTATUS_TX_DATA_MASK;
+       len = min(SYNQUACER_HSSPI_FIFO_DEPTH - len,
+                   sspi->tx_words);
+
+       switch (sspi->bpw) {
+       case 8: {
+               const u8 *buf = sspi->tx_buf;
+
+               writesb(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO, buf, len);
+               sspi->tx_buf = buf + len;
+               break;
+       }
+       case 16: {
+               const u16 *buf = sspi->tx_buf;
+
+               writesw(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO, buf, len);
+               sspi->tx_buf = buf + len;
+               break;
+       }
+       case 24:
+               /* fallthrough, should use 32-bits access */
+       case 32: {
+               const u32 *buf = sspi->tx_buf;
+
+               writesl(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO, buf, len);
+               sspi->tx_buf = buf + len;
+               break;
+       }
+       default:
+               return -EINVAL;
+       }
+
+       sspi->tx_words -= len;
+       return 0;
+}
+
+static int synquacer_spi_config(struct spi_master *master,
+                               struct spi_device *spi,
+                               struct spi_transfer *xfer)
+{
+       struct synquacer_spi *sspi = spi_master_get_devdata(master);
+       unsigned int speed, mode, bpw, cs, bus_width, transfer_mode;
+       u32 rate, val, div;
+
+       /* Full Duplex only on 1-bit wide bus */
+       if (xfer->rx_buf && xfer->tx_buf &&
+           (xfer->rx_nbits != 1 || xfer->tx_nbits != 1)) {
+               dev_err(sspi->dev,
+                       "RX and TX bus widths must be 1-bit for Full-Duplex!\n");
+               return -EINVAL;
+       }
+
+       if (xfer->tx_buf) {
+               bus_width = xfer->tx_nbits;
+               transfer_mode = SYNQUACER_HSSPI_TRANSFER_MODE_TX;
+       } else {
+               bus_width = xfer->rx_nbits;
+               transfer_mode = SYNQUACER_HSSPI_TRANSFER_MODE_RX;
+       }
+
+       mode = spi->mode;
+       cs = spi->chip_select;
+       speed = xfer->speed_hz;
+       bpw = xfer->bits_per_word;
+
+       /* return if nothing to change */
+       if (speed == sspi->speed &&
+               bus_width == sspi->bus_width && bpw == sspi->bpw &&
+               mode == sspi->mode && cs == sspi->cs &&
+               transfer_mode == sspi->transfer_mode) {
+               return 0;
+       }
+
+       sspi->transfer_mode = transfer_mode;
+       rate = master->max_speed_hz;
+
+       div = DIV_ROUND_UP(rate, speed);
+       if (div > 254) {
+               dev_err(sspi->dev, "Requested rate too low (%u)\n",
+                       sspi->speed);
+               return -EINVAL;
+       }
+
+       val = readl(sspi->regs + SYNQUACER_HSSPI_REG_PCC(cs));
+       val &= ~SYNQUACER_HSSPI_PCC_SAFESYNC;
+       if (bpw == 8 && (mode & (SPI_TX_DUAL | SPI_RX_DUAL)) && div < 3)
+               val |= SYNQUACER_HSSPI_PCC_SAFESYNC;
+       if (bpw == 8 && (mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 6)
+               val |= SYNQUACER_HSSPI_PCC_SAFESYNC;
+       if (bpw == 16 && (mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 3)
+               val |= SYNQUACER_HSSPI_PCC_SAFESYNC;
+
+       if (mode & SPI_CPHA)
+               val |= SYNQUACER_HSSPI_PCC_CPHA;
+       else
+               val &= ~SYNQUACER_HSSPI_PCC_CPHA;
+
+       if (mode & SPI_CPOL)
+               val |= SYNQUACER_HSSPI_PCC_CPOL;
+       else
+               val &= ~SYNQUACER_HSSPI_PCC_CPOL;
+
+       if (mode & SPI_CS_HIGH)
+               val |= SYNQUACER_HSSPI_PCC_SSPOL;
+       else
+               val &= ~SYNQUACER_HSSPI_PCC_SSPOL;
+
+       if (mode & SPI_LSB_FIRST)
+               val |= SYNQUACER_HSSPI_PCC_SDIR;
+       else
+               val &= ~SYNQUACER_HSSPI_PCC_SDIR;
+
+       if (sspi->aces)
+               val |= SYNQUACER_HSSPI_PCC_ACES;
+       else
+               val &= ~SYNQUACER_HSSPI_PCC_ACES;
+
+       if (sspi->rtm)
+               val |= SYNQUACER_HSSPI_PCC_RTM;
+       else
+               val &= ~SYNQUACER_HSSPI_PCC_RTM;
+
+       val |= (3 << SYNQUACER_HSSPI_PCC_SS2CD_SHIFT);
+       val |= SYNQUACER_HSSPI_PCC_SENDIAN;
+
+       val &= ~(SYNQUACER_HSSPI_PCC_CDRS_MASK <<
+                SYNQUACER_HSSPI_PCC_CDRS_SHIFT);
+       val |= ((div >> 1) << SYNQUACER_HSSPI_PCC_CDRS_SHIFT);
+
+       writel(val, sspi->regs + SYNQUACER_HSSPI_REG_PCC(cs));
+
+       val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
+       val &= ~(SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_MASK <<
+                SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT);
+       val |= ((bpw / 8 - 1) << SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT);
+       writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
+
+       val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+       val &= ~(SYNQUACER_HSSPI_DMTRP_DATA_MASK <<
+                SYNQUACER_HSSPI_DMTRP_DATA_SHIFT);
+
+       if (xfer->rx_buf)
+               val |= (SYNQUACER_HSSPI_DMTRP_DATA_RX <<
+                       SYNQUACER_HSSPI_DMTRP_DATA_SHIFT);
+       else
+               val |= (SYNQUACER_HSSPI_DMTRP_DATA_TX <<
+                       SYNQUACER_HSSPI_DMTRP_DATA_SHIFT);
+
+       val &= ~(3 << SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT);
+       val |= ((bus_width >> 1) << SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT);
+       writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+
+       sspi->bpw = bpw;
+       sspi->mode = mode;
+       sspi->speed = speed;
+       sspi->cs = spi->chip_select;
+       sspi->bus_width = bus_width;
+
+       return 0;
+}
+
+static int synquacer_spi_transfer_one(struct spi_master *master,
+                                     struct spi_device *spi,
+                                     struct spi_transfer *xfer)
+{
+       struct synquacer_spi *sspi = spi_master_get_devdata(master);
+       int ret;
+       int status = 0;
+       u32 words;
+       u8 bpw;
+       u32 val;
+
+       val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+       val &= ~SYNQUACER_HSSPI_DMSTOP_STOP;
+       writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+
+       val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
+       val |= SYNQUACER_HSSPI_FIFOCFG_RX_FLUSH;
+       val |= SYNQUACER_HSSPI_FIFOCFG_TX_FLUSH;
+       writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
+
+       /*
+        * See if we can transfer 4-bytes as 1 word
+        * to maximize the FIFO buffer efficiency.
+        */
+       bpw = xfer->bits_per_word;
+       if (bpw == 8 && !(xfer->len % 4) && !(spi->mode & SPI_LSB_FIRST))
+               xfer->bits_per_word = 32;
+
+       ret = synquacer_spi_config(master, spi, xfer);
+
+       /* restore */
+       xfer->bits_per_word = bpw;
+
+       if (ret)
+               return ret;
+
+       reinit_completion(&sspi->transfer_done);
+
+       sspi->tx_buf = xfer->tx_buf;
+       sspi->rx_buf = xfer->rx_buf;
+
+       switch (sspi->bpw) {
+       case 8:
+               words = xfer->len;
+               break;
+       case 16:
+               words = xfer->len / 2;
+               break;
+       case 24:
+               /* fallthrough, should use 32-bits access */
+       case 32:
+               words = xfer->len / 4;
+               break;
+       default:
+               dev_err(sspi->dev, "unsupported bpw: %d\n", sspi->bpw);
+               return -EINVAL;
+       }
+
+       if (xfer->tx_buf)
+               sspi->tx_words = words;
+       else
+               sspi->tx_words = 0;
+
+       if (xfer->rx_buf)
+               sspi->rx_words = words;
+       else
+               sspi->rx_words = 0;
+
+       if (xfer->tx_buf) {
+               status = write_fifo(sspi);
+               if (status < 0) {
+                       dev_err(sspi->dev, "failed write_fifo. status: 0x%x\n",
+                               status);
+                       return status;
+               }
+       }
+
+       if (xfer->rx_buf) {
+               val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
+               val &= ~(SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_MASK <<
+                        SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT);
+               val |= ((sspi->rx_words > SYNQUACER_HSSPI_FIFO_DEPTH ?
+                       SYNQUACER_HSSPI_FIFO_RX_THRESHOLD : sspi->rx_words) <<
+                       SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT);
+               writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
+       }
+
+       writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_TXC);
+       writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_RXC);
+
+       /* Trigger */
+       val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+       val |= SYNQUACER_HSSPI_DMSTART_START;
+       writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+
+       if (xfer->tx_buf) {
+               val = SYNQUACER_HSSPI_TXE_FIFO_EMPTY;
+               writel(val, sspi->regs + SYNQUACER_HSSPI_REG_TXE);
+               status = wait_for_completion_timeout(&sspi->transfer_done,
+                       msecs_to_jiffies(SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC));
+               writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE);
+       }
+
+       if (xfer->rx_buf) {
+               u32 buf[SYNQUACER_HSSPI_FIFO_DEPTH];
+
+               val = SYNQUACER_HSSPI_RXE_FIFO_MORE_THAN_THRESHOLD |
+                     SYNQUACER_HSSPI_RXE_SLAVE_RELEASED;
+               writel(val, sspi->regs + SYNQUACER_HSSPI_REG_RXE);
+               status = wait_for_completion_timeout(&sspi->transfer_done,
+                       msecs_to_jiffies(SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC));
+               writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE);
+
+               /* stop RX and clean RXFIFO */
+               val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+               val |= SYNQUACER_HSSPI_DMSTOP_STOP;
+               writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+               sspi->rx_buf = buf;
+               sspi->rx_words = SYNQUACER_HSSPI_FIFO_DEPTH;
+               read_fifo(sspi);
+       }
+
+       if (status < 0) {
+               dev_err(sspi->dev, "failed to transfer. status: 0x%x\n",
+                       status);
+               return status;
+       }
+
+       return 0;
+}
+
+static void synquacer_spi_set_cs(struct spi_device *spi, bool enable)
+{
+       struct synquacer_spi *sspi = spi_master_get_devdata(spi->master);
+       u32 val;
+
+       val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+       val &= ~(SYNQUACER_HSSPI_DMPSEL_CS_MASK <<
+                SYNQUACER_HSSPI_DMPSEL_CS_SHIFT);
+       val |= spi->chip_select << SYNQUACER_HSSPI_DMPSEL_CS_SHIFT;
+       writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
+}
+
+static int synquacer_spi_wait_status_update(struct synquacer_spi *sspi,
+                                           bool enable)
+{
+       u32 val;
+       unsigned long timeout = jiffies +
+               msecs_to_jiffies(SYNQUACER_HSSPI_ENABLE_TMOUT_MSEC);
+
+       /* wait MES(Module Enable Status) is updated */
+       do {
+               val = readl(sspi->regs + SYNQUACER_HSSPI_REG_MCTRL) &
+                     SYNQUACER_HSSPI_MCTRL_MES;
+               if (enable && val)
+                       return 0;
+               if (!enable && !val)
+                       return 0;
+       } while (time_before(jiffies, timeout));
+
+       dev_err(sspi->dev, "timeout occurs in updating Module Enable Status\n");
+       return -EBUSY;
+}
+
+static int synquacer_spi_enable(struct spi_master *master)
+{
+       u32 val;
+       int status;
+       struct synquacer_spi *sspi = spi_master_get_devdata(master);
+
+       /* Disable module */
+       writel(0, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL);
+       status = synquacer_spi_wait_status_update(sspi, false);
+       if (status < 0)
+               return status;
+
+       writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE);
+       writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE);
+       writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_TXC);
+       writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_RXC);
+       writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_FAULTC);
+
+       val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMCFG);
+       val &= ~SYNQUACER_HSSPI_DMCFG_SSDC;
+       val &= ~SYNQUACER_HSSPI_DMCFG_MSTARTEN;
+       writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMCFG);
+
+       val = readl(sspi->regs + SYNQUACER_HSSPI_REG_MCTRL);
+       if (sspi->clk_src_type == SYNQUACER_HSSPI_CLOCK_SRC_IPCLK)
+               val |= SYNQUACER_HSSPI_MCTRL_CDSS;
+       else
+               val &= ~SYNQUACER_HSSPI_MCTRL_CDSS;
+
+       val &= ~SYNQUACER_HSSPI_MCTRL_COMMAND_SEQUENCE_EN;
+       val |= SYNQUACER_HSSPI_MCTRL_MEN;
+       val |= SYNQUACER_HSSPI_MCTRL_SYNCON;
+
+       /* Enable module */
+       writel(val, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL);
+       status = synquacer_spi_wait_status_update(sspi, true);
+       if (status < 0)
+               return status;
+
+       return 0;
+}
+
+static irqreturn_t sq_spi_rx_handler(int irq, void *priv)
+{
+       uint32_t val;
+       struct synquacer_spi *sspi = priv;
+
+       val = readl(sspi->regs + SYNQUACER_HSSPI_REG_RXF);
+       if ((val & SYNQUACER_HSSPI_RXF_SLAVE_RELEASED) ||
+           (val & SYNQUACER_HSSPI_RXF_FIFO_MORE_THAN_THRESHOLD)) {
+               read_fifo(sspi);
+
+               if (sspi->rx_words == 0) {
+                       writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE);
+                       complete(&sspi->transfer_done);
+               }
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static irqreturn_t sq_spi_tx_handler(int irq, void *priv)
+{
+       uint32_t val;
+       struct synquacer_spi *sspi = priv;
+
+       val = readl(sspi->regs + SYNQUACER_HSSPI_REG_TXF);
+       if (val & SYNQUACER_HSSPI_TXF_FIFO_EMPTY) {
+               if (sspi->tx_words == 0) {
+                       writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE);
+                       complete(&sspi->transfer_done);
+               } else {
+                       write_fifo(sspi);
+               }
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static int synquacer_spi_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct spi_master *master;
+       struct synquacer_spi *sspi;
+       int ret;
+       int rx_irq, tx_irq;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
+       if (!master)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, master);
+
+       sspi = spi_master_get_devdata(master);
+       sspi->dev = &pdev->dev;
+
+       init_completion(&sspi->transfer_done);
+
+       sspi->regs = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(sspi->regs)) {
+               ret = PTR_ERR(sspi->regs);
+               goto put_spi;
+       }
+
+       sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; /* Default */
+       device_property_read_u32(&pdev->dev, "socionext,ihclk-rate",
+                                &master->max_speed_hz); /* for ACPI */
+
+       if (dev_of_node(&pdev->dev)) {
+               if (device_property_match_string(&pdev->dev,
+                                        "clock-names", "iHCLK") >= 0) {
+                       sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK;
+                       sspi->clk = devm_clk_get(sspi->dev, "iHCLK");
+               } else if (device_property_match_string(&pdev->dev,
+                                               "clock-names", "iPCLK") >= 0) {
+                       sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IPCLK;
+                       sspi->clk = devm_clk_get(sspi->dev, "iPCLK");
+               } else {
+                       dev_err(&pdev->dev, "specified wrong clock source\n");
+                       ret = -EINVAL;
+                       goto put_spi;
+               }
+
+               if (IS_ERR(sspi->clk)) {
+                       if (!(PTR_ERR(sspi->clk) == -EPROBE_DEFER))
+                               dev_err(&pdev->dev, "clock not found\n");
+                       ret = PTR_ERR(sspi->clk);
+                       goto put_spi;
+               }
+
+               ret = clk_prepare_enable(sspi->clk);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to enable clock (%d)\n",
+                               ret);
+                       goto put_spi;
+               }
+
+               master->max_speed_hz = clk_get_rate(sspi->clk);
+       }
+
+       if (!master->max_speed_hz) {
+               dev_err(&pdev->dev, "missing clock source\n");
+               return -EINVAL;
+       }
+       master->min_speed_hz = master->max_speed_hz / 254;
+
+       sspi->aces = device_property_read_bool(&pdev->dev,
+                                              "socionext,set-aces");
+       sspi->rtm = device_property_read_bool(&pdev->dev, "socionext,use-rtm");
+
+       master->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT;
+
+       rx_irq = platform_get_irq(pdev, 0);
+       if (rx_irq <= 0) {
+               dev_err(&pdev->dev, "get rx_irq failed (%d)\n", rx_irq);
+               ret = rx_irq;
+               goto put_spi;
+       }
+       snprintf(sspi->rx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-rx",
+                dev_name(&pdev->dev));
+       ret = devm_request_irq(&pdev->dev, rx_irq, sq_spi_rx_handler,
+                               0, sspi->rx_irq_name, sspi);
+       if (ret) {
+               dev_err(&pdev->dev, "request rx_irq failed (%d)\n", ret);
+               goto put_spi;
+       }
+
+       tx_irq = platform_get_irq(pdev, 1);
+       if (tx_irq <= 0) {
+               dev_err(&pdev->dev, "get tx_irq failed (%d)\n", tx_irq);
+               ret = tx_irq;
+               goto put_spi;
+       }
+       snprintf(sspi->tx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-tx",
+                dev_name(&pdev->dev));
+       ret = devm_request_irq(&pdev->dev, tx_irq, sq_spi_tx_handler,
+                               0, sspi->tx_irq_name, sspi);
+       if (ret) {
+               dev_err(&pdev->dev, "request tx_irq failed (%d)\n", ret);
+               goto put_spi;
+       }
+
+       master->dev.of_node = np;
+       master->dev.fwnode = pdev->dev.fwnode;
+       master->auto_runtime_pm = true;
+       master->bus_num = pdev->id;
+
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL |
+                           SPI_TX_QUAD | SPI_RX_QUAD;
+       master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) |
+                                    SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
+
+       master->set_cs = synquacer_spi_set_cs;
+       master->transfer_one = synquacer_spi_transfer_one;
+
+       ret = synquacer_spi_enable(master);
+       if (ret)
+               goto fail_enable;
+
+       pm_runtime_set_active(sspi->dev);
+       pm_runtime_enable(sspi->dev);
+
+       ret = devm_spi_register_master(sspi->dev, master);
+       if (ret)
+               goto disable_pm;
+
+       return 0;
+
+disable_pm:
+       pm_runtime_disable(sspi->dev);
+fail_enable:
+       clk_disable_unprepare(sspi->clk);
+put_spi:
+       spi_master_put(master);
+
+       return ret;
+}
+
+static int synquacer_spi_remove(struct platform_device *pdev)
+{
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct synquacer_spi *sspi = spi_master_get_devdata(master);
+
+       pm_runtime_disable(sspi->dev);
+
+       clk_disable_unprepare(sspi->clk);
+
+       return 0;
+}
+
+static int __maybe_unused synquacer_spi_suspend(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct synquacer_spi *sspi = spi_master_get_devdata(master);
+       int ret;
+
+       ret = spi_master_suspend(master);
+       if (ret)
+               return ret;
+
+       if (!pm_runtime_suspended(dev))
+               clk_disable_unprepare(sspi->clk);
+
+       return ret;
+}
+
+static int __maybe_unused synquacer_spi_resume(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct synquacer_spi *sspi = spi_master_get_devdata(master);
+       int ret;
+
+       if (!pm_runtime_suspended(dev)) {
+               /* Ensure reconfigure during next xfer */
+               sspi->speed = 0;
+
+               ret = clk_prepare_enable(sspi->clk);
+               if (ret < 0) {
+                       dev_err(dev, "failed to enable clk (%d)\n",
+                               ret);
+                       return ret;
+               }
+
+               ret = synquacer_spi_enable(master);
+               if (ret) {
+                       dev_err(dev, "failed to enable spi (%d)\n", ret);
+                       return ret;
+               }
+       }
+
+       ret = spi_master_resume(master);
+       if (ret < 0)
+               clk_disable_unprepare(sspi->clk);
+
+       return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(synquacer_spi_pm_ops, synquacer_spi_suspend,
+                        synquacer_spi_resume);
+
+static const struct of_device_id synquacer_spi_of_match[] = {
+       {.compatible = "socionext,synquacer-spi"},
+       {}
+};
+MODULE_DEVICE_TABLE(of, synquacer_spi_of_match);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id synquacer_hsspi_acpi_ids[] = {
+       { "SCX0004" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(acpi, synquacer_hsspi_acpi_ids);
+#endif
+
+static struct platform_driver synquacer_spi_driver = {
+       .driver = {
+               .name = "synquacer-spi",
+               .pm = &synquacer_spi_pm_ops,
+               .of_match_table = synquacer_spi_of_match,
+               .acpi_match_table = ACPI_PTR(synquacer_hsspi_acpi_ids),
+       },
+       .probe = synquacer_spi_probe,
+       .remove = synquacer_spi_remove,
+};
+module_platform_driver(synquacer_spi_driver);
+
+MODULE_DESCRIPTION("Socionext Synquacer HS-SPI controller driver");
+MODULE_AUTHOR("Masahisa Kojima <masahisa.kojima@linaro.org>");
+MODULE_AUTHOR("Jassi Brar <jaswinder.singh@linaro.org>");
+MODULE_LICENSE("GPL v2");
index d22f4d1..39374c2 100644 (file)
                (reg = (((val) & 0x1) << ((cs) * 8 + 5)) |      \
                        ((reg) & ~(1 << ((cs) * 8 + 5))))
 #define SPI_SET_CYCLES_BETWEEN_PACKETS(reg, cs, val)           \
-               (reg = (((val) & 0xF) << ((cs) * 8)) |          \
-                       ((reg) & ~(0xF << ((cs) * 8))))
+               (reg = (((val) & 0x1F) << ((cs) * 8)) |         \
+                       ((reg) & ~(0x1F << ((cs) * 8))))
+#define MAX_SETUP_HOLD_CYCLES                  16
+#define MAX_INACTIVE_CYCLES                    32
 
 #define SPI_TRANS_STATUS                       0x010
 #define SPI_BLK_CNT(val)                       (((val) >> 0) & 0xFFFF)
@@ -156,6 +158,11 @@ struct tegra_spi_soc_data {
        bool has_intr_mask_reg;
 };
 
+struct tegra_spi_client_data {
+       int tx_clk_tap_delay;
+       int rx_clk_tap_delay;
+};
+
 struct tegra_spi_data {
        struct device                           *dev;
        struct spi_master                       *master;
@@ -182,6 +189,7 @@ struct tegra_spi_data {
        unsigned                                dma_buf_size;
        unsigned                                max_buf_size;
        bool                                    is_curr_dma_xfer;
+       bool                                    use_hw_based_cs;
 
        struct completion                       rx_dma_complete;
        struct completion                       tx_dma_complete;
@@ -194,6 +202,10 @@ struct tegra_spi_data {
        u32                                     command1_reg;
        u32                                     dma_control_reg;
        u32                                     def_command1_reg;
+       u32                                     def_command2_reg;
+       u32                                     spi_cs_timing1;
+       u32                                     spi_cs_timing2;
+       u8                                      last_used_cs;
 
        struct completion                       xfer_completion;
        struct spi_transfer                     *curr_xfer;
@@ -711,14 +723,55 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi,
        dma_release_channel(dma_chan);
 }
 
+static void tegra_spi_set_hw_cs_timing(struct spi_device *spi, u8 setup_dly,
+                                      u8 hold_dly, u8 inactive_dly)
+{
+       struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+       u32 setup_hold;
+       u32 spi_cs_timing;
+       u32 inactive_cycles;
+       u8 cs_state;
+
+       setup_dly = min_t(u8, setup_dly, MAX_SETUP_HOLD_CYCLES);
+       hold_dly = min_t(u8, hold_dly, MAX_SETUP_HOLD_CYCLES);
+       if (setup_dly && hold_dly) {
+               setup_hold = SPI_SETUP_HOLD(setup_dly - 1, hold_dly - 1);
+               spi_cs_timing = SPI_CS_SETUP_HOLD(tspi->spi_cs_timing1,
+                                                 spi->chip_select,
+                                                 setup_hold);
+               if (tspi->spi_cs_timing1 != spi_cs_timing) {
+                       tspi->spi_cs_timing1 = spi_cs_timing;
+                       tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING1);
+               }
+       }
+
+       inactive_cycles = min_t(u8, inactive_dly, MAX_INACTIVE_CYCLES);
+       if (inactive_cycles)
+               inactive_cycles--;
+       cs_state = inactive_cycles ? 0 : 1;
+       spi_cs_timing = tspi->spi_cs_timing2;
+       SPI_SET_CS_ACTIVE_BETWEEN_PACKETS(spi_cs_timing, spi->chip_select,
+                                         cs_state);
+       SPI_SET_CYCLES_BETWEEN_PACKETS(spi_cs_timing, spi->chip_select,
+                                      inactive_cycles);
+       if (tspi->spi_cs_timing2 != spi_cs_timing) {
+               tspi->spi_cs_timing2 = spi_cs_timing;
+               tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING2);
+       }
+}
+
 static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
-               struct spi_transfer *t, bool is_first_of_msg)
+                                       struct spi_transfer *t,
+                                       bool is_first_of_msg,
+                                       bool is_single_xfer)
 {
        struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+       struct tegra_spi_client_data *cdata = spi->controller_data;
        u32 speed = t->speed_hz;
        u8 bits_per_word = t->bits_per_word;
-       u32 command1;
+       u32 command1, command2;
        int req_mode;
+       u32 tx_tap = 0, rx_tap = 0;
 
        if (speed != tspi->cur_speed) {
                clk_set_rate(tspi->clk, speed);
@@ -765,13 +818,34 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
                } else
                        tegra_spi_writel(tspi, command1, SPI_COMMAND1);
 
-               command1 |= SPI_CS_SW_HW;
-               if (spi->mode & SPI_CS_HIGH)
-                       command1 |= SPI_CS_SW_VAL;
-               else
-                       command1 &= ~SPI_CS_SW_VAL;
+               /* GPIO based chip select control */
+               if (spi->cs_gpiod)
+                       gpiod_set_value(spi->cs_gpiod, 1);
+
+               if (is_single_xfer && !(t->cs_change)) {
+                       tspi->use_hw_based_cs = true;
+                       command1 &= ~(SPI_CS_SW_HW | SPI_CS_SW_VAL);
+               } else {
+                       tspi->use_hw_based_cs = false;
+                       command1 |= SPI_CS_SW_HW;
+                       if (spi->mode & SPI_CS_HIGH)
+                               command1 |= SPI_CS_SW_VAL;
+                       else
+                               command1 &= ~SPI_CS_SW_VAL;
+               }
+
+               if (tspi->last_used_cs != spi->chip_select) {
+                       if (cdata && cdata->tx_clk_tap_delay)
+                               tx_tap = cdata->tx_clk_tap_delay;
+                       if (cdata && cdata->rx_clk_tap_delay)
+                               rx_tap = cdata->rx_clk_tap_delay;
+                       command2 = SPI_TX_TAP_DELAY(tx_tap) |
+                                  SPI_RX_TAP_DELAY(rx_tap);
+                       if (command2 != tspi->def_command2_reg)
+                               tegra_spi_writel(tspi, command2, SPI_COMMAND2);
+                       tspi->last_used_cs = spi->chip_select;
+               }
 
-               tegra_spi_writel(tspi, 0, SPI_COMMAND2);
        } else {
                command1 = tspi->command1_reg;
                command1 &= ~SPI_BIT_LENGTH(~0);
@@ -827,9 +901,42 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi,
        return ret;
 }
 
+static struct tegra_spi_client_data
+       *tegra_spi_parse_cdata_dt(struct spi_device *spi)
+{
+       struct tegra_spi_client_data *cdata;
+       struct device_node *slave_np;
+
+       slave_np = spi->dev.of_node;
+       if (!slave_np) {
+               dev_dbg(&spi->dev, "device node not found\n");
+               return NULL;
+       }
+
+       cdata = kzalloc(sizeof(*cdata), GFP_KERNEL);
+       if (!cdata)
+               return NULL;
+
+       of_property_read_u32(slave_np, "nvidia,tx-clk-tap-delay",
+                            &cdata->tx_clk_tap_delay);
+       of_property_read_u32(slave_np, "nvidia,rx-clk-tap-delay",
+                            &cdata->rx_clk_tap_delay);
+       return cdata;
+}
+
+static void tegra_spi_cleanup(struct spi_device *spi)
+{
+       struct tegra_spi_client_data *cdata = spi->controller_data;
+
+       spi->controller_data = NULL;
+       if (spi->dev.of_node)
+               kfree(cdata);
+}
+
 static int tegra_spi_setup(struct spi_device *spi)
 {
        struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+       struct tegra_spi_client_data *cdata = spi->controller_data;
        u32 val;
        unsigned long flags;
        int ret;
@@ -840,9 +947,16 @@ static int tegra_spi_setup(struct spi_device *spi)
                spi->mode & SPI_CPHA ? "" : "~",
                spi->max_speed_hz);
 
+       if (!cdata) {
+               cdata = tegra_spi_parse_cdata_dt(spi);
+               spi->controller_data = cdata;
+       }
+
        ret = pm_runtime_get_sync(tspi->dev);
        if (ret < 0) {
                dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
+               if (cdata)
+                       tegra_spi_cleanup(spi);
                return ret;
        }
 
@@ -853,6 +967,10 @@ static int tegra_spi_setup(struct spi_device *spi)
        }
 
        spin_lock_irqsave(&tspi->lock, flags);
+       /* GPIO based chip select control */
+       if (spi->cs_gpiod)
+               gpiod_set_value(spi->cs_gpiod, 0);
+
        val = tspi->def_command1_reg;
        if (spi->mode & SPI_CS_HIGH)
                val &= ~SPI_CS_POL_INACTIVE(spi->chip_select);
@@ -882,11 +1000,18 @@ static void tegra_spi_transfer_end(struct spi_device *spi)
        struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
        int cs_val = (spi->mode & SPI_CS_HIGH) ? 0 : 1;
 
-       if (cs_val)
-               tspi->command1_reg |= SPI_CS_SW_VAL;
-       else
-               tspi->command1_reg &= ~SPI_CS_SW_VAL;
-       tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
+       /* GPIO based chip select control */
+       if (spi->cs_gpiod)
+               gpiod_set_value(spi->cs_gpiod, 0);
+
+       if (!tspi->use_hw_based_cs) {
+               if (cs_val)
+                       tspi->command1_reg |= SPI_CS_SW_VAL;
+               else
+                       tspi->command1_reg &= ~SPI_CS_SW_VAL;
+               tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
+       }
+
        tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
 }
 
@@ -913,16 +1038,19 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
        struct spi_device *spi = msg->spi;
        int ret;
        bool skip = false;
+       int single_xfer;
 
        msg->status = 0;
        msg->actual_length = 0;
 
+       single_xfer = list_is_singular(&msg->transfers);
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
                u32 cmd1;
 
                reinit_completion(&tspi->xfer_completion);
 
-               cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg);
+               cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg,
+                                                   single_xfer);
 
                if (!xfer->len) {
                        ret = 0;
@@ -955,6 +1083,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
                        reset_control_assert(tspi->rst);
                        udelay(2);
                        reset_control_deassert(tspi->rst);
+                       tspi->last_used_cs = master->num_chipselect + 1;
                        goto complete_xfer;
                }
 
@@ -1188,11 +1317,14 @@ static int tegra_spi_probe(struct platform_device *pdev)
                master->max_speed_hz = 25000000; /* 25MHz */
 
        /* the spi->mode bits understood by this driver: */
+       master->use_gpio_descriptors = true;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
                            SPI_TX_DUAL | SPI_RX_DUAL | SPI_3WIRE;
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
        master->setup = tegra_spi_setup;
+       master->cleanup = tegra_spi_cleanup;
        master->transfer_one_message = tegra_spi_transfer_one_message;
+       master->set_cs_timing = tegra_spi_set_hw_cs_timing;
        master->num_chipselect = MAX_CHIP_SELECT;
        master->auto_runtime_pm = true;
        bus_num = of_alias_get_id(pdev->dev.of_node, "spi");
@@ -1268,6 +1400,10 @@ static int tegra_spi_probe(struct platform_device *pdev)
        reset_control_deassert(tspi->rst);
        tspi->def_command1_reg  = SPI_M_S;
        tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
+       tspi->spi_cs_timing1 = tegra_spi_readl(tspi, SPI_CS_TIMING1);
+       tspi->spi_cs_timing2 = tegra_spi_readl(tspi, SPI_CS_TIMING2);
+       tspi->def_command2_reg = tegra_spi_readl(tspi, SPI_COMMAND2);
+       tspi->last_used_cs = master->num_chipselect + 1;
        pm_runtime_put(&pdev->dev);
        ret = request_threaded_irq(tspi->irq, tegra_spi_isr,
                                   tegra_spi_isr_thread, IRQF_ONESHOT,
@@ -1340,6 +1476,8 @@ static int tegra_spi_resume(struct device *dev)
                return ret;
        }
        tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
+       tegra_spi_writel(tspi, tspi->def_command2_reg, SPI_COMMAND2);
+       tspi->last_used_cs = master->num_chipselect + 1;
        pm_runtime_put(dev);
 
        return spi_master_resume(master);
index 5e75944..bced687 100644 (file)
@@ -1090,6 +1090,60 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
        return 0;
 }
 
+static void _spi_transfer_delay_ns(u32 ns)
+{
+       if (!ns)
+               return;
+       if (ns <= 1000) {
+               ndelay(ns);
+       } else {
+               u32 us = DIV_ROUND_UP(ns, 1000);
+
+               if (us <= 10)
+                       udelay(us);
+               else
+                       usleep_range(us, us + DIV_ROUND_UP(us, 10));
+       }
+}
+
+static void _spi_transfer_cs_change_delay(struct spi_message *msg,
+                                         struct spi_transfer *xfer)
+{
+       u32 delay = xfer->cs_change_delay;
+       u32 unit = xfer->cs_change_delay_unit;
+       u32 hz;
+
+       /* return early on "fast" mode - for everything but USECS */
+       if (!delay && unit != SPI_DELAY_UNIT_USECS)
+               return;
+
+       switch (unit) {
+       case SPI_DELAY_UNIT_USECS:
+               /* for compatibility use default of 10us */
+               if (!delay)
+                       delay = 10000;
+               else
+                       delay *= 1000;
+               break;
+       case SPI_DELAY_UNIT_NSECS: /* nothing to do here */
+               break;
+       case SPI_DELAY_UNIT_SCK:
+               /* if there is no effective speed know, then approximate
+                * by underestimating with half the requested hz
+                */
+               hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2;
+               delay *= DIV_ROUND_UP(1000000000, hz);
+               break;
+       default:
+               dev_err_once(&msg->spi->dev,
+                            "Use of unsupported delay unit %i, using default of 10us\n",
+                            xfer->cs_change_delay_unit);
+               delay = 10000;
+       }
+       /* now sleep for the requested amount of time */
+       _spi_transfer_delay_ns(delay);
+}
+
 /*
  * spi_transfer_one_message - Default implementation of transfer_one_message()
  *
@@ -1148,14 +1202,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
                if (msg->status != -EINPROGRESS)
                        goto out;
 
-               if (xfer->delay_usecs) {
-                       u16 us = xfer->delay_usecs;
-
-                       if (us <= 10)
-                               udelay(us);
-                       else
-                               usleep_range(us, us + DIV_ROUND_UP(us, 10));
-               }
+               if (xfer->delay_usecs)
+                       _spi_transfer_delay_ns(xfer->delay_usecs * 1000);
 
                if (xfer->cs_change) {
                        if (list_is_last(&xfer->transfer_list,
@@ -1163,7 +1211,7 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
                                keep_cs = true;
                        } else {
                                spi_set_cs(msg->spi, false);
-                               udelay(10);
+                               _spi_transfer_cs_change_delay(msg, xfer);
                                spi_set_cs(msg->spi, true);
                        }
                }
@@ -1181,10 +1229,10 @@ out:
        if (msg->status && ctlr->handle_err)
                ctlr->handle_err(ctlr, msg);
 
-       spi_finalize_current_message(ctlr);
-
        spi_res_release(ctlr, msg);
 
+       spi_finalize_current_message(ctlr);
+
        return ret;
 }
 
@@ -1307,10 +1355,15 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
                ret = ctlr->prepare_transfer_hardware(ctlr);
                if (ret) {
                        dev_err(&ctlr->dev,
-                               "failed to prepare transfer hardware\n");
+                               "failed to prepare transfer hardware: %d\n",
+                               ret);
 
                        if (ctlr->auto_runtime_pm)
                                pm_runtime_put(ctlr->dev.parent);
+
+                       ctlr->cur_msg->status = ret;
+                       spi_finalize_current_message(ctlr);
+
                        mutex_unlock(&ctlr->io_mutex);
                        return;
                }
@@ -2697,8 +2750,7 @@ struct spi_replaced_transfers *spi_replace_transfers(
 
        /* allocate the structure using spi_res */
        rxfer = spi_res_alloc(msg->spi, __spi_replace_transfers_release,
-                             insert * sizeof(struct spi_transfer)
-                             + sizeof(struct spi_replaced_transfers)
+                             struct_size(rxfer, inserted_transfers, insert)
                              + extradatasize,
                              gfp);
        if (!rxfer)
@@ -3078,6 +3130,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
         */
        message->frame_length = 0;
        list_for_each_entry(xfer, &message->transfers, transfer_list) {
+               xfer->effective_speed_hz = 0;
                message->frame_length += xfer->len;
                if (!xfer->bits_per_word)
                        xfer->bits_per_word = spi->bits_per_word;
@@ -3757,4 +3810,3 @@ err0:
  * include needing to have boardinfo data structures be much more public.
  */
 postcore_initcall(spi_init);
-
index 422bac8..255786f 100644 (file)
@@ -663,6 +663,8 @@ static const struct of_device_id spidev_dt_ids[] = {
        { .compatible = "ge,achc" },
        { .compatible = "semtech,sx1301" },
        { .compatible = "lwn,bk4" },
+       { .compatible = "dh,dhcom-board" },
+       { .compatible = "menlo,m53cpld" },
        {},
 };
 MODULE_DEVICE_TABLE(of, spidev_dt_ids);
index ba4e4bb..8d5df58 100644 (file)
@@ -14,8 +14,6 @@
 
 /* Board specific platform_data */
 struct mtk_chip_config {
-       u32 tx_mlsb;
-       u32 rx_mlsb;
        u32 cs_pol;
        u32 sample_sel;
 };
index 053abd2..d0c5ba7 100644 (file)
@@ -735,6 +735,9 @@ extern void spi_res_release(struct spi_controller *ctlr,
  * @bits_per_word: select a bits_per_word other than the device default
  *      for this transfer. If 0 the default (from @spi_device) is used.
  * @cs_change: affects chipselect after this transfer completes
+ * @cs_change_delay: delay between cs deassert and assert when
+ *      @cs_change is set and @spi_transfer is not the last in @spi_message
+ * @cs_change_delay_unit: unit of cs_change_delay
  * @delay_usecs: microseconds to delay after this transfer before
  *     (optionally) changing the chipselect status, then starting
  *     the next transfer or completing this @spi_message.
@@ -742,6 +745,9 @@ extern void spi_res_release(struct spi_controller *ctlr,
  *     (set by bits_per_word) transmission.
  * @word_delay: clock cycles to inter word delay after each word size
  *     (set by bits_per_word) transmission.
+ * @effective_speed_hz: the effective SCK-speed that was used to
+ *      transfer this transfer. Set to 0 if the spi bus driver does
+ *      not support it.
  * @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
@@ -824,9 +830,16 @@ struct spi_transfer {
        u8              bits_per_word;
        u8              word_delay_usecs;
        u16             delay_usecs;
+       u16             cs_change_delay;
+       u8              cs_change_delay_unit;
+#define SPI_DELAY_UNIT_USECS   0
+#define SPI_DELAY_UNIT_NSECS   1
+#define SPI_DELAY_UNIT_SCK     2
        u32             speed_hz;
        u16             word_delay;
 
+       u32             effective_speed_hz;
+
        struct list_head transfer_list;
 };
 
@@ -997,6 +1010,26 @@ spi_max_transfer_size(struct spi_device *spi)
        return min(tr_max, msg_max);
 }
 
+/**
+ * spi_is_bpw_supported - Check if bits per word is supported
+ * @spi: SPI device
+ * @bpw: Bits per word
+ *
+ * This function checks to see if the SPI controller supports @bpw.
+ *
+ * Returns:
+ * True if @bpw is supported, false otherwise.
+ */
+static inline bool spi_is_bpw_supported(struct spi_device *spi, u32 bpw)
+{
+       u32 bpw_mask = spi->master->bits_per_word_mask;
+
+       if (bpw == 8 || (bpw <= 32 && bpw_mask & SPI_BPW_MASK(bpw)))
+               return true;
+
+       return false;
+}
+
 /*---------------------------------------------------------------------------*/
 
 /* SPI transfer replacement methods which make use of spi_res */