From: michael lee <[email protected]>

support for all
* 2 spi master
* use device tree to set spi bus number for driver use
* fast read

new features for mt7620
* hardware spi flash command/user mode support
* fast read dual out. (make sure SPI_NOR_DUAL_READ flag is
  enabled at spi-nor.c, device tree also need to modify
  spi-rx-bus-width = <2>, m25p,fast-read and adjuest
  spi-max-frequency according to flash datasheet)

need verify
* gpio pin as chip select
* second spi master
* fast read quad out

test results on mt7620. use dd read bs=512 with 15744 records
old driver : 20.88s
new driver : 11.30s
new driver + fast read + clock from 10MHz to 80MHz : 1.83s
new driver + fast read dual out + 80MHz clock : 1.18s

Signed-off-by: Michael Lee <[email protected]>
---
 target/linux/ramips/dts/mt7620a.dtsi               |  32 +-
 target/linux/ramips/dts/mt7620n.dtsi               |  32 +-
 target/linux/ramips/dts/rt3050.dtsi                |   6 +-
 target/linux/ramips/dts/rt3352.dtsi                |  31 +-
 target/linux/ramips/dts/rt3883.dtsi                |  25 +-
 target/linux/ramips/dts/rt5350.dtsi                |  29 +-
 ...0050-SPI-ralink-add-Ralink-SoC-spi-driver.patch | 837 ++++++++++++++++-----
 .../0051-rt5350-spi-second-device.patch            | 368 ---------
 8 files changed, 796 insertions(+), 564 deletions(-)
 delete mode 100644 
target/linux/ramips/patches-3.18/0051-rt5350-spi-second-device.patch

diff --git a/target/linux/ramips/dts/mt7620a.dtsi 
b/target/linux/ramips/dts/mt7620a.dtsi
index 80e8977..5b39c84 100644
--- a/target/linux/ramips/dts/mt7620a.dtsi
+++ b/target/linux/ramips/dts/mt7620a.dtsi
@@ -20,6 +20,11 @@
                compatible = "mti,cpu-interrupt-controller";
        };
 
+       aliases {
+               spi0 = &spi0;
+               spi1 = &spi1;
+       };
+
        palmbus@10000000 {
                compatible = "palmbus";
                reg = <0x10000000 0x200000>;
@@ -202,9 +207,9 @@
                        status = "disabled";
                };
 
-               spi@b00 {
+               spi0: spi@b00 {
                        compatible = "ralink,mt7620a-spi", "ralink,rt2880-spi";
-                       reg = <0xb00 0x100>;
+                       reg = <0xb00 0x40>;
 
                        resets = <&rstctrl 18>;
                        reset-names = "spi";
@@ -218,6 +223,22 @@
                        pinctrl-0 = <&spi_pins>;
                };
 
+               spi1: spi@b40 {
+                       compatible = "ralink,rt2880-spi";
+                       reg = <0xb40 0x60>;
+
+                       resets = <&rstctrl 18>;
+                       reset-names = "spi";
+
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       status = "disabled";
+
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&spi_cs1>;
+               };
+
                uartlite@c00 {
                        compatible = "ralink,mt7620a-uart", 
"ralink,rt2880-uart", "ns16550a";
                        reg = <0xc00 0x100>;
@@ -305,6 +326,13 @@
                        };
                };
 
+               spi_cs1: spi1 {
+                       spi1 {
+                               ralink,group = "spi_cs1";
+                               ralink,function = "spi_cs1";
+                       };
+               };
+
                i2c_pins: i2c {
                        i2c {
                                ralink,group = "i2c";
diff --git a/target/linux/ramips/dts/mt7620n.dtsi 
b/target/linux/ramips/dts/mt7620n.dtsi
index e886c6f..61fff00 100644
--- a/target/linux/ramips/dts/mt7620n.dtsi
+++ b/target/linux/ramips/dts/mt7620n.dtsi
@@ -20,6 +20,11 @@
                compatible = "mti,cpu-interrupt-controller";
        };
 
+       aliases {
+               spi0 = &spi0;
+               spi1 = &spi1;
+       };
+
        palmbus@10000000 {
                compatible = "palmbus";
                reg = <0x10000000 0x200000>;
@@ -154,9 +159,9 @@
                        status = "disabled";
                };
 
-               spi@b00 {
+               spi0: spi@b00 {
                        compatible = "ralink,mt7620a-spi", "ralink,rt2880-spi";
-                       reg = <0xb00 0x100>;
+                       reg = <0xb00 0x40>;
 
                        resets = <&rstctrl 18>;
                        reset-names = "spi";
@@ -170,6 +175,22 @@
                        pinctrl-0 = <&spi_pins>;
                };
 
+               spi1: spi@b40 {
+                       compatible = "ralink,rt2880-spi";
+                       reg = <0xb40 0x60>;
+
+                       resets = <&rstctrl 18>;
+                       reset-names = "spi";
+
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       status = "disabled";
+
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&spi_cs1>;
+               };
+
                uartlite@c00 {
                        compatible = "ralink,mt7620a-uart", 
"ralink,rt2880-uart", "ns16550a";
                        reg = <0xc00 0x100>;
@@ -213,6 +234,13 @@
                        };
                };
 
+               spi_cs1: spi1 {
+                       spi1 {
+                               ralink,group = "spi_cs1";
+                               ralink,function = "spi_cs1";
+                       };
+               };
+
                uartlite_pins: uartlite {
                        uart {
                                ralink,group = "uartlite";
diff --git a/target/linux/ramips/dts/rt3050.dtsi 
b/target/linux/ramips/dts/rt3050.dtsi
index 27e4179..7f0fb4a 100644
--- a/target/linux/ramips/dts/rt3050.dtsi
+++ b/target/linux/ramips/dts/rt3050.dtsi
@@ -13,6 +13,10 @@
                bootargs = "console=ttyS0,57600";
        };
 
+       aliases {
+               spi0 = &spi0;
+       };
+
        cpuintc: cpuintc@0 {
                #address-cells = <0>;
                #interrupt-cells = <1>;
@@ -144,7 +148,7 @@
                        status = "disabled";
                };
 
-               spi@b00 {
+               spi0: spi@b00 {
                        compatible = "ralink,rt3050-spi", "ralink,rt2880-spi";
                        reg = <0xb00 0x100>;
 
diff --git a/target/linux/ramips/dts/rt3352.dtsi 
b/target/linux/ramips/dts/rt3352.dtsi
index 009277f..89296f8 100644
--- a/target/linux/ramips/dts/rt3352.dtsi
+++ b/target/linux/ramips/dts/rt3352.dtsi
@@ -20,6 +20,11 @@
                compatible = "mti,cpu-interrupt-controller";
        };
 
+       aliases {
+               spi0 = &spi0;
+               spi1 = &spi1;
+       };
+
        palmbus@10000000 {
                compatible = "palmbus";
                reg = <0x10000000 0x200000>;
@@ -140,9 +145,9 @@
                        status = "disabled";
                };
 
-               spi@b00 {
+               spi0: spi@b00 {
                        compatible = "ralink,rt3352-spi", "ralink,rt2880-spi";
-                       reg = <0xb00 0x100>;
+                       reg = <0xb00 0x40>;
                        #address-cells = <1>;
                        #size-cells = <1>;
 
@@ -155,6 +160,21 @@
                        status = "disabled";
                };
 
+               spi1: spi@b40 {
+                       compatible = "ralink,rt3352-spi", "ralink,rt2880-spi";
+                       reg = <0xb40 0x60>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       resets = <&rstctrl 18>;
+                       reset-names = "spi";
+
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&spi_cs1>;
+
+                       status = "disabled";
+               };
+
                uartlite@c00 {
                        compatible = "ralink,rt3352-uart", 
"ralink,rt2880-uart", "ns16550a";
                        reg = <0xc00 0x100>;
@@ -188,6 +208,13 @@
                        };
                };
 
+               spi_cs1: spi1 {
+                       spi1 {
+                               ralink,group = "spi_cs1";
+                               ralink,function = "spi_cs1";
+                       };
+               };
+
                uartlite_pins: uartlite {
                        uart {
                                ralink,group = "uartlite";
diff --git a/target/linux/ramips/dts/rt3883.dtsi 
b/target/linux/ramips/dts/rt3883.dtsi
index dc26782..6592b3b 100644
--- a/target/linux/ramips/dts/rt3883.dtsi
+++ b/target/linux/ramips/dts/rt3883.dtsi
@@ -15,6 +15,7 @@
 
        aliases {
                spi0 = &spi0;
+               spi1 = &spi1;
        };
 
        cpuintc: cpuintc@0 {
@@ -166,7 +167,7 @@
 
                spi0: spi@b00 {
                        compatible = "ralink,rt3883-spi", "ralink,rt2880-spi";
-                       reg = <0xb00 0x100>;
+                       reg = <0xb00 0x40>;
                        #address-cells = <1>;
                        #size-cells = <0>;
 
@@ -179,6 +180,21 @@
                        status = "disabled";
                };
 
+               spi1: spi@b40 {
+                       compatible = "ralink,rt3883-spi", "ralink,rt2880-spi";
+                       reg = <0xb40 0x60>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       resets = <&rstctrl 18>;
+                       reset-names = "spi";
+
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&spi_cs1>;
+
+                       status = "disabled";
+               };
+
                uartlite@c00 {
                        compatible = "ralink,rt3883-uart", 
"ralink,rt2880-uart", "ns16550a";
                        reg = <0xc00 0x100>;
@@ -212,6 +228,13 @@
                        };
                };
 
+               spi_cs1: spi1 {
+                       spi1 {
+                               ralink,group = "spi_cs1";
+                               ralink,function = "spi_cs1";
+                       };
+               };
+
                uartlite_pins: uartlite {
                        uart {
                                ralink,group = "uartlite";
diff --git a/target/linux/ramips/dts/rt5350.dtsi 
b/target/linux/ramips/dts/rt5350.dtsi
index 5282e5b..8a9ef5c 100644
--- a/target/linux/ramips/dts/rt5350.dtsi
+++ b/target/linux/ramips/dts/rt5350.dtsi
@@ -20,6 +20,11 @@
                compatible = "mti,cpu-interrupt-controller";
        };
 
+       aliases {
+               spi0 = &spi0;
+               spi1 = &spi1;
+       };
+
        palmbus@10000000 {
                compatible = "palmbus";
                reg = <0x10000000 0x200000>;
@@ -150,9 +155,25 @@
                        status = "disabled";
                };
 
-               spi@b00 {
-                       compatible = "ralink,rt5350-spi";
-                       reg = <0xb00 0x100>;
+               spi0: spi@b00 {
+                       compatible = "ralink,rt5350-spi", "ralink,rt2880-spi";
+                       reg = <0xb00 0x40>;
+
+                       resets = <&rstctrl 18>;
+                       reset-names = "spi";
+
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&spi_pins>;
+
+                       status = "disabled";
+               };
+
+               spi1: spi@b40 {
+                       compatible = "ralink,rt5350-spi", "ralink,rt2880-spi";
+                       reg = <0xb40 0x60>;
 
                        resets = <&rstctrl 18>;
                        reset-names = "spi";
@@ -161,7 +182,7 @@
                        #size-cells = <1>;
 
                        pinctrl-names = "default";
-                       pinctrl-0 = <&spi_pins &spi_cs1>;
+                       pinctrl-0 = <&spi_cs1>;
 
                        status = "disabled";
                };
diff --git 
a/target/linux/ramips/patches-3.18/0050-SPI-ralink-add-Ralink-SoC-spi-driver.patch
 
b/target/linux/ramips/patches-3.18/0050-SPI-ralink-add-Ralink-SoC-spi-driver.patch
index cb691f3..00637a7 100644
--- 
a/target/linux/ramips/patches-3.18/0050-SPI-ralink-add-Ralink-SoC-spi-driver.patch
+++ 
b/target/linux/ramips/patches-3.18/0050-SPI-ralink-add-Ralink-SoC-spi-driver.patch
@@ -41,12 +41,13 @@ Acked-by: John Crispin <[email protected]>
  spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o
 --- /dev/null
 +++ b/drivers/spi/spi-rt2880.c
-@@ -0,0 +1,432 @@
+@@ -0,0 +1,901 @@
 +/*
 + * spi-rt2880.c -- Ralink RT288x/RT305x SPI controller driver
 + *
 + * Copyright (C) 2011 Sergiy <[email protected]>
 + * Copyright (C) 2011-2013 Gabor Juhos <[email protected]>
++ * Copyright (C) 2015 Michael Lee <[email protected]>
 + *
 + * Some parts are based on spi-orion.c:
 + *   Author: Shadi Ammouri <[email protected]>
@@ -65,29 +66,45 @@ Acked-by: John Crispin <[email protected]>
 +#include <linux/io.h>
 +#include <linux/reset.h>
 +#include <linux/spi/spi.h>
++#include <linux/of_device.h>
 +#include <linux/platform_device.h>
++#include <linux/gpio.h>
++#include <linux/mtd/spi-nor.h>
++#include <linux/list.h>
++
++#include <ralink_regs.h>
 +
 +#define DRIVER_NAME                   "spi-rt2880"
-+/* only one slave is supported*/
-+#define RALINK_NUM_CHIPSELECTS                1
-+/* in usec */
-+#define RALINK_SPI_WAIT_MAX_LOOP      2000
 +
 +#define RAMIPS_SPI_STAT                       0x00
 +#define RAMIPS_SPI_CFG                        0x10
 +#define RAMIPS_SPI_CTL                        0x14
 +#define RAMIPS_SPI_DATA                       0x20
++#define RAMIPS_SPI_ADDR                       0x24
++#define RAMIPS_SPI_BS                 0x28
++#define RAMIPS_SPI_USER                       0x2C
++#define RAMIPS_SPI_TXFIFO             0x30
++#define RAMIPS_SPI_RXFIFO             0x34
 +#define RAMIPS_SPI_FIFO_STAT          0x38
++#define RAMIPS_SPI_MODE                       0x3C
++#define RAMIPS_SPI_DEV_OFFSET         0x40
++#define RAMIPS_SPI_DMA                        0x80
++#define RAMIPS_SPI_DMASTAT            0x84
++#define RAMIPS_SPI_ARBITER            0xF0
 +
 +/* SPISTAT register bit field */
 +#define SPISTAT_BUSY                  BIT(0)
 +
 +/* SPICFG register bit field */
-+#define SPICFG_LSBFIRST                       0
++#define SPICFG_ADDRMODE                       BIT(12)
++#define SPICFG_RXENVDIS                       BIT(11)
++#define SPICFG_RXCAP                  BIT(10)
++#define SPICFG_SPIENMODE              BIT(9)
 +#define SPICFG_MSBFIRST                       BIT(8)
 +#define SPICFG_SPICLKPOL              BIT(6)
 +#define SPICFG_RXCLKEDGE_FALLING      BIT(5)
 +#define SPICFG_TXCLKEDGE_FALLING      BIT(4)
++#define SPICFG_HIZSPI                 BIT(3)
 +#define SPICFG_SPICLK_PRESCALE_MASK   0x7
 +#define SPICFG_SPICLK_DIV2            0
 +#define SPICFG_SPICLK_DIV4            1
@@ -99,21 +116,109 @@ Acked-by: John Crispin <[email protected]>
 +#define SPICFG_SPICLK_DISABLE         7
 +
 +/* SPICTL register bit field */
++#define SPICTL_START                  BIT(4)
 +#define SPICTL_HIZSDO                 BIT(3)
 +#define SPICTL_STARTWR                        BIT(2)
 +#define SPICTL_STARTRD                        BIT(1)
 +#define SPICTL_SPIENA                 BIT(0)
 +
++/* SPIUSER register bit field */
++#define SPIUSER_USERMODE              BIT(21)
++#define SPIUSER_INSTR_PHASE           BIT(20)
++#define SPIUSER_ADDR_PHASE_MASK               0x7
++#define SPIUSER_ADDR_PHASE_OFFSET     17
++#define SPIUSER_MODE_PHASE            BIT(16)
++#define SPIUSER_DUMMY_PHASE_MASK      0x3
++#define SPIUSER_DUMMY_PHASE_OFFSET    14
++#define SPIUSER_DATA_PHASE_MASK               0x3
++#define SPIUSER_DATA_PHASE_OFFSET     12
++#define SPIUSER_DATA_READ             (BIT(0) << SPIUSER_DATA_PHASE_OFFSET)
++#define SPIUSER_DATA_WRITE            (BIT(1) << SPIUSER_DATA_PHASE_OFFSET)
++#define SPIUSER_ADDR_TYPE_OFFSET      9
++#define SPIUSER_MODE_TYPE_OFFSET      6
++#define SPIUSER_DUMMY_TYPE_OFFSET     3
++#define SPIUSER_DATA_TYPE_OFFSET      0
++#define SPIUSER_TRANSFER_MASK         0x7
++#define SPIUSER_TRANSFER_SINGLE               BIT(0)
++#define SPIUSER_TRANSFER_DUAL         BIT(1)
++#define SPIUSER_TRANSFER_QUAD         BIT(2)
++
++#define SPIUSER_TRANSFER_TYPE(type) ( \
++      (type << SPIUSER_ADDR_TYPE_OFFSET) | \
++      (type << SPIUSER_MODE_TYPE_OFFSET) | \
++      (type << SPIUSER_DUMMY_TYPE_OFFSET) | \
++      (type << SPIUSER_DATA_TYPE_OFFSET) \
++)
++
 +/* SPIFIFOSTAT register bit field */
++#define SPIFIFOSTAT_TXEMPTY           BIT(19)
++#define SPIFIFOSTAT_RXEMPTY           BIT(18)
 +#define SPIFIFOSTAT_TXFULL            BIT(17)
++#define SPIFIFOSTAT_RXFULL            BIT(16)
++#define SPIFIFOSTAT_FIFO_MASK         0xff
++#define SPIFIFOSTAT_TX_OFFSET         8
++#define SPIFIFOSTAT_RX_OFFSET         0
++
++#define SPI_FIFO_DEPTH                        16
++
++/* SPIMODE register bit field */
++#define SPIMODE_MODE_OFFSET           24
++#define SPIMODE_DUMMY_OFFSET          0
++
++/* SPIARB register bit field */
++#define SPICTL_ARB_EN                 BIT(31)
++#define SPICTL_CSCTL1                 BIT(16)
++#define SPI1_POR                      BIT(1)
++#define SPI0_POR                      BIT(0)
++
++#define RT2880_SPI_MODE_BITS  (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | \
++              SPI_CS_HIGH)
++#define MT7620_SPI_MODE_BITS  (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | \
++              SPI_CS_HIGH | SPI_RX_DUAL | SPI_RX_QUAD)
++
++static atomic_t hw_reset_count = ATOMIC_INIT(0);
++
++/* cmd flags */
++#define SPI_CMD_ADDR  BIT(0)
++#define SPI_CMD_DUMMY BIT(1)
++#define SPI_CMD_TX    BIT(2)
++#define SPI_CMD_RX    BIT(3)
++#define SPI_CMD_USER  BIT(4)
++#define SPI_CMD_EN4B  BIT(5)
++#define SPI_CMD_EX4B  BIT(6)
++
++/* cmd status */
++#define SPI_STATE_OPCODE      0
++#define SPI_STATE_DATA                1
++
++struct mt7620_spi_cmd {
++      u8 opcode;
++      u8 status;
++      u16 flags;
++      u32 addr;
++      const u8 *tx_buf;
++      u8 *rx_buf;
++      u32 len;
++};
++
++#define SPI_FLAG_HW_MODE      0x1
++struct rt2880_spi_ops {
++      u32 flags;
++      int (*transfer_one)(struct spi_master *master, struct spi_device *spi,
++                      struct spi_transfer *transfer);
++};
 +
 +struct rt2880_spi {
 +      struct spi_master       *master;
 +      void __iomem            *base;
-+      unsigned int            sys_freq;
-+      unsigned int            speed;
++      u32                     speed;
++      u16                     wait_loops;
++      u16                     mode;
 +      struct clk              *clk;
-+      spinlock_t              lock;
++      int                     addr_width;
++
++      struct rt2880_spi_ops   *ops;
++      struct mt7620_spi_cmd   cmd;
 +};
 +
 +static inline struct rt2880_spi *spidev_to_rt2880_spi(struct spi_device *spi)
@@ -126,7 +231,8 @@ Acked-by: John Crispin <[email protected]>
 +      return ioread32(rs->base + reg);
 +}
 +
-+static inline void rt2880_spi_write(struct rt2880_spi *rs, u32 reg, u32 val)
++static inline void rt2880_spi_write(struct rt2880_spi *rs, u32 reg,
++              const u32 val)
 +{
 +      iowrite32(val, rs->base + reg);
 +}
@@ -134,132 +240,172 @@ Acked-by: John Crispin <[email protected]>
 +static inline void rt2880_spi_setbits(struct rt2880_spi *rs, u32 reg, u32 
mask)
 +{
 +      void __iomem *addr = rs->base + reg;
-+      unsigned long flags;
-+      u32 val;
-+
-+      spin_lock_irqsave(&rs->lock, flags);
-+      val = ioread32(addr);
-+      val |= mask;
-+      iowrite32(val, addr);
-+      spin_unlock_irqrestore(&rs->lock, flags);
++
++      iowrite32((ioread32(addr) | mask), addr);
 +}
 +
 +static inline void rt2880_spi_clrbits(struct rt2880_spi *rs, u32 reg, u32 
mask)
 +{
 +      void __iomem *addr = rs->base + reg;
-+      unsigned long flags;
-+      u32 val;
-+
-+      spin_lock_irqsave(&rs->lock, flags);
-+      val = ioread32(addr);
-+      val &= ~mask;
-+      iowrite32(val, addr);
-+      spin_unlock_irqrestore(&rs->lock, flags);
++
++      iowrite32((ioread32(addr) & ~mask), addr);
 +}
 +
-+static int rt2880_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
++static u32 rt2880_spi_baudrate_get(struct spi_device *spi, unsigned int speed)
 +{
 +      struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
 +      u32 rate;
 +      u32 prescale;
-+      u32 reg;
-+
-+      dev_dbg(&spi->dev, "speed:%u\n", speed);
 +
 +      /*
 +       * the supported rates are: 2, 4, 8, ... 128
 +       * round up as we look for equal or less speed
 +       */
-+      rate = DIV_ROUND_UP(rs->sys_freq, speed);
-+      dev_dbg(&spi->dev, "rate-1:%u\n", rate);
++      rate = DIV_ROUND_UP(clk_get_rate(rs->clk), speed);
 +      rate = roundup_pow_of_two(rate);
-+      dev_dbg(&spi->dev, "rate-2:%u\n", rate);
-+
-+      /* check if requested speed is too small */
-+      if (rate > 128)
-+              return -EINVAL;
-+
-+      if (rate < 2)
-+              rate = 2;
 +
 +      /* Convert the rate to SPI clock divisor value. */
 +      prescale = ilog2(rate / 2);
-+      dev_dbg(&spi->dev, "prescale:%u\n", prescale);
 +
-+      reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
-+      reg = ((reg & ~SPICFG_SPICLK_PRESCALE_MASK) | prescale);
-+      rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
++      /* some tolerance. double and add 100 */
++      rs->wait_loops = (8 * HZ * loops_per_jiffy) /
++              (clk_get_rate(rs->clk) / rate);
++      rs->wait_loops = (rs->wait_loops << 1) + 100;
 +      rs->speed = speed;
-+      return 0;
++
++      dev_dbg(&spi->dev, "speed: %lu/%u, rate: %u, prescal: %u, loops: %hu\n",
++                      clk_get_rate(rs->clk) / rate, speed, rate, prescale,
++                      rs->wait_loops);
++
++      return prescale;
 +}
 +
-+/*
-+ * called only when no transfer is active on the bus
-+ */
-+static int
-+rt2880_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
++static u32 get_arbiter_offset(struct spi_master *master)
 +{
-+      struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
-+      unsigned int speed = spi->max_speed_hz;
-+      int rc;
-+
-+      if ((t != NULL) && t->speed_hz)
-+              speed = t->speed_hz;
++      u32 offset;
 +
-+      if (rs->speed != speed) {
-+              dev_dbg(&spi->dev, "speed_hz:%u\n", speed);
-+              rc = rt2880_spi_baudrate_set(spi, speed);
-+              if (rc)
-+                      return rc;
-+      }
++      offset = RAMIPS_SPI_ARBITER;
++      if (master->bus_num == 1)
++              offset -= RAMIPS_SPI_DEV_OFFSET;
 +
-+      return 0;
++      return offset;
 +}
 +
-+static void rt2880_spi_set_cs(struct rt2880_spi *rs, int enable)
++static void rt2880_spi_set_cs(struct spi_device *spi, bool enable)
 +{
++      struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
++
 +      if (enable)
++              rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
++      else
 +              rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
++}
++
++static void mt7620_set_4byte(struct rt2880_spi *rs, bool enable)
++{
++      if (enable)
++              rt2880_spi_setbits(rs, RAMIPS_SPI_CFG, SPICFG_ADDRMODE);
 +      else
-+              rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
++              rt2880_spi_clrbits(rs, RAMIPS_SPI_CFG, SPICFG_ADDRMODE);
 +}
 +
-+static inline int rt2880_spi_wait_till_ready(struct rt2880_spi *rs)
++static int rt2880_spi_wait_ready(struct rt2880_spi *rs, int len)
 +{
-+      int i;
++      int loop = rs->wait_loops * len;
++
++      while ((rt2880_spi_read(rs, RAMIPS_SPI_STAT) & SPISTAT_BUSY) && --loop)
++              cpu_relax();
 +
-+      for (i = 0; i < RALINK_SPI_WAIT_MAX_LOOP; i++) {
-+              u32 status;
++      if (loop)
++              return 0;
 +
-+              status = rt2880_spi_read(rs, RAMIPS_SPI_STAT);
-+              if ((status & SPISTAT_BUSY) == 0)
-+                      return 0;
++      return -ETIMEDOUT;
++}
++
++/* return free fifo count */
++static int mt7620_spi_fifo_ready(struct rt2880_spi *rs, u32 check_bit, bool 
tx)
++{
++      int loop = rs->wait_loops;
++      u32 stat;
 +
++      stat = rt2880_spi_read(rs, RAMIPS_SPI_FIFO_STAT);
++      while ((stat & check_bit) && --loop) {
 +              cpu_relax();
-+              udelay(1);
++              stat = rt2880_spi_read(rs, RAMIPS_SPI_FIFO_STAT);
++      }
++
++      if (loop) {
++              if (tx)
++                      stat >>= SPIFIFOSTAT_TX_OFFSET;
++              stat &= SPIFIFOSTAT_FIFO_MASK;
++              if (tx)
++                      stat = SPI_FIFO_DEPTH - stat;
++
++              return (int)stat;
 +      }
 +
 +      return -ETIMEDOUT;
 +}
 +
-+static unsigned int
-+rt2880_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
++static void rt2880_dump_reg(struct spi_master *master)
 +{
-+      struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
-+      unsigned count = 0;
-+      u8 *rx = xfer->rx_buf;
-+      const u8 *tx = xfer->tx_buf;
-+      int err;
++      struct rt2880_spi *rs = spi_master_get_devdata(master);
 +
-+      dev_dbg(&spi->dev, "read (%d): %s %s\n", xfer->len,
-+                (tx != NULL) ? "tx" : "  ",
-+                (rx != NULL) ? "rx" : "  ");
++      if (rs->ops->flags && (master->bus_num == 0)) {
++              dev_dbg(&master->dev, "stat: %08x, cfg: %08x, ctl: %08x, " \
++                              "data: %08x, addr: %08x, bs: %08x, " \
++                              "user: %08x, txfifo: %08x, rxfifo: %08x, " \
++                              "fifo_sta: %08x, mode: %08x, dma: " \
++                              "%08x, dmastat: %08x, arb: %08x\n",
++                              rt2880_spi_read(rs, RAMIPS_SPI_STAT),
++                              rt2880_spi_read(rs, RAMIPS_SPI_CFG),
++                              rt2880_spi_read(rs, RAMIPS_SPI_CTL),
++                              rt2880_spi_read(rs, RAMIPS_SPI_DATA),
++                              rt2880_spi_read(rs, RAMIPS_SPI_ADDR),
++                              rt2880_spi_read(rs, RAMIPS_SPI_BS),
++                              rt2880_spi_read(rs, RAMIPS_SPI_USER),
++                              rt2880_spi_read(rs, RAMIPS_SPI_TXFIFO),
++                              rt2880_spi_read(rs, RAMIPS_SPI_RXFIFO),
++                              rt2880_spi_read(rs, RAMIPS_SPI_FIFO_STAT),
++                              rt2880_spi_read(rs, RAMIPS_SPI_MODE),
++                              rt2880_spi_read(rs, RAMIPS_SPI_DMA),
++                              rt2880_spi_read(rs, RAMIPS_SPI_DMASTAT),
++                              rt2880_spi_read(rs, RAMIPS_SPI_ARBITER));
++      } else {
++              dev_dbg(&master->dev, "stat: %08x, cfg: %08x, ctl: %08x, " \
++                              "data: %08x, arb: %08x\n",
++                              rt2880_spi_read(rs, RAMIPS_SPI_STAT),
++                              rt2880_spi_read(rs, RAMIPS_SPI_CFG),
++                              rt2880_spi_read(rs, RAMIPS_SPI_CTL),
++                              rt2880_spi_read(rs, RAMIPS_SPI_DATA),
++                              rt2880_spi_read(rs, 
get_arbiter_offset(master)));
++      }
++}
++
++static int rt2880_spi_transfer_one(struct spi_master *master,
++              struct spi_device *spi, struct spi_transfer *xfer)
++{
++      struct rt2880_spi *rs = spi_master_get_devdata(master);
++      unsigned len;
++      const u8 *tx = xfer->tx_buf;
++      u8 *rx = xfer->rx_buf;
++      int err = 0;
++
++      /* change clock speed  */
++      if (unlikely(rs->speed != xfer->speed_hz)) {
++              u32 reg;
++              reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
++              reg &= ~SPICFG_SPICLK_PRESCALE_MASK;
++              reg |= rt2880_spi_baudrate_get(spi, xfer->speed_hz);
++              rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
++      }
 +
 +      if (tx) {
-+              for (count = 0; count < xfer->len; count++) {
-+                      rt2880_spi_write(rs, RAMIPS_SPI_DATA, tx[count]);
++              len = xfer->len;
++              while (len-- > 0) {
++                      rt2880_spi_write(rs, RAMIPS_SPI_DATA, *tx++);
 +                      rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTWR);
-+                      err = rt2880_spi_wait_till_ready(rs);
++                      err = rt2880_spi_wait_ready(rs, 1);
 +                      if (err) {
 +                              dev_err(&spi->dev, "TX failed, err=%d\n", err);
 +                              goto out;
@@ -268,125 +414,436 @@ Acked-by: John Crispin <[email protected]>
 +      }
 +
 +      if (rx) {
-+              for (count = 0; count < xfer->len; count++) {
++              len = xfer->len;
++              while (len-- > 0) {
 +                      rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTRD);
-+                      err = rt2880_spi_wait_till_ready(rs);
++                      err = rt2880_spi_wait_ready(rs, 1);
 +                      if (err) {
 +                              dev_err(&spi->dev, "RX failed, err=%d\n", err);
 +                              goto out;
 +                      }
-+                      rx[count] = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA);
++                      *rx++ = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA);
++              }
++      }
++
++out:
++      return err;
++}
++
++static unsigned int m25p_cmd2addr(int addr_width, const u8 *cmd)
++{
++      unsigned int addr;
++
++      /* opcode is in cmd[0] */
++      addr = cmd[1] << (addr_width * 8 - 8);
++      addr |= cmd[2] << (addr_width * 8 - 16);
++      addr |= cmd[3] << (addr_width * 8 - 24);
++      addr |= cmd[4] << (addr_width * 8 - 32);
++
++      return addr;
++}
++
++static int setup_spi_cmd(struct rt2880_spi *rs, const u8 *tx, u32 len,
++              struct mt7620_spi_cmd *cmd)
++{
++      int ret = 0;
++      u32 reg;
++
++      switch (tx[0]) {
++      /* hw support command */
++      case SPINOR_OP_RDSR:
++      case SPINOR_OP_RDID:
++              cmd->flags = SPI_CMD_RX;
++              break;
++      case SPINOR_OP_WRSR:
++              cmd->flags = SPI_CMD_TX;
++              cmd->tx_buf = tx + 1;
++              cmd->len = len - 1;
++              break;
++      case SPINOR_OP_WREN:
++      case SPINOR_OP_WRDI:
++              break;
++      case SPINOR_OP_SE:
++              cmd->flags = SPI_CMD_ADDR;
++              break;
++      case SPINOR_OP_READ:
++              cmd->flags = SPI_CMD_ADDR | SPI_CMD_RX;
++              break;
++      case SPINOR_OP_PP:
++              cmd->flags = SPI_CMD_ADDR | SPI_CMD_TX;
++              break;
++      case SPINOR_OP_READ_FAST:
++      case SPINOR_OP_READ_1_1_2:
++      case SPINOR_OP_READ_1_1_4:
++              cmd->flags = SPI_CMD_ADDR | SPI_CMD_DUMMY | SPI_CMD_RX;
++              break;
++      /* hw unsupport command */
++      case SPINOR_OP_EN4B:
++              cmd->flags = SPI_CMD_USER | SPI_CMD_EN4B;
++              break;
++      case SPINOR_OP_EX4B:
++              cmd->flags = SPI_CMD_USER | SPI_CMD_EX4B;
++              break;
++      case SPINOR_OP_BRWR:
++              if (tx[1] == BIT(7))
++                      cmd->flags = SPI_CMD_TX | SPI_CMD_USER | SPI_CMD_EN4B;
++              else
++                      cmd->flags = SPI_CMD_TX | SPI_CMD_USER | SPI_CMD_EX4B;
++              cmd->tx_buf = tx + 1;
++              cmd->len = len - 1;
++              break;
++      /* don't know hw support or not. assume unsupport */
++      case SPINOR_OP_CHIP_ERASE:
++              cmd->flags = SPI_CMD_USER;
++              break;
++      case SPINOR_OP_RDFSR:
++      case SPINOR_OP_RDCR:
++              cmd->flags = SPI_CMD_RX | SPI_CMD_USER;
++              break;
++      default:
++              ret = -EINVAL;
++              goto out;
++      }
++
++      /* setup 4 bytes address mode */
++      if (cmd->flags & SPI_CMD_EN4B) {
++              mt7620_set_4byte(rs, true);
++              rs->addr_width = 4;
++      } else if (cmd->flags & SPI_CMD_EX4B) {
++              mt7620_set_4byte(rs, false);
++              rs->addr_width = 3;
++      }
++
++      /* opcode */
++      cmd->opcode = tx[0];
++      rt2880_spi_write(rs, RAMIPS_SPI_DATA, cmd->opcode);
++
++      /* address */
++      if (cmd->flags & SPI_CMD_ADDR) {
++              cmd->addr = m25p_cmd2addr(rs->addr_width, tx);
++              if (rs->addr_width == 3)
++                      rt2880_spi_write(rs, RAMIPS_SPI_ADDR, (cmd->addr << 8));
++              else if (rs->addr_width == 4)
++                      rt2880_spi_write(rs, RAMIPS_SPI_ADDR, cmd->addr);
++              else {
++                      ret = -EINVAL;
++                      goto out;
 +              }
++      } else
++              rt2880_spi_write(rs, RAMIPS_SPI_ADDR, 0);
++
++      /* setup user mode */
++      if (cmd->flags & SPI_CMD_USER) {
++              reg = SPIUSER_USERMODE | SPIUSER_INSTR_PHASE |
++                      SPIUSER_TRANSFER_TYPE(SPIUSER_TRANSFER_SINGLE);
++              if (cmd->flags & SPI_CMD_ADDR)
++                      reg |= (rs->addr_width << SPIUSER_ADDR_PHASE_OFFSET);
++              if (cmd->flags & SPI_CMD_DUMMY)
++                      reg |= (1 << SPIUSER_DUMMY_PHASE_OFFSET);
++              if (cmd->flags & SPI_CMD_TX)
++                      reg |= SPIUSER_DATA_WRITE;
++              else if (cmd->flags & SPI_CMD_RX)
++                      reg |= SPIUSER_DATA_READ;
++              rt2880_spi_write(rs, RAMIPS_SPI_USER, reg);
 +      }
 +
 +out:
-+      return count;
++      return ret;
 +}
 +
-+static int rt2880_spi_transfer_one_message(struct spi_master *master,
-+                                         struct spi_message *m)
++static int mt7620_spi_transfer_one(struct spi_master *master,
++              struct spi_device *spi, struct spi_transfer *xfer)
 +{
 +      struct rt2880_spi *rs = spi_master_get_devdata(master);
-+      struct spi_device *spi = m->spi;
-+      struct spi_transfer *t = NULL;
-+      int par_override = 0;
-+      int status = 0;
-+      int cs_active = 0;
-+
-+      /* Load defaults */
-+      status = rt2880_spi_setup_transfer(spi, NULL);
-+      if (status < 0)
-+              goto msg_done;
-+
-+      list_for_each_entry(t, &m->transfers, transfer_list) {
-+              if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
-+                      dev_err(&spi->dev,
-+                              "message rejected: invalid transfer data 
buffers\n");
-+                      status = -EIO;
-+                      goto msg_done;
++      struct mt7620_spi_cmd *cmd;
++      const u8 *tx;
++      u8 *rx;
++      int len, ret = 0;
++
++      cmd = &rs->cmd;
++      if (cmd->status == SPI_STATE_OPCODE) {
++              if (!xfer->tx_buf)
++                      dev_err(&spi->dev, "only support spi flash device\n");
++
++              memset(cmd, 0, sizeof(*cmd));
++              ret = setup_spi_cmd(rs, xfer->tx_buf, xfer->len, cmd);
++              if (ret < 0) {
++                      dev_err(&spi->dev, "unknown spi command %02x\n",
++                                      *(u8 *)xfer->tx_buf);
++                      goto err;
 +              }
 +
-+              if (t->speed_hz && t->speed_hz < (rs->sys_freq / 128)) {
-+                      dev_err(&spi->dev,
-+                              "message rejected: device min speed (%d Hz) 
exceeds required transfer speed (%d Hz)\n",
-+                              (rs->sys_freq / 128), t->speed_hz);
-+                      status = -EIO;
-+                      goto msg_done;
++              /* need data at next transfer */
++              if ((cmd->flags & (SPI_CMD_TX | SPI_CMD_RX)) &&
++                              !cmd->tx_buf && !cmd->rx_buf) {
++                      cmd->status = SPI_STATE_DATA;
++                      return ret;
++              }
++      } else {
++              if (((cmd->flags & SPI_CMD_TX) && !xfer->tx_buf) ||
++                              ((cmd->flags & SPI_CMD_RX) && !xfer->rx_buf)) {
++                      dev_err(&spi->dev, "no spi data found\n");
++                      ret = -EINVAL;
++                      goto err;
 +              }
++              cmd->len = xfer->len;
++              cmd->tx_buf = xfer->tx_buf;
++              cmd->rx_buf = xfer->rx_buf;
++      }
++
++      /* set block size */
++      rt2880_spi_write(rs, RAMIPS_SPI_BS, cmd->len);
++
++      /* start transaction */
++      rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_START);
++
++      tx = cmd->tx_buf;
++      rx = cmd->rx_buf;
 +
-+              if (par_override || t->speed_hz || t->bits_per_word) {
-+                      par_override = 1;
-+                      status = rt2880_spi_setup_transfer(spi, t);
-+                      if (status < 0)
-+                              goto msg_done;
-+                      if (!t->speed_hz && !t->bits_per_word)
-+                              par_override = 0;
++      /* handle data */
++      if (tx) {
++              len = cmd->len;
++              while (len) {
++                      /* wait until tx fifo not full */
++                      ret = mt7620_spi_fifo_ready(rs, SPIFIFOSTAT_TXFULL,
++                                      true);
++                      if (ret < 0) {
++                              dev_err(&spi->dev, "tx fifo full timeout\n");
++                              goto err;
++                      }
++                      ret = min(len, ret);
++                      len -= ret;
++                      while (ret--)
++                              rt2880_spi_write(rs, RAMIPS_SPI_TXFIFO, *tx++);
 +              }
++      }
 +
-+              if (!cs_active) {
-+                      rt2880_spi_set_cs(rs, 1);
-+                      cs_active = 1;
++      if (rx) {
++              len = cmd->len;
++              while (len) {
++                      /* wait until rx fifo not empty */
++                      ret = mt7620_spi_fifo_ready(rs, SPIFIFOSTAT_RXEMPTY,
++                                      false);
++                      if (ret < 0) {
++                              dev_err(&spi->dev, "rx fifo empty timeout\n");
++                              goto err;
++                      }
++                      ret = min(len, ret);
++                      len -= ret;
++                      while (ret--)
++                              *rx++ = (u8)rt2880_spi_read(rs,
++                                              RAMIPS_SPI_RXFIFO);
 +              }
++      }
++
++      len = min((int)cmd->len + 1, SPI_FIFO_DEPTH);
++      ret = rt2880_spi_wait_ready(rs, len);
++      if (ret)
++              dev_err(&spi->dev, "wait timeout\n");
++
++err:
++      cmd->status = SPI_STATE_OPCODE;
++
++      /* clean user mode */
++      if (cmd->flags & SPI_CMD_USER)
++              rt2880_spi_write(rs, RAMIPS_SPI_USER, 0);
++
++      if (ret)
++              rt2880_dump_reg(master);
 +
-+              if (t->len)
-+                      m->actual_length += rt2880_spi_write_read(spi, t);
++      return ret;
++}
++
++/* copy from spi.c */
++static void spi_set_cs(struct spi_device *spi, bool enable)
++{
++      if (spi->mode & SPI_CS_HIGH)
++              enable = !enable;
++
++      if (spi->cs_gpio >= 0)
++              gpio_set_value(spi->cs_gpio, !enable);
++      else if (spi->master->set_cs)
++              spi->master->set_cs(spi, !enable);
++}
 +
-+              if (t->delay_usecs)
-+                      udelay(t->delay_usecs);
++static int rt2880_spi_setup(struct spi_device *spi)
++{
++      struct spi_master *master = spi->master;
++      struct rt2880_spi *rs = spi_master_get_devdata(master);
++      u32 reg, old_reg, arbit_off;
 +
-+              if (t->cs_change) {
-+                      rt2880_spi_set_cs(rs, 0);
-+                      cs_active = 0;
++      if ((spi->max_speed_hz > master->max_speed_hz) ||
++                      (spi->max_speed_hz < master->min_speed_hz)) {
++              dev_err(&spi->dev, "invalide requested speed %d Hz\n",
++                              spi->max_speed_hz);
++              return -EINVAL;
++      }
++
++      if (!(master->bits_per_word_mask &
++                              BIT(spi->bits_per_word - 1))) {
++              dev_err(&spi->dev, "invalide bits_per_word %d\n",
++                              spi->bits_per_word);
++              return -EINVAL;
++      }
++
++      /* the hardware seems can't work on mode0 force it to mode3 */
++      if ((spi->mode & (SPI_CPOL | SPI_CPHA)) == SPI_MODE_0) {
++              dev_warn(&spi->dev, "force spi mode3\n");
++              spi->mode |= SPI_MODE_3;
++      }
++
++      /* chip polarity */
++      arbit_off = get_arbiter_offset(master);
++      reg = old_reg = rt2880_spi_read(rs, arbit_off);
++      if (spi->mode & SPI_CS_HIGH) {
++              switch (master->bus_num) {
++              case 1:
++                      reg |= SPI1_POR;
++                      break;
++              default:
++                      reg |= SPI0_POR;
++                      break;
++              }
++      } else {
++              switch (master->bus_num) {
++              case 1:
++                      reg &= ~SPI1_POR;
++                      break;
++              default:
++                      reg &= ~SPI0_POR;
++                      break;
 +              }
 +      }
 +
-+msg_done:
-+      if (cs_active)
-+              rt2880_spi_set_cs(rs, 0);
++      /* enable spi1 */
++      if (master->bus_num == 1) {
++              reg |= SPICTL_ARB_EN;
++              /* enable cs1 support? */
++              if (rs->ops->flags & SPI_FLAG_HW_MODE)
++                      reg |= SPICTL_CSCTL1;
++      }
 +
-+      m->status = status;
-+      spi_finalize_current_message(master);
++      if (reg != old_reg)
++              rt2880_spi_write(rs, arbit_off, reg);
++
++      /* deselected the spi device */
++      spi_set_cs(spi, false);
 +
 +      return 0;
 +}
 +
-+static int rt2880_spi_setup(struct spi_device *spi)
++static int rt2880_spi_prepare_message(struct spi_master *master,
++              struct spi_message *msg)
 +{
-+      struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
++      struct rt2880_spi *rs = spi_master_get_devdata(master);
++      struct spi_device *spi = msg->spi;
++      u32 reg;
 +
-+      if ((spi->max_speed_hz == 0) ||
-+          (spi->max_speed_hz > (rs->sys_freq / 2)))
-+              spi->max_speed_hz = (rs->sys_freq / 2);
++      if ((rs->mode == spi->mode) && (rs->speed == spi->max_speed_hz)) {
++              if (rs->ops->flags & SPI_FLAG_HW_MODE) {
++                      rt2880_spi_setbits(rs, RAMIPS_SPI_CFG,
++                                      (SPICFG_RXENVDIS | SPICFG_SPIENMODE));
++                      rs->cmd.status = SPI_STATE_OPCODE;
++              }
++              return 0;
++      }
 +
-+      if (spi->max_speed_hz < (rs->sys_freq / 128)) {
-+              dev_err(&spi->dev, "setup: requested speed is too low %d Hz\n",
-+                      spi->max_speed_hz);
-+              return -EINVAL;
++#if 0
++      /* set spido to tri-state */
++      rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_HIZSDO);
++#endif
++
++      reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
++
++      reg &= ~(SPICFG_MSBFIRST | SPICFG_SPICLKPOL |
++                      SPICFG_RXCLKEDGE_FALLING |
++                      SPICFG_TXCLKEDGE_FALLING |
++                      SPICFG_SPICLK_PRESCALE_MASK);
++
++      /* MSB */
++      if (!(spi->mode & SPI_LSB_FIRST))
++              reg |= SPICFG_MSBFIRST;
++
++      /* spi mode */
++      switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
++      case SPI_MODE_0:
++              reg |= SPICFG_TXCLKEDGE_FALLING;
++              break;
++      case SPI_MODE_1:
++              reg |= SPICFG_RXCLKEDGE_FALLING;
++              break;
++      case SPI_MODE_2:
++              reg |= SPICFG_SPICLKPOL | SPICFG_RXCLKEDGE_FALLING;
++              break;
++      case SPI_MODE_3:
++              reg |= SPICFG_SPICLKPOL | SPICFG_TXCLKEDGE_FALLING;
++              break;
 +      }
++      rs->mode = spi->mode;
++
++#if 0
++      /* set spiclk and spiena to tri-state */
++      reg |= SPICFG_HIZSPI;
++#endif
++
++      /* clock divide */
++      reg |= rt2880_spi_baudrate_get(spi, spi->max_speed_hz);
++
++      /* set chip select is control by hw */
++      if (rs->ops->flags & SPI_FLAG_HW_MODE) {
++              reg |= (SPICFG_RXENVDIS | SPICFG_SPIENMODE);
++              rs->cmd.status = SPI_STATE_OPCODE;
++      }
++
++      rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
 +
-+      /*
-+       * baudrate & width will be set rt2880_spi_setup_transfer
-+       */
 +      return 0;
 +}
 +
-+static void rt2880_spi_reset(struct rt2880_spi *rs)
++static int rt2880_spi_unprepare_message(struct spi_master *master,
++              struct spi_message *message)
 +{
-+      rt2880_spi_write(rs, RAMIPS_SPI_CFG,
-+                       SPICFG_MSBFIRST | SPICFG_TXCLKEDGE_FALLING |
-+                       SPICFG_SPICLK_DIV16 | SPICFG_SPICLKPOL);
-+      rt2880_spi_write(rs, RAMIPS_SPI_CTL, SPICTL_HIZSDO | SPICTL_SPIENA);
++      struct rt2880_spi *rs = spi_master_get_devdata(master);
++
++      /* disable chip select is control by hw */
++      if (rs->ops->flags & SPI_FLAG_HW_MODE)
++              rt2880_spi_clrbits(rs, RAMIPS_SPI_CFG,
++                              (SPICFG_RXENVDIS | SPICFG_SPIENMODE));
++
++      return 0;
 +}
 +
++static struct rt2880_spi_ops spi_ops[] = {
++      {
++              .transfer_one = rt2880_spi_transfer_one,
++      }, {
++              .flags = SPI_FLAG_HW_MODE,
++              .transfer_one = mt7620_spi_transfer_one,
++      },
++};
++
++static const struct of_device_id rt2880_spi_match[] = {
++      { .compatible = "ralink,rt2880-spi", .data = &spi_ops[0]},
++      { .compatible = "ralink,mt7620a-spi", .data = &spi_ops[1]},
++      {},
++};
++MODULE_DEVICE_TABLE(of, rt2880_spi_match);
++
 +static int rt2880_spi_probe(struct platform_device *pdev)
 +{
++      const struct of_device_id *match;
 +      struct spi_master *master;
 +      struct rt2880_spi *rs;
-+      unsigned long flags;
 +      void __iomem *base;
 +      struct resource *r;
-+      int status = 0;
 +      struct clk *clk;
++      struct rt2880_spi_ops *ops;
++      int ret;
++
++      match = of_match_device(rt2880_spi_match, &pdev->dev);
++      if (!match)
++              return -EINVAL;
++      ops = (struct rt2880_spi_ops *)match->data;
 +
 +      r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 +      base = devm_ioremap_resource(&pdev->dev, r);
@@ -395,45 +852,63 @@ Acked-by: John Crispin <[email protected]>
 +
 +      clk = devm_clk_get(&pdev->dev, NULL);
 +      if (IS_ERR(clk)) {
-+              dev_err(&pdev->dev, "unable to get SYS clock, err=%d\n",
-+                      status);
++              dev_err(&pdev->dev, "unable to get SYS clock\n");
 +              return PTR_ERR(clk);
 +      }
 +
-+      status = clk_prepare_enable(clk);
-+      if (status)
-+              return status;
++      ret = clk_prepare_enable(clk);
++      if (ret)
++              goto err_clk;
 +
 +      master = spi_alloc_master(&pdev->dev, sizeof(*rs));
 +      if (master == NULL) {
 +              dev_dbg(&pdev->dev, "master allocation failed\n");
-+              return -ENOMEM;
++              ret = -ENOMEM;
++              goto err_clk;
 +      }
 +
-+      /* we support only mode 0, and no options */
-+      master->mode_bits = 0;
-+
-+      master->setup = rt2880_spi_setup;
-+      master->transfer_one_message = rt2880_spi_transfer_one_message;
-+      master->num_chipselect = RALINK_NUM_CHIPSELECTS;
-+      master->bits_per_word_mask = SPI_BPW_MASK(8);
 +      master->dev.of_node = pdev->dev.of_node;
++      if (ops->flags)
++              master->mode_bits = MT7620_SPI_MODE_BITS;
++      else
++              master->mode_bits = RT2880_SPI_MODE_BITS;
++      master->bits_per_word_mask = SPI_BPW_MASK(8);
++      master->min_speed_hz = clk_get_rate(clk) / 128;
++      master->max_speed_hz = clk_get_rate(clk) / 2;
++      master->flags = SPI_MASTER_HALF_DUPLEX;
++      master->setup = rt2880_spi_setup;
++      master->prepare_message = rt2880_spi_prepare_message;
++      master->unprepare_message = rt2880_spi_unprepare_message;
++      master->set_cs = rt2880_spi_set_cs;
++      master->transfer_one = ops->transfer_one;
 +
 +      dev_set_drvdata(&pdev->dev, master);
 +
 +      rs = spi_master_get_devdata(master);
++      rs->master = master;
 +      rs->base = base;
 +      rs->clk = clk;
-+      rs->master = master;
-+      rs->sys_freq = clk_get_rate(rs->clk);
-+      dev_dbg(&pdev->dev, "sys_freq: %u\n", rs->sys_freq);
-+      spin_lock_irqsave(&rs->lock, flags);
++      rs->addr_width = 3;
++      rs->ops = ops;
++
++      if (atomic_inc_return(&hw_reset_count) == 1)
++              device_reset(&pdev->dev);
 +
-+      device_reset(&pdev->dev);
++      ret = devm_spi_register_master(&pdev->dev, master);
++      if (ret < 0) {
++              dev_err(&pdev->dev, "devm_spi_register_master error.\n");
++              goto err_master;
++      }
 +
-+      rt2880_spi_reset(rs);
++      return ret;
 +
-+      return spi_register_master(master);
++err_master:
++      spi_master_put(master);
++      kfree(master);
++err_clk:
++      clk_disable_unprepare(clk);
++
++      return ret;
 +}
 +
 +static int rt2880_spi_remove(struct platform_device *pdev)
@@ -444,20 +919,14 @@ Acked-by: John Crispin <[email protected]>
 +      master = dev_get_drvdata(&pdev->dev);
 +      rs = spi_master_get_devdata(master);
 +
-+      clk_disable(rs->clk);
-+      spi_unregister_master(master);
++      clk_disable_unprepare(rs->clk);
++      atomic_dec(&hw_reset_count);
 +
 +      return 0;
 +}
 +
 +MODULE_ALIAS("platform:" DRIVER_NAME);
 +
-+static const struct of_device_id rt2880_spi_match[] = {
-+      { .compatible = "ralink,rt2880-spi" },
-+      {},
-+};
-+MODULE_DEVICE_TABLE(of, rt2880_spi_match);
-+
 +static struct platform_driver rt2880_spi_driver = {
 +      .driver = {
 +              .name = DRIVER_NAME,
diff --git 
a/target/linux/ramips/patches-3.18/0051-rt5350-spi-second-device.patch 
b/target/linux/ramips/patches-3.18/0051-rt5350-spi-second-device.patch
deleted file mode 100644
index 2da8151..0000000
--- a/target/linux/ramips/patches-3.18/0051-rt5350-spi-second-device.patch
+++ /dev/null
@@ -1,368 +0,0 @@
-From 27b11d4f1888e1a3d6d75b46d4d5a4d86fc03891 Mon Sep 17 00:00:00 2001
-From: John Crispin <[email protected]>
-Date: Wed, 6 Aug 2014 10:53:40 +0200
-Subject: [PATCH 51/57] SPI: MIPS: ralink: add rt5350 dual SPI support
-
-Signed-off-by: John Crispin <[email protected]>
-Signed-off-by: Felix Fietkau <[email protected]>
----
- drivers/spi/spi-rt2880.c |  218 +++++++++++++++++++++++++++++++++++++++++++---
- 1 file changed, 205 insertions(+), 13 deletions(-)
-
---- a/drivers/spi/spi-rt2880.c
-+++ b/drivers/spi/spi-rt2880.c
-@@ -21,19 +21,25 @@
- #include <linux/io.h>
- #include <linux/reset.h>
- #include <linux/spi/spi.h>
-+#include <linux/of_device.h>
- #include <linux/platform_device.h>
- 
-+#include <ralink_regs.h>
-+
-+#define SPI_BPW_MASK(bits) BIT((bits) - 1)
-+
- #define DRIVER_NAME                   "spi-rt2880"
--/* only one slave is supported*/
--#define RALINK_NUM_CHIPSELECTS                1
- /* in usec */
- #define RALINK_SPI_WAIT_MAX_LOOP      2000
- 
--#define RAMIPS_SPI_STAT                       0x00
--#define RAMIPS_SPI_CFG                        0x10
--#define RAMIPS_SPI_CTL                        0x14
--#define RAMIPS_SPI_DATA                       0x20
--#define RAMIPS_SPI_FIFO_STAT          0x38
-+#define RAMIPS_SPI_DEV_OFFSET         0x40
-+
-+#define RAMIPS_SPI_STAT(cs)           (0x00 + (cs * RAMIPS_SPI_DEV_OFFSET))
-+#define RAMIPS_SPI_CFG(cs)            (0x10 + (cs * RAMIPS_SPI_DEV_OFFSET))
-+#define RAMIPS_SPI_CTL(cs)            (0x14 + (cs * RAMIPS_SPI_DEV_OFFSET))
-+#define RAMIPS_SPI_DATA(cs)           (0x20 + (cs * RAMIPS_SPI_DEV_OFFSET))
-+#define RAMIPS_SPI_FIFO_STAT(cs)      (0x38 + (cs * RAMIPS_SPI_DEV_OFFSET))
-+#define RAMIPS_SPI_ARBITER            0xF0
- 
- /* SPISTAT register bit field */
- #define SPISTAT_BUSY                  BIT(0)
-@@ -63,6 +69,19 @@
- /* SPIFIFOSTAT register bit field */
- #define SPIFIFOSTAT_TXFULL            BIT(17)
- 
-+#define SPICTL_ARB_EN                 BIT(31)
-+#define SPI1_POR                      BIT(1)
-+#define SPI0_POR                      BIT(0)
-+
-+#define RT2880_SPI_MODE_BITS  (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | 
SPI_CS_HIGH)
-+
-+struct rt2880_spi;
-+
-+struct rt2880_spi_ops {
-+      void (*init_hw)(struct rt2880_spi *rs);
-+      int num_cs;
-+};
-+
- struct rt2880_spi {
-       struct spi_master       *master;
-       void __iomem            *base;
-@@ -70,6 +89,8 @@ struct rt2880_spi {
-       unsigned int            speed;
-       struct clk              *clk;
-       spinlock_t              lock;
-+
-+      struct rt2880_spi_ops   *ops;
- };
- 
- static inline struct rt2880_spi *spidev_to_rt2880_spi(struct spi_device *spi)
-@@ -115,6 +136,7 @@ static inline void rt2880_spi_clrbits(st
- 
- static int rt2880_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
- {
-+      int cs = spi->chip_select;
-       struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
-       u32 rate;
-       u32 prescale;
-@@ -142,9 +164,9 @@ static int rt2880_spi_baudrate_set(struc
-       prescale = ilog2(rate / 2);
-       dev_dbg(&spi->dev, "prescale:%u\n", prescale);
- 
--      reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
-+      reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG(cs));
-       reg = ((reg & ~SPICFG_SPICLK_PRESCALE_MASK) | prescale);
--      rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
-+      rt2880_spi_write(rs, RAMIPS_SPI_CFG(cs), reg);
-       rs->speed = speed;
-       return 0;
- }
-@@ -157,7 +179,8 @@ rt2880_spi_setup_transfer(struct spi_dev
- {
-       struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
-       unsigned int speed = spi->max_speed_hz;
--      int rc;
-+      int rc, cs = spi->chip_select;
-+      u32 reg;
- 
-       if ((t != NULL) && t->speed_hz)
-               speed = t->speed_hz;
-@@ -169,25 +192,68 @@ rt2880_spi_setup_transfer(struct spi_dev
-                       return rc;
-       }
- 
-+      reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG(cs));
-+
-+      reg = (reg & ~SPICFG_MSBFIRST);
-+      if (!(spi->mode & SPI_LSB_FIRST))
-+              reg |= SPICFG_MSBFIRST;
-+
-+      reg = (reg & ~(SPICFG_SPICLKPOL | SPICFG_RXCLKEDGE_FALLING 
|SPICFG_TXCLKEDGE_FALLING));
-+      switch(spi->mode & (SPI_CPOL | SPI_CPHA)) {
-+              case SPI_MODE_0:
-+                      reg |= SPICFG_SPICLKPOL | SPICFG_TXCLKEDGE_FALLING;
-+                      break;
-+              case SPI_MODE_1:
-+                      reg |= SPICFG_SPICLKPOL | SPICFG_RXCLKEDGE_FALLING;
-+                      break;
-+              case SPI_MODE_2:
-+                      reg |= SPICFG_RXCLKEDGE_FALLING;
-+                      break;
-+              case SPI_MODE_3:
-+                      reg |= SPICFG_TXCLKEDGE_FALLING;
-+                      break;
-+      }
-+
-+      rt2880_spi_write(rs, RAMIPS_SPI_CFG(cs), reg);
-+
-+      reg = SPICTL_ARB_EN;
-+      if (spi->mode & SPI_CS_HIGH) {
-+              switch(cs) {
-+                      case 0:
-+                              reg |= SPI0_POR;
-+                              break;
-+                      case 1:
-+                              reg |= SPI1_POR;
-+                              break;
-+              }
-+      }
-+
-+      rt2880_spi_write(rs, RAMIPS_SPI_ARBITER, reg);
-+
-       return 0;
- }
- 
--static void rt2880_spi_set_cs(struct rt2880_spi *rs, int enable)
-+static void rt2880_spi_set_cs(struct spi_device *spi, int enable)
- {
-+      struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
-+      int cs = spi->chip_select;
-+
-       if (enable)
--              rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
-+              rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL(cs), SPICTL_SPIENA);
-       else
--              rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
-+              rt2880_spi_setbits(rs, RAMIPS_SPI_CTL(cs), SPICTL_SPIENA);
- }
- 
--static inline int rt2880_spi_wait_till_ready(struct rt2880_spi *rs)
-+static inline int rt2880_spi_wait_till_ready(struct spi_device *spi)
- {
-+      struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
-+      int cs = spi->chip_select;
-       int i;
- 
-       for (i = 0; i < RALINK_SPI_WAIT_MAX_LOOP; i++) {
-               u32 status;
- 
--              status = rt2880_spi_read(rs, RAMIPS_SPI_STAT);
-+              status = rt2880_spi_read(rs, RAMIPS_SPI_STAT(cs));
-               if ((status & SPISTAT_BUSY) == 0)
-                       return 0;
- 
-@@ -199,9 +265,10 @@ static inline int rt2880_spi_wait_till_r
- }
- 
- static unsigned int
--rt2880_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
-+rt2880_spi_write_read(struct spi_device *spi, struct list_head *list, struct 
spi_transfer *xfer)
- {
-       struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
-+      int cs = spi->chip_select;
-       unsigned count = 0;
-       u8 *rx = xfer->rx_buf;
-       const u8 *tx = xfer->tx_buf;
-@@ -213,9 +280,9 @@ rt2880_spi_write_read(struct spi_device
- 
-       if (tx) {
-               for (count = 0; count < xfer->len; count++) {
--                      rt2880_spi_write(rs, RAMIPS_SPI_DATA, tx[count]);
--                      rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTWR);
--                      err = rt2880_spi_wait_till_ready(rs);
-+                      rt2880_spi_write(rs, RAMIPS_SPI_DATA(cs), tx[count]);
-+                      rt2880_spi_setbits(rs, RAMIPS_SPI_CTL(cs), 
SPICTL_STARTWR);
-+                      err = rt2880_spi_wait_till_ready(spi);
-                       if (err) {
-                               dev_err(&spi->dev, "TX failed, err=%d\n", err);
-                               goto out;
-@@ -225,13 +292,13 @@ rt2880_spi_write_read(struct spi_device
- 
-       if (rx) {
-               for (count = 0; count < xfer->len; count++) {
--                      rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTRD);
--                      err = rt2880_spi_wait_till_ready(rs);
-+                      rt2880_spi_setbits(rs, RAMIPS_SPI_CTL(cs), 
SPICTL_STARTRD);
-+                      err = rt2880_spi_wait_till_ready(spi);
-                       if (err) {
-                               dev_err(&spi->dev, "RX failed, err=%d\n", err);
-                               goto out;
-                       }
--                      rx[count] = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA);
-+                      rx[count] = (u8) rt2880_spi_read(rs, 
RAMIPS_SPI_DATA(cs));
-               }
-       }
- 
-@@ -280,25 +347,25 @@ static int rt2880_spi_transfer_one_messa
-               }
- 
-               if (!cs_active) {
--                      rt2880_spi_set_cs(rs, 1);
-+                      rt2880_spi_set_cs(spi, 1);
-                       cs_active = 1;
-               }
- 
-               if (t->len)
--                      m->actual_length += rt2880_spi_write_read(spi, t);
-+                      m->actual_length += rt2880_spi_write_read(spi, 
&m->transfers, t);
- 
-               if (t->delay_usecs)
-                       udelay(t->delay_usecs);
- 
-               if (t->cs_change) {
--                      rt2880_spi_set_cs(rs, 0);
-+                      rt2880_spi_set_cs(spi, 0);
-                       cs_active = 0;
-               }
-       }
- 
- msg_done:
-       if (cs_active)
--              rt2880_spi_set_cs(rs, 0);
-+              rt2880_spi_set_cs(spi, 0);
- 
-       m->status = status;
-       spi_finalize_current_message(master);
-@@ -311,7 +378,7 @@ static int rt2880_spi_setup(struct spi_d
-       struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
- 
-       if ((spi->max_speed_hz == 0) ||
--          (spi->max_speed_hz > (rs->sys_freq / 2)))
-+              (spi->max_speed_hz > (rs->sys_freq / 2)))
-               spi->max_speed_hz = (rs->sys_freq / 2);
- 
-       if (spi->max_speed_hz < (rs->sys_freq / 128)) {
-@@ -328,14 +395,47 @@ static int rt2880_spi_setup(struct spi_d
- 
- static void rt2880_spi_reset(struct rt2880_spi *rs)
- {
--      rt2880_spi_write(rs, RAMIPS_SPI_CFG,
-+      rt2880_spi_write(rs, RAMIPS_SPI_CFG(0),
-                        SPICFG_MSBFIRST | SPICFG_TXCLKEDGE_FALLING |
-                        SPICFG_SPICLK_DIV16 | SPICFG_SPICLKPOL);
--      rt2880_spi_write(rs, RAMIPS_SPI_CTL, SPICTL_HIZSDO | SPICTL_SPIENA);
-+      rt2880_spi_write(rs, RAMIPS_SPI_CTL(0), SPICTL_HIZSDO | SPICTL_SPIENA);
- }
- 
-+static void rt5350_spi_reset(struct rt2880_spi *rs)
-+{
-+      int cs;
-+
-+      rt2880_spi_write(rs, RAMIPS_SPI_ARBITER,
-+                       SPICTL_ARB_EN);
-+
-+      for (cs = 0; cs < rs->ops->num_cs; cs++) {
-+              rt2880_spi_write(rs, RAMIPS_SPI_CFG(cs),
-+                               SPICFG_MSBFIRST | SPICFG_TXCLKEDGE_FALLING |
-+                               SPICFG_SPICLK_DIV16 | SPICFG_SPICLKPOL);
-+              rt2880_spi_write(rs, RAMIPS_SPI_CTL(cs), SPICTL_HIZSDO | 
SPICTL_SPIENA);
-+      }
-+}
-+
-+static struct rt2880_spi_ops spi_ops[] = {
-+      {
-+              .init_hw = rt2880_spi_reset,
-+              .num_cs = 1,
-+      }, {
-+              .init_hw = rt5350_spi_reset,
-+              .num_cs = 2,
-+      },
-+};
-+
-+static const struct of_device_id rt2880_spi_match[] = {
-+      { .compatible = "ralink,rt2880-spi", .data = &spi_ops[0]},
-+      { .compatible = "ralink,rt5350-spi", .data = &spi_ops[1]},
-+      {},
-+};
-+MODULE_DEVICE_TABLE(of, rt2880_spi_match);
-+
- static int rt2880_spi_probe(struct platform_device *pdev)
- {
-+      const struct of_device_id *match;
-       struct spi_master *master;
-       struct rt2880_spi *rs;
-       unsigned long flags;
-@@ -343,6 +443,12 @@ static int rt2880_spi_probe(struct platf
-       struct resource *r;
-       int status = 0;
-       struct clk *clk;
-+      struct rt2880_spi_ops *ops;
-+
-+      match = of_match_device(rt2880_spi_match, &pdev->dev);
-+      if (!match)
-+              return -EINVAL;
-+      ops = (struct rt2880_spi_ops *)match->data;
- 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(&pdev->dev, r);
-@@ -366,14 +472,13 @@ static int rt2880_spi_probe(struct platf
-               return -ENOMEM;
-       }
- 
--      /* we support only mode 0, and no options */
--      master->mode_bits = 0;
-+      master->mode_bits = RT2880_SPI_MODE_BITS;
- 
-       master->setup = rt2880_spi_setup;
-       master->transfer_one_message = rt2880_spi_transfer_one_message;
--      master->num_chipselect = RALINK_NUM_CHIPSELECTS;
-       master->bits_per_word_mask = SPI_BPW_MASK(8);
-       master->dev.of_node = pdev->dev.of_node;
-+      master->num_chipselect = ops->num_cs;
- 
-       dev_set_drvdata(&pdev->dev, master);
- 
-@@ -382,12 +487,13 @@ static int rt2880_spi_probe(struct platf
-       rs->clk = clk;
-       rs->master = master;
-       rs->sys_freq = clk_get_rate(rs->clk);
-+      rs->ops = ops;
-       dev_dbg(&pdev->dev, "sys_freq: %u\n", rs->sys_freq);
-       spin_lock_irqsave(&rs->lock, flags);
- 
-       device_reset(&pdev->dev);
- 
--      rt2880_spi_reset(rs);
-+      rs->ops->init_hw(rs);
- 
-       return spi_register_master(master);
- }
-@@ -408,12 +514,6 @@ static int rt2880_spi_remove(struct plat
- 
- MODULE_ALIAS("platform:" DRIVER_NAME);
- 
--static const struct of_device_id rt2880_spi_match[] = {
--      { .compatible = "ralink,rt2880-spi" },
--      {},
--};
--MODULE_DEVICE_TABLE(of, rt2880_spi_match);
--
- static struct platform_driver rt2880_spi_driver = {
-       .driver = {
-               .name = DRIVER_NAME,
-- 
2.3.6
_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to