aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ramips/patches-3.18/0051-rt5350-spi-second-device.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/ramips/patches-3.18/0051-rt5350-spi-second-device.patch')
-rw-r--r--target/linux/ramips/patches-3.18/0051-rt5350-spi-second-device.patch368
1 files changed, 368 insertions, 0 deletions
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
new file mode 100644
index 0000000..2da8151
--- /dev/null
+++ b/target/linux/ramips/patches-3.18/0051-rt5350-spi-second-device.patch
@@ -0,0 +1,368 @@
+From 27b11d4f1888e1a3d6d75b46d4d5a4d86fc03891 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+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 <blogic@openwrt.org>
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+ 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,