162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * TI QSPI driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com
662306a36Sopenharmony_ci * Author: Sourav Poddar <sourav.poddar@ti.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/interrupt.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/device.h>
1462306a36Sopenharmony_ci#include <linux/delay.h>
1562306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1662306a36Sopenharmony_ci#include <linux/dmaengine.h>
1762306a36Sopenharmony_ci#include <linux/omap-dma.h>
1862306a36Sopenharmony_ci#include <linux/platform_device.h>
1962306a36Sopenharmony_ci#include <linux/err.h>
2062306a36Sopenharmony_ci#include <linux/clk.h>
2162306a36Sopenharmony_ci#include <linux/io.h>
2262306a36Sopenharmony_ci#include <linux/slab.h>
2362306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2462306a36Sopenharmony_ci#include <linux/of.h>
2562306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
2662306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
2762306a36Sopenharmony_ci#include <linux/regmap.h>
2862306a36Sopenharmony_ci#include <linux/sizes.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include <linux/spi/spi.h>
3162306a36Sopenharmony_ci#include <linux/spi/spi-mem.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistruct ti_qspi_regs {
3462306a36Sopenharmony_ci	u32 clkctrl;
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistruct ti_qspi {
3862306a36Sopenharmony_ci	struct completion	transfer_complete;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	/* list synchronization */
4162306a36Sopenharmony_ci	struct mutex            list_lock;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	struct spi_master	*master;
4462306a36Sopenharmony_ci	void __iomem            *base;
4562306a36Sopenharmony_ci	void __iomem            *mmap_base;
4662306a36Sopenharmony_ci	size_t			mmap_size;
4762306a36Sopenharmony_ci	struct regmap		*ctrl_base;
4862306a36Sopenharmony_ci	unsigned int		ctrl_reg;
4962306a36Sopenharmony_ci	struct clk		*fclk;
5062306a36Sopenharmony_ci	struct device           *dev;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	struct ti_qspi_regs     ctx_reg;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	dma_addr_t		mmap_phys_base;
5562306a36Sopenharmony_ci	dma_addr_t		rx_bb_dma_addr;
5662306a36Sopenharmony_ci	void			*rx_bb_addr;
5762306a36Sopenharmony_ci	struct dma_chan		*rx_chan;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	u32 cmd;
6062306a36Sopenharmony_ci	u32 dc;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	bool mmap_enabled;
6362306a36Sopenharmony_ci	int current_cs;
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define QSPI_PID			(0x0)
6762306a36Sopenharmony_ci#define QSPI_SYSCONFIG			(0x10)
6862306a36Sopenharmony_ci#define QSPI_SPI_CLOCK_CNTRL_REG	(0x40)
6962306a36Sopenharmony_ci#define QSPI_SPI_DC_REG			(0x44)
7062306a36Sopenharmony_ci#define QSPI_SPI_CMD_REG		(0x48)
7162306a36Sopenharmony_ci#define QSPI_SPI_STATUS_REG		(0x4c)
7262306a36Sopenharmony_ci#define QSPI_SPI_DATA_REG		(0x50)
7362306a36Sopenharmony_ci#define QSPI_SPI_SETUP_REG(n)		((0x54 + 4 * n))
7462306a36Sopenharmony_ci#define QSPI_SPI_SWITCH_REG		(0x64)
7562306a36Sopenharmony_ci#define QSPI_SPI_DATA_REG_1		(0x68)
7662306a36Sopenharmony_ci#define QSPI_SPI_DATA_REG_2		(0x6c)
7762306a36Sopenharmony_ci#define QSPI_SPI_DATA_REG_3		(0x70)
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#define QSPI_COMPLETION_TIMEOUT		msecs_to_jiffies(2000)
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/* Clock Control */
8262306a36Sopenharmony_ci#define QSPI_CLK_EN			(1 << 31)
8362306a36Sopenharmony_ci#define QSPI_CLK_DIV_MAX		0xffff
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/* Command */
8662306a36Sopenharmony_ci#define QSPI_EN_CS(n)			(n << 28)
8762306a36Sopenharmony_ci#define QSPI_WLEN(n)			((n - 1) << 19)
8862306a36Sopenharmony_ci#define QSPI_3_PIN			(1 << 18)
8962306a36Sopenharmony_ci#define QSPI_RD_SNGL			(1 << 16)
9062306a36Sopenharmony_ci#define QSPI_WR_SNGL			(2 << 16)
9162306a36Sopenharmony_ci#define QSPI_RD_DUAL			(3 << 16)
9262306a36Sopenharmony_ci#define QSPI_RD_QUAD			(7 << 16)
9362306a36Sopenharmony_ci#define QSPI_INVAL			(4 << 16)
9462306a36Sopenharmony_ci#define QSPI_FLEN(n)			((n - 1) << 0)
9562306a36Sopenharmony_ci#define QSPI_WLEN_MAX_BITS		128
9662306a36Sopenharmony_ci#define QSPI_WLEN_MAX_BYTES		16
9762306a36Sopenharmony_ci#define QSPI_WLEN_MASK			QSPI_WLEN(QSPI_WLEN_MAX_BITS)
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/* STATUS REGISTER */
10062306a36Sopenharmony_ci#define BUSY				0x01
10162306a36Sopenharmony_ci#define WC				0x02
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/* Device Control */
10462306a36Sopenharmony_ci#define QSPI_DD(m, n)			(m << (3 + n * 8))
10562306a36Sopenharmony_ci#define QSPI_CKPHA(n)			(1 << (2 + n * 8))
10662306a36Sopenharmony_ci#define QSPI_CSPOL(n)			(1 << (1 + n * 8))
10762306a36Sopenharmony_ci#define QSPI_CKPOL(n)			(1 << (n * 8))
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#define	QSPI_FRAME			4096
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define QSPI_AUTOSUSPEND_TIMEOUT         2000
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#define MEM_CS_EN(n)			((n + 1) << 8)
11462306a36Sopenharmony_ci#define MEM_CS_MASK			(7 << 8)
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci#define MM_SWITCH			0x1
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#define QSPI_SETUP_RD_NORMAL		(0x0 << 12)
11962306a36Sopenharmony_ci#define QSPI_SETUP_RD_DUAL		(0x1 << 12)
12062306a36Sopenharmony_ci#define QSPI_SETUP_RD_QUAD		(0x3 << 12)
12162306a36Sopenharmony_ci#define QSPI_SETUP_ADDR_SHIFT		8
12262306a36Sopenharmony_ci#define QSPI_SETUP_DUMMY_SHIFT		10
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#define QSPI_DMA_BUFFER_SIZE            SZ_64K
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic inline unsigned long ti_qspi_read(struct ti_qspi *qspi,
12762306a36Sopenharmony_ci		unsigned long reg)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	return readl(qspi->base + reg);
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic inline void ti_qspi_write(struct ti_qspi *qspi,
13362306a36Sopenharmony_ci		unsigned long val, unsigned long reg)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	writel(val, qspi->base + reg);
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic int ti_qspi_setup(struct spi_device *spi)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct ti_qspi	*qspi = spi_master_get_devdata(spi->master);
14162306a36Sopenharmony_ci	int ret;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (spi->master->busy) {
14462306a36Sopenharmony_ci		dev_dbg(qspi->dev, "master busy doing other transfers\n");
14562306a36Sopenharmony_ci		return -EBUSY;
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	if (!qspi->master->max_speed_hz) {
14962306a36Sopenharmony_ci		dev_err(qspi->dev, "spi max frequency not defined\n");
15062306a36Sopenharmony_ci		return -EINVAL;
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	spi->max_speed_hz = min(spi->max_speed_hz, qspi->master->max_speed_hz);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(qspi->dev);
15662306a36Sopenharmony_ci	if (ret < 0) {
15762306a36Sopenharmony_ci		dev_err(qspi->dev, "pm_runtime_get_sync() failed\n");
15862306a36Sopenharmony_ci		return ret;
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	pm_runtime_mark_last_busy(qspi->dev);
16262306a36Sopenharmony_ci	ret = pm_runtime_put_autosuspend(qspi->dev);
16362306a36Sopenharmony_ci	if (ret < 0) {
16462306a36Sopenharmony_ci		dev_err(qspi->dev, "pm_runtime_put_autosuspend() failed\n");
16562306a36Sopenharmony_ci		return ret;
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	return 0;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic void ti_qspi_setup_clk(struct ti_qspi *qspi, u32 speed_hz)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg;
17462306a36Sopenharmony_ci	int clk_div;
17562306a36Sopenharmony_ci	u32 clk_ctrl_reg, clk_rate, clk_ctrl_new;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	clk_rate = clk_get_rate(qspi->fclk);
17862306a36Sopenharmony_ci	clk_div = DIV_ROUND_UP(clk_rate, speed_hz) - 1;
17962306a36Sopenharmony_ci	clk_div = clamp(clk_div, 0, QSPI_CLK_DIV_MAX);
18062306a36Sopenharmony_ci	dev_dbg(qspi->dev, "hz: %d, clock divider %d\n", speed_hz, clk_div);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	pm_runtime_resume_and_get(qspi->dev);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	clk_ctrl_new = QSPI_CLK_EN | clk_div;
18562306a36Sopenharmony_ci	if (ctx_reg->clkctrl != clk_ctrl_new) {
18662306a36Sopenharmony_ci		clk_ctrl_reg = ti_qspi_read(qspi, QSPI_SPI_CLOCK_CNTRL_REG);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci		clk_ctrl_reg &= ~QSPI_CLK_EN;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci		/* disable SCLK */
19162306a36Sopenharmony_ci		ti_qspi_write(qspi, clk_ctrl_reg, QSPI_SPI_CLOCK_CNTRL_REG);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci		/* enable SCLK */
19462306a36Sopenharmony_ci		ti_qspi_write(qspi, clk_ctrl_new, QSPI_SPI_CLOCK_CNTRL_REG);
19562306a36Sopenharmony_ci		ctx_reg->clkctrl = clk_ctrl_new;
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	pm_runtime_mark_last_busy(qspi->dev);
19962306a36Sopenharmony_ci	pm_runtime_put_autosuspend(qspi->dev);
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic void ti_qspi_restore_ctx(struct ti_qspi *qspi)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG);
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic inline u32 qspi_is_busy(struct ti_qspi *qspi)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	u32 stat;
21262306a36Sopenharmony_ci	unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
21562306a36Sopenharmony_ci	while ((stat & BUSY) && time_after(timeout, jiffies)) {
21662306a36Sopenharmony_ci		cpu_relax();
21762306a36Sopenharmony_ci		stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	WARN(stat & BUSY, "qspi busy\n");
22162306a36Sopenharmony_ci	return stat & BUSY;
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic inline int ti_qspi_poll_wc(struct ti_qspi *qspi)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	u32 stat;
22762306a36Sopenharmony_ci	unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	do {
23062306a36Sopenharmony_ci		stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
23162306a36Sopenharmony_ci		if (stat & WC)
23262306a36Sopenharmony_ci			return 0;
23362306a36Sopenharmony_ci		cpu_relax();
23462306a36Sopenharmony_ci	} while (time_after(timeout, jiffies));
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
23762306a36Sopenharmony_ci	if (stat & WC)
23862306a36Sopenharmony_ci		return 0;
23962306a36Sopenharmony_ci	return  -ETIMEDOUT;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t,
24362306a36Sopenharmony_ci			  int count)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	int wlen, xfer_len;
24662306a36Sopenharmony_ci	unsigned int cmd;
24762306a36Sopenharmony_ci	const u8 *txbuf;
24862306a36Sopenharmony_ci	u32 data;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	txbuf = t->tx_buf;
25162306a36Sopenharmony_ci	cmd = qspi->cmd | QSPI_WR_SNGL;
25262306a36Sopenharmony_ci	wlen = t->bits_per_word >> 3;	/* in bytes */
25362306a36Sopenharmony_ci	xfer_len = wlen;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	while (count) {
25662306a36Sopenharmony_ci		if (qspi_is_busy(qspi))
25762306a36Sopenharmony_ci			return -EBUSY;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		switch (wlen) {
26062306a36Sopenharmony_ci		case 1:
26162306a36Sopenharmony_ci			dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n",
26262306a36Sopenharmony_ci					cmd, qspi->dc, *txbuf);
26362306a36Sopenharmony_ci			if (count >= QSPI_WLEN_MAX_BYTES) {
26462306a36Sopenharmony_ci				u32 *txp = (u32 *)txbuf;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci				data = cpu_to_be32(*txp++);
26762306a36Sopenharmony_ci				writel(data, qspi->base +
26862306a36Sopenharmony_ci				       QSPI_SPI_DATA_REG_3);
26962306a36Sopenharmony_ci				data = cpu_to_be32(*txp++);
27062306a36Sopenharmony_ci				writel(data, qspi->base +
27162306a36Sopenharmony_ci				       QSPI_SPI_DATA_REG_2);
27262306a36Sopenharmony_ci				data = cpu_to_be32(*txp++);
27362306a36Sopenharmony_ci				writel(data, qspi->base +
27462306a36Sopenharmony_ci				       QSPI_SPI_DATA_REG_1);
27562306a36Sopenharmony_ci				data = cpu_to_be32(*txp++);
27662306a36Sopenharmony_ci				writel(data, qspi->base +
27762306a36Sopenharmony_ci				       QSPI_SPI_DATA_REG);
27862306a36Sopenharmony_ci				xfer_len = QSPI_WLEN_MAX_BYTES;
27962306a36Sopenharmony_ci				cmd |= QSPI_WLEN(QSPI_WLEN_MAX_BITS);
28062306a36Sopenharmony_ci			} else {
28162306a36Sopenharmony_ci				writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG);
28262306a36Sopenharmony_ci				cmd = qspi->cmd | QSPI_WR_SNGL;
28362306a36Sopenharmony_ci				xfer_len = wlen;
28462306a36Sopenharmony_ci				cmd |= QSPI_WLEN(wlen);
28562306a36Sopenharmony_ci			}
28662306a36Sopenharmony_ci			break;
28762306a36Sopenharmony_ci		case 2:
28862306a36Sopenharmony_ci			dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n",
28962306a36Sopenharmony_ci					cmd, qspi->dc, *txbuf);
29062306a36Sopenharmony_ci			writew(*((u16 *)txbuf), qspi->base + QSPI_SPI_DATA_REG);
29162306a36Sopenharmony_ci			break;
29262306a36Sopenharmony_ci		case 4:
29362306a36Sopenharmony_ci			dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %08x\n",
29462306a36Sopenharmony_ci					cmd, qspi->dc, *txbuf);
29562306a36Sopenharmony_ci			writel(*((u32 *)txbuf), qspi->base + QSPI_SPI_DATA_REG);
29662306a36Sopenharmony_ci			break;
29762306a36Sopenharmony_ci		}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci		ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
30062306a36Sopenharmony_ci		if (ti_qspi_poll_wc(qspi)) {
30162306a36Sopenharmony_ci			dev_err(qspi->dev, "write timed out\n");
30262306a36Sopenharmony_ci			return -ETIMEDOUT;
30362306a36Sopenharmony_ci		}
30462306a36Sopenharmony_ci		txbuf += xfer_len;
30562306a36Sopenharmony_ci		count -= xfer_len;
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	return 0;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t,
31262306a36Sopenharmony_ci			 int count)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	int wlen;
31562306a36Sopenharmony_ci	unsigned int cmd;
31662306a36Sopenharmony_ci	u32 rx;
31762306a36Sopenharmony_ci	u8 rxlen, rx_wlen;
31862306a36Sopenharmony_ci	u8 *rxbuf;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	rxbuf = t->rx_buf;
32162306a36Sopenharmony_ci	cmd = qspi->cmd;
32262306a36Sopenharmony_ci	switch (t->rx_nbits) {
32362306a36Sopenharmony_ci	case SPI_NBITS_DUAL:
32462306a36Sopenharmony_ci		cmd |= QSPI_RD_DUAL;
32562306a36Sopenharmony_ci		break;
32662306a36Sopenharmony_ci	case SPI_NBITS_QUAD:
32762306a36Sopenharmony_ci		cmd |= QSPI_RD_QUAD;
32862306a36Sopenharmony_ci		break;
32962306a36Sopenharmony_ci	default:
33062306a36Sopenharmony_ci		cmd |= QSPI_RD_SNGL;
33162306a36Sopenharmony_ci		break;
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci	wlen = t->bits_per_word >> 3;	/* in bytes */
33462306a36Sopenharmony_ci	rx_wlen = wlen;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	while (count) {
33762306a36Sopenharmony_ci		dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc);
33862306a36Sopenharmony_ci		if (qspi_is_busy(qspi))
33962306a36Sopenharmony_ci			return -EBUSY;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci		switch (wlen) {
34262306a36Sopenharmony_ci		case 1:
34362306a36Sopenharmony_ci			/*
34462306a36Sopenharmony_ci			 * Optimize the 8-bit words transfers, as used by
34562306a36Sopenharmony_ci			 * the SPI flash devices.
34662306a36Sopenharmony_ci			 */
34762306a36Sopenharmony_ci			if (count >= QSPI_WLEN_MAX_BYTES) {
34862306a36Sopenharmony_ci				rxlen = QSPI_WLEN_MAX_BYTES;
34962306a36Sopenharmony_ci			} else {
35062306a36Sopenharmony_ci				rxlen = min(count, 4);
35162306a36Sopenharmony_ci			}
35262306a36Sopenharmony_ci			rx_wlen = rxlen << 3;
35362306a36Sopenharmony_ci			cmd &= ~QSPI_WLEN_MASK;
35462306a36Sopenharmony_ci			cmd |= QSPI_WLEN(rx_wlen);
35562306a36Sopenharmony_ci			break;
35662306a36Sopenharmony_ci		default:
35762306a36Sopenharmony_ci			rxlen = wlen;
35862306a36Sopenharmony_ci			break;
35962306a36Sopenharmony_ci		}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
36262306a36Sopenharmony_ci		if (ti_qspi_poll_wc(qspi)) {
36362306a36Sopenharmony_ci			dev_err(qspi->dev, "read timed out\n");
36462306a36Sopenharmony_ci			return -ETIMEDOUT;
36562306a36Sopenharmony_ci		}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		switch (wlen) {
36862306a36Sopenharmony_ci		case 1:
36962306a36Sopenharmony_ci			/*
37062306a36Sopenharmony_ci			 * Optimize the 8-bit words transfers, as used by
37162306a36Sopenharmony_ci			 * the SPI flash devices.
37262306a36Sopenharmony_ci			 */
37362306a36Sopenharmony_ci			if (count >= QSPI_WLEN_MAX_BYTES) {
37462306a36Sopenharmony_ci				u32 *rxp = (u32 *) rxbuf;
37562306a36Sopenharmony_ci				rx = readl(qspi->base + QSPI_SPI_DATA_REG_3);
37662306a36Sopenharmony_ci				*rxp++ = be32_to_cpu(rx);
37762306a36Sopenharmony_ci				rx = readl(qspi->base + QSPI_SPI_DATA_REG_2);
37862306a36Sopenharmony_ci				*rxp++ = be32_to_cpu(rx);
37962306a36Sopenharmony_ci				rx = readl(qspi->base + QSPI_SPI_DATA_REG_1);
38062306a36Sopenharmony_ci				*rxp++ = be32_to_cpu(rx);
38162306a36Sopenharmony_ci				rx = readl(qspi->base + QSPI_SPI_DATA_REG);
38262306a36Sopenharmony_ci				*rxp++ = be32_to_cpu(rx);
38362306a36Sopenharmony_ci			} else {
38462306a36Sopenharmony_ci				u8 *rxp = rxbuf;
38562306a36Sopenharmony_ci				rx = readl(qspi->base + QSPI_SPI_DATA_REG);
38662306a36Sopenharmony_ci				if (rx_wlen >= 8)
38762306a36Sopenharmony_ci					*rxp++ = rx >> (rx_wlen - 8);
38862306a36Sopenharmony_ci				if (rx_wlen >= 16)
38962306a36Sopenharmony_ci					*rxp++ = rx >> (rx_wlen - 16);
39062306a36Sopenharmony_ci				if (rx_wlen >= 24)
39162306a36Sopenharmony_ci					*rxp++ = rx >> (rx_wlen - 24);
39262306a36Sopenharmony_ci				if (rx_wlen >= 32)
39362306a36Sopenharmony_ci					*rxp++ = rx;
39462306a36Sopenharmony_ci			}
39562306a36Sopenharmony_ci			break;
39662306a36Sopenharmony_ci		case 2:
39762306a36Sopenharmony_ci			*((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG);
39862306a36Sopenharmony_ci			break;
39962306a36Sopenharmony_ci		case 4:
40062306a36Sopenharmony_ci			*((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG);
40162306a36Sopenharmony_ci			break;
40262306a36Sopenharmony_ci		}
40362306a36Sopenharmony_ci		rxbuf += rxlen;
40462306a36Sopenharmony_ci		count -= rxlen;
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	return 0;
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t,
41162306a36Sopenharmony_ci			     int count)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	int ret;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if (t->tx_buf) {
41662306a36Sopenharmony_ci		ret = qspi_write_msg(qspi, t, count);
41762306a36Sopenharmony_ci		if (ret) {
41862306a36Sopenharmony_ci			dev_dbg(qspi->dev, "Error while writing\n");
41962306a36Sopenharmony_ci			return ret;
42062306a36Sopenharmony_ci		}
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (t->rx_buf) {
42462306a36Sopenharmony_ci		ret = qspi_read_msg(qspi, t, count);
42562306a36Sopenharmony_ci		if (ret) {
42662306a36Sopenharmony_ci			dev_dbg(qspi->dev, "Error while reading\n");
42762306a36Sopenharmony_ci			return ret;
42862306a36Sopenharmony_ci		}
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	return 0;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic void ti_qspi_dma_callback(void *param)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	struct ti_qspi *qspi = param;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	complete(&qspi->transfer_complete);
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic int ti_qspi_dma_xfer(struct ti_qspi *qspi, dma_addr_t dma_dst,
44262306a36Sopenharmony_ci			    dma_addr_t dma_src, size_t len)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	struct dma_chan *chan = qspi->rx_chan;
44562306a36Sopenharmony_ci	dma_cookie_t cookie;
44662306a36Sopenharmony_ci	enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
44762306a36Sopenharmony_ci	struct dma_async_tx_descriptor *tx;
44862306a36Sopenharmony_ci	int ret;
44962306a36Sopenharmony_ci	unsigned long time_left;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len, flags);
45262306a36Sopenharmony_ci	if (!tx) {
45362306a36Sopenharmony_ci		dev_err(qspi->dev, "device_prep_dma_memcpy error\n");
45462306a36Sopenharmony_ci		return -EIO;
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	tx->callback = ti_qspi_dma_callback;
45862306a36Sopenharmony_ci	tx->callback_param = qspi;
45962306a36Sopenharmony_ci	cookie = tx->tx_submit(tx);
46062306a36Sopenharmony_ci	reinit_completion(&qspi->transfer_complete);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	ret = dma_submit_error(cookie);
46362306a36Sopenharmony_ci	if (ret) {
46462306a36Sopenharmony_ci		dev_err(qspi->dev, "dma_submit_error %d\n", cookie);
46562306a36Sopenharmony_ci		return -EIO;
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	dma_async_issue_pending(chan);
46962306a36Sopenharmony_ci	time_left = wait_for_completion_timeout(&qspi->transfer_complete,
47062306a36Sopenharmony_ci					  msecs_to_jiffies(len));
47162306a36Sopenharmony_ci	if (time_left == 0) {
47262306a36Sopenharmony_ci		dmaengine_terminate_sync(chan);
47362306a36Sopenharmony_ci		dev_err(qspi->dev, "DMA wait_for_completion_timeout\n");
47462306a36Sopenharmony_ci		return -ETIMEDOUT;
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	return 0;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic int ti_qspi_dma_bounce_buffer(struct ti_qspi *qspi, loff_t offs,
48162306a36Sopenharmony_ci				     void *to, size_t readsize)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	dma_addr_t dma_src = qspi->mmap_phys_base + offs;
48462306a36Sopenharmony_ci	int ret = 0;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	/*
48762306a36Sopenharmony_ci	 * Use bounce buffer as FS like jffs2, ubifs may pass
48862306a36Sopenharmony_ci	 * buffers that does not belong to kernel lowmem region.
48962306a36Sopenharmony_ci	 */
49062306a36Sopenharmony_ci	while (readsize != 0) {
49162306a36Sopenharmony_ci		size_t xfer_len = min_t(size_t, QSPI_DMA_BUFFER_SIZE,
49262306a36Sopenharmony_ci					readsize);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci		ret = ti_qspi_dma_xfer(qspi, qspi->rx_bb_dma_addr,
49562306a36Sopenharmony_ci				       dma_src, xfer_len);
49662306a36Sopenharmony_ci		if (ret != 0)
49762306a36Sopenharmony_ci			return ret;
49862306a36Sopenharmony_ci		memcpy(to, qspi->rx_bb_addr, xfer_len);
49962306a36Sopenharmony_ci		readsize -= xfer_len;
50062306a36Sopenharmony_ci		dma_src += xfer_len;
50162306a36Sopenharmony_ci		to += xfer_len;
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	return ret;
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic int ti_qspi_dma_xfer_sg(struct ti_qspi *qspi, struct sg_table rx_sg,
50862306a36Sopenharmony_ci			       loff_t from)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct scatterlist *sg;
51162306a36Sopenharmony_ci	dma_addr_t dma_src = qspi->mmap_phys_base + from;
51262306a36Sopenharmony_ci	dma_addr_t dma_dst;
51362306a36Sopenharmony_ci	int i, len, ret;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	for_each_sg(rx_sg.sgl, sg, rx_sg.nents, i) {
51662306a36Sopenharmony_ci		dma_dst = sg_dma_address(sg);
51762306a36Sopenharmony_ci		len = sg_dma_len(sg);
51862306a36Sopenharmony_ci		ret = ti_qspi_dma_xfer(qspi, dma_dst, dma_src, len);
51962306a36Sopenharmony_ci		if (ret)
52062306a36Sopenharmony_ci			return ret;
52162306a36Sopenharmony_ci		dma_src += len;
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	return 0;
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic void ti_qspi_enable_memory_map(struct spi_device *spi)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct ti_qspi  *qspi = spi_master_get_devdata(spi->master);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG);
53262306a36Sopenharmony_ci	if (qspi->ctrl_base) {
53362306a36Sopenharmony_ci		regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg,
53462306a36Sopenharmony_ci				   MEM_CS_MASK,
53562306a36Sopenharmony_ci				   MEM_CS_EN(spi_get_chipselect(spi, 0)));
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci	qspi->mmap_enabled = true;
53862306a36Sopenharmony_ci	qspi->current_cs = spi_get_chipselect(spi, 0);
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic void ti_qspi_disable_memory_map(struct spi_device *spi)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	struct ti_qspi  *qspi = spi_master_get_devdata(spi->master);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG);
54662306a36Sopenharmony_ci	if (qspi->ctrl_base)
54762306a36Sopenharmony_ci		regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg,
54862306a36Sopenharmony_ci				   MEM_CS_MASK, 0);
54962306a36Sopenharmony_ci	qspi->mmap_enabled = false;
55062306a36Sopenharmony_ci	qspi->current_cs = -1;
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cistatic void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode,
55462306a36Sopenharmony_ci				    u8 data_nbits, u8 addr_width,
55562306a36Sopenharmony_ci				    u8 dummy_bytes)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	struct ti_qspi  *qspi = spi_master_get_devdata(spi->master);
55862306a36Sopenharmony_ci	u32 memval = opcode;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	switch (data_nbits) {
56162306a36Sopenharmony_ci	case SPI_NBITS_QUAD:
56262306a36Sopenharmony_ci		memval |= QSPI_SETUP_RD_QUAD;
56362306a36Sopenharmony_ci		break;
56462306a36Sopenharmony_ci	case SPI_NBITS_DUAL:
56562306a36Sopenharmony_ci		memval |= QSPI_SETUP_RD_DUAL;
56662306a36Sopenharmony_ci		break;
56762306a36Sopenharmony_ci	default:
56862306a36Sopenharmony_ci		memval |= QSPI_SETUP_RD_NORMAL;
56962306a36Sopenharmony_ci		break;
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci	memval |= ((addr_width - 1) << QSPI_SETUP_ADDR_SHIFT |
57262306a36Sopenharmony_ci		   dummy_bytes << QSPI_SETUP_DUMMY_SHIFT);
57362306a36Sopenharmony_ci	ti_qspi_write(qspi, memval,
57462306a36Sopenharmony_ci		      QSPI_SPI_SETUP_REG(spi_get_chipselect(spi, 0)));
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic int ti_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
58062306a36Sopenharmony_ci	size_t max_len;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_IN) {
58362306a36Sopenharmony_ci		if (op->addr.val < qspi->mmap_size) {
58462306a36Sopenharmony_ci			/* Limit MMIO to the mmaped region */
58562306a36Sopenharmony_ci			if (op->addr.val + op->data.nbytes > qspi->mmap_size) {
58662306a36Sopenharmony_ci				max_len = qspi->mmap_size - op->addr.val;
58762306a36Sopenharmony_ci				op->data.nbytes = min((size_t) op->data.nbytes,
58862306a36Sopenharmony_ci						      max_len);
58962306a36Sopenharmony_ci			}
59062306a36Sopenharmony_ci		} else {
59162306a36Sopenharmony_ci			/*
59262306a36Sopenharmony_ci			 * Use fallback mode (SW generated transfers) above the
59362306a36Sopenharmony_ci			 * mmaped region.
59462306a36Sopenharmony_ci			 * Adjust size to comply with the QSPI max frame length.
59562306a36Sopenharmony_ci			 */
59662306a36Sopenharmony_ci			max_len = QSPI_FRAME;
59762306a36Sopenharmony_ci			max_len -= 1 + op->addr.nbytes + op->dummy.nbytes;
59862306a36Sopenharmony_ci			op->data.nbytes = min((size_t) op->data.nbytes,
59962306a36Sopenharmony_ci					      max_len);
60062306a36Sopenharmony_ci		}
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	return 0;
60462306a36Sopenharmony_ci}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_cistatic int ti_qspi_exec_mem_op(struct spi_mem *mem,
60762306a36Sopenharmony_ci			       const struct spi_mem_op *op)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	struct ti_qspi *qspi = spi_master_get_devdata(mem->spi->master);
61062306a36Sopenharmony_ci	u32 from = 0;
61162306a36Sopenharmony_ci	int ret = 0;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	/* Only optimize read path. */
61462306a36Sopenharmony_ci	if (!op->data.nbytes || op->data.dir != SPI_MEM_DATA_IN ||
61562306a36Sopenharmony_ci	    !op->addr.nbytes || op->addr.nbytes > 4)
61662306a36Sopenharmony_ci		return -ENOTSUPP;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/* Address exceeds MMIO window size, fall back to regular mode. */
61962306a36Sopenharmony_ci	from = op->addr.val;
62062306a36Sopenharmony_ci	if (from + op->data.nbytes > qspi->mmap_size)
62162306a36Sopenharmony_ci		return -ENOTSUPP;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	mutex_lock(&qspi->list_lock);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	if (!qspi->mmap_enabled || qspi->current_cs != spi_get_chipselect(mem->spi, 0)) {
62662306a36Sopenharmony_ci		ti_qspi_setup_clk(qspi, mem->spi->max_speed_hz);
62762306a36Sopenharmony_ci		ti_qspi_enable_memory_map(mem->spi);
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci	ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth,
63062306a36Sopenharmony_ci				op->addr.nbytes, op->dummy.nbytes);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	if (qspi->rx_chan) {
63362306a36Sopenharmony_ci		struct sg_table sgt;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci		if (virt_addr_valid(op->data.buf.in) &&
63662306a36Sopenharmony_ci		    !spi_controller_dma_map_mem_op_data(mem->spi->master, op,
63762306a36Sopenharmony_ci							&sgt)) {
63862306a36Sopenharmony_ci			ret = ti_qspi_dma_xfer_sg(qspi, sgt, from);
63962306a36Sopenharmony_ci			spi_controller_dma_unmap_mem_op_data(mem->spi->master,
64062306a36Sopenharmony_ci							     op, &sgt);
64162306a36Sopenharmony_ci		} else {
64262306a36Sopenharmony_ci			ret = ti_qspi_dma_bounce_buffer(qspi, from,
64362306a36Sopenharmony_ci							op->data.buf.in,
64462306a36Sopenharmony_ci							op->data.nbytes);
64562306a36Sopenharmony_ci		}
64662306a36Sopenharmony_ci	} else {
64762306a36Sopenharmony_ci		memcpy_fromio(op->data.buf.in, qspi->mmap_base + from,
64862306a36Sopenharmony_ci			      op->data.nbytes);
64962306a36Sopenharmony_ci	}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	mutex_unlock(&qspi->list_lock);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	return ret;
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_cistatic const struct spi_controller_mem_ops ti_qspi_mem_ops = {
65762306a36Sopenharmony_ci	.exec_op = ti_qspi_exec_mem_op,
65862306a36Sopenharmony_ci	.adjust_op_size = ti_qspi_adjust_op_size,
65962306a36Sopenharmony_ci};
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic int ti_qspi_start_transfer_one(struct spi_master *master,
66262306a36Sopenharmony_ci		struct spi_message *m)
66362306a36Sopenharmony_ci{
66462306a36Sopenharmony_ci	struct ti_qspi *qspi = spi_master_get_devdata(master);
66562306a36Sopenharmony_ci	struct spi_device *spi = m->spi;
66662306a36Sopenharmony_ci	struct spi_transfer *t;
66762306a36Sopenharmony_ci	int status = 0, ret;
66862306a36Sopenharmony_ci	unsigned int frame_len_words, transfer_len_words;
66962306a36Sopenharmony_ci	int wlen;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	/* setup device control reg */
67262306a36Sopenharmony_ci	qspi->dc = 0;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	if (spi->mode & SPI_CPHA)
67562306a36Sopenharmony_ci		qspi->dc |= QSPI_CKPHA(spi_get_chipselect(spi, 0));
67662306a36Sopenharmony_ci	if (spi->mode & SPI_CPOL)
67762306a36Sopenharmony_ci		qspi->dc |= QSPI_CKPOL(spi_get_chipselect(spi, 0));
67862306a36Sopenharmony_ci	if (spi->mode & SPI_CS_HIGH)
67962306a36Sopenharmony_ci		qspi->dc |= QSPI_CSPOL(spi_get_chipselect(spi, 0));
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	frame_len_words = 0;
68262306a36Sopenharmony_ci	list_for_each_entry(t, &m->transfers, transfer_list)
68362306a36Sopenharmony_ci		frame_len_words += t->len / (t->bits_per_word >> 3);
68462306a36Sopenharmony_ci	frame_len_words = min_t(unsigned int, frame_len_words, QSPI_FRAME);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	/* setup command reg */
68762306a36Sopenharmony_ci	qspi->cmd = 0;
68862306a36Sopenharmony_ci	qspi->cmd |= QSPI_EN_CS(spi_get_chipselect(spi, 0));
68962306a36Sopenharmony_ci	qspi->cmd |= QSPI_FLEN(frame_len_words);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	ti_qspi_write(qspi, qspi->dc, QSPI_SPI_DC_REG);
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	mutex_lock(&qspi->list_lock);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	if (qspi->mmap_enabled)
69662306a36Sopenharmony_ci		ti_qspi_disable_memory_map(spi);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	list_for_each_entry(t, &m->transfers, transfer_list) {
69962306a36Sopenharmony_ci		qspi->cmd = ((qspi->cmd & ~QSPI_WLEN_MASK) |
70062306a36Sopenharmony_ci			     QSPI_WLEN(t->bits_per_word));
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci		wlen = t->bits_per_word >> 3;
70362306a36Sopenharmony_ci		transfer_len_words = min(t->len / wlen, frame_len_words);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci		ti_qspi_setup_clk(qspi, t->speed_hz);
70662306a36Sopenharmony_ci		ret = qspi_transfer_msg(qspi, t, transfer_len_words * wlen);
70762306a36Sopenharmony_ci		if (ret) {
70862306a36Sopenharmony_ci			dev_dbg(qspi->dev, "transfer message failed\n");
70962306a36Sopenharmony_ci			mutex_unlock(&qspi->list_lock);
71062306a36Sopenharmony_ci			return -EINVAL;
71162306a36Sopenharmony_ci		}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci		m->actual_length += transfer_len_words * wlen;
71462306a36Sopenharmony_ci		frame_len_words -= transfer_len_words;
71562306a36Sopenharmony_ci		if (frame_len_words == 0)
71662306a36Sopenharmony_ci			break;
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	mutex_unlock(&qspi->list_lock);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG);
72262306a36Sopenharmony_ci	m->status = status;
72362306a36Sopenharmony_ci	spi_finalize_current_message(master);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	return status;
72662306a36Sopenharmony_ci}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_cistatic int ti_qspi_runtime_resume(struct device *dev)
72962306a36Sopenharmony_ci{
73062306a36Sopenharmony_ci	struct ti_qspi      *qspi;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	qspi = dev_get_drvdata(dev);
73362306a36Sopenharmony_ci	ti_qspi_restore_ctx(qspi);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	return 0;
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_cistatic void ti_qspi_dma_cleanup(struct ti_qspi *qspi)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	if (qspi->rx_bb_addr)
74162306a36Sopenharmony_ci		dma_free_coherent(qspi->dev, QSPI_DMA_BUFFER_SIZE,
74262306a36Sopenharmony_ci				  qspi->rx_bb_addr,
74362306a36Sopenharmony_ci				  qspi->rx_bb_dma_addr);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	if (qspi->rx_chan)
74662306a36Sopenharmony_ci		dma_release_channel(qspi->rx_chan);
74762306a36Sopenharmony_ci}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_cistatic const struct of_device_id ti_qspi_match[] = {
75062306a36Sopenharmony_ci	{.compatible = "ti,dra7xxx-qspi" },
75162306a36Sopenharmony_ci	{.compatible = "ti,am4372-qspi" },
75262306a36Sopenharmony_ci	{},
75362306a36Sopenharmony_ci};
75462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ti_qspi_match);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_cistatic int ti_qspi_probe(struct platform_device *pdev)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	struct  ti_qspi *qspi;
75962306a36Sopenharmony_ci	struct spi_master *master;
76062306a36Sopenharmony_ci	struct resource         *r, *res_mmap;
76162306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
76262306a36Sopenharmony_ci	u32 max_freq;
76362306a36Sopenharmony_ci	int ret = 0, num_cs, irq;
76462306a36Sopenharmony_ci	dma_cap_mask_t mask;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	master = spi_alloc_master(&pdev->dev, sizeof(*qspi));
76762306a36Sopenharmony_ci	if (!master)
76862306a36Sopenharmony_ci		return -ENOMEM;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	master->flags = SPI_CONTROLLER_HALF_DUPLEX;
77362306a36Sopenharmony_ci	master->setup = ti_qspi_setup;
77462306a36Sopenharmony_ci	master->auto_runtime_pm = true;
77562306a36Sopenharmony_ci	master->transfer_one_message = ti_qspi_start_transfer_one;
77662306a36Sopenharmony_ci	master->dev.of_node = pdev->dev.of_node;
77762306a36Sopenharmony_ci	master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
77862306a36Sopenharmony_ci				     SPI_BPW_MASK(8);
77962306a36Sopenharmony_ci	master->mem_ops = &ti_qspi_mem_ops;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	if (!of_property_read_u32(np, "num-cs", &num_cs))
78262306a36Sopenharmony_ci		master->num_chipselect = num_cs;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	qspi = spi_master_get_devdata(master);
78562306a36Sopenharmony_ci	qspi->master = master;
78662306a36Sopenharmony_ci	qspi->dev = &pdev->dev;
78762306a36Sopenharmony_ci	platform_set_drvdata(pdev, qspi);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_base");
79062306a36Sopenharmony_ci	if (r == NULL) {
79162306a36Sopenharmony_ci		r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
79262306a36Sopenharmony_ci		if (r == NULL) {
79362306a36Sopenharmony_ci			dev_err(&pdev->dev, "missing platform data\n");
79462306a36Sopenharmony_ci			ret = -ENODEV;
79562306a36Sopenharmony_ci			goto free_master;
79662306a36Sopenharmony_ci		}
79762306a36Sopenharmony_ci	}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	res_mmap = platform_get_resource_byname(pdev,
80062306a36Sopenharmony_ci			IORESOURCE_MEM, "qspi_mmap");
80162306a36Sopenharmony_ci	if (res_mmap == NULL) {
80262306a36Sopenharmony_ci		res_mmap = platform_get_resource(pdev, IORESOURCE_MEM, 1);
80362306a36Sopenharmony_ci		if (res_mmap == NULL) {
80462306a36Sopenharmony_ci			dev_err(&pdev->dev,
80562306a36Sopenharmony_ci				"memory mapped resource not required\n");
80662306a36Sopenharmony_ci		}
80762306a36Sopenharmony_ci	}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	if (res_mmap)
81062306a36Sopenharmony_ci		qspi->mmap_size = resource_size(res_mmap);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
81362306a36Sopenharmony_ci	if (irq < 0) {
81462306a36Sopenharmony_ci		ret = irq;
81562306a36Sopenharmony_ci		goto free_master;
81662306a36Sopenharmony_ci	}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	mutex_init(&qspi->list_lock);
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	qspi->base = devm_ioremap_resource(&pdev->dev, r);
82162306a36Sopenharmony_ci	if (IS_ERR(qspi->base)) {
82262306a36Sopenharmony_ci		ret = PTR_ERR(qspi->base);
82362306a36Sopenharmony_ci		goto free_master;
82462306a36Sopenharmony_ci	}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	if (of_property_read_bool(np, "syscon-chipselects")) {
82862306a36Sopenharmony_ci		qspi->ctrl_base =
82962306a36Sopenharmony_ci		syscon_regmap_lookup_by_phandle(np,
83062306a36Sopenharmony_ci						"syscon-chipselects");
83162306a36Sopenharmony_ci		if (IS_ERR(qspi->ctrl_base)) {
83262306a36Sopenharmony_ci			ret = PTR_ERR(qspi->ctrl_base);
83362306a36Sopenharmony_ci			goto free_master;
83462306a36Sopenharmony_ci		}
83562306a36Sopenharmony_ci		ret = of_property_read_u32_index(np,
83662306a36Sopenharmony_ci						 "syscon-chipselects",
83762306a36Sopenharmony_ci						 1, &qspi->ctrl_reg);
83862306a36Sopenharmony_ci		if (ret) {
83962306a36Sopenharmony_ci			dev_err(&pdev->dev,
84062306a36Sopenharmony_ci				"couldn't get ctrl_mod reg index\n");
84162306a36Sopenharmony_ci			goto free_master;
84262306a36Sopenharmony_ci		}
84362306a36Sopenharmony_ci	}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	qspi->fclk = devm_clk_get(&pdev->dev, "fck");
84662306a36Sopenharmony_ci	if (IS_ERR(qspi->fclk)) {
84762306a36Sopenharmony_ci		ret = PTR_ERR(qspi->fclk);
84862306a36Sopenharmony_ci		dev_err(&pdev->dev, "could not get clk: %d\n", ret);
84962306a36Sopenharmony_ci	}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	pm_runtime_use_autosuspend(&pdev->dev);
85262306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(&pdev->dev, QSPI_AUTOSUSPEND_TIMEOUT);
85362306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
85662306a36Sopenharmony_ci		master->max_speed_hz = max_freq;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	dma_cap_zero(mask);
85962306a36Sopenharmony_ci	dma_cap_set(DMA_MEMCPY, mask);
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	qspi->rx_chan = dma_request_chan_by_mask(&mask);
86262306a36Sopenharmony_ci	if (IS_ERR(qspi->rx_chan)) {
86362306a36Sopenharmony_ci		dev_err(qspi->dev,
86462306a36Sopenharmony_ci			"No Rx DMA available, trying mmap mode\n");
86562306a36Sopenharmony_ci		qspi->rx_chan = NULL;
86662306a36Sopenharmony_ci		ret = 0;
86762306a36Sopenharmony_ci		goto no_dma;
86862306a36Sopenharmony_ci	}
86962306a36Sopenharmony_ci	qspi->rx_bb_addr = dma_alloc_coherent(qspi->dev,
87062306a36Sopenharmony_ci					      QSPI_DMA_BUFFER_SIZE,
87162306a36Sopenharmony_ci					      &qspi->rx_bb_dma_addr,
87262306a36Sopenharmony_ci					      GFP_KERNEL | GFP_DMA);
87362306a36Sopenharmony_ci	if (!qspi->rx_bb_addr) {
87462306a36Sopenharmony_ci		dev_err(qspi->dev,
87562306a36Sopenharmony_ci			"dma_alloc_coherent failed, using PIO mode\n");
87662306a36Sopenharmony_ci		dma_release_channel(qspi->rx_chan);
87762306a36Sopenharmony_ci		goto no_dma;
87862306a36Sopenharmony_ci	}
87962306a36Sopenharmony_ci	master->dma_rx = qspi->rx_chan;
88062306a36Sopenharmony_ci	init_completion(&qspi->transfer_complete);
88162306a36Sopenharmony_ci	if (res_mmap)
88262306a36Sopenharmony_ci		qspi->mmap_phys_base = (dma_addr_t)res_mmap->start;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_cino_dma:
88562306a36Sopenharmony_ci	if (!qspi->rx_chan && res_mmap) {
88662306a36Sopenharmony_ci		qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap);
88762306a36Sopenharmony_ci		if (IS_ERR(qspi->mmap_base)) {
88862306a36Sopenharmony_ci			dev_info(&pdev->dev,
88962306a36Sopenharmony_ci				 "mmap failed with error %ld using PIO mode\n",
89062306a36Sopenharmony_ci				 PTR_ERR(qspi->mmap_base));
89162306a36Sopenharmony_ci			qspi->mmap_base = NULL;
89262306a36Sopenharmony_ci			master->mem_ops = NULL;
89362306a36Sopenharmony_ci		}
89462306a36Sopenharmony_ci	}
89562306a36Sopenharmony_ci	qspi->mmap_enabled = false;
89662306a36Sopenharmony_ci	qspi->current_cs = -1;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	ret = devm_spi_register_master(&pdev->dev, master);
89962306a36Sopenharmony_ci	if (!ret)
90062306a36Sopenharmony_ci		return 0;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	ti_qspi_dma_cleanup(qspi);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
90562306a36Sopenharmony_cifree_master:
90662306a36Sopenharmony_ci	spi_master_put(master);
90762306a36Sopenharmony_ci	return ret;
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_cistatic int ti_qspi_remove(struct platform_device *pdev)
91162306a36Sopenharmony_ci{
91262306a36Sopenharmony_ci	struct ti_qspi *qspi = platform_get_drvdata(pdev);
91362306a36Sopenharmony_ci	int rc;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	rc = spi_master_suspend(qspi->master);
91662306a36Sopenharmony_ci	if (rc)
91762306a36Sopenharmony_ci		return rc;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
92062306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	ti_qspi_dma_cleanup(qspi);
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	return 0;
92562306a36Sopenharmony_ci}
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_cistatic const struct dev_pm_ops ti_qspi_pm_ops = {
92862306a36Sopenharmony_ci	.runtime_resume = ti_qspi_runtime_resume,
92962306a36Sopenharmony_ci};
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_cistatic struct platform_driver ti_qspi_driver = {
93262306a36Sopenharmony_ci	.probe	= ti_qspi_probe,
93362306a36Sopenharmony_ci	.remove = ti_qspi_remove,
93462306a36Sopenharmony_ci	.driver = {
93562306a36Sopenharmony_ci		.name	= "ti-qspi",
93662306a36Sopenharmony_ci		.pm =   &ti_qspi_pm_ops,
93762306a36Sopenharmony_ci		.of_match_table = ti_qspi_match,
93862306a36Sopenharmony_ci	}
93962306a36Sopenharmony_ci};
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_cimodule_platform_driver(ti_qspi_driver);
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ciMODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>");
94462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
94562306a36Sopenharmony_ciMODULE_DESCRIPTION("TI QSPI controller driver");
94662306a36Sopenharmony_ciMODULE_ALIAS("platform:ti-qspi");
947