Devicetree
 help / color / mirror / Atom feed
diff for duplicates of <20260930065945.88008-3-eleanor.lin@realtek.com>

diff --git a/a/1.txt b/N1/1.txt
index 7039447..8e342b0 100644
--- a/a/1.txt
+++ b/N1/1.txt
@@ -1,713 +1,49 @@
-From: Jyan Chou <jyanchou@realtek.com>
+Commit aca8cbecdd2e ("spi: spi-mem: Add Realtek SPI NOR flash
+controller driver") from Sep 30, 2026 (linux-next), leads to the
+following Smatch static checker warning:
 
-Add a spi-mem driver for the SPI NOR Flash Controller (SFC) found on
-Realtek DHC SoC. SFC supports Dual I/O.
+	drivers/spi/spi-rtk-nor.c:347 rtk_spi_supports_op()
+	warn: '(-95)' is not bool
 
-Implement the exec_op API for regular control commands and the dirmap API
-for hardware-accelerated read/write operations.
+On Wed, 30 Sep 2026 14:59:45 +0800 Yu-Chun Lin <eleanor.lin@realtek.com> wrote:
+> +static bool rtk_spi_supports_op(struct spi_mem *mem,
+> +				const struct spi_mem_op *op)
+> +{
+> +	if (op->cmd.buswidth != 1)
+> +		return false;
+> +
+> +	if (op->cmd.dtr || op->addr.dtr || op->data.dtr)
+> +		return false;
+> +
+> +	if (op->addr.nbytes != 0) {
+> +		if (op->addr.buswidth > 1)
+> +			return false;
+> +		if (op->addr.nbytes < 3 || op->addr.nbytes > 4)
+> +			return false;
+> +	}
+> +
+> +	/*
+> +	 * The data window is access-triggered: each CPU access to host->iobase
+> +	 * generates one complete SPI transaction. Consecutive byte accesses
+> +	 * therefore cannot be merged into a single transaction, so
+> +	 * multi-byte stateless commands are not supported by this controller.
+> +	 */
+> +	if (!op->addr.nbytes && op->data.nbytes > 1)
+> +		return -EOPNOTSUPP;
 
-The controller is described by three register ranges. The first one (ctrl)
-holds the control registers. The second one (dma) holds the DMA engine
-registers, used to transfer the payload between the flash and main memory.
-The third range is the memory aperture (dirmap) that maps the flash
-contents.
+This is a bool function.  s/-EOPNOTSUPP/false/?
 
-Signed-off-by: Jyan Chou <jyanchou@realtek.com>
-Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
-Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
----
-Changes in v5:
-- Fix the initialization and teardown sequences.
-- Add the check for unsupported multi-byte stateless commands in
-rtk_spi_supports_op().
-- Move the hardware workaround for 4-byte mode switching to rtk_spi_exec_op().
----
- MAINTAINERS               |   6 +
- drivers/spi/Kconfig       |  10 +
- drivers/spi/Makefile      |   1 +
- drivers/spi/spi-rtk-nor.c | 624 ++++++++++++++++++++++++++++++++++++++
- 4 files changed, 641 insertions(+)
- create mode 100644 drivers/spi/spi-rtk-nor.c
+regards,
+dan carpenter
 
-diff --git a/MAINTAINERS b/MAINTAINERS
-index 34d5c9a0d562..20cd9332f823 100644
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -22754,6 +22754,12 @@ S:	Maintained
- F:	Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml
- F:	drivers/spi/spi-realtek-rtl-snand.c
- 
-+REALTEK SPI-NOR
-+M:	Jyan Chou <jyanchou@realtek.com>
-+M:	Yu-Chun Lin <eleanor.lin@realtek.com>
-+S:	Supported
-+F:	drivers/spi/spi-rtk-nor.c
-+
- REALTEK SYSTIMER DRIVER
- M:	Hao-Wen Ting <haowen.ting@realtek.com>
- S:	Maintained
-diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
-index 8782514bb89b..d45baa15a601 100644
---- a/drivers/spi/Kconfig
-+++ b/drivers/spi/Kconfig
-@@ -957,6 +957,16 @@ config SPI_RSPI
- 	help
- 	  SPI driver for Renesas RSPI and QSPI blocks.
- 
-+config SPI_RTK_NOR
-+	tristate "Realtek SPI-NOR flash controller"
-+	depends on ARCH_REALTEK || COMPILE_TEST
-+	depends on SPI_MEM
-+	help
-+	  This enables support for the SPI NOR Flash Controller found on
-+	  Realtek DHC SoCs. The controller supports single and dual I/O
-+	  transfers and offloads the payload to an integrated DMA engine.
-+	  Say Y or M here if you are building a kernel for a Realtek DHC SoC
-+
- config SPI_RZV2H_RSPI
- 	tristate "Renesas RZ/V2H RSPI controller"
- 	depends on ARCH_RENESAS || COMPILE_TEST
-diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
-index 9fa12498ce8c..68f4d3283e0c 100644
---- a/drivers/spi/Makefile
-+++ b/drivers/spi/Makefile
-@@ -131,6 +131,7 @@ obj-$(CONFIG_MACH_REALTEK_RTL)		+= spi-realtek-rtl.o
- obj-$(CONFIG_SPI_REALTEK_SNAND)		+= spi-realtek-rtl-snand.o
- obj-$(CONFIG_SPI_RPCIF)			+= spi-rpc-if.o
- obj-$(CONFIG_SPI_RSPI)			+= spi-rspi.o
-+obj-$(CONFIG_SPI_RTK_NOR)		+= spi-rtk-nor.o
- obj-$(CONFIG_SPI_RZV2H_RSPI)		+= spi-rzv2h-rspi.o
- obj-$(CONFIG_SPI_RZV2M_CSI)		+= spi-rzv2m-csi.o
- obj-$(CONFIG_SPI_S3C64XX)		+= spi-s3c64xx.o
-diff --git a/drivers/spi/spi-rtk-nor.c b/drivers/spi/spi-rtk-nor.c
-new file mode 100644
-index 000000000000..7f56346506b3
---- /dev/null
-+++ b/drivers/spi/spi-rtk-nor.c
-@@ -0,0 +1,624 @@
-+// SPDX-License-Identifier: GPL-2.0
-+//
-+//  Realtek SPI Nor Flash Controller Driver (SFC)
-+//
-+//  Copyright (c) 2024-2026 Realtek Semiconductor Corp.
-+
-+#include <linux/bits.h>
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/errno.h>
-+#include <linux/iopoll.h>
-+#include <linux/minmax.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/reset.h>
-+#include <linux/spi/spi.h>
-+#include <linux/spi/spi-mem.h>
-+#include <linux/types.h>
-+
-+#define SFC_OPCODE		0x00
-+#define DUAL_MODE_EN		BIT(9)
-+
-+#define SFC_CTL			0x04
-+#define RW_DATAEN		BIT(4)
-+#define ADDR_EN			BIT(3)
-+
-+#define SFC_SCK			0x08
-+#define FDIV_MASK		GENMASK(7, 0)
-+
-+#define SFC_CE			0x0c
-+#define DESLT_TIME		0x1a
-+#define DESLT_TIME_SHIFT	16
-+#define PH_CNT			0x13
-+#define PH_CNT_SHIFT		8
-+#define PL_CNT			0x7
-+
-+#define WT_PROM_DONE		BIT(8)
-+
-+#define SFC_POS_LATCH		0x14
-+#define FALLING_EDGE_EN		0x0
-+
-+#define SFC_WAIT_WR		0x18
-+#define SFC_EN_WR		0x1c
-+#define WT_PROM_EN		BIT(8)
-+
-+#define SFC_ADR_FOUR_BYTE_EN	0x28
-+
-+#define MD_FDMA_DDR_SADDR	0x0c
-+#define MD_FDMA_FL_SADDR	0x10
-+
-+#define MD_FDMA_CTRL2		0x14
-+#define MAX_XFER_DMA_LEN	(BIT(26) | BIT(27))
-+#define MAX_XFER_256		BIT(26)
-+#define DMA_TO_FLASH		BIT(25)
-+
-+#define MD_FDMA_CTRL1		0x18
-+#define DMA_W_EN_START		BIT(3)
-+#define DMA_END			BIT(2)
-+#define DMA_W_EN		BIT(1)
-+#define DMA_START		BIT(0)
-+
-+#define MD_FDMA_DDR_SADDR1	0x20
-+
-+#define SFC_DMA_TIMEOUT		20000
-+#define SFC_DMA_MAX_LEN		0x100
-+
-+#define SFC_CTL_DMYCNT_MASK	GENMASK(31, 24)
-+#define SFC_CTL_DMYCNT_SHIFT	24
-+
-+#define DMA_HIGH_BITS_MASK	0x7
-+
-+#define RTK_SPI_OP_RDSR		0x05
-+#define RTK_SPI_OP_WREN		0x06
-+#define RTK_SPI_OP_EN4B		0xb7
-+#define RTK_SPI_OP_EX4B		0xe9
-+
-+#define SFC_AUTOSUSPEND_TIMEOUT	2000
-+
-+struct rtk_spi_host {
-+	struct device		*dev;
-+	struct clk		*clk;
-+	struct reset_control	*rstc;
-+	void __iomem		*regbase;
-+	void __iomem		*iobase;
-+	void __iomem		*mdbase;
-+	void			*buffer;
-+	bool			is_4byte;
-+	dma_addr_t		dma_buffer;
-+	resource_size_t		flash_phys_base;
-+	size_t			dirmap_size;
-+};
-+
-+static u32 rtk_spi_calc_dummy_cycles(const struct spi_mem_op *op)
-+{
-+	if (!op->dummy.nbytes)
-+		return 0;
-+
-+	return (op->dummy.nbytes * 8) / op->dummy.buswidth;
-+}
-+
-+static void rtk_spi_read_mode(struct rtk_spi_host *host, const struct spi_mem_op *op)
-+{
-+	u32 opcode = op->cmd.opcode;
-+	u32 dummy_cycles, val;
-+
-+	if (op->data.buswidth == 2)
-+		opcode |= DUAL_MODE_EN;
-+
-+	writel(opcode, host->regbase + SFC_OPCODE);
-+
-+	val = readl(host->regbase + SFC_CTL);
-+	val |= RW_DATAEN | ADDR_EN;
-+
-+	dummy_cycles = rtk_spi_calc_dummy_cycles(op);
-+
-+	val &= ~SFC_CTL_DMYCNT_MASK;
-+	val |= (dummy_cycles << SFC_CTL_DMYCNT_SHIFT) & SFC_CTL_DMYCNT_MASK;
-+	writel(val, host->regbase + SFC_CTL);
-+
-+	readl(host->iobase);
-+}
-+
-+static void rtk_spi_write_mode(struct rtk_spi_host *host,
-+			       const struct spi_mem_op *op)
-+{
-+	u32 opcode = op->cmd.opcode;
-+	u32 val;
-+
-+	writel(opcode, host->regbase + SFC_OPCODE);
-+
-+	val = readl(host->regbase + SFC_CTL);
-+	val |= RW_DATAEN | ADDR_EN;
-+	writel(val, host->regbase + SFC_CTL);
-+}
-+
-+static void rtk_spi_enable_auto_write(struct rtk_spi_host *host)
-+{
-+	u32 val;
-+
-+	val = WT_PROM_DONE | RTK_SPI_OP_RDSR;
-+	writel(val, host->regbase + SFC_WAIT_WR);
-+
-+	val = WT_PROM_EN | RTK_SPI_OP_WREN;
-+	writel(val, host->regbase + SFC_EN_WR);
-+}
-+
-+static void rtk_spi_disable_auto_write(struct rtk_spi_host *host)
-+{
-+	writel(RTK_SPI_OP_RDSR, host->regbase + SFC_WAIT_WR);
-+	writel(RTK_SPI_OP_WREN, host->regbase + SFC_EN_WR);
-+}
-+
-+static int rtk_spi_byte_transfer(struct rtk_spi_host *host, loff_t offset,
-+				 size_t len, unsigned char *buf, bool is_read)
-+{
-+	if (offset + len > host->dirmap_size) {
-+		dev_err(host->dev, "PIO transfer out of bounds\n");
-+		return -EINVAL;
-+	}
-+
-+	if (is_read)
-+		memcpy_fromio(buf, host->iobase + offset, len);
-+	else
-+		memcpy_toio(host->iobase + offset, buf, len);
-+
-+	return 0;
-+}
-+
-+static void rtk_spi_init(struct rtk_spi_host *host)
-+{
-+	u32 val;
-+
-+	val = readl(host->regbase + SFC_SCK);
-+	val &= ~FDIV_MASK;
-+	val |= (3 << 0) & FDIV_MASK;
-+	writel(val, host->regbase + SFC_SCK);
-+
-+	val = (DESLT_TIME << DESLT_TIME_SHIFT) | (PH_CNT << PH_CNT_SHIFT) | PL_CNT;
-+	writel(val, host->regbase + SFC_CE);
-+
-+	writel(FALLING_EDGE_EN, host->regbase + SFC_POS_LATCH);
-+	writel(RTK_SPI_OP_RDSR, host->regbase + SFC_WAIT_WR);
-+	writel(RTK_SPI_OP_WREN, host->regbase + SFC_EN_WR);
-+
-+	writel(host->is_4byte ? 0x1 : 0x0, host->regbase + SFC_ADR_FOUR_BYTE_EN);
-+}
-+
-+static int rtk_spi_command_read(struct rtk_spi_host *host, const struct spi_mem_op *op)
-+{
-+	size_t len = op->data.nbytes;
-+	loff_t offset = op->addr.val;
-+	u8 opcode = op->cmd.opcode;
-+	u32 dummy_cycles, val;
-+
-+	writel(opcode, host->regbase + SFC_OPCODE);
-+
-+	val = readl(host->regbase + SFC_CTL);
-+	val &= ~(SFC_CTL_DMYCNT_MASK | ADDR_EN);
-+	val |= RW_DATAEN;
-+
-+	if (op->addr.nbytes > 0)
-+		val |= ADDR_EN;
-+
-+	dummy_cycles = rtk_spi_calc_dummy_cycles(op);
-+	val |= (dummy_cycles << SFC_CTL_DMYCNT_SHIFT) & SFC_CTL_DMYCNT_MASK;
-+	writel(val, host->regbase + SFC_CTL);
-+
-+	return rtk_spi_byte_transfer(host, offset, len, op->data.buf.in, true);
-+}
-+
-+static int rtk_spi_do_write_and_cmds(struct rtk_spi_host *host, const struct spi_mem_op *op)
-+{
-+	u8 opcode = op->cmd.opcode;
-+	u32 ctl_val = 0;
-+
-+	writel(opcode, host->regbase + SFC_OPCODE);
-+
-+	if (op->data.nbytes > 0)
-+		ctl_val |= RW_DATAEN;
-+
-+	if (op->addr.nbytes > 0)
-+		ctl_val |= ADDR_EN;
-+
-+	writel(ctl_val, host->regbase + SFC_CTL);
-+
-+	if (op->data.nbytes > 0) {
-+		const u8 *buf = op->data.buf.out;
-+
-+		if (op->addr.val + op->data.nbytes > host->dirmap_size)
-+			return -EINVAL;
-+
-+		writeb(*buf, host->iobase + op->addr.val);
-+	} else {
-+		if (op->addr.val >= host->dirmap_size)
-+			return -EINVAL;
-+
-+		readb(host->iobase + op->addr.val);
-+	}
-+
-+	return 0;
-+}
-+
-+static int rtk_spi_dma_transfer(struct rtk_spi_host *host, loff_t offset,
-+				size_t len, bool is_read)
-+{
-+	u64 dma_buffer, timeout_us = SFC_DMA_TIMEOUT * 100;
-+	u32 flash_phys_addr, val;
-+	int ret;
-+
-+	if (offset + len > host->dirmap_size) {
-+		dev_err(host->dev, "DMA transfer out of bounds\n");
-+		return -EINVAL;
-+	}
-+
-+	writel(DMA_W_EN_START | DMA_W_EN, host->mdbase + MD_FDMA_CTRL1);
-+
-+	dma_buffer = host->dma_buffer;
-+
-+	/* Setup MD DDR address and flash address */
-+	writel(lower_32_bits(dma_buffer), host->mdbase + MD_FDMA_DDR_SADDR);
-+	writel(upper_32_bits(dma_buffer) & DMA_HIGH_BITS_MASK,
-+	       host->mdbase + MD_FDMA_DDR_SADDR1);
-+
-+	/* MD_FDMA_FL_SADDR is a 32-bit hardware register */
-+	flash_phys_addr = lower_32_bits(host->flash_phys_base + offset);
-+	writel(flash_phys_addr, host->mdbase + MD_FDMA_FL_SADDR);
-+
-+	if (is_read)
-+		val = MAX_XFER_DMA_LEN | len;
-+	else
-+		val = DMA_TO_FLASH | MAX_XFER_256 | len;
-+
-+	writel(val, host->mdbase + MD_FDMA_CTRL2);
-+
-+	writel(DMA_W_EN | DMA_START, host->mdbase + MD_FDMA_CTRL1);
-+	udelay(1);
-+
-+	ret = readl_poll_timeout(host->mdbase + MD_FDMA_CTRL1, val,
-+				 !(val & DMA_START), 100, timeout_us);
-+	if (ret) {
-+		dev_err(host->dev, "DMA transfer timed out\n");
-+		val = readl(host->mdbase + MD_FDMA_CTRL1);
-+		val |= DMA_END | DMA_W_EN_START;
-+		writel(val, host->mdbase + MD_FDMA_CTRL1);
-+
-+		if (readl_poll_timeout(host->mdbase + MD_FDMA_CTRL1, val,
-+				       !(val & DMA_END), 10, 1000)) {
-+			dev_err(host->dev, "Failed to stop DMA gracefully\n");
-+		}
-+
-+		return ret;
-+	}
-+
-+	return 0;
-+}
-+
-+static int rtk_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
-+{
-+	struct rtk_spi_host *host = spi_controller_get_devdata(mem->spi->controller);
-+	u32 opcode = op->cmd.opcode;
-+
-+	/*
-+	 * Hardware Workaround:
-+	 * The controller's auto-mode engine requires SFC_ADR_FOUR_BYTE_EN to be
-+	 * explicitly updated when the flash enters or exits 4-byte mode via control
-+	 * commands.
-+	 */
-+	if ((op->addr.nbytes == 4 || opcode == RTK_SPI_OP_EN4B) && !host->is_4byte) {
-+		host->is_4byte = true;
-+		writel(0x1, host->regbase + SFC_ADR_FOUR_BYTE_EN);
-+	} else if ((op->addr.nbytes == 3 || opcode == RTK_SPI_OP_EX4B) && host->is_4byte) {
-+		host->is_4byte = false;
-+		writel(0x0, host->regbase + SFC_ADR_FOUR_BYTE_EN);
-+	}
-+
-+	if (op->data.dir == SPI_MEM_DATA_IN)
-+		return rtk_spi_command_read(host, op);
-+
-+	return rtk_spi_do_write_and_cmds(host, op);
-+}
-+
-+static bool rtk_spi_supports_op(struct spi_mem *mem,
-+				const struct spi_mem_op *op)
-+{
-+	if (op->cmd.buswidth != 1)
-+		return false;
-+
-+	if (op->cmd.dtr || op->addr.dtr || op->data.dtr)
-+		return false;
-+
-+	if (op->addr.nbytes != 0) {
-+		if (op->addr.buswidth > 1)
-+			return false;
-+		if (op->addr.nbytes < 3 || op->addr.nbytes > 4)
-+			return false;
-+	}
-+
-+	/*
-+	 * The data window is access-triggered: each CPU access to host->iobase
-+	 * generates one complete SPI transaction. Consecutive byte accesses
-+	 * therefore cannot be merged into a single transaction, so
-+	 * multi-byte stateless commands are not supported by this controller.
-+	 */
-+	if (!op->addr.nbytes && op->data.nbytes > 1)
-+		return -EOPNOTSUPP;
-+
-+	if (op->dummy.nbytes != 0) {
-+		if (op->dummy.buswidth > 1 || op->dummy.nbytes > 7)
-+			return false;
-+	}
-+
-+	if (op->data.nbytes != 0 && op->data.buswidth > 2)
-+		return false;
-+
-+	return spi_mem_default_supports_op(mem, op);
-+}
-+
-+static int rtk_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
-+{
-+	const struct spi_mem_op *op = desc->info.op_tmpl;
-+
-+	if (op->data.dir == SPI_MEM_DATA_IN && op->addr.nbytes != 3 && op->addr.nbytes != 4)
-+		return -EOPNOTSUPP;
-+
-+	if (op->data.dir != SPI_MEM_DATA_IN && op->data.dir != SPI_MEM_DATA_OUT)
-+		return -EOPNOTSUPP;
-+
-+	return 0;
-+}
-+
-+static ssize_t rtk_spi_dirmap_read(struct spi_mem_dirmap_desc *desc,
-+				   u64 offs, size_t len, void *buf)
-+{
-+	struct rtk_spi_host *host = spi_controller_get_devdata(desc->mem->spi->controller);
-+	const struct spi_mem_op *op = desc->info.op_tmpl;
-+	loff_t addr = desc->info.offset + offs;
-+	size_t chunk_len;
-+	int ret;
-+
-+	/*
-+	 * Handle unaligned address bytes at the beginning of the read operation.
-+	 * The hardware requires 4-byte alignment for DMA transfers.
-+	 */
-+	if (addr & 0x3) {
-+		rtk_spi_read_mode(host, op);
-+		chunk_len = min_t(size_t, 4 - (addr & 0x3), len);
-+		ret = rtk_spi_byte_transfer(host, addr, chunk_len, buf, true);
-+		if (ret)
-+			return ret;
-+
-+		return chunk_len;
-+	}
-+
-+	rtk_spi_read_mode(host, op);
-+	chunk_len = min_t(size_t, len, SFC_DMA_MAX_LEN);
-+	ret = rtk_spi_dma_transfer(host, addr, chunk_len, true);
-+	if (ret) {
-+		dev_err(host->dev, "DMA read transfer failed: %d\n", ret);
-+		return ret;
-+	}
-+
-+	memcpy(buf, host->buffer, chunk_len);
-+
-+	return chunk_len;
-+}
-+
-+static ssize_t rtk_spi_dirmap_write(struct spi_mem_dirmap_desc *desc,
-+				    u64 offs, size_t len, const void *buf)
-+{
-+	struct rtk_spi_host *host = spi_controller_get_devdata(desc->mem->spi->controller);
-+	const struct spi_mem_op *op = desc->info.op_tmpl;
-+	loff_t addr = desc->info.offset + offs;
-+	size_t chunk_len;
-+	int ret = 0;
-+
-+	rtk_spi_enable_auto_write(host);
-+	rtk_spi_write_mode(host, op);
-+
-+	/*
-+	 * Handle unaligned address bytes at the beginning of the write operation.
-+	 * The hardware requires 4-byte alignment for DMA transfers.
-+	 */
-+	if (addr & 0x3) {
-+		chunk_len = min_t(size_t, 4 - (addr & 0x3), len);
-+		ret = rtk_spi_byte_transfer(host, addr, chunk_len, (u8 *)buf, false);
-+
-+		goto out;
-+	}
-+
-+	chunk_len = min_t(size_t, len, SFC_DMA_MAX_LEN);
-+
-+	memcpy(host->buffer, buf, chunk_len);
-+
-+	ret = rtk_spi_dma_transfer(host, addr, chunk_len, false);
-+	if (ret)
-+		dev_err(host->dev, "DMA write transfer failed: %d\n", ret);
-+
-+out:
-+	rtk_spi_disable_auto_write(host);
-+
-+	return ret < 0 ? ret : chunk_len;
-+}
-+
-+static const struct spi_controller_mem_ops rtk_spi_mem_ops = {
-+	.supports_op = rtk_spi_supports_op,
-+	.exec_op = rtk_spi_exec_op,
-+	.dirmap_create = rtk_spi_dirmap_create,
-+	.dirmap_read = rtk_spi_dirmap_read,
-+	.dirmap_write = rtk_spi_dirmap_write,
-+};
-+
-+static int rtk_spi_probe(struct platform_device *pdev)
-+{
-+	struct device *dev = &pdev->dev;
-+	struct spi_controller *ctrl;
-+	struct rtk_spi_host *host;
-+	struct resource *res;
-+	int ret;
-+
-+	ctrl = devm_spi_alloc_host(dev, sizeof(*host));
-+	if (!ctrl)
-+		return -ENOMEM;
-+
-+	platform_set_drvdata(pdev, ctrl);
-+	host = spi_controller_get_devdata(ctrl);
-+	host->dev = dev;
-+
-+	host->clk = devm_clk_get(dev, NULL);
-+	if (IS_ERR(host->clk))
-+		return PTR_ERR(host->clk);
-+
-+	host->rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
-+	if (IS_ERR(host->rstc))
-+		return PTR_ERR(host->rstc);
-+
-+	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(35));
-+	if (ret) {
-+		dev_err(dev, "Failed to set dma mask\n");
-+		return ret;
-+	}
-+
-+	host->buffer = dmam_alloc_coherent(dev, SFC_DMA_MAX_LEN,
-+					   &host->dma_buffer, GFP_KERNEL);
-+	if (!host->buffer)
-+		return  -ENOMEM;
-+
-+	host->regbase = devm_platform_ioremap_resource_byname(pdev, "ctrl");
-+	if (IS_ERR(host->regbase))
-+		return PTR_ERR(host->regbase);
-+
-+	host->mdbase = devm_platform_ioremap_resource_byname(pdev, "dma");
-+	if (IS_ERR(host->mdbase))
-+		return PTR_ERR(host->mdbase);
-+
-+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap");
-+	host->iobase = devm_ioremap_resource(dev, res);
-+	if (IS_ERR(host->iobase))
-+		return PTR_ERR(host->iobase);
-+
-+	host->dirmap_size = resource_size(res);
-+	host->flash_phys_base = res->start;
-+	host->is_4byte = false;
-+
-+	ret = clk_prepare_enable(host->clk);
-+	if (ret)
-+		return ret;
-+
-+	ret = reset_control_assert(host->rstc);
-+	usleep_range(10, 20);
-+	ret = reset_control_deassert(host->rstc);
-+
-+	rtk_spi_init(host);
-+
-+	pm_runtime_set_autosuspend_delay(dev, SFC_AUTOSUSPEND_TIMEOUT);
-+	pm_runtime_use_autosuspend(dev);
-+	pm_runtime_set_active(dev);
-+	pm_runtime_enable(dev);
-+	pm_runtime_get_noresume(dev);
-+
-+	ctrl->mode_bits = SPI_RX_DUAL | SPI_TX_DUAL;
-+	ctrl->bus_num = -1;
-+	ctrl->mem_ops = &rtk_spi_mem_ops;
-+	ctrl->num_chipselect = 1;
-+	ctrl->auto_runtime_pm = true;
-+
-+	ret = spi_register_controller(ctrl);
-+	if (ret < 0) {
-+		dev_err(dev, "failed to register controller\n");
-+		goto err_pm_disable;
-+	}
-+
-+	pm_runtime_put_autosuspend(dev);
-+
-+	return 0;
-+
-+err_pm_disable:
-+	pm_runtime_put_noidle(dev);
-+	pm_runtime_disable(dev);
-+	pm_runtime_set_suspended(dev);
-+	pm_runtime_dont_use_autosuspend(dev);
-+	reset_control_assert(host->rstc);
-+	clk_disable_unprepare(host->clk);
-+
-+	return ret;
-+}
-+
-+static void rtk_spi_remove(struct platform_device *pdev)
-+{
-+	struct spi_controller *ctrl = platform_get_drvdata(pdev);
-+	struct rtk_spi_host *host = spi_controller_get_devdata(ctrl);
-+	struct device *dev = &pdev->dev;
-+
-+	spi_unregister_controller(ctrl);
-+
-+	if (pm_runtime_resume_and_get(dev) < 0)
-+		dev_warn(dev, "Failed to resume device during remove\n");
-+
-+	pm_runtime_put_noidle(dev);
-+	pm_runtime_disable(dev);
-+	pm_runtime_set_suspended(dev);
-+	pm_runtime_dont_use_autosuspend(dev);
-+	reset_control_assert(host->rstc);
-+	clk_disable_unprepare(host->clk);
-+}
-+
-+static const struct of_device_id rtk_spi_dt_ids[] = {
-+	{ .compatible = "realtek,rtd1625-nor" },
-+	{ /* sentinel */ }
-+};
-+
-+MODULE_DEVICE_TABLE(of, rtk_spi_dt_ids);
-+
-+static int rtk_spi_runtime_suspend(struct device *dev)
-+{
-+	struct spi_controller *ctlr = dev_get_drvdata(dev);
-+	struct rtk_spi_host *host = spi_controller_get_devdata(ctlr);
-+
-+	reset_control_assert(host->rstc);
-+
-+	clk_disable_unprepare(host->clk);
-+
-+	return 0;
-+}
-+
-+static int rtk_spi_runtime_resume(struct device *dev)
-+{
-+	struct spi_controller *ctlr = dev_get_drvdata(dev);
-+	struct rtk_spi_host *host = spi_controller_get_devdata(ctlr);
-+	int ret;
-+
-+	ret = clk_prepare_enable(host->clk);
-+	if (ret < 0) {
-+		dev_err(dev, "clk_prepare_enable failed: %d\n", ret);
-+		return ret;
-+	}
-+
-+	reset_control_assert(host->rstc);
-+	usleep_range(10, 20);
-+	reset_control_deassert(host->rstc);
-+
-+	rtk_spi_init(host);
-+
-+	return 0;
-+}
-+
-+static DEFINE_RUNTIME_DEV_PM_OPS(rtk_spi_pm_ops, rtk_spi_runtime_suspend,
-+				 rtk_spi_runtime_resume, NULL);
-+
-+static struct platform_driver rtk_spi_driver = {
-+	.driver = {
-+		.name = "rtk-spi-nor",
-+		.of_match_table = rtk_spi_dt_ids,
-+		.pm = pm_ptr(&rtk_spi_pm_ops),
-+	},
-+	.probe	= rtk_spi_probe,
-+	.remove	= rtk_spi_remove,
-+};
-+module_platform_driver(rtk_spi_driver);
-+
-+MODULE_DESCRIPTION("Realtek SPI Nor Controller Driver");
-+MODULE_AUTHOR("Jyan Chou <jyanchou@realtek.com>");
-+MODULE_LICENSE("GPL");
--- 
-2.43.0
+> +
+> +	if (op->dummy.nbytes != 0) {
+> +		if (op->dummy.buswidth > 1 || op->dummy.nbytes > 7)
+> +			return false;
+> +	}
+> +
+> +	if (op->data.nbytes != 0 && op->data.buswidth > 2)
+> +		return false;
+> +
+> +	return spi_mem_default_supports_op(mem, op);
+> +}
diff --git a/a/content_digest b/N1/content_digest
index 6d83bbd..cefe053 100644
--- a/a/content_digest
+++ b/N1/content_digest
@@ -1,734 +1,70 @@
  "ref\020260930065945.88008-1-eleanor.lin@realtek.com\0"
- "From\0Yu-Chun Lin <eleanor.lin@realtek.com>\0"
+ "From\0Dan Carpenter <error27@gmail.com>\0"
  "Subject\0[PATCH v5 2/2] spi: spi-mem: Add Realtek SPI NOR flash controller driver\0"
- "Date\0Wed, 30 Sep 2026 14:59:45 +0800\0"
- "To\0<broonie@kernel.org>"
-  <robh@kernel.org>
-  <krzk+dt@kernel.org>
- " <conor+dt@kernel.org>\0"
- "Cc\0<p.zabel@pengutronix.de>"
-  <james.tai@realtek.com>
-  <cy.huang@realtek.com>
-  <stanley_chang@realtek.com>
-  <eleanor.lin@realtek.com>
-  <jyanchou@realtek.com>
-  <linux-spi@vger.kernel.org>
-  <devicetree@vger.kernel.org>
- " <linux-kernel@vger.kernel.org>\0"
+ "Date\0Fri, 2 Oct 2026 14:12:38 +0300\0"
+ "To\0broonie@kernel.org"
+  robh@kernel.org
+  krzk+dt@kernel.org
+ " conor+dt@kernel.org\0"
+ "Cc\0p.zabel@pengutronix.de"
+  james.tai@realtek.com
+  cy.huang@realtek.com
+  stanley_chang@realtek.com
+  eleanor.lin@realtek.com
+  jyanchou@realtek.com
+  linux-spi@vger.kernel.org
+  devicetree@vger.kernel.org
+ " linux-kernel@vger.kernel.org\0"
  "\00:1\0"
  "b\0"
- "From: Jyan Chou <jyanchou@realtek.com>\n"
+ "Commit aca8cbecdd2e (\"spi: spi-mem: Add Realtek SPI NOR flash\n"
+ "controller driver\") from Sep 30, 2026 (linux-next), leads to the\n"
+ "following Smatch static checker warning:\n"
  "\n"
- "Add a spi-mem driver for the SPI NOR Flash Controller (SFC) found on\n"
- "Realtek DHC SoC. SFC supports Dual I/O.\n"
+ "\tdrivers/spi/spi-rtk-nor.c:347 rtk_spi_supports_op()\n"
+ "\twarn: '(-95)' is not bool\n"
  "\n"
- "Implement the exec_op API for regular control commands and the dirmap API\n"
- "for hardware-accelerated read/write operations.\n"
+ "On Wed, 30 Sep 2026 14:59:45 +0800 Yu-Chun Lin <eleanor.lin@realtek.com> wrote:\n"
+ "> +static bool rtk_spi_supports_op(struct spi_mem *mem,\n"
+ "> +\t\t\t\tconst struct spi_mem_op *op)\n"
+ "> +{\n"
+ "> +\tif (op->cmd.buswidth != 1)\n"
+ "> +\t\treturn false;\n"
+ "> +\n"
+ "> +\tif (op->cmd.dtr || op->addr.dtr || op->data.dtr)\n"
+ "> +\t\treturn false;\n"
+ "> +\n"
+ "> +\tif (op->addr.nbytes != 0) {\n"
+ "> +\t\tif (op->addr.buswidth > 1)\n"
+ "> +\t\t\treturn false;\n"
+ "> +\t\tif (op->addr.nbytes < 3 || op->addr.nbytes > 4)\n"
+ "> +\t\t\treturn false;\n"
+ "> +\t}\n"
+ "> +\n"
+ "> +\t/*\n"
+ "> +\t * The data window is access-triggered: each CPU access to host->iobase\n"
+ "> +\t * generates one complete SPI transaction. Consecutive byte accesses\n"
+ "> +\t * therefore cannot be merged into a single transaction, so\n"
+ "> +\t * multi-byte stateless commands are not supported by this controller.\n"
+ "> +\t */\n"
+ "> +\tif (!op->addr.nbytes && op->data.nbytes > 1)\n"
+ "> +\t\treturn -EOPNOTSUPP;\n"
  "\n"
- "The controller is described by three register ranges. The first one (ctrl)\n"
- "holds the control registers. The second one (dma) holds the DMA engine\n"
- "registers, used to transfer the payload between the flash and main memory.\n"
- "The third range is the memory aperture (dirmap) that maps the flash\n"
- "contents.\n"
+ "This is a bool function.  s/-EOPNOTSUPP/false/?\n"
  "\n"
- "Signed-off-by: Jyan Chou <jyanchou@realtek.com>\n"
- "Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>\n"
- "Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>\n"
- "---\n"
- "Changes in v5:\n"
- "- Fix the initialization and teardown sequences.\n"
- "- Add the check for unsupported multi-byte stateless commands in\n"
- "rtk_spi_supports_op().\n"
- "- Move the hardware workaround for 4-byte mode switching to rtk_spi_exec_op().\n"
- "---\n"
- " MAINTAINERS               |   6 +\n"
- " drivers/spi/Kconfig       |  10 +\n"
- " drivers/spi/Makefile      |   1 +\n"
- " drivers/spi/spi-rtk-nor.c | 624 ++++++++++++++++++++++++++++++++++++++\n"
- " 4 files changed, 641 insertions(+)\n"
- " create mode 100644 drivers/spi/spi-rtk-nor.c\n"
+ "regards,\n"
+ "dan carpenter\n"
  "\n"
- "diff --git a/MAINTAINERS b/MAINTAINERS\n"
- "index 34d5c9a0d562..20cd9332f823 100644\n"
- "--- a/MAINTAINERS\n"
- "+++ b/MAINTAINERS\n"
- "@@ -22754,6 +22754,12 @@ S:\tMaintained\n"
- " F:\tDocumentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml\n"
- " F:\tdrivers/spi/spi-realtek-rtl-snand.c\n"
- " \n"
- "+REALTEK SPI-NOR\n"
- "+M:\tJyan Chou <jyanchou@realtek.com>\n"
- "+M:\tYu-Chun Lin <eleanor.lin@realtek.com>\n"
- "+S:\tSupported\n"
- "+F:\tdrivers/spi/spi-rtk-nor.c\n"
- "+\n"
- " REALTEK SYSTIMER DRIVER\n"
- " M:\tHao-Wen Ting <haowen.ting@realtek.com>\n"
- " S:\tMaintained\n"
- "diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig\n"
- "index 8782514bb89b..d45baa15a601 100644\n"
- "--- a/drivers/spi/Kconfig\n"
- "+++ b/drivers/spi/Kconfig\n"
- "@@ -957,6 +957,16 @@ config SPI_RSPI\n"
- " \thelp\n"
- " \t  SPI driver for Renesas RSPI and QSPI blocks.\n"
- " \n"
- "+config SPI_RTK_NOR\n"
- "+\ttristate \"Realtek SPI-NOR flash controller\"\n"
- "+\tdepends on ARCH_REALTEK || COMPILE_TEST\n"
- "+\tdepends on SPI_MEM\n"
- "+\thelp\n"
- "+\t  This enables support for the SPI NOR Flash Controller found on\n"
- "+\t  Realtek DHC SoCs. The controller supports single and dual I/O\n"
- "+\t  transfers and offloads the payload to an integrated DMA engine.\n"
- "+\t  Say Y or M here if you are building a kernel for a Realtek DHC SoC\n"
- "+\n"
- " config SPI_RZV2H_RSPI\n"
- " \ttristate \"Renesas RZ/V2H RSPI controller\"\n"
- " \tdepends on ARCH_RENESAS || COMPILE_TEST\n"
- "diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile\n"
- "index 9fa12498ce8c..68f4d3283e0c 100644\n"
- "--- a/drivers/spi/Makefile\n"
- "+++ b/drivers/spi/Makefile\n"
- "@@ -131,6 +131,7 @@ obj-$(CONFIG_MACH_REALTEK_RTL)\t\t+= spi-realtek-rtl.o\n"
- " obj-$(CONFIG_SPI_REALTEK_SNAND)\t\t+= spi-realtek-rtl-snand.o\n"
- " obj-$(CONFIG_SPI_RPCIF)\t\t\t+= spi-rpc-if.o\n"
- " obj-$(CONFIG_SPI_RSPI)\t\t\t+= spi-rspi.o\n"
- "+obj-$(CONFIG_SPI_RTK_NOR)\t\t+= spi-rtk-nor.o\n"
- " obj-$(CONFIG_SPI_RZV2H_RSPI)\t\t+= spi-rzv2h-rspi.o\n"
- " obj-$(CONFIG_SPI_RZV2M_CSI)\t\t+= spi-rzv2m-csi.o\n"
- " obj-$(CONFIG_SPI_S3C64XX)\t\t+= spi-s3c64xx.o\n"
- "diff --git a/drivers/spi/spi-rtk-nor.c b/drivers/spi/spi-rtk-nor.c\n"
- "new file mode 100644\n"
- "index 000000000000..7f56346506b3\n"
- "--- /dev/null\n"
- "+++ b/drivers/spi/spi-rtk-nor.c\n"
- "@@ -0,0 +1,624 @@\n"
- "+// SPDX-License-Identifier: GPL-2.0\n"
- "+//\n"
- "+//  Realtek SPI Nor Flash Controller Driver (SFC)\n"
- "+//\n"
- "+//  Copyright (c) 2024-2026 Realtek Semiconductor Corp.\n"
- "+\n"
- "+#include <linux/bits.h>\n"
- "+#include <linux/clk.h>\n"
- "+#include <linux/delay.h>\n"
- "+#include <linux/dma-mapping.h>\n"
- "+#include <linux/errno.h>\n"
- "+#include <linux/iopoll.h>\n"
- "+#include <linux/minmax.h>\n"
- "+#include <linux/module.h>\n"
- "+#include <linux/platform_device.h>\n"
- "+#include <linux/pm_runtime.h>\n"
- "+#include <linux/reset.h>\n"
- "+#include <linux/spi/spi.h>\n"
- "+#include <linux/spi/spi-mem.h>\n"
- "+#include <linux/types.h>\n"
- "+\n"
- "+#define SFC_OPCODE\t\t0x00\n"
- "+#define DUAL_MODE_EN\t\tBIT(9)\n"
- "+\n"
- "+#define SFC_CTL\t\t\t0x04\n"
- "+#define RW_DATAEN\t\tBIT(4)\n"
- "+#define ADDR_EN\t\t\tBIT(3)\n"
- "+\n"
- "+#define SFC_SCK\t\t\t0x08\n"
- "+#define FDIV_MASK\t\tGENMASK(7, 0)\n"
- "+\n"
- "+#define SFC_CE\t\t\t0x0c\n"
- "+#define DESLT_TIME\t\t0x1a\n"
- "+#define DESLT_TIME_SHIFT\t16\n"
- "+#define PH_CNT\t\t\t0x13\n"
- "+#define PH_CNT_SHIFT\t\t8\n"
- "+#define PL_CNT\t\t\t0x7\n"
- "+\n"
- "+#define WT_PROM_DONE\t\tBIT(8)\n"
- "+\n"
- "+#define SFC_POS_LATCH\t\t0x14\n"
- "+#define FALLING_EDGE_EN\t\t0x0\n"
- "+\n"
- "+#define SFC_WAIT_WR\t\t0x18\n"
- "+#define SFC_EN_WR\t\t0x1c\n"
- "+#define WT_PROM_EN\t\tBIT(8)\n"
- "+\n"
- "+#define SFC_ADR_FOUR_BYTE_EN\t0x28\n"
- "+\n"
- "+#define MD_FDMA_DDR_SADDR\t0x0c\n"
- "+#define MD_FDMA_FL_SADDR\t0x10\n"
- "+\n"
- "+#define MD_FDMA_CTRL2\t\t0x14\n"
- "+#define MAX_XFER_DMA_LEN\t(BIT(26) | BIT(27))\n"
- "+#define MAX_XFER_256\t\tBIT(26)\n"
- "+#define DMA_TO_FLASH\t\tBIT(25)\n"
- "+\n"
- "+#define MD_FDMA_CTRL1\t\t0x18\n"
- "+#define DMA_W_EN_START\t\tBIT(3)\n"
- "+#define DMA_END\t\t\tBIT(2)\n"
- "+#define DMA_W_EN\t\tBIT(1)\n"
- "+#define DMA_START\t\tBIT(0)\n"
- "+\n"
- "+#define MD_FDMA_DDR_SADDR1\t0x20\n"
- "+\n"
- "+#define SFC_DMA_TIMEOUT\t\t20000\n"
- "+#define SFC_DMA_MAX_LEN\t\t0x100\n"
- "+\n"
- "+#define SFC_CTL_DMYCNT_MASK\tGENMASK(31, 24)\n"
- "+#define SFC_CTL_DMYCNT_SHIFT\t24\n"
- "+\n"
- "+#define DMA_HIGH_BITS_MASK\t0x7\n"
- "+\n"
- "+#define RTK_SPI_OP_RDSR\t\t0x05\n"
- "+#define RTK_SPI_OP_WREN\t\t0x06\n"
- "+#define RTK_SPI_OP_EN4B\t\t0xb7\n"
- "+#define RTK_SPI_OP_EX4B\t\t0xe9\n"
- "+\n"
- "+#define SFC_AUTOSUSPEND_TIMEOUT\t2000\n"
- "+\n"
- "+struct rtk_spi_host {\n"
- "+\tstruct device\t\t*dev;\n"
- "+\tstruct clk\t\t*clk;\n"
- "+\tstruct reset_control\t*rstc;\n"
- "+\tvoid __iomem\t\t*regbase;\n"
- "+\tvoid __iomem\t\t*iobase;\n"
- "+\tvoid __iomem\t\t*mdbase;\n"
- "+\tvoid\t\t\t*buffer;\n"
- "+\tbool\t\t\tis_4byte;\n"
- "+\tdma_addr_t\t\tdma_buffer;\n"
- "+\tresource_size_t\t\tflash_phys_base;\n"
- "+\tsize_t\t\t\tdirmap_size;\n"
- "+};\n"
- "+\n"
- "+static u32 rtk_spi_calc_dummy_cycles(const struct spi_mem_op *op)\n"
- "+{\n"
- "+\tif (!op->dummy.nbytes)\n"
- "+\t\treturn 0;\n"
- "+\n"
- "+\treturn (op->dummy.nbytes * 8) / op->dummy.buswidth;\n"
- "+}\n"
- "+\n"
- "+static void rtk_spi_read_mode(struct rtk_spi_host *host, const struct spi_mem_op *op)\n"
- "+{\n"
- "+\tu32 opcode = op->cmd.opcode;\n"
- "+\tu32 dummy_cycles, val;\n"
- "+\n"
- "+\tif (op->data.buswidth == 2)\n"
- "+\t\topcode |= DUAL_MODE_EN;\n"
- "+\n"
- "+\twritel(opcode, host->regbase + SFC_OPCODE);\n"
- "+\n"
- "+\tval = readl(host->regbase + SFC_CTL);\n"
- "+\tval |= RW_DATAEN | ADDR_EN;\n"
- "+\n"
- "+\tdummy_cycles = rtk_spi_calc_dummy_cycles(op);\n"
- "+\n"
- "+\tval &= ~SFC_CTL_DMYCNT_MASK;\n"
- "+\tval |= (dummy_cycles << SFC_CTL_DMYCNT_SHIFT) & SFC_CTL_DMYCNT_MASK;\n"
- "+\twritel(val, host->regbase + SFC_CTL);\n"
- "+\n"
- "+\treadl(host->iobase);\n"
- "+}\n"
- "+\n"
- "+static void rtk_spi_write_mode(struct rtk_spi_host *host,\n"
- "+\t\t\t       const struct spi_mem_op *op)\n"
- "+{\n"
- "+\tu32 opcode = op->cmd.opcode;\n"
- "+\tu32 val;\n"
- "+\n"
- "+\twritel(opcode, host->regbase + SFC_OPCODE);\n"
- "+\n"
- "+\tval = readl(host->regbase + SFC_CTL);\n"
- "+\tval |= RW_DATAEN | ADDR_EN;\n"
- "+\twritel(val, host->regbase + SFC_CTL);\n"
- "+}\n"
- "+\n"
- "+static void rtk_spi_enable_auto_write(struct rtk_spi_host *host)\n"
- "+{\n"
- "+\tu32 val;\n"
- "+\n"
- "+\tval = WT_PROM_DONE | RTK_SPI_OP_RDSR;\n"
- "+\twritel(val, host->regbase + SFC_WAIT_WR);\n"
- "+\n"
- "+\tval = WT_PROM_EN | RTK_SPI_OP_WREN;\n"
- "+\twritel(val, host->regbase + SFC_EN_WR);\n"
- "+}\n"
- "+\n"
- "+static void rtk_spi_disable_auto_write(struct rtk_spi_host *host)\n"
- "+{\n"
- "+\twritel(RTK_SPI_OP_RDSR, host->regbase + SFC_WAIT_WR);\n"
- "+\twritel(RTK_SPI_OP_WREN, host->regbase + SFC_EN_WR);\n"
- "+}\n"
- "+\n"
- "+static int rtk_spi_byte_transfer(struct rtk_spi_host *host, loff_t offset,\n"
- "+\t\t\t\t size_t len, unsigned char *buf, bool is_read)\n"
- "+{\n"
- "+\tif (offset + len > host->dirmap_size) {\n"
- "+\t\tdev_err(host->dev, \"PIO transfer out of bounds\\n\");\n"
- "+\t\treturn -EINVAL;\n"
- "+\t}\n"
- "+\n"
- "+\tif (is_read)\n"
- "+\t\tmemcpy_fromio(buf, host->iobase + offset, len);\n"
- "+\telse\n"
- "+\t\tmemcpy_toio(host->iobase + offset, buf, len);\n"
- "+\n"
- "+\treturn 0;\n"
- "+}\n"
- "+\n"
- "+static void rtk_spi_init(struct rtk_spi_host *host)\n"
- "+{\n"
- "+\tu32 val;\n"
- "+\n"
- "+\tval = readl(host->regbase + SFC_SCK);\n"
- "+\tval &= ~FDIV_MASK;\n"
- "+\tval |= (3 << 0) & FDIV_MASK;\n"
- "+\twritel(val, host->regbase + SFC_SCK);\n"
- "+\n"
- "+\tval = (DESLT_TIME << DESLT_TIME_SHIFT) | (PH_CNT << PH_CNT_SHIFT) | PL_CNT;\n"
- "+\twritel(val, host->regbase + SFC_CE);\n"
- "+\n"
- "+\twritel(FALLING_EDGE_EN, host->regbase + SFC_POS_LATCH);\n"
- "+\twritel(RTK_SPI_OP_RDSR, host->regbase + SFC_WAIT_WR);\n"
- "+\twritel(RTK_SPI_OP_WREN, host->regbase + SFC_EN_WR);\n"
- "+\n"
- "+\twritel(host->is_4byte ? 0x1 : 0x0, host->regbase + SFC_ADR_FOUR_BYTE_EN);\n"
- "+}\n"
- "+\n"
- "+static int rtk_spi_command_read(struct rtk_spi_host *host, const struct spi_mem_op *op)\n"
- "+{\n"
- "+\tsize_t len = op->data.nbytes;\n"
- "+\tloff_t offset = op->addr.val;\n"
- "+\tu8 opcode = op->cmd.opcode;\n"
- "+\tu32 dummy_cycles, val;\n"
- "+\n"
- "+\twritel(opcode, host->regbase + SFC_OPCODE);\n"
- "+\n"
- "+\tval = readl(host->regbase + SFC_CTL);\n"
- "+\tval &= ~(SFC_CTL_DMYCNT_MASK | ADDR_EN);\n"
- "+\tval |= RW_DATAEN;\n"
- "+\n"
- "+\tif (op->addr.nbytes > 0)\n"
- "+\t\tval |= ADDR_EN;\n"
- "+\n"
- "+\tdummy_cycles = rtk_spi_calc_dummy_cycles(op);\n"
- "+\tval |= (dummy_cycles << SFC_CTL_DMYCNT_SHIFT) & SFC_CTL_DMYCNT_MASK;\n"
- "+\twritel(val, host->regbase + SFC_CTL);\n"
- "+\n"
- "+\treturn rtk_spi_byte_transfer(host, offset, len, op->data.buf.in, true);\n"
- "+}\n"
- "+\n"
- "+static int rtk_spi_do_write_and_cmds(struct rtk_spi_host *host, const struct spi_mem_op *op)\n"
- "+{\n"
- "+\tu8 opcode = op->cmd.opcode;\n"
- "+\tu32 ctl_val = 0;\n"
- "+\n"
- "+\twritel(opcode, host->regbase + SFC_OPCODE);\n"
- "+\n"
- "+\tif (op->data.nbytes > 0)\n"
- "+\t\tctl_val |= RW_DATAEN;\n"
- "+\n"
- "+\tif (op->addr.nbytes > 0)\n"
- "+\t\tctl_val |= ADDR_EN;\n"
- "+\n"
- "+\twritel(ctl_val, host->regbase + SFC_CTL);\n"
- "+\n"
- "+\tif (op->data.nbytes > 0) {\n"
- "+\t\tconst u8 *buf = op->data.buf.out;\n"
- "+\n"
- "+\t\tif (op->addr.val + op->data.nbytes > host->dirmap_size)\n"
- "+\t\t\treturn -EINVAL;\n"
- "+\n"
- "+\t\twriteb(*buf, host->iobase + op->addr.val);\n"
- "+\t} else {\n"
- "+\t\tif (op->addr.val >= host->dirmap_size)\n"
- "+\t\t\treturn -EINVAL;\n"
- "+\n"
- "+\t\treadb(host->iobase + op->addr.val);\n"
- "+\t}\n"
- "+\n"
- "+\treturn 0;\n"
- "+}\n"
- "+\n"
- "+static int rtk_spi_dma_transfer(struct rtk_spi_host *host, loff_t offset,\n"
- "+\t\t\t\tsize_t len, bool is_read)\n"
- "+{\n"
- "+\tu64 dma_buffer, timeout_us = SFC_DMA_TIMEOUT * 100;\n"
- "+\tu32 flash_phys_addr, val;\n"
- "+\tint ret;\n"
- "+\n"
- "+\tif (offset + len > host->dirmap_size) {\n"
- "+\t\tdev_err(host->dev, \"DMA transfer out of bounds\\n\");\n"
- "+\t\treturn -EINVAL;\n"
- "+\t}\n"
- "+\n"
- "+\twritel(DMA_W_EN_START | DMA_W_EN, host->mdbase + MD_FDMA_CTRL1);\n"
- "+\n"
- "+\tdma_buffer = host->dma_buffer;\n"
- "+\n"
- "+\t/* Setup MD DDR address and flash address */\n"
- "+\twritel(lower_32_bits(dma_buffer), host->mdbase + MD_FDMA_DDR_SADDR);\n"
- "+\twritel(upper_32_bits(dma_buffer) & DMA_HIGH_BITS_MASK,\n"
- "+\t       host->mdbase + MD_FDMA_DDR_SADDR1);\n"
- "+\n"
- "+\t/* MD_FDMA_FL_SADDR is a 32-bit hardware register */\n"
- "+\tflash_phys_addr = lower_32_bits(host->flash_phys_base + offset);\n"
- "+\twritel(flash_phys_addr, host->mdbase + MD_FDMA_FL_SADDR);\n"
- "+\n"
- "+\tif (is_read)\n"
- "+\t\tval = MAX_XFER_DMA_LEN | len;\n"
- "+\telse\n"
- "+\t\tval = DMA_TO_FLASH | MAX_XFER_256 | len;\n"
- "+\n"
- "+\twritel(val, host->mdbase + MD_FDMA_CTRL2);\n"
- "+\n"
- "+\twritel(DMA_W_EN | DMA_START, host->mdbase + MD_FDMA_CTRL1);\n"
- "+\tudelay(1);\n"
- "+\n"
- "+\tret = readl_poll_timeout(host->mdbase + MD_FDMA_CTRL1, val,\n"
- "+\t\t\t\t !(val & DMA_START), 100, timeout_us);\n"
- "+\tif (ret) {\n"
- "+\t\tdev_err(host->dev, \"DMA transfer timed out\\n\");\n"
- "+\t\tval = readl(host->mdbase + MD_FDMA_CTRL1);\n"
- "+\t\tval |= DMA_END | DMA_W_EN_START;\n"
- "+\t\twritel(val, host->mdbase + MD_FDMA_CTRL1);\n"
- "+\n"
- "+\t\tif (readl_poll_timeout(host->mdbase + MD_FDMA_CTRL1, val,\n"
- "+\t\t\t\t       !(val & DMA_END), 10, 1000)) {\n"
- "+\t\t\tdev_err(host->dev, \"Failed to stop DMA gracefully\\n\");\n"
- "+\t\t}\n"
- "+\n"
- "+\t\treturn ret;\n"
- "+\t}\n"
- "+\n"
- "+\treturn 0;\n"
- "+}\n"
- "+\n"
- "+static int rtk_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)\n"
- "+{\n"
- "+\tstruct rtk_spi_host *host = spi_controller_get_devdata(mem->spi->controller);\n"
- "+\tu32 opcode = op->cmd.opcode;\n"
- "+\n"
- "+\t/*\n"
- "+\t * Hardware Workaround:\n"
- "+\t * The controller's auto-mode engine requires SFC_ADR_FOUR_BYTE_EN to be\n"
- "+\t * explicitly updated when the flash enters or exits 4-byte mode via control\n"
- "+\t * commands.\n"
- "+\t */\n"
- "+\tif ((op->addr.nbytes == 4 || opcode == RTK_SPI_OP_EN4B) && !host->is_4byte) {\n"
- "+\t\thost->is_4byte = true;\n"
- "+\t\twritel(0x1, host->regbase + SFC_ADR_FOUR_BYTE_EN);\n"
- "+\t} else if ((op->addr.nbytes == 3 || opcode == RTK_SPI_OP_EX4B) && host->is_4byte) {\n"
- "+\t\thost->is_4byte = false;\n"
- "+\t\twritel(0x0, host->regbase + SFC_ADR_FOUR_BYTE_EN);\n"
- "+\t}\n"
- "+\n"
- "+\tif (op->data.dir == SPI_MEM_DATA_IN)\n"
- "+\t\treturn rtk_spi_command_read(host, op);\n"
- "+\n"
- "+\treturn rtk_spi_do_write_and_cmds(host, op);\n"
- "+}\n"
- "+\n"
- "+static bool rtk_spi_supports_op(struct spi_mem *mem,\n"
- "+\t\t\t\tconst struct spi_mem_op *op)\n"
- "+{\n"
- "+\tif (op->cmd.buswidth != 1)\n"
- "+\t\treturn false;\n"
- "+\n"
- "+\tif (op->cmd.dtr || op->addr.dtr || op->data.dtr)\n"
- "+\t\treturn false;\n"
- "+\n"
- "+\tif (op->addr.nbytes != 0) {\n"
- "+\t\tif (op->addr.buswidth > 1)\n"
- "+\t\t\treturn false;\n"
- "+\t\tif (op->addr.nbytes < 3 || op->addr.nbytes > 4)\n"
- "+\t\t\treturn false;\n"
- "+\t}\n"
- "+\n"
- "+\t/*\n"
- "+\t * The data window is access-triggered: each CPU access to host->iobase\n"
- "+\t * generates one complete SPI transaction. Consecutive byte accesses\n"
- "+\t * therefore cannot be merged into a single transaction, so\n"
- "+\t * multi-byte stateless commands are not supported by this controller.\n"
- "+\t */\n"
- "+\tif (!op->addr.nbytes && op->data.nbytes > 1)\n"
- "+\t\treturn -EOPNOTSUPP;\n"
- "+\n"
- "+\tif (op->dummy.nbytes != 0) {\n"
- "+\t\tif (op->dummy.buswidth > 1 || op->dummy.nbytes > 7)\n"
- "+\t\t\treturn false;\n"
- "+\t}\n"
- "+\n"
- "+\tif (op->data.nbytes != 0 && op->data.buswidth > 2)\n"
- "+\t\treturn false;\n"
- "+\n"
- "+\treturn spi_mem_default_supports_op(mem, op);\n"
- "+}\n"
- "+\n"
- "+static int rtk_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)\n"
- "+{\n"
- "+\tconst struct spi_mem_op *op = desc->info.op_tmpl;\n"
- "+\n"
- "+\tif (op->data.dir == SPI_MEM_DATA_IN && op->addr.nbytes != 3 && op->addr.nbytes != 4)\n"
- "+\t\treturn -EOPNOTSUPP;\n"
- "+\n"
- "+\tif (op->data.dir != SPI_MEM_DATA_IN && op->data.dir != SPI_MEM_DATA_OUT)\n"
- "+\t\treturn -EOPNOTSUPP;\n"
- "+\n"
- "+\treturn 0;\n"
- "+}\n"
- "+\n"
- "+static ssize_t rtk_spi_dirmap_read(struct spi_mem_dirmap_desc *desc,\n"
- "+\t\t\t\t   u64 offs, size_t len, void *buf)\n"
- "+{\n"
- "+\tstruct rtk_spi_host *host = spi_controller_get_devdata(desc->mem->spi->controller);\n"
- "+\tconst struct spi_mem_op *op = desc->info.op_tmpl;\n"
- "+\tloff_t addr = desc->info.offset + offs;\n"
- "+\tsize_t chunk_len;\n"
- "+\tint ret;\n"
- "+\n"
- "+\t/*\n"
- "+\t * Handle unaligned address bytes at the beginning of the read operation.\n"
- "+\t * The hardware requires 4-byte alignment for DMA transfers.\n"
- "+\t */\n"
- "+\tif (addr & 0x3) {\n"
- "+\t\trtk_spi_read_mode(host, op);\n"
- "+\t\tchunk_len = min_t(size_t, 4 - (addr & 0x3), len);\n"
- "+\t\tret = rtk_spi_byte_transfer(host, addr, chunk_len, buf, true);\n"
- "+\t\tif (ret)\n"
- "+\t\t\treturn ret;\n"
- "+\n"
- "+\t\treturn chunk_len;\n"
- "+\t}\n"
- "+\n"
- "+\trtk_spi_read_mode(host, op);\n"
- "+\tchunk_len = min_t(size_t, len, SFC_DMA_MAX_LEN);\n"
- "+\tret = rtk_spi_dma_transfer(host, addr, chunk_len, true);\n"
- "+\tif (ret) {\n"
- "+\t\tdev_err(host->dev, \"DMA read transfer failed: %d\\n\", ret);\n"
- "+\t\treturn ret;\n"
- "+\t}\n"
- "+\n"
- "+\tmemcpy(buf, host->buffer, chunk_len);\n"
- "+\n"
- "+\treturn chunk_len;\n"
- "+}\n"
- "+\n"
- "+static ssize_t rtk_spi_dirmap_write(struct spi_mem_dirmap_desc *desc,\n"
- "+\t\t\t\t    u64 offs, size_t len, const void *buf)\n"
- "+{\n"
- "+\tstruct rtk_spi_host *host = spi_controller_get_devdata(desc->mem->spi->controller);\n"
- "+\tconst struct spi_mem_op *op = desc->info.op_tmpl;\n"
- "+\tloff_t addr = desc->info.offset + offs;\n"
- "+\tsize_t chunk_len;\n"
- "+\tint ret = 0;\n"
- "+\n"
- "+\trtk_spi_enable_auto_write(host);\n"
- "+\trtk_spi_write_mode(host, op);\n"
- "+\n"
- "+\t/*\n"
- "+\t * Handle unaligned address bytes at the beginning of the write operation.\n"
- "+\t * The hardware requires 4-byte alignment for DMA transfers.\n"
- "+\t */\n"
- "+\tif (addr & 0x3) {\n"
- "+\t\tchunk_len = min_t(size_t, 4 - (addr & 0x3), len);\n"
- "+\t\tret = rtk_spi_byte_transfer(host, addr, chunk_len, (u8 *)buf, false);\n"
- "+\n"
- "+\t\tgoto out;\n"
- "+\t}\n"
- "+\n"
- "+\tchunk_len = min_t(size_t, len, SFC_DMA_MAX_LEN);\n"
- "+\n"
- "+\tmemcpy(host->buffer, buf, chunk_len);\n"
- "+\n"
- "+\tret = rtk_spi_dma_transfer(host, addr, chunk_len, false);\n"
- "+\tif (ret)\n"
- "+\t\tdev_err(host->dev, \"DMA write transfer failed: %d\\n\", ret);\n"
- "+\n"
- "+out:\n"
- "+\trtk_spi_disable_auto_write(host);\n"
- "+\n"
- "+\treturn ret < 0 ? ret : chunk_len;\n"
- "+}\n"
- "+\n"
- "+static const struct spi_controller_mem_ops rtk_spi_mem_ops = {\n"
- "+\t.supports_op = rtk_spi_supports_op,\n"
- "+\t.exec_op = rtk_spi_exec_op,\n"
- "+\t.dirmap_create = rtk_spi_dirmap_create,\n"
- "+\t.dirmap_read = rtk_spi_dirmap_read,\n"
- "+\t.dirmap_write = rtk_spi_dirmap_write,\n"
- "+};\n"
- "+\n"
- "+static int rtk_spi_probe(struct platform_device *pdev)\n"
- "+{\n"
- "+\tstruct device *dev = &pdev->dev;\n"
- "+\tstruct spi_controller *ctrl;\n"
- "+\tstruct rtk_spi_host *host;\n"
- "+\tstruct resource *res;\n"
- "+\tint ret;\n"
- "+\n"
- "+\tctrl = devm_spi_alloc_host(dev, sizeof(*host));\n"
- "+\tif (!ctrl)\n"
- "+\t\treturn -ENOMEM;\n"
- "+\n"
- "+\tplatform_set_drvdata(pdev, ctrl);\n"
- "+\thost = spi_controller_get_devdata(ctrl);\n"
- "+\thost->dev = dev;\n"
- "+\n"
- "+\thost->clk = devm_clk_get(dev, NULL);\n"
- "+\tif (IS_ERR(host->clk))\n"
- "+\t\treturn PTR_ERR(host->clk);\n"
- "+\n"
- "+\thost->rstc = devm_reset_control_get_optional_exclusive(dev, NULL);\n"
- "+\tif (IS_ERR(host->rstc))\n"
- "+\t\treturn PTR_ERR(host->rstc);\n"
- "+\n"
- "+\tret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(35));\n"
- "+\tif (ret) {\n"
- "+\t\tdev_err(dev, \"Failed to set dma mask\\n\");\n"
- "+\t\treturn ret;\n"
- "+\t}\n"
- "+\n"
- "+\thost->buffer = dmam_alloc_coherent(dev, SFC_DMA_MAX_LEN,\n"
- "+\t\t\t\t\t   &host->dma_buffer, GFP_KERNEL);\n"
- "+\tif (!host->buffer)\n"
- "+\t\treturn  -ENOMEM;\n"
- "+\n"
- "+\thost->regbase = devm_platform_ioremap_resource_byname(pdev, \"ctrl\");\n"
- "+\tif (IS_ERR(host->regbase))\n"
- "+\t\treturn PTR_ERR(host->regbase);\n"
- "+\n"
- "+\thost->mdbase = devm_platform_ioremap_resource_byname(pdev, \"dma\");\n"
- "+\tif (IS_ERR(host->mdbase))\n"
- "+\t\treturn PTR_ERR(host->mdbase);\n"
- "+\n"
- "+\tres = platform_get_resource_byname(pdev, IORESOURCE_MEM, \"dirmap\");\n"
- "+\thost->iobase = devm_ioremap_resource(dev, res);\n"
- "+\tif (IS_ERR(host->iobase))\n"
- "+\t\treturn PTR_ERR(host->iobase);\n"
- "+\n"
- "+\thost->dirmap_size = resource_size(res);\n"
- "+\thost->flash_phys_base = res->start;\n"
- "+\thost->is_4byte = false;\n"
- "+\n"
- "+\tret = clk_prepare_enable(host->clk);\n"
- "+\tif (ret)\n"
- "+\t\treturn ret;\n"
- "+\n"
- "+\tret = reset_control_assert(host->rstc);\n"
- "+\tusleep_range(10, 20);\n"
- "+\tret = reset_control_deassert(host->rstc);\n"
- "+\n"
- "+\trtk_spi_init(host);\n"
- "+\n"
- "+\tpm_runtime_set_autosuspend_delay(dev, SFC_AUTOSUSPEND_TIMEOUT);\n"
- "+\tpm_runtime_use_autosuspend(dev);\n"
- "+\tpm_runtime_set_active(dev);\n"
- "+\tpm_runtime_enable(dev);\n"
- "+\tpm_runtime_get_noresume(dev);\n"
- "+\n"
- "+\tctrl->mode_bits = SPI_RX_DUAL | SPI_TX_DUAL;\n"
- "+\tctrl->bus_num = -1;\n"
- "+\tctrl->mem_ops = &rtk_spi_mem_ops;\n"
- "+\tctrl->num_chipselect = 1;\n"
- "+\tctrl->auto_runtime_pm = true;\n"
- "+\n"
- "+\tret = spi_register_controller(ctrl);\n"
- "+\tif (ret < 0) {\n"
- "+\t\tdev_err(dev, \"failed to register controller\\n\");\n"
- "+\t\tgoto err_pm_disable;\n"
- "+\t}\n"
- "+\n"
- "+\tpm_runtime_put_autosuspend(dev);\n"
- "+\n"
- "+\treturn 0;\n"
- "+\n"
- "+err_pm_disable:\n"
- "+\tpm_runtime_put_noidle(dev);\n"
- "+\tpm_runtime_disable(dev);\n"
- "+\tpm_runtime_set_suspended(dev);\n"
- "+\tpm_runtime_dont_use_autosuspend(dev);\n"
- "+\treset_control_assert(host->rstc);\n"
- "+\tclk_disable_unprepare(host->clk);\n"
- "+\n"
- "+\treturn ret;\n"
- "+}\n"
- "+\n"
- "+static void rtk_spi_remove(struct platform_device *pdev)\n"
- "+{\n"
- "+\tstruct spi_controller *ctrl = platform_get_drvdata(pdev);\n"
- "+\tstruct rtk_spi_host *host = spi_controller_get_devdata(ctrl);\n"
- "+\tstruct device *dev = &pdev->dev;\n"
- "+\n"
- "+\tspi_unregister_controller(ctrl);\n"
- "+\n"
- "+\tif (pm_runtime_resume_and_get(dev) < 0)\n"
- "+\t\tdev_warn(dev, \"Failed to resume device during remove\\n\");\n"
- "+\n"
- "+\tpm_runtime_put_noidle(dev);\n"
- "+\tpm_runtime_disable(dev);\n"
- "+\tpm_runtime_set_suspended(dev);\n"
- "+\tpm_runtime_dont_use_autosuspend(dev);\n"
- "+\treset_control_assert(host->rstc);\n"
- "+\tclk_disable_unprepare(host->clk);\n"
- "+}\n"
- "+\n"
- "+static const struct of_device_id rtk_spi_dt_ids[] = {\n"
- "+\t{ .compatible = \"realtek,rtd1625-nor\" },\n"
- "+\t{ /* sentinel */ }\n"
- "+};\n"
- "+\n"
- "+MODULE_DEVICE_TABLE(of, rtk_spi_dt_ids);\n"
- "+\n"
- "+static int rtk_spi_runtime_suspend(struct device *dev)\n"
- "+{\n"
- "+\tstruct spi_controller *ctlr = dev_get_drvdata(dev);\n"
- "+\tstruct rtk_spi_host *host = spi_controller_get_devdata(ctlr);\n"
- "+\n"
- "+\treset_control_assert(host->rstc);\n"
- "+\n"
- "+\tclk_disable_unprepare(host->clk);\n"
- "+\n"
- "+\treturn 0;\n"
- "+}\n"
- "+\n"
- "+static int rtk_spi_runtime_resume(struct device *dev)\n"
- "+{\n"
- "+\tstruct spi_controller *ctlr = dev_get_drvdata(dev);\n"
- "+\tstruct rtk_spi_host *host = spi_controller_get_devdata(ctlr);\n"
- "+\tint ret;\n"
- "+\n"
- "+\tret = clk_prepare_enable(host->clk);\n"
- "+\tif (ret < 0) {\n"
- "+\t\tdev_err(dev, \"clk_prepare_enable failed: %d\\n\", ret);\n"
- "+\t\treturn ret;\n"
- "+\t}\n"
- "+\n"
- "+\treset_control_assert(host->rstc);\n"
- "+\tusleep_range(10, 20);\n"
- "+\treset_control_deassert(host->rstc);\n"
- "+\n"
- "+\trtk_spi_init(host);\n"
- "+\n"
- "+\treturn 0;\n"
- "+}\n"
- "+\n"
- "+static DEFINE_RUNTIME_DEV_PM_OPS(rtk_spi_pm_ops, rtk_spi_runtime_suspend,\n"
- "+\t\t\t\t rtk_spi_runtime_resume, NULL);\n"
- "+\n"
- "+static struct platform_driver rtk_spi_driver = {\n"
- "+\t.driver = {\n"
- "+\t\t.name = \"rtk-spi-nor\",\n"
- "+\t\t.of_match_table = rtk_spi_dt_ids,\n"
- "+\t\t.pm = pm_ptr(&rtk_spi_pm_ops),\n"
- "+\t},\n"
- "+\t.probe\t= rtk_spi_probe,\n"
- "+\t.remove\t= rtk_spi_remove,\n"
- "+};\n"
- "+module_platform_driver(rtk_spi_driver);\n"
- "+\n"
- "+MODULE_DESCRIPTION(\"Realtek SPI Nor Controller Driver\");\n"
- "+MODULE_AUTHOR(\"Jyan Chou <jyanchou@realtek.com>\");\n"
- "+MODULE_LICENSE(\"GPL\");\n"
- "-- \n"
- 2.43.0
+ "> +\n"
+ "> +\tif (op->dummy.nbytes != 0) {\n"
+ "> +\t\tif (op->dummy.buswidth > 1 || op->dummy.nbytes > 7)\n"
+ "> +\t\t\treturn false;\n"
+ "> +\t}\n"
+ "> +\n"
+ "> +\tif (op->data.nbytes != 0 && op->data.buswidth > 2)\n"
+ "> +\t\treturn false;\n"
+ "> +\n"
+ "> +\treturn spi_mem_default_supports_op(mem, op);\n"
+ > +}
 
-ff2f688906166280c44ffb31af534b0431488d52c69776aa57c2c0d905c7d3fa
+ce653c4d8f5c74fa358d13edfd78357a5f648ffa33ca7b956c9436f9f6ab584b

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox