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