aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch')
-rw-r--r--target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch219
1 files changed, 121 insertions, 98 deletions
diff --git a/target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch b/target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch
index d9bc48d69b..8367675ff5 100644
--- a/target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch
+++ b/target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch
@@ -5,6 +5,8 @@ Subject: [PATCH 43/53] spi: add mt7621 support
Signed-off-by: John Crispin <blogic@openwrt.org>
---
+Note: This patch contains upstream mt7621-spi at 9c562d8411a54f6731cdc587c29968d9e8610c85
+
drivers/spi/Kconfig | 6 +
drivers/spi/Makefile | 1 +
drivers/spi/spi-mt7621.c | 480 ++++++++++++++++++++++++++++++++++++++++++++++
@@ -38,7 +40,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o
--- /dev/null
+++ b/drivers/spi/spi-mt7621.c
-@@ -0,0 +1,494 @@
+@@ -0,0 +1,515 @@
+/*
+ * spi-mt7621.c -- MediaTek MT7621 SPI controller driver
+ *
@@ -96,7 +98,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+#define MT7621_CPOL BIT(4)
+#define MT7621_LSB_FIRST BIT(3)
+
-+#define RT2880_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH)
++#define RT2880_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | \
++ SPI_LSB_FIRST | SPI_CS_HIGH)
+
+struct mt7621_spi;
+
@@ -106,6 +109,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+ unsigned int sys_freq;
+ unsigned int speed;
+ struct clk *clk;
++ int pending_write;
+
+ struct mt7621_spi_ops *ops;
+};
@@ -131,14 +135,13 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+
+ master |= 7 << 29;
+ master |= 1 << 2;
-+#ifdef CONFIG_SOC_MT7620
+ if (duplex)
+ master |= 1 << 10;
+ else
-+#endif
+ master &= ~(1 << 10);
+
+ mt7621_spi_write(rs, MT7621_SPI_MASTER, master);
++ rs->pending_write = 0;
+}
+
+static void mt7621_spi_set_cs(struct spi_device *spi, int enable)
@@ -147,7 +150,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+ int cs = spi->chip_select;
+ u32 polar = 0;
+
-+ mt7621_spi_reset(rs, cs);
++ mt7621_spi_reset(rs, cs);
+ if (enable)
+ polar = BIT(cs);
+ mt7621_spi_write(rs, MT7621_SPI_POLAR, polar);
@@ -180,36 +183,34 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+ reg |= MT7621_LSB_FIRST;
+
+ reg &= ~(MT7621_CPHA | MT7621_CPOL);
-+ switch(spi->mode & (SPI_CPOL | SPI_CPHA)) {
-+ case SPI_MODE_0:
-+ break;
-+ case SPI_MODE_1:
-+ reg |= MT7621_CPHA;
-+ break;
-+ case SPI_MODE_2:
-+ reg |= MT7621_CPOL;
-+ break;
-+ case SPI_MODE_3:
-+ reg |= MT7621_CPOL | MT7621_CPHA;
-+ break;
++ switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
++ case SPI_MODE_0:
++ break;
++ case SPI_MODE_1:
++ reg |= MT7621_CPHA;
++ break;
++ case SPI_MODE_2:
++ reg |= MT7621_CPOL;
++ break;
++ case SPI_MODE_3:
++ reg |= MT7621_CPOL | MT7621_CPHA;
++ break;
+ }
+ mt7621_spi_write(rs, MT7621_SPI_MASTER, reg);
+
+ return 0;
+}
+
-+static inline int mt7621_spi_wait_till_ready(struct spi_device *spi)
++static inline int mt7621_spi_wait_till_ready(struct mt7621_spi *rs)
+{
-+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
+ int i;
+
+ for (i = 0; i < RALINK_SPI_WAIT_MAX_LOOP; i++) {
+ u32 status;
+
+ status = mt7621_spi_read(rs, MT7621_SPI_TRANS);
-+ if ((status & SPITRANS_BUSY) == 0) {
++ if ((status & SPITRANS_BUSY) == 0)
+ return 0;
-+ }
+ cpu_relax();
+ udelay(1);
+ }
@@ -217,92 +218,124 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+ return -ETIMEDOUT;
+}
+
-+static int mt7621_spi_transfer_half_duplex(struct spi_master *master,
-+ struct spi_message *m)
++static void mt7621_spi_read_half_duplex(struct mt7621_spi *rs,
++ int rx_len, u8 *buf)
+{
-+ struct mt7621_spi *rs = spi_master_get_devdata(master);
-+ struct spi_device *spi = m->spi;
-+ unsigned int speed = spi->max_speed_hz;
-+ struct spi_transfer *t = NULL;
-+ int status = 0;
-+ int i, len = 0;
-+ int rx_len = 0;
-+ u32 data[9] = { 0 };
-+ u32 val;
++ /* Combine with any pending write, and perform one or
++ * more half-duplex transactions reading 'len' bytes.
++ * Data to be written is already in MT7621_SPI_DATA*
++ */
++ int tx_len = rs->pending_write;
+
-+ mt7621_spi_wait_till_ready(spi);
++ rs->pending_write = 0;
+
-+ list_for_each_entry(t, &m->transfers, transfer_list) {
-+ const u8 *buf = t->tx_buf;
++ while (rx_len || tx_len) {
++ int i;
++ u32 val = (min(tx_len, 4) * 8) << 24;
++ int rx = min(rx_len, 32);
+
-+ if (t->rx_buf)
-+ rx_len += t->len;
++ if (tx_len > 4)
++ val |= (tx_len - 4) * 8;
++ val |= (rx * 8) << 12;
++ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val);
+
-+ if (!buf)
-+ continue;
++ tx_len = 0;
+
-+ if (t->speed_hz < speed)
-+ speed = t->speed_hz;
++ val = mt7621_spi_read(rs, MT7621_SPI_TRANS);
++ val |= SPI_CTL_START;
++ mt7621_spi_write(rs, MT7621_SPI_TRANS, val);
+
-+ /*
-+ * m25p80 might attempt to write more data than we can handle.
-+ * truncate the message to what we can fit into the registers
-+ */
-+ if (len + t->len > 36)
-+ t->len = 36 - len;
++ mt7621_spi_wait_till_ready(rs);
+
-+ for (i = 0; i < t->len; i++, len++)
-+ data[len / 4] |= buf[i] << (8 * (len & 3));
++ for (i = 0; i < rx; i++) {
++ if ((i % 4) == 0)
++ val = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i);
++ *buf++ = val & 0xff;
++ val >>= 8;
++ }
++ rx_len -= i;
+ }
++}
+
-+ if (WARN_ON(rx_len > 32)) {
-+ status = -EIO;
-+ goto msg_done;
-+ }
++static inline void mt7621_spi_flush(struct mt7621_spi *rs)
++{
++ mt7621_spi_read_half_duplex(rs, 0, NULL);
++}
+
-+ if (mt7621_spi_prepare(spi, speed)) {
-+ status = -EIO;
-+ goto msg_done;
++static void mt7621_spi_write_half_duplex(struct mt7621_spi *rs,
++ int tx_len, const u8 *buf)
++{
++ int val = 0;
++ int len = rs->pending_write;
++
++ if (len & 3) {
++ val = mt7621_spi_read(rs, MT7621_SPI_OPCODE + (len & ~3));
++ if (len < 4) {
++ val <<= (4 - len) * 8;
++ val = swab32(val);
++ }
+ }
-+ data[0] = swab32(data[0]);
-+ if (len < 4)
-+ data[0] >>= (4 - len) * 8;
-+
-+ for (i = 0; i < len; i += 4)
-+ mt7621_spi_write(rs, MT7621_SPI_OPCODE + i, data[i / 4]);
-+
-+ val = (min_t(int, len, 4) * 8) << 24;
-+ if (len > 4)
-+ val |= (len - 4) * 8;
-+ val |= (rx_len * 8) << 12;
-+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val);
+
-+ mt7621_spi_set_cs(spi, 1);
++ while (tx_len > 0) {
++ if (len >= 36) {
++ rs->pending_write = len;
++ mt7621_spi_flush(rs);
++ len = 0;
++ }
+
-+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS);
-+ val |= SPI_CTL_START;
-+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val);
++ val |= *buf++ << (8 * (len & 3));
++ len++;
++ if ((len & 3) == 0) {
++ if (len == 4)
++ /* The byte-order of the opcode is weird! */
++ val = swab32(val);
++ mt7621_spi_write(rs, MT7621_SPI_OPCODE + len - 4, val);
++ val = 0;
++ }
++ tx_len -= 1;
++ }
++ if (len & 3) {
++ if (len < 4) {
++ val = swab32(val);
++ val >>= (4 - len) * 8;
++ }
++ mt7621_spi_write(rs, MT7621_SPI_OPCODE + (len & ~3), val);
++ }
++ rs->pending_write = len;
++}
+
-+ mt7621_spi_wait_till_ready(spi);
++static int mt7621_spi_transfer_half_duplex(struct spi_master *master,
++ struct spi_message *m)
++{
++ struct mt7621_spi *rs = spi_master_get_devdata(master);
++ struct spi_device *spi = m->spi;
++ unsigned int speed = spi->max_speed_hz;
++ struct spi_transfer *t = NULL;
++ int status = 0;
+
-+ mt7621_spi_set_cs(spi, 0);
++ mt7621_spi_wait_till_ready(rs);
+
-+ for (i = 0; i < rx_len; i += 4)
-+ data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i);
++ list_for_each_entry(t, &m->transfers, transfer_list)
++ if (t->speed_hz < speed)
++ speed = t->speed_hz;
+
-+ m->actual_length = len + rx_len;
++ if (mt7621_spi_prepare(spi, speed)) {
++ status = -EIO;
++ goto msg_done;
++ }
+
-+ len = 0;
++ mt7621_spi_set_cs(spi, 1);
++ m->actual_length = 0;
+ list_for_each_entry(t, &m->transfers, transfer_list) {
-+ u8 *buf = t->rx_buf;
-+
-+ if (!buf)
-+ continue;
-+
-+ for (i = 0; i < t->len; i++, len++)
-+ buf[i] = data[len / 4] >> (8 * (len & 3));
++ if (t->rx_buf)
++ mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf);
++ else if (t->tx_buf)
++ mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf);
++ m->actual_length += t->len;
+ }
++ mt7621_spi_flush(rs);
+
++ mt7621_spi_set_cs(spi, 0);
+msg_done:
+ m->status = status;
+ spi_finalize_current_message(master);
@@ -310,7 +343,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+ return 0;
+}
+
-+#ifdef CONFIG_SOC_MT7620
+static int mt7621_spi_transfer_full_duplex(struct spi_master *master,
+ struct spi_message *m)
+{
@@ -324,7 +356,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+ u32 data[9] = { 0 };
+ u32 val = 0;
+
-+ mt7621_spi_wait_till_ready(spi);
++ mt7621_spi_wait_till_ready(rs);
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ const u8 *buf = t->tx_buf;
@@ -369,7 +401,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+ val |= SPI_CTL_START;
+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val);
+
-+ mt7621_spi_wait_till_ready(spi);
++ mt7621_spi_wait_till_ready(rs);
+
+ mt7621_spi_set_cs(spi, 0);
+
@@ -395,18 +427,15 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+
+ return 0;
+}
-+#endif
+
+static int mt7621_spi_transfer_one_message(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct spi_device *spi = m->spi;
-+#ifdef CONFIG_SOC_MT7620
+ int cs = spi->chip_select;
+
+ if (cs)
+ return mt7621_spi_transfer_full_duplex(master, m);
-+#endif
+ return mt7621_spi_transfer_half_duplex(master, m);
+}
+
@@ -433,11 +462,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+};
+MODULE_DEVICE_TABLE(of, mt7621_spi_match);
+
-+static size_t mt7621_max_transfer_size(struct spi_device *spi)
-+{
-+ return 32;
-+}
-+
+static int mt7621_spi_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
@@ -483,7 +507,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->dev.of_node = pdev->dev.of_node;
+ master->num_chipselect = 2;
-+ master->max_transfer_size = mt7621_max_transfer_size;
+
+ dev_set_drvdata(&pdev->dev, master);
+
@@ -493,6 +516,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+ rs->master = master;
+ rs->sys_freq = clk_get_rate(rs->clk);
+ rs->ops = ops;
++ rs->pending_write = 0;
+ dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq);
+
+ device_reset(&pdev->dev);
@@ -521,7 +545,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+static struct platform_driver mt7621_spi_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
+ .of_match_table = mt7621_spi_match,
+ },
+ .probe = mt7621_spi_probe,