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,
