@@ -25,7 +25,7 @@
obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o
--- /dev/null
+++ b/drivers/spi/spi-mt7621.c
-@@ -0,0 +1,565 @@
+@@ -0,0 +1,582 @@
+/*
+ * spi-mt7621.c -- MediaTek MT7621 SPI controller driver
+ *
@@ -57,8 +57,6 @@
+#include <ralink_regs.h>
+
+#define DRIVER_NAME "spi-mt7621"
-+/* in usec */
-+#define RALINK_SPI_WAIT_MAX_LOOP 2000
+
+#define MT7621_SPI_TRANS 0x00
+#define MT7621_SPI_OPCODE 0x04
@@ -147,8 +145,9 @@
+struct mt7621_spi {
+ struct spi_master *master;
+ void __iomem *base;
-+ unsigned int speed;
++ u32 speed;
+ u16 wait_loops;
++ u16 mode;
+ struct clk *clk;
+};
+
@@ -181,6 +180,34 @@
+ iowrite32((ioread32(addr) & ~mask), addr);
+}
+
++static u32 mt7621_spi_baudrate_get(struct spi_device *spi, unsigned int speed)
++{
++ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
++ u32 rate;
++ u32 prescale;
++
++ /*
++ * the supported rates are: 2, 3, 4, ... 4096
++ * round up as we look for equal or less speed
++ */
++ rate = DIV_ROUND_UP(clk_get_rate(rs->clk), speed);
++
++ /* Convert the rate to SPI clock divisor value. */
++ prescale = rate - 2;
++
++ /* some tolerance. double and add 100 */
++ rs->wait_loops = (8 * HZ * loops_per_jiffy) /
++ (clk_get_rate(rs->clk) / rate);
++ rs->wait_loops = (rs->wait_loops << 1) + 100;
++ rs->speed = speed;
++
++ dev_dbg(&spi->dev, "speed: %lu/%u, rate: %u, prescal: %u, loops: %hu\n",
++ clk_get_rate(rs->clk) / rate, speed, rate, prescale,
++ rs->wait_loops);
++
++ return (prescale << SPIMASTER_CLKSEL_OFFSET);
++}
++
+static void mt7621_spi_reset(struct mt7621_spi *rs, int duplex)
+{
+ u32 master = mt7621_spi_read(rs, MT7621_SPI_MASTER);
@@ -207,50 +234,6 @@
+ mt7621_spi_write(rs, MT7621_SPI_POLAR, polar);
+}
+
-+static int mt7621_spi_prepare(struct spi_device *spi, unsigned int speed)
-+{
-+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
-+ u32 rate;
-+ u32 reg;
-+
-+ dev_dbg(&spi->dev, "speed:%u\n", speed);
-+
-+ rate = DIV_ROUND_UP(clk_get_rate(rs->clk), speed);
-+ dev_dbg(&spi->dev, "rate-1:%u\n", rate);
-+
-+ reg = mt7621_spi_read(rs, MT7621_SPI_MASTER);
-+ reg &= ~(0xfff << 16);
-+ reg |= (rate - 2) << 16;
-+
-+ /* some tolerance. double and add 100 */
-+ rs->wait_loops = (8 * HZ * loops_per_jiffy) /
-+ (clk_get_rate(rs->clk) / rate);
-+ rs->wait_loops = (rs->wait_loops << 1) + 100;
-+ rs->speed = speed;
-+
-+ reg &= ~SPIMASTER_LSB;
-+ if (spi->mode & SPI_LSB_FIRST)
-+ reg |= SPIMASTER_LSB;
-+
-+ reg &= ~(SPIMASTER_CPHA | SPIMASTER_CPOL);
-+ switch(spi->mode & (SPI_CPOL | SPI_CPHA)) {
-+ case SPI_MODE_0:
-+ break;
-+ case SPI_MODE_1:
-+ reg |= SPIMASTER_CPHA;
-+ break;
-+ case SPI_MODE_2:
-+ reg |= SPIMASTER_CPOL;
-+ break;
-+ case SPI_MODE_3:
-+ reg |= SPIMASTER_CPOL | SPIMASTER_CPHA;
-+ break;
-+ }
-+ mt7621_spi_write(rs, MT7621_SPI_MASTER, reg);
-+
-+ return 0;
-+}
-+
+static inline int mt7621_spi_wait_ready(struct mt7621_spi *rs, int len)
+{
+ int loop = rs->wait_loops * len;
@@ -269,7 +252,6 @@
+{
+ 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;
@@ -302,10 +284,6 @@
+ goto msg_done;
+ }
+
-+ if (mt7621_spi_prepare(spi, speed)) {
-+ status = -EIO;
-+ goto msg_done;
-+ }
+ data[0] = swab32(data[0]);
+ if (len < 4)
+ data[0] >>= (4 - len) * 8;
@@ -392,11 +370,6 @@
+ goto msg_done;
+ }
+
-+ if (mt7621_spi_prepare(spi, speed)) {
-+ status = -EIO;
-+ goto msg_done;
-+ }
-+
+ for (i = 0; i < len; i += 4)
+ mt7621_spi_write(rs, MT7621_SPI_DATA0 + i, data[i / 4]);
+
@@ -481,6 +454,49 @@
+ return 0;
+}
+
++static int mt7621_spi_prepare_message(struct spi_master *master,
++ struct spi_message *msg)
++{
++ struct mt7621_spi *rs = spi_master_get_devdata(master);
++ struct spi_device *spi = msg->spi;
++ u32 reg;
++
++ if ((rs->mode == spi->mode) && (rs->speed == spi->max_speed_hz))
++ return 0;
++
++ reg = mt7621_spi_read(rs, MT7621_SPI_MASTER);
++ reg &= ~((SPIMASTER_CLKSEL_MASK << SPIMASTER_CLKSEL_OFFSET) |
++ SPIMASTER_CPHA | SPIMASTER_CPOL |
++ SPIMASTER_LSB);
++
++ /* LSB */
++ if (spi->mode & SPI_LSB_FIRST)
++ reg |= SPIMASTER_LSB;
++
++ /* spi mode */
++ switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
++ case SPI_MODE_0:
++ break;
++ case SPI_MODE_1:
++ reg |= SPIMASTER_CPHA;
++ break;
++ case SPI_MODE_2:
++ reg |= SPIMASTER_CPOL;
++ break;
++ case SPI_MODE_3:
++ reg |= SPIMASTER_CPOL | SPIMASTER_CPHA;
++ break;
++ }
++ rs->mode = spi->mode;
++
++ /* clock divide */
++ reg |= mt7621_spi_baudrate_get(spi, spi->max_speed_hz);
++
++ mt7621_spi_write(rs, MT7621_SPI_MASTER, reg);
++
++ return 0;
++}
++
+static const struct of_device_id mt7621_spi_match[] = {
+ { .compatible = "ralink,mt7621-spi" },
+ {},
@@ -530,6 +546,7 @@
+ master->max_speed_hz = clk_get_rate(clk) / 2;
+ master->flags = SPI_MASTER_HALF_DUPLEX;
+ master->setup = mt7621_spi_setup;
++ master->prepare_message = mt7621_spi_prepare_message;
+ master->transfer_one_message = mt7621_spi_transfer_one_message;
+ master->num_chipselect = 2;
+
before spi transfer. use spi_prepare_message to setup spi hardware. it will setup MSB, spi mode and speed Signed-off-by: Michael Lee <igvtee@gmail.com> --- ...0061-SPI-ralink-add-mt7621-SoC-spi-driver.patch | 133 ++++++++++++--------- 1 file changed, 75 insertions(+), 58 deletions(-)