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 <igv...@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@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to