[OpenWrt-Devel] [PATCH 7/8] ramips: use transfer_one instead of transfer_one_message on mt7621 spi
Michael Lee
igvtee at gmail.com
Sat Oct 10 23:54:33 EDT 2015
use kernel buildin transfer_one_message. we only need to implement
transfer_one
the hardware support max 5 bytes for opcode and address. max 32 bytes
for tx/rx data. when first transfer fill data to op/addr register then
wait second transfer and fill data to data register. finally start
hardware transfer
Signed-off-by: Michael Lee <igvtee at gmail.com>
---
...0061-SPI-ralink-add-mt7621-SoC-spi-driver.patch | 265 ++++++++-------------
1 file changed, 103 insertions(+), 162 deletions(-)
diff --git a/target/linux/ramips/patches-3.18/0061-SPI-ralink-add-mt7621-SoC-spi-driver.patch b/target/linux/ramips/patches-3.18/0061-SPI-ralink-add-mt7621-SoC-spi-driver.patch
index 1b2476c..57ab71d 100644
--- a/target/linux/ramips/patches-3.18/0061-SPI-ralink-add-mt7621-SoC-spi-driver.patch
+++ b/target/linux/ramips/patches-3.18/0061-SPI-ralink-add-mt7621-SoC-spi-driver.patch
@@ -25,7 +25,7 @@
obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o
--- /dev/null
+++ b/drivers/spi/spi-mt7621.c
-@@ -0,0 +1,623 @@
+@@ -0,0 +1,564 @@
+/*
+ * spi-mt7621.c -- MediaTek MT7621 SPI controller driver
+ *
@@ -141,7 +141,26 @@
+#define MT7621_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | \
+ SPI_CS_HIGH)
+
-+struct mt7621_spi;
++struct mt7621_mb_reg {
++ u32 mosi_bit:12,
++ miso_bit:12,
++ cmd_bit:8;
++};
++
++struct mt7621_spi_data {
++ struct spi_message *msg;
++ union {
++ u32 mb_reg;
++ struct mt7621_mb_reg mb;
++ };
++};
++
++struct mt7621_spi_buf {
++ union {
++ u32 data[8];
++ u8 buf[32];
++ };
++};
+
+struct mt7621_spi {
+ struct spi_master *master;
@@ -150,6 +169,8 @@
+ u16 wait_loops;
+ u16 mode;
+ struct clk *clk;
++
++ struct mt7621_spi_data data;
+};
+
+static inline struct mt7621_spi *spidev_to_mt7621_spi(struct spi_device *spi)
@@ -273,190 +294,109 @@
+ mt7621_spi_read(rs, MT7621_SPI_SPACE));
+}
+
-+/* copy from spi.c */
-+static void spi_set_cs(struct spi_device *spi, bool enable)
++static void mt7621_fill_cmd(struct mt7621_spi *rs,
++ const u8 *data, unsigned len)
+{
-+ if (spi->mode & SPI_CS_HIGH)
-+ enable = !enable;
++ struct mt7621_spi_buf tmp;
+
-+ if (spi->cs_gpio >= 0)
-+ gpio_set_value(spi->cs_gpio, !enable);
-+ else if (spi->master->set_cs)
-+ spi->master->set_cs(spi, !enable);
-+}
-+
-+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;
-+ struct spi_transfer *t = NULL;
-+ int status = 0;
-+ int i, len = 0;
-+ int rx_len = 0;
-+ u32 data[9] = { 0 };
-+ u32 val;
++ rs->data.mb.cmd_bit = len << 3;
+
-+ mt7621_spi_wait_ready(rs, 1);
-+
-+ list_for_each_entry(t, &m->transfers, transfer_list) {
-+ const u8 *buf = t->tx_buf;
-+
-+ if (t->rx_buf)
-+ rx_len += t->len;
-+
-+ if (!buf)
-+ continue;
-+
-+ if (WARN_ON(len + t->len > 36)) {
-+ status = -EIO;
-+ goto msg_done;
-+ }
-+
-+ for (i = 0; i < t->len; i++, len++)
-+ data[len / 4] |= buf[i] << (8 * (len & 3));
-+ }
-+
-+ if (WARN_ON(rx_len > 32)) {
-+ status = -EIO;
-+ goto msg_done;
++ if (len == 5) {
++ tmp.data[0] = mt7621_spi_read(rs, MT7621_SPI_TRANS);
++ tmp.data[0] &= ~(SPITRANS_ADDREXT_MASK << SPITRANS_ADDREXT_OFFSET);
++ tmp.data[0] |= (data[0] << SPITRANS_ADDREXT_OFFSET);
++ mt7621_spi_write(rs, MT7621_SPI_TRANS, tmp.data[0]);
++ data++;
++ len--;
+ }
+
-+ data[0] = swab32(data[0]);
++ tmp.data[0] = 0;
++ memcpy(tmp.buf, data, len);
++ tmp.data[0] = cpu_to_be32(tmp.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);
-+
-+ spi_set_cs(spi, true);
-+
-+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS);
-+ val |= SPITRANS_START;
-+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val);
-+
-+ mt7621_spi_wait_ready(rs, 36);
-+
-+ spi_set_cs(spi, false);
-+
-+ for (i = 0; i < rx_len; i += 4)
-+ data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i);
-+
-+ m->actual_length = len + rx_len;
++ tmp.data[0] >>= ((4 - len) << 3);
+
-+ len = 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));
-+ }
-+
-+msg_done:
-+ m->status = status;
-+ spi_finalize_current_message(master);
-+
-+ return 0;
++ mt7621_spi_write(rs, MT7621_SPI_OPCODE, tmp.data[0]);
+}
+
-+static int mt7621_spi_transfer_full_duplex(struct spi_master *master,
-+ struct spi_message *m)
++static int mt7621_spi_transfer_one(struct spi_master *master,
++ struct spi_device *spi, struct spi_transfer *xfer)
+{
+ 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 = 0;
-+
-+ mt7621_spi_wait_ready(rs, 1);
-+
-+ list_for_each_entry(t, &m->transfers, transfer_list) {
-+ const u8 *buf = t->tx_buf;
-+
-+ if (t->rx_buf)
-+ rx_len += t->len;
-+
-+ if (!buf)
-+ continue;
-+
-+ if (WARN_ON(len + t->len > 16)) {
-+ status = -EIO;
-+ goto msg_done;
++ int i, last_xfer, len, ret = 0;
++ struct mt7621_spi_buf tmp;
++
++ if (rs->data.mb.cmd_bit == 0) {
++ if (unlikely(!xfer->tx_buf || (xfer->len > 5))) {
++ dev_err(&spi->dev, "error op/addr length: %d\n",
++ xfer->len);
++ ret = -EINVAL;
++ goto err;
+ }
-+
-+ for (i = 0; i < t->len; i++, len++)
-+ data[len / 4] |= buf[i] << (8 * (len & 3));
-+ if (speed > t->speed_hz)
-+ speed = t->speed_hz;
-+ }
-+
-+ if (WARN_ON(rx_len > 16)) {
-+ status = -EIO;
-+ goto msg_done;
++ mt7621_fill_cmd(rs, xfer->tx_buf, xfer->len);
++ last_xfer = list_is_last(&xfer->transfer_list,
++ &rs->data.msg->transfers);
++ } else {
++ if (unlikely(xfer->len > 32)) {
++ dev_err(&spi->dev, "error data length: %d\n",
++ xfer->len);
++ ret = -EINVAL;
++ goto err;
++ }
++ if (xfer->tx_buf) {
++ rs->data.mb.mosi_bit = xfer->len << 3;
++ memcpy(tmp.buf, xfer->tx_buf, xfer->len);
++ for (i = 0; i < xfer->len; i += 4)
++ mt7621_spi_write(rs, (MT7621_SPI_DATA0 + i),
++ tmp.data[(i >> 2)]);
++ }
++ if (xfer->rx_buf)
++ rs->data.mb.miso_bit = xfer->len << 3;
++ last_xfer = 1;
+ }
+
-+ for (i = 0; i < len; i += 4)
-+ mt7621_spi_write(rs, MT7621_SPI_DATA0 + i, data[i / 4]);
-+
-+ val |= len * 8;
-+ val |= (rx_len * 8) << 12;
-+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val);
++ if (!last_xfer)
++ return ret;
+
-+ spi_set_cs(spi, true);
++ /* set more buf size */
++ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, rs->data.mb_reg);
+
-+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS);
-+ val |= SPITRANS_START;
-+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val);
++ /* start transaction */
++ mt7621_spi_setbits(rs, MT7621_SPI_TRANS, SPITRANS_START);
+
-+ mt7621_spi_wait_ready(rs, 36);
-+
-+ spi_set_cs(spi, false);
-+
-+ for (i = 0; i < rx_len; i += 4)
-+ data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA4 + i);
-+
-+ m->actual_length = rx_len;
-+
-+ len = 0;
-+ list_for_each_entry(t, &m->transfers, transfer_list) {
-+ u8 *buf = t->rx_buf;
-+
-+ if (!buf)
-+ continue;
++ len = (rs->data.mb.cmd_bit + rs->data.mb.miso_bit +
++ rs->data.mb.mosi_bit) >> 3;
++ ret = mt7621_spi_wait_ready(rs, len);
++ if (ret) {
++ dev_err(&spi->dev, "spi wait timeout\n");
++ goto err;
++ }
+
-+ for (i = 0; i < t->len; i++, len++)
-+ buf[i] = data[len / 4] >> (8 * (len & 3));
++ if (xfer->rx_buf) {
++ for (i = 0; i < xfer->len; i += 4)
++ tmp.data[(i >> 2)] = mt7621_spi_read(rs,
++ (MT7621_SPI_DATA0 + i));
++ memcpy(xfer->rx_buf, tmp.buf, xfer->len);
+ }
+
-+msg_done:
-+ m->status = status;
-+ spi_finalize_current_message(master);
++err:
++ rs->data.mb_reg = 0;
++ if (unlikely(ret))
++ mt7621_dump_reg(master, __func__);
+
-+ return 0;
++ return ret;
+}
+
-+static int mt7621_spi_transfer_one_message(struct spi_master *master,
-+ struct spi_message *m)
++/* copy from spi.c */
++static void spi_set_cs(struct spi_device *spi, bool enable)
+{
-+ struct spi_device *spi = m->spi;
-+ int cs = spi->chip_select;
++ if (spi->mode & SPI_CS_HIGH)
++ enable = !enable;
+
-+ if (cs)
-+ return mt7621_spi_transfer_full_duplex(master, m);
-+ return mt7621_spi_transfer_half_duplex(master, m);
++ if (spi->cs_gpio >= 0)
++ gpio_set_value(spi->cs_gpio, !enable);
++ else if (spi->master->set_cs)
++ spi->master->set_cs(spi, !enable);
+}
+
+static int mt7621_spi_setup(struct spi_device *spi)
@@ -504,6 +444,7 @@
+ struct spi_device *spi = msg->spi;
+ u32 reg;
+
++ rs->data.msg = msg;
+ if ((rs->mode == spi->mode) && (rs->speed == spi->max_speed_hz))
+ return 0;
+
@@ -591,7 +532,7 @@
+ master->setup = mt7621_spi_setup;
+ master->prepare_message = mt7621_spi_prepare_message;
+ master->set_cs = mt7621_spi_set_cs;
-+ master->transfer_one_message = mt7621_spi_transfer_one_message;
++ master->transfer_one = mt7621_spi_transfer_one;
+
+ dev_set_drvdata(&pdev->dev, master);
+
--
2.3.6
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
More information about the openwrt-devel
mailing list