ramips: backport mt7621-spi from linux-next-20190329

Upstream driver has gone through a series of cleanup and was moved
from drivers/staging into drivers/spi. Backport it to replace our
messy driver.

Tested-by: Jörg Schüler-Maroldt <joerg-linux@arcor.de>
[LinkIt Smart 7688, AcSIP AI7688H Wi-Fi module]
Tested-by: Rosen Penev <rosenp@gmail.com>
Tested-by: Tian Xiao bo <peterwillcn@gmail.com>
[Newifi-D2 MediaTek MT7621 ver:1 eco:3]
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
This commit is contained in:
Chuanhong Guo 2019-03-29 17:46:36 +08:00 committed by Christian Lamparter
parent 8252511dc0
commit d80a1c6e2c

View file

@ -1,15 +1,45 @@
From 87a5fcd57c577cd94b5b080deb98885077c13a42 Mon Sep 17 00:00:00 2001 From cbd66c626e16743b05af807ad48012c0a097b9fb Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org> From: Stefan Roese <sr@denx.de>
Date: Sun, 27 Jul 2014 09:49:07 +0100 Date: Mon, 25 Mar 2019 09:29:25 +0100
Subject: [PATCH 43/53] spi: add mt7621 support Subject: [PATCH] spi: mt7621: Move SPI driver out of staging
Signed-off-by: John Crispin <blogic@openwrt.org> This patch moves the MT7621 SPI driver, which is used on some Ralink /
MediaTek MT76xx MIPS SoC's, out of the staging directory. No changes to
the source code are done in this patch.
This driver version was tested successfully on an MT7688 based platform
with an SPI NOR on CS0 and an SPI NAND on CS1 without any issues (so
far).
This patch also documents the devicetree bindings for the MT7621 SPI
device driver.
Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Rob Herring <robh@kernel.org>
Cc: Mark Brown <broonie@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: NeilBrown <neil@brown.name>
Cc: Sankalp Negi <sankalpnegi2310@gmail.com>
Cc: Chuanhong Guo <gch981213@gmail.com>
Cc: John Crispin <john@phrozen.org>
Cc: Armando Miraglia <arma2ff0@gmail.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
--- ---
drivers/spi/Kconfig | 6 + .../devicetree/bindings/spi/spi-mt7621.txt | 26 ++++++
drivers/spi/Makefile | 1 + drivers/spi/Kconfig | 6 ++
drivers/spi/spi-mt7621.c | 480 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/spi/Makefile | 1 +
3 files changed, 487 insertions(+) .../{staging/mt7621-spi => spi}/spi-mt7621.c | 83 +++++++++----------
create mode 100644 drivers/spi/spi-mt7621.c drivers/staging/Kconfig | 2 -
drivers/staging/Makefile | 1 -
drivers/staging/mt7621-spi/Kconfig | 6 --
drivers/staging/mt7621-spi/Makefile | 1 -
drivers/staging/mt7621-spi/TODO | 5 --
9 files changed, 74 insertions(+), 57 deletions(-)
create mode 100644 Documentation/devicetree/bindings/spi/spi-mt7621.txt
rename drivers/{staging/mt7621-spi => spi}/spi-mt7621.c (88%)
delete mode 100644 drivers/staging/mt7621-spi/Kconfig
delete mode 100644 drivers/staging/mt7621-spi/Makefile
delete mode 100644 drivers/staging/mt7621-spi/TODO
--- a/drivers/spi/Kconfig --- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig
@ -38,45 +68,34 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o
--- /dev/null --- /dev/null
+++ b/drivers/spi/spi-mt7621.c +++ b/drivers/spi/spi-mt7621.c
@@ -0,0 +1,494 @@ @@ -0,0 +1,416 @@
+/* +// SPDX-License-Identifier: GPL-2.0
+ * spi-mt7621.c -- MediaTek MT7621 SPI controller driver +//
+ * +// spi-mt7621.c -- MediaTek MT7621 SPI controller driver
+ * Copyright (C) 2011 Sergiy <piratfm@gmail.com> +//
+ * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org> +// Copyright (C) 2011 Sergiy <piratfm@gmail.com>
+ * Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name> +// Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
+ * +// Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name>
+ * Some parts are based on spi-orion.c: +//
+ * Author: Shadi Ammouri <shadi@marvell.com> +// Some parts are based on spi-orion.c:
+ * Copyright (C) 2007-2008 Marvell Ltd. +// Author: Shadi Ammouri <shadi@marvell.com>
+ * +// Copyright (C) 2007-2008 Marvell Ltd.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+ +
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/clk.h> +#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h> +#include <linux/delay.h>
+#include <linux/io.h> +#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/reset.h> +#include <linux/reset.h>
+#include <linux/spi/spi.h> +#include <linux/spi/spi.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/swab.h>
+ +
+#include <ralink_regs.h> +#define DRIVER_NAME "spi-mt7621"
+ +
+#define SPI_BPW_MASK(bits) BIT((bits) - 1)
+
+#define DRIVER_NAME "spi-mt7621"
+/* in usec */ +/* in usec */
+#define RALINK_SPI_WAIT_MAX_LOOP 2000 +#define RALINK_SPI_WAIT_MAX_LOOP 2000
+ +
+/* SPISTAT register bit field */ +/* SPISTAT register bit field */
+#define SPISTAT_BUSY BIT(0) +#define SPISTAT_BUSY BIT(0)
+ +
+#define MT7621_SPI_TRANS 0x00 +#define MT7621_SPI_TRANS 0x00
+#define SPITRANS_BUSY BIT(16) +#define SPITRANS_BUSY BIT(16)
@ -87,32 +106,33 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+#define SPI_CTL_TX_RX_CNT_MASK 0xff +#define SPI_CTL_TX_RX_CNT_MASK 0xff
+#define SPI_CTL_START BIT(8) +#define SPI_CTL_START BIT(8)
+ +
+#define MT7621_SPI_POLAR 0x38
+#define MT7621_SPI_MASTER 0x28 +#define MT7621_SPI_MASTER 0x28
+#define MASTER_MORE_BUFMODE BIT(2)
+#define MASTER_FULL_DUPLEX BIT(10)
+#define MASTER_RS_CLK_SEL GENMASK(27, 16)
+#define MASTER_RS_CLK_SEL_SHIFT 16
+#define MASTER_RS_SLAVE_SEL GENMASK(31, 29)
+
+#define MT7621_SPI_MOREBUF 0x2c +#define MT7621_SPI_MOREBUF 0x2c
+#define MT7621_SPI_POLAR 0x38
+#define MT7621_SPI_SPACE 0x3c +#define MT7621_SPI_SPACE 0x3c
+ +
+#define MT7621_CPHA BIT(5) +#define MT7621_CPHA BIT(5)
+#define MT7621_CPOL BIT(4) +#define MT7621_CPOL BIT(4)
+#define MT7621_LSB_FIRST BIT(3) +#define MT7621_LSB_FIRST BIT(3)
+ +
+#define RT2880_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH)
+
+struct mt7621_spi;
+
+struct mt7621_spi { +struct mt7621_spi {
+ struct spi_master *master; + struct spi_controller *master;
+ void __iomem *base; + void __iomem *base;
+ unsigned int sys_freq; + unsigned int sys_freq;
+ unsigned int speed; + unsigned int speed;
+ struct clk *clk; + struct clk *clk;
+ + int pending_write;
+ struct mt7621_spi_ops *ops;
+}; +};
+ +
+static inline struct mt7621_spi *spidev_to_mt7621_spi(struct spi_device *spi) +static inline struct mt7621_spi *spidev_to_mt7621_spi(struct spi_device *spi)
+{ +{
+ return spi_master_get_devdata(spi->master); + return spi_controller_get_devdata(spi->master);
+} +}
+ +
+static inline u32 mt7621_spi_read(struct mt7621_spi *rs, u32 reg) +static inline u32 mt7621_spi_read(struct mt7621_spi *rs, u32 reg)
@ -125,29 +145,25 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+ iowrite32(val, rs->base + reg); + iowrite32(val, rs->base + reg);
+} +}
+ +
+static void mt7621_spi_reset(struct mt7621_spi *rs, int duplex)
+{
+ u32 master = mt7621_spi_read(rs, MT7621_SPI_MASTER);
+
+ master |= 7 << 29;
+ master |= 1 << 2;
+#ifdef CONFIG_SOC_MT7620
+ if (duplex)
+ master |= 1 << 10;
+ else
+#endif
+ master &= ~(1 << 10);
+
+ mt7621_spi_write(rs, MT7621_SPI_MASTER, master);
+}
+
+static void mt7621_spi_set_cs(struct spi_device *spi, int enable) +static void mt7621_spi_set_cs(struct spi_device *spi, int enable)
+{ +{
+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); + struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
+ int cs = spi->chip_select; + int cs = spi->chip_select;
+ u32 polar = 0; + u32 polar = 0;
+ u32 master;
+
+ /*
+ * Select SPI device 7, enable "more buffer mode" and disable
+ * full-duplex (only half-duplex really works on this chip
+ * reliably)
+ */
+ master = mt7621_spi_read(rs, MT7621_SPI_MASTER);
+ master |= MASTER_RS_SLAVE_SEL | MASTER_MORE_BUFMODE;
+ master &= ~MASTER_FULL_DUPLEX;
+ mt7621_spi_write(rs, MT7621_SPI_MASTER, master);
+
+ rs->pending_write = 0;
+ +
+ mt7621_spi_reset(rs, cs);
+ if (enable) + if (enable)
+ polar = BIT(cs); + polar = BIT(cs);
+ mt7621_spi_write(rs, MT7621_SPI_POLAR, polar); + mt7621_spi_write(rs, MT7621_SPI_POLAR, polar);
@ -171,45 +187,36 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+ rate = 2; + rate = 2;
+ +
+ reg = mt7621_spi_read(rs, MT7621_SPI_MASTER); + reg = mt7621_spi_read(rs, MT7621_SPI_MASTER);
+ reg &= ~(0xfff << 16); + reg &= ~MASTER_RS_CLK_SEL;
+ reg |= (rate - 2) << 16; + reg |= (rate - 2) << MASTER_RS_CLK_SEL_SHIFT;
+ rs->speed = speed; + rs->speed = speed;
+ +
+ reg &= ~MT7621_LSB_FIRST; + reg &= ~MT7621_LSB_FIRST;
+ if (spi->mode & SPI_LSB_FIRST) + if (spi->mode & SPI_LSB_FIRST)
+ reg |= MT7621_LSB_FIRST; + reg |= MT7621_LSB_FIRST;
+ +
+ /*
+ * This SPI controller seems to be tested on SPI flash only and some
+ * bits are swizzled under other SPI modes probably due to incorrect
+ * wiring inside the silicon. Only mode 0 works correctly.
+ */
+ reg &= ~(MT7621_CPHA | MT7621_CPOL); + reg &= ~(MT7621_CPHA | MT7621_CPOL);
+ switch(spi->mode & (SPI_CPOL | SPI_CPHA)) { +
+ case SPI_MODE_0:
+ break;
+ case SPI_MODE_1:
+ reg |= MT7621_CPHA;
+ break;
+ case SPI_MODE_2:
+ reg |= MT7621_CPOL;
+ break;
+ case SPI_MODE_3:
+ reg |= MT7621_CPOL | MT7621_CPHA;
+ break;
+ }
+ mt7621_spi_write(rs, MT7621_SPI_MASTER, reg); + mt7621_spi_write(rs, MT7621_SPI_MASTER, reg);
+ +
+ return 0; + return 0;
+} +}
+ +
+static inline int mt7621_spi_wait_till_ready(struct spi_device *spi) +static inline int mt7621_spi_wait_till_ready(struct mt7621_spi *rs)
+{ +{
+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
+ int i; + int i;
+ +
+ for (i = 0; i < RALINK_SPI_WAIT_MAX_LOOP; i++) { + for (i = 0; i < RALINK_SPI_WAIT_MAX_LOOP; i++) {
+ u32 status; + u32 status;
+ +
+ status = mt7621_spi_read(rs, MT7621_SPI_TRANS); + status = mt7621_spi_read(rs, MT7621_SPI_TRANS);
+ if ((status & SPITRANS_BUSY) == 0) { + if ((status & SPITRANS_BUSY) == 0)
+ return 0; + return 0;
+ }
+ cpu_relax(); + cpu_relax();
+ udelay(1); + udelay(1);
+ } + }
@ -217,205 +224,157 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+ return -ETIMEDOUT; + return -ETIMEDOUT;
+} +}
+ +
+static int mt7621_spi_transfer_half_duplex(struct spi_master *master, +static void mt7621_spi_read_half_duplex(struct mt7621_spi *rs,
+ int rx_len, u8 *buf)
+{
+ int tx_len;
+
+ /*
+ * Combine with any pending write, and perform one or more half-duplex
+ * transactions reading 'len' bytes. Data to be written is already in
+ * MT7621_SPI_DATA.
+ */
+ tx_len = rs->pending_write;
+ rs->pending_write = 0;
+
+ while (rx_len || tx_len) {
+ int i;
+ u32 val = (min(tx_len, 4) * 8) << 24;
+ int rx = min(rx_len, 32);
+
+ if (tx_len > 4)
+ val |= (tx_len - 4) * 8;
+ val |= (rx * 8) << 12;
+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val);
+
+ tx_len = 0;
+
+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS);
+ val |= SPI_CTL_START;
+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val);
+
+ mt7621_spi_wait_till_ready(rs);
+
+ for (i = 0; i < rx; i++) {
+ if ((i % 4) == 0)
+ val = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i);
+ *buf++ = val & 0xff;
+ val >>= 8;
+ }
+
+ rx_len -= i;
+ }
+}
+
+static inline void mt7621_spi_flush(struct mt7621_spi *rs)
+{
+ mt7621_spi_read_half_duplex(rs, 0, NULL);
+}
+
+static void mt7621_spi_write_half_duplex(struct mt7621_spi *rs,
+ int tx_len, const u8 *buf)
+{
+ int len = rs->pending_write;
+ int val = 0;
+
+ if (len & 3) {
+ val = mt7621_spi_read(rs, MT7621_SPI_OPCODE + (len & ~3));
+ if (len < 4) {
+ val <<= (4 - len) * 8;
+ val = swab32(val);
+ }
+ }
+
+ while (tx_len > 0) {
+ if (len >= 36) {
+ rs->pending_write = len;
+ mt7621_spi_flush(rs);
+ len = 0;
+ }
+
+ val |= *buf++ << (8 * (len & 3));
+ len++;
+ if ((len & 3) == 0) {
+ if (len == 4)
+ /* The byte-order of the opcode is weird! */
+ val = swab32(val);
+ mt7621_spi_write(rs, MT7621_SPI_OPCODE + len - 4, val);
+ val = 0;
+ }
+ tx_len -= 1;
+ }
+
+ if (len & 3) {
+ if (len < 4) {
+ val = swab32(val);
+ val >>= (4 - len) * 8;
+ }
+ mt7621_spi_write(rs, MT7621_SPI_OPCODE + (len & ~3), val);
+ }
+
+ rs->pending_write = len;
+}
+
+static int mt7621_spi_transfer_one_message(struct spi_controller *master,
+ struct spi_message *m) + struct spi_message *m)
+{ +{
+ struct mt7621_spi *rs = spi_master_get_devdata(master); + struct mt7621_spi *rs = spi_controller_get_devdata(master);
+ struct spi_device *spi = m->spi; + struct spi_device *spi = m->spi;
+ unsigned int speed = spi->max_speed_hz; + unsigned int speed = spi->max_speed_hz;
+ struct spi_transfer *t = NULL; + struct spi_transfer *t = NULL;
+ int status = 0; + int status = 0;
+ int i, len = 0;
+ int rx_len = 0;
+ u32 data[9] = { 0 };
+ u32 val;
+ +
+ mt7621_spi_wait_till_ready(spi); + mt7621_spi_wait_till_ready(rs);
+
+ 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;
+ +
+ list_for_each_entry(t, &m->transfers, transfer_list)
+ if (t->speed_hz < speed) + if (t->speed_hz < speed)
+ speed = t->speed_hz; + speed = t->speed_hz;
+ +
+ /*
+ * m25p80 might attempt to write more data than we can handle.
+ * truncate the message to what we can fit into the registers
+ */
+ if (len + t->len > 36)
+ t->len = 36 - len;
+
+ 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 (mt7621_spi_prepare(spi, speed)) { + if (mt7621_spi_prepare(spi, speed)) {
+ status = -EIO; + status = -EIO;
+ goto msg_done; + goto msg_done;
+ } + }
+ data[0] = swab32(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);
+ +
+ /* Assert CS */
+ mt7621_spi_set_cs(spi, 1); + mt7621_spi_set_cs(spi, 1);
+ +
+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS); + m->actual_length = 0;
+ val |= SPI_CTL_START;
+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val);
+
+ mt7621_spi_wait_till_ready(spi);
+
+ mt7621_spi_set_cs(spi, 0);
+
+ 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;
+
+ len = 0;
+ list_for_each_entry(t, &m->transfers, transfer_list) { + list_for_each_entry(t, &m->transfers, transfer_list) {
+ u8 *buf = t->rx_buf; + if ((t->rx_buf) && (t->tx_buf)) {
+ + /*
+ if (!buf) + * This controller will shift some extra data out
+ continue; + * of spi_opcode if (mosi_bit_cnt > 0) &&
+ + * (cmd_bit_cnt == 0). So the claimed full-duplex
+ for (i = 0; i < t->len; i++, len++) + * support is broken since we have no way to read
+ buf[i] = data[len / 4] >> (8 * (len & 3)); + * the MISO value during that bit.
+ } + */
+
+msg_done:
+ m->status = status;
+ spi_finalize_current_message(master);
+
+ return 0;
+}
+
+#ifdef CONFIG_SOC_MT7620
+static int mt7621_spi_transfer_full_duplex(struct spi_master *master,
+ struct spi_message *m)
+{
+ 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_till_ready(spi);
+
+ 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; + status = -EIO;
+ goto msg_done; + goto msg_done;
+ } else if (t->rx_buf) {
+ mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf);
+ } else if (t->tx_buf) {
+ mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf);
+ } + }
+ + m->actual_length += t->len;
+ 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)) { + /* Flush data and deassert CS */
+ status = -EIO; + mt7621_spi_flush(rs);
+ 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]);
+
+ val |= len * 8;
+ val |= (rx_len * 8) << 12;
+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val);
+
+ mt7621_spi_set_cs(spi, 1);
+
+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS);
+ val |= SPI_CTL_START;
+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val);
+
+ mt7621_spi_wait_till_ready(spi);
+
+ mt7621_spi_set_cs(spi, 0); + mt7621_spi_set_cs(spi, 0);
+ +
+ 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;
+
+ for (i = 0; i < t->len; i++, len++)
+ buf[i] = data[len / 4] >> (8 * (len & 3));
+ }
+
+msg_done: +msg_done:
+ m->status = status; + m->status = status;
+ spi_finalize_current_message(master); + spi_finalize_current_message(master);
+ +
+ return 0; + return 0;
+} +}
+#endif
+
+static int mt7621_spi_transfer_one_message(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct spi_device *spi = m->spi;
+#ifdef CONFIG_SOC_MT7620
+ int cs = spi->chip_select;
+
+ if (cs)
+ return mt7621_spi_transfer_full_duplex(master, m);
+#endif
+ return mt7621_spi_transfer_half_duplex(master, m);
+}
+ +
+static int mt7621_spi_setup(struct spi_device *spi) +static int mt7621_spi_setup(struct spi_device *spi)
+{ +{
+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); + struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
+ +
+ if ((spi->max_speed_hz == 0) || + if ((spi->max_speed_hz == 0) ||
+ (spi->max_speed_hz > (rs->sys_freq / 2))) + (spi->max_speed_hz > (rs->sys_freq / 2)))
+ spi->max_speed_hz = (rs->sys_freq / 2); + spi->max_speed_hz = (rs->sys_freq / 2);
+ +
+ if (spi->max_speed_hz < (rs->sys_freq / 4097)) { + if (spi->max_speed_hz < (rs->sys_freq / 4097)) {
@ -433,26 +392,20 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+}; +};
+MODULE_DEVICE_TABLE(of, mt7621_spi_match); +MODULE_DEVICE_TABLE(of, mt7621_spi_match);
+ +
+static size_t mt7621_max_transfer_size(struct spi_device *spi)
+{
+ return 32;
+}
+
+static int mt7621_spi_probe(struct platform_device *pdev) +static int mt7621_spi_probe(struct platform_device *pdev)
+{ +{
+ const struct of_device_id *match; + const struct of_device_id *match;
+ struct spi_master *master; + struct spi_controller *master;
+ struct mt7621_spi *rs; + struct mt7621_spi *rs;
+ void __iomem *base; + void __iomem *base;
+ struct resource *r; + struct resource *r;
+ int status = 0; + int status = 0;
+ struct clk *clk; + struct clk *clk;
+ struct mt7621_spi_ops *ops; + int ret;
+ +
+ match = of_match_device(mt7621_spi_match, &pdev->dev); + match = of_match_device(mt7621_spi_match, &pdev->dev);
+ if (!match) + if (!match)
+ return -EINVAL; + return -EINVAL;
+ ops = (struct mt7621_spi_ops *)match->data;
+ +
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, r); + base = devm_ioremap_resource(&pdev->dev, r);
@ -471,47 +424,47 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+ return status; + return status;
+ +
+ master = spi_alloc_master(&pdev->dev, sizeof(*rs)); + master = spi_alloc_master(&pdev->dev, sizeof(*rs));
+ if (master == NULL) { + if (!master) {
+ dev_info(&pdev->dev, "master allocation failed\n"); + dev_info(&pdev->dev, "master allocation failed\n");
+ return -ENOMEM; + return -ENOMEM;
+ } + }
+ +
+ master->mode_bits = RT2880_SPI_MODE_BITS; + master->mode_bits = SPI_LSB_FIRST;
+ + master->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ master->setup = mt7621_spi_setup; + master->setup = mt7621_spi_setup;
+ master->transfer_one_message = mt7621_spi_transfer_one_message; + master->transfer_one_message = mt7621_spi_transfer_one_message;
+ master->bits_per_word_mask = SPI_BPW_MASK(8); + master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->dev.of_node = pdev->dev.of_node; + master->dev.of_node = pdev->dev.of_node;
+ master->num_chipselect = 2; + master->num_chipselect = 2;
+ master->max_transfer_size = mt7621_max_transfer_size;
+ +
+ dev_set_drvdata(&pdev->dev, master); + dev_set_drvdata(&pdev->dev, master);
+ +
+ rs = spi_master_get_devdata(master); + rs = spi_controller_get_devdata(master);
+ rs->base = base; + rs->base = base;
+ rs->clk = clk; + rs->clk = clk;
+ rs->master = master; + rs->master = master;
+ rs->sys_freq = clk_get_rate(rs->clk); + rs->sys_freq = clk_get_rate(rs->clk);
+ rs->ops = ops; + rs->pending_write = 0;
+ dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq); + dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq);
+ +
+ device_reset(&pdev->dev); + ret = device_reset(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "SPI reset failed!\n");
+ return ret;
+ }
+ +
+ mt7621_spi_reset(rs, 0); + return devm_spi_register_controller(&pdev->dev, master);
+
+ return spi_register_master(master);
+} +}
+ +
+static int mt7621_spi_remove(struct platform_device *pdev) +static int mt7621_spi_remove(struct platform_device *pdev)
+{ +{
+ struct spi_master *master; + struct spi_controller *master;
+ struct mt7621_spi *rs; + struct mt7621_spi *rs;
+ +
+ master = dev_get_drvdata(&pdev->dev); + master = dev_get_drvdata(&pdev->dev);
+ rs = spi_master_get_devdata(master); + rs = spi_controller_get_devdata(master);
+ +
+ clk_disable(rs->clk); + clk_disable_unprepare(rs->clk);
+ spi_unregister_master(master);
+ +
+ return 0; + return 0;
+} +}
@ -521,7 +474,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
+static struct platform_driver mt7621_spi_driver = { +static struct platform_driver mt7621_spi_driver = {
+ .driver = { + .driver = {
+ .name = DRIVER_NAME, + .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = mt7621_spi_match, + .of_match_table = mt7621_spi_match,
+ }, + },
+ .probe = mt7621_spi_probe, + .probe = mt7621_spi_probe,