From: Chuanhong Guo Date: Fri, 29 Mar 2019 09:46:36 +0000 (+0800) Subject: ramips: backport mt7621-spi from linux-next-20190329 X-Git-Tag: v19.07.0-rc1~840 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=d80a1c6e2cca46d52870bd6674f3a4466bd7013d;p=openwrt%2Fopenwrt.git 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 [LinkIt Smart 7688, AcSIP AI7688H Wi-Fi module] Tested-by: Rosen Penev Tested-by: Tian Xiao bo [Newifi-D2 MediaTek MT7621 ver:1 eco:3] Signed-off-by: Chuanhong Guo --- diff --git a/target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch b/target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch index d9bc48d69b..b607f2bdf4 100644 --- a/target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch +++ b/target/linux/ramips/patches-4.14/0043-spi-add-mt7621-support.patch @@ -1,15 +1,45 @@ -From 87a5fcd57c577cd94b5b080deb98885077c13a42 Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Sun, 27 Jul 2014 09:49:07 +0100 -Subject: [PATCH 43/53] spi: add mt7621 support +From cbd66c626e16743b05af807ad48012c0a097b9fb Mon Sep 17 00:00:00 2001 +From: Stefan Roese +Date: Mon, 25 Mar 2019 09:29:25 +0100 +Subject: [PATCH] spi: mt7621: Move SPI driver out of staging -Signed-off-by: John Crispin +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 +Cc: Rob Herring +Cc: Mark Brown +Cc: Greg Kroah-Hartman +Cc: NeilBrown +Cc: Sankalp Negi +Cc: Chuanhong Guo +Cc: John Crispin +Cc: Armando Miraglia +Signed-off-by: Mark Brown --- - drivers/spi/Kconfig | 6 + - drivers/spi/Makefile | 1 + - drivers/spi/spi-mt7621.c | 480 ++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 487 insertions(+) - create mode 100644 drivers/spi/spi-mt7621.c + .../devicetree/bindings/spi/spi-mt7621.txt | 26 ++++++ + drivers/spi/Kconfig | 6 ++ + drivers/spi/Makefile | 1 + + .../{staging/mt7621-spi => spi}/spi-mt7621.c | 83 +++++++++---------- + 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 +++ b/drivers/spi/Kconfig @@ -38,45 +68,34 @@ Signed-off-by: John Crispin obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o --- /dev/null +++ b/drivers/spi/spi-mt7621.c -@@ -0,0 +1,494 @@ -+/* -+ * spi-mt7621.c -- MediaTek MT7621 SPI controller driver -+ * -+ * Copyright (C) 2011 Sergiy -+ * Copyright (C) 2011-2013 Gabor Juhos -+ * Copyright (C) 2014-2015 Felix Fietkau -+ * -+ * Some parts are based on spi-orion.c: -+ * Author: Shadi Ammouri -+ * 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 -+#include +@@ -0,0 +1,416 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// ++// spi-mt7621.c -- MediaTek MT7621 SPI controller driver ++// ++// Copyright (C) 2011 Sergiy ++// Copyright (C) 2011-2013 Gabor Juhos ++// Copyright (C) 2014-2015 Felix Fietkau ++// ++// Some parts are based on spi-orion.c: ++// Author: Shadi Ammouri ++// Copyright (C) 2007-2008 Marvell Ltd. ++ +#include -+#include +#include +#include ++#include ++#include +#include +#include -+#include -+#include -+#include + -+#include ++#define DRIVER_NAME "spi-mt7621" + -+#define SPI_BPW_MASK(bits) BIT((bits) - 1) -+ -+#define DRIVER_NAME "spi-mt7621" +/* in usec */ -+#define RALINK_SPI_WAIT_MAX_LOOP 2000 ++#define RALINK_SPI_WAIT_MAX_LOOP 2000 + +/* SPISTAT register bit field */ -+#define SPISTAT_BUSY BIT(0) ++#define SPISTAT_BUSY BIT(0) + +#define MT7621_SPI_TRANS 0x00 +#define SPITRANS_BUSY BIT(16) @@ -87,32 +106,33 @@ Signed-off-by: John Crispin +#define SPI_CTL_TX_RX_CNT_MASK 0xff +#define SPI_CTL_START BIT(8) + -+#define MT7621_SPI_POLAR 0x38 +#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_POLAR 0x38 +#define MT7621_SPI_SPACE 0x3c + +#define MT7621_CPHA BIT(5) +#define MT7621_CPOL BIT(4) +#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 spi_master *master; ++ struct spi_controller *master; + void __iomem *base; + unsigned int sys_freq; + unsigned int speed; + struct clk *clk; -+ -+ struct mt7621_spi_ops *ops; ++ int pending_write; +}; + +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) @@ -125,29 +145,25 @@ Signed-off-by: John Crispin + 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) +{ + struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); + int cs = spi->chip_select; + 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) + polar = BIT(cs); + mt7621_spi_write(rs, MT7621_SPI_POLAR, polar); @@ -171,45 +187,36 @@ Signed-off-by: John Crispin + rate = 2; + + reg = mt7621_spi_read(rs, MT7621_SPI_MASTER); -+ reg &= ~(0xfff << 16); -+ reg |= (rate - 2) << 16; ++ reg &= ~MASTER_RS_CLK_SEL; ++ reg |= (rate - 2) << MASTER_RS_CLK_SEL_SHIFT; + rs->speed = speed; + + reg &= ~MT7621_LSB_FIRST; + if (spi->mode & SPI_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); -+ 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); + + 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; + + for (i = 0; i < RALINK_SPI_WAIT_MAX_LOOP; i++) { + u32 status; + + status = mt7621_spi_read(rs, MT7621_SPI_TRANS); -+ if ((status & SPITRANS_BUSY) == 0) { ++ if ((status & SPITRANS_BUSY) == 0) + return 0; -+ } + cpu_relax(); + udelay(1); + } @@ -217,205 +224,157 @@ Signed-off-by: John Crispin + return -ETIMEDOUT; +} + -+static int mt7621_spi_transfer_half_duplex(struct spi_master *master, -+ struct spi_message *m) ++static void mt7621_spi_read_half_duplex(struct mt7621_spi *rs, ++ int rx_len, u8 *buf) +{ -+ 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; -+ -+ 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 (t->speed_hz < speed) -+ 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; ++ 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; ++ } + -+ for (i = 0; i < t->len; i++, len++) -+ data[len / 4] |= buf[i] << (8 * (len & 3)); ++ rx_len -= i; + } ++} + -+ if (WARN_ON(rx_len > 32)) { -+ status = -EIO; -+ goto msg_done; -+ } ++static inline void mt7621_spi_flush(struct mt7621_spi *rs) ++{ ++ mt7621_spi_read_half_duplex(rs, 0, NULL); ++} + -+ if (mt7621_spi_prepare(spi, speed)) { -+ status = -EIO; -+ goto msg_done; ++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); ++ } + } -+ 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); -+ -+ 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); -+ -+ 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) { -+ u8 *buf = t->rx_buf; -+ -+ if (!buf) -+ continue; ++ while (tx_len > 0) { ++ if (len >= 36) { ++ rs->pending_write = len; ++ mt7621_spi_flush(rs); ++ len = 0; ++ } + -+ for (i = 0; i < t->len; i++, len++) -+ buf[i] = data[len / 4] >> (8 * (len & 3)); ++ 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; + } + -+msg_done: -+ m->status = status; -+ spi_finalize_current_message(master); ++ if (len & 3) { ++ if (len < 4) { ++ val = swab32(val); ++ val >>= (4 - len) * 8; ++ } ++ mt7621_spi_write(rs, MT7621_SPI_OPCODE + (len & ~3), val); ++ } + -+ return 0; ++ rs->pending_write = len; +} + -+#ifdef CONFIG_SOC_MT7620 -+static int mt7621_spi_transfer_full_duplex(struct spi_master *master, ++static int mt7621_spi_transfer_one_message(struct spi_controller *master, + 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; + 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); ++ 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; -+ -+ if (WARN_ON(len + t->len > 16)) { -+ status = -EIO; -+ goto msg_done; -+ } -+ -+ for (i = 0; i < t->len; i++, len++) -+ data[len / 4] |= buf[i] << (8 * (len & 3)); -+ if (speed > t->speed_hz) ++ list_for_each_entry(t, &m->transfers, transfer_list) ++ if (t->speed_hz < speed) + speed = t->speed_hz; -+ } -+ -+ if (WARN_ON(rx_len > 16)) { -+ status = -EIO; -+ 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); -+ ++ /* Assert CS */ + 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); -+ -+ 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; ++ m->actual_length = 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)); ++ if ((t->rx_buf) && (t->tx_buf)) { ++ /* ++ * This controller will shift some extra data out ++ * of spi_opcode if (mosi_bit_cnt > 0) && ++ * (cmd_bit_cnt == 0). So the claimed full-duplex ++ * support is broken since we have no way to read ++ * the MISO value during that bit. ++ */ ++ status = -EIO; ++ 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; + } + ++ /* Flush data and deassert CS */ ++ mt7621_spi_flush(rs); ++ mt7621_spi_set_cs(spi, 0); ++ +msg_done: + m->status = status; + spi_finalize_current_message(master); + + 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) +{ + struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); + + 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); + + if (spi->max_speed_hz < (rs->sys_freq / 4097)) { @@ -433,26 +392,20 @@ Signed-off-by: John Crispin +}; +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) +{ + const struct of_device_id *match; -+ struct spi_master *master; ++ struct spi_controller *master; + struct mt7621_spi *rs; + void __iomem *base; + struct resource *r; + int status = 0; + struct clk *clk; -+ struct mt7621_spi_ops *ops; ++ int ret; + + match = of_match_device(mt7621_spi_match, &pdev->dev); + if (!match) + return -EINVAL; -+ ops = (struct mt7621_spi_ops *)match->data; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, r); @@ -471,47 +424,47 @@ Signed-off-by: John Crispin + return status; + + master = spi_alloc_master(&pdev->dev, sizeof(*rs)); -+ if (master == NULL) { ++ if (!master) { + dev_info(&pdev->dev, "master allocation failed\n"); + 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->transfer_one_message = mt7621_spi_transfer_one_message; + master->bits_per_word_mask = SPI_BPW_MASK(8); + master->dev.of_node = pdev->dev.of_node; + master->num_chipselect = 2; -+ master->max_transfer_size = mt7621_max_transfer_size; + + dev_set_drvdata(&pdev->dev, master); + -+ rs = spi_master_get_devdata(master); ++ rs = spi_controller_get_devdata(master); + rs->base = base; + rs->clk = clk; + rs->master = master; + 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); + -+ device_reset(&pdev->dev); -+ -+ mt7621_spi_reset(rs, 0); ++ ret = device_reset(&pdev->dev); ++ if (ret) { ++ dev_err(&pdev->dev, "SPI reset failed!\n"); ++ return ret; ++ } + -+ return spi_register_master(master); ++ return devm_spi_register_controller(&pdev->dev, master); +} + +static int mt7621_spi_remove(struct platform_device *pdev) +{ -+ struct spi_master *master; ++ struct spi_controller *master; + struct mt7621_spi *rs; + + master = dev_get_drvdata(&pdev->dev); -+ rs = spi_master_get_devdata(master); ++ rs = spi_controller_get_devdata(master); + -+ clk_disable(rs->clk); -+ spi_unregister_master(master); ++ clk_disable_unprepare(rs->clk); + + return 0; +} @@ -521,7 +474,6 @@ Signed-off-by: John Crispin +static struct platform_driver mt7621_spi_driver = { + .driver = { + .name = DRIVER_NAME, -+ .owner = THIS_MODULE, + .of_match_table = mt7621_spi_match, + }, + .probe = mt7621_spi_probe,