[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