Skip to content

Commit

Permalink
ramips: mt7621-spi: replace the driver with upstream staging one
Browse files Browse the repository at this point in the history
That driver is more efficient thanks to the refactor of spi reading operation.

Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
  • Loading branch information
981213 authored and blogic committed Nov 26, 2018
1 parent 20b09a2 commit a44f000
Showing 1 changed file with 121 additions and 98 deletions.
219 changes: 121 additions & 98 deletions target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch
Original file line number Diff line number Diff line change
Expand Up @@ -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 ++++++++++++++++++++++++++++++++++++++++++++++
Expand Down Expand Up @@ -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
+ *
Expand Down Expand Up @@ -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;
+
Expand All @@ -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;
+};
Expand All @@ -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)
Expand All @@ -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);
Expand Down Expand Up @@ -180,137 +183,166 @@ 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);
+ }
+
+ 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);
+
+ return 0;
+}
+
+#ifdef CONFIG_SOC_MT7620
+static int mt7621_spi_transfer_full_duplex(struct spi_master *master,
+ struct spi_message *m)
+{
Expand All @@ -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;
Expand Down Expand Up @@ -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);
+
Expand All @@ -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);
+}
+
Expand All @@ -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;
Expand Down Expand Up @@ -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);
+
Expand All @@ -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);
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit a44f000

Please sign in to comment.