Merge remote-tracking branches 'spi/fix/complete', 'spi/fix/efm32', 'spi/fix/omap2...
authorMark Brown <broonie@linaro.org>
Thu, 10 Apr 2014 22:39:52 +0000 (23:39 +0100)
committerMark Brown <broonie@linaro.org>
Thu, 10 Apr 2014 22:39:52 +0000 (23:39 +0100)
87 files changed:
Documentation/devicetree/bindings/spi/efm32-spi.txt
Documentation/devicetree/bindings/spi/qcom,spi-qup.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/sh-hspi.txt
Documentation/devicetree/bindings/spi/sh-msiof.txt
Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
Documentation/devicetree/bindings/spi/spi-rspi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-sun4i.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-sun6i.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt [new file with mode: 0644]
Documentation/spi/spidev
Documentation/spi/spidev_fdx.c
Documentation/spi/spidev_test.c
MAINTAINERS
drivers/base/power/Makefile
drivers/base/power/runtime.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/spi-altera.c
drivers/spi/spi-ath79.c
drivers/spi/spi-atmel.c
drivers/spi/spi-au1550.c
drivers/spi/spi-bcm2835.c
drivers/spi/spi-bcm63xx-hsspi.c
drivers/spi/spi-bcm63xx.c
drivers/spi/spi-bfin-sport.c
drivers/spi/spi-bfin-v3.c
drivers/spi/spi-bfin5xx.c
drivers/spi/spi-bitbang.c
drivers/spi/spi-butterfly.c
drivers/spi/spi-clps711x.c
drivers/spi/spi-coldfire-qspi.c
drivers/spi/spi-davinci.c
drivers/spi/spi-dw-mmio.c
drivers/spi/spi-dw.c
drivers/spi/spi-efm32.c
drivers/spi/spi-ep93xx.c
drivers/spi/spi-falcon.c
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-fsl-espi.c
drivers/spi/spi-fsl-lib.c
drivers/spi/spi-fsl-spi.c
drivers/spi/spi-gpio.c
drivers/spi/spi-imx.c
drivers/spi/spi-mpc512x-psc.c
drivers/spi/spi-mpc52xx-psc.c
drivers/spi/spi-mpc52xx.c
drivers/spi/spi-mxs.c
drivers/spi/spi-nuc900.c
drivers/spi/spi-oc-tiny.c
drivers/spi/spi-octeon.c
drivers/spi/spi-omap-100k.c
drivers/spi/spi-omap-uwire.c
drivers/spi/spi-omap2-mcspi.c
drivers/spi/spi-orion.c
drivers/spi/spi-pl022.c
drivers/spi/spi-ppc4xx.c
drivers/spi/spi-pxa2xx-dma.c
drivers/spi/spi-pxa2xx-pxadma.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-qup.c [new file with mode: 0644]
drivers/spi/spi-rspi.c
drivers/spi/spi-s3c24xx.c
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-sc18is602.c
drivers/spi/spi-sh-hspi.c
drivers/spi/spi-sh-msiof.c
drivers/spi/spi-sh-sci.c
drivers/spi/spi-sirf.c
drivers/spi/spi-sun4i.c [new file with mode: 0644]
drivers/spi/spi-sun6i.c [new file with mode: 0644]
drivers/spi/spi-tegra114.c
drivers/spi/spi-tegra20-sflash.c
drivers/spi/spi-tegra20-slink.c
drivers/spi/spi-ti-qspi.c
drivers/spi/spi-ti-ssp.c [deleted file]
drivers/spi/spi-topcliff-pch.c
drivers/spi/spi-txx9.c
drivers/spi/spi-xcomm.c
drivers/spi/spi-xilinx.c
drivers/spi/spi-xtensa-xtfpga.c [new file with mode: 0644]
drivers/spi/spi.c
drivers/spi/spidev.c
include/linux/platform_data/spi-s3c64xx.h
include/linux/pm_runtime.h
include/linux/spi/spi.h
include/linux/spi/spi_bitbang.h
include/uapi/linux/spi/spidev.h

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