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
