xref: /linux/drivers/spi/spi-ma35d1-qspi.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
178b16af1SChi-Wen Weng // SPDX-License-Identifier: GPL-2.0-or-later
278b16af1SChi-Wen Weng //
378b16af1SChi-Wen Weng // Nuvoton MA35D1 QSPI controller driver
478b16af1SChi-Wen Weng //
578b16af1SChi-Wen Weng // Copyright (c) 2026 Nuvoton Technology Corp.
678b16af1SChi-Wen Weng // Author: Chi-Wen Weng <cwweng@nuvoton.com>
778b16af1SChi-Wen Weng 
878b16af1SChi-Wen Weng #include <linux/bitfield.h>
978b16af1SChi-Wen Weng #include <linux/bits.h>
1078b16af1SChi-Wen Weng #include <linux/clk.h>
1178b16af1SChi-Wen Weng #include <linux/delay.h>
1278b16af1SChi-Wen Weng #include <linux/device.h>
1378b16af1SChi-Wen Weng #include <linux/io.h>
1478b16af1SChi-Wen Weng #include <linux/iopoll.h>
1578b16af1SChi-Wen Weng #include <linux/module.h>
1678b16af1SChi-Wen Weng #include <linux/platform_device.h>
1778b16af1SChi-Wen Weng #include <linux/property.h>
1878b16af1SChi-Wen Weng #include <linux/reset.h>
1978b16af1SChi-Wen Weng #include <linux/sizes.h>
2078b16af1SChi-Wen Weng #include <linux/spi/spi.h>
2178b16af1SChi-Wen Weng #include <linux/spi/spi-mem.h>
2278b16af1SChi-Wen Weng #include <linux/spinlock.h>
2378b16af1SChi-Wen Weng 
2478b16af1SChi-Wen Weng /* Register offset definitions */
2578b16af1SChi-Wen Weng #define NUVOTON_QSPI_CTL_OFFSET		0x00 /* Control Register, RW */
2678b16af1SChi-Wen Weng #define NUVOTON_QSPI_CLKDIV_OFFSET	0x04 /* Clock Divider Register, RW */
2778b16af1SChi-Wen Weng #define NUVOTON_QSPI_SSCTL_OFFSET	0x08 /* Slave Select Register, RW */
2878b16af1SChi-Wen Weng #define NUVOTON_QSPI_FIFOCTL_OFFSET	0x10 /* FIFO Control Register, RW */
2978b16af1SChi-Wen Weng #define NUVOTON_QSPI_STATUS_OFFSET	0x14 /* Status Register, RW */
3078b16af1SChi-Wen Weng #define NUVOTON_QSPI_TX_OFFSET		0x20 /* Data Transmit Register, WO */
3178b16af1SChi-Wen Weng #define NUVOTON_QSPI_RX_OFFSET		0x30 /* Data Receive Register, RO */
3278b16af1SChi-Wen Weng 
3378b16af1SChi-Wen Weng /* QSPI Control Register bit masks */
3415e9362fSMiquel Raynal #define NUVOTON_QSPI_CTL_DTREN_MASK	BIT(23) /* DTR I/O Mode Enable */
3578b16af1SChi-Wen Weng #define NUVOTON_QSPI_CTL_QUADIOEN_MASK	BIT(22) /* Quad I/O Mode Enable */
3678b16af1SChi-Wen Weng #define NUVOTON_QSPI_CTL_DUALIOEN_MASK	BIT(21) /* Dual I/O Mode Enable */
3778b16af1SChi-Wen Weng #define NUVOTON_QSPI_CTL_DATDIR_MASK	BIT(20) /* Data Port Direction Control */
3878b16af1SChi-Wen Weng #define NUVOTON_QSPI_CTL_REORDER_MASK	BIT(19) /* Byte Reorder Function Enable */
3978b16af1SChi-Wen Weng #define NUVOTON_QSPI_CTL_LSB_MASK	BIT(13) /* Send LSB First */
4078b16af1SChi-Wen Weng #define NUVOTON_QSPI_CTL_DWIDTH_MASK	GENMASK(12, 8) /* Data Width */
4178b16af1SChi-Wen Weng #define NUVOTON_QSPI_CTL_SUSPITV_MASK	GENMASK(7, 4) /* Suspend Interval */
4278b16af1SChi-Wen Weng #define NUVOTON_QSPI_CTL_CLKPOL_MASK	BIT(3) /* Clock Polarity */
4378b16af1SChi-Wen Weng #define NUVOTON_QSPI_CTL_TXNEG_MASK	BIT(2) /* Transmit on Negative Edge */
4478b16af1SChi-Wen Weng #define NUVOTON_QSPI_CTL_RXNEG_MASK	BIT(1) /* Receive on Negative Edge */
4578b16af1SChi-Wen Weng #define NUVOTON_QSPI_CTL_SPIEN_MASK	BIT(0) /* QSPI Transfer Control Enable */
4678b16af1SChi-Wen Weng 
4778b16af1SChi-Wen Weng /* QSPI Clock Divider Register bit masks */
4878b16af1SChi-Wen Weng #define NUVOTON_QSPI_CLKDIV_MASK	GENMASK(8, 0) /* Clock Divider */
4978b16af1SChi-Wen Weng 
5078b16af1SChi-Wen Weng /* QSPI Slave Select Control Register bit masks */
5178b16af1SChi-Wen Weng #define NUVOTON_QSPI_SSCTL_SS1_MASK	BIT(1) /* Slave Selection 1 Control */
5278b16af1SChi-Wen Weng #define NUVOTON_QSPI_SSCTL_SS0_MASK	BIT(0) /* Slave Selection 0 Control */
5378b16af1SChi-Wen Weng 
5478b16af1SChi-Wen Weng /* QSPI FIFO Control Register bit masks */
5578b16af1SChi-Wen Weng #define NUVOTON_QSPI_FIFOCTL_TXRST_MASK	BIT(1) /* Transmit Reset */
5678b16af1SChi-Wen Weng #define NUVOTON_QSPI_FIFOCTL_RXRST_MASK	BIT(0) /* Receive Reset */
5778b16af1SChi-Wen Weng 
5878b16af1SChi-Wen Weng /* QSPI Status Register bit masks */
5978b16af1SChi-Wen Weng #define NUVOTON_QSPI_STATUS_TXRXRST_MASK	BIT(23) /* TX or RX Reset Status */
6078b16af1SChi-Wen Weng #define NUVOTON_QSPI_STATUS_TXFULL_MASK	BIT(17) /* Transmit FIFO Full */
6178b16af1SChi-Wen Weng #define NUVOTON_QSPI_STATUS_SPIENSTS_MASK	BIT(15) /* QSPI Enable Status */
6278b16af1SChi-Wen Weng #define NUVOTON_QSPI_STATUS_RXEMPTY_MASK	BIT(8) /* Receive FIFO Empty */
6378b16af1SChi-Wen Weng #define NUVOTON_QSPI_STATUS_BUSY_MASK	BIT(0) /* Busy Status */
6478b16af1SChi-Wen Weng 
6578b16af1SChi-Wen Weng #define NUVOTON_QSPI_MAX_NUM_CS		2
6678b16af1SChi-Wen Weng #define NUVOTON_QSPI_DEFAULT_NUM_CS	2
6778b16af1SChi-Wen Weng #define NUVOTON_QSPI_DEFAULT_BPW	8
6878b16af1SChi-Wen Weng /* Bound PIO operations to avoid long atomic polling loops. */
6978b16af1SChi-Wen Weng #define NUVOTON_QSPI_MAX_TRANSFER_SIZE	SZ_4K
7078b16af1SChi-Wen Weng #define NUVOTON_QSPI_MAX_MESSAGE_SIZE	SZ_8K
7178b16af1SChi-Wen Weng #define NUVOTON_QSPI_TIMEOUT_US		10000
7278b16af1SChi-Wen Weng 
7378b16af1SChi-Wen Weng struct nuvoton_qspi {
7478b16af1SChi-Wen Weng 	void __iomem *regs;
7578b16af1SChi-Wen Weng 	struct clk *clk;
7678b16af1SChi-Wen Weng 	struct device *dev;
7778b16af1SChi-Wen Weng 
7878b16af1SChi-Wen Weng 	/* Protects read-modify-write accesses to the SSCTL register. */
7978b16af1SChi-Wen Weng 	spinlock_t ssctl_lock;
8078b16af1SChi-Wen Weng 	u32 speed_hz;
8178b16af1SChi-Wen Weng };
8278b16af1SChi-Wen Weng 
8378b16af1SChi-Wen Weng static u32 nuvoton_qspi_read(struct nuvoton_qspi *qspi, u32 reg)
8478b16af1SChi-Wen Weng {
8578b16af1SChi-Wen Weng 	return readl(qspi->regs + reg);
8678b16af1SChi-Wen Weng }
8778b16af1SChi-Wen Weng 
8878b16af1SChi-Wen Weng static void nuvoton_qspi_write(struct nuvoton_qspi *qspi, u32 val, u32 reg)
8978b16af1SChi-Wen Weng {
9078b16af1SChi-Wen Weng 	writel(val, qspi->regs + reg);
9178b16af1SChi-Wen Weng }
9278b16af1SChi-Wen Weng 
9378b16af1SChi-Wen Weng static void nuvoton_qspi_update_bits(struct nuvoton_qspi *qspi, u32 reg,
9478b16af1SChi-Wen Weng 				     u32 mask, u32 val)
9578b16af1SChi-Wen Weng {
9678b16af1SChi-Wen Weng 	u32 tmp;
9778b16af1SChi-Wen Weng 
9878b16af1SChi-Wen Weng 	tmp = nuvoton_qspi_read(qspi, reg);
9978b16af1SChi-Wen Weng 	tmp &= ~mask;
10078b16af1SChi-Wen Weng 	tmp |= val & mask;
10178b16af1SChi-Wen Weng 	nuvoton_qspi_write(qspi, tmp, reg);
10278b16af1SChi-Wen Weng }
10378b16af1SChi-Wen Weng 
10478b16af1SChi-Wen Weng static int nuvoton_qspi_wait_ready(struct nuvoton_qspi *qspi)
10578b16af1SChi-Wen Weng {
10678b16af1SChi-Wen Weng 	u32 val;
10778b16af1SChi-Wen Weng 
10878b16af1SChi-Wen Weng 	return readl_poll_timeout(qspi->regs + NUVOTON_QSPI_STATUS_OFFSET,
10978b16af1SChi-Wen Weng 				  val,
11078b16af1SChi-Wen Weng 				  !(val & NUVOTON_QSPI_STATUS_BUSY_MASK),
11178b16af1SChi-Wen Weng 				  0, NUVOTON_QSPI_TIMEOUT_US);
11278b16af1SChi-Wen Weng }
11378b16af1SChi-Wen Weng 
11478b16af1SChi-Wen Weng static int nuvoton_qspi_reset_fifo(struct nuvoton_qspi *qspi)
11578b16af1SChi-Wen Weng {
11678b16af1SChi-Wen Weng 	u32 val;
11778b16af1SChi-Wen Weng 
118*0730bb35SMiquel Raynal 	nuvoton_qspi_update_bits(qspi, NUVOTON_QSPI_FIFOCTL_OFFSET,
119*0730bb35SMiquel Raynal 				 NUVOTON_QSPI_FIFOCTL_TXRST_MASK |
120*0730bb35SMiquel Raynal 				 NUVOTON_QSPI_FIFOCTL_RXRST_MASK,
121*0730bb35SMiquel Raynal 				 NUVOTON_QSPI_FIFOCTL_TXRST_MASK |
122*0730bb35SMiquel Raynal 				 NUVOTON_QSPI_FIFOCTL_RXRST_MASK);
12378b16af1SChi-Wen Weng 
12478b16af1SChi-Wen Weng 	/*
12578b16af1SChi-Wen Weng 	 * Give the controller a short time to latch the FIFO reset request
12678b16af1SChi-Wen Weng 	 * before polling the reset status bit.
12778b16af1SChi-Wen Weng 	 */
12878b16af1SChi-Wen Weng 	udelay(1);
12978b16af1SChi-Wen Weng 
13078b16af1SChi-Wen Weng 	return readl_poll_timeout_atomic(qspi->regs + NUVOTON_QSPI_STATUS_OFFSET,
13178b16af1SChi-Wen Weng 					 val,
13278b16af1SChi-Wen Weng 					 !(val & NUVOTON_QSPI_STATUS_TXRXRST_MASK),
13378b16af1SChi-Wen Weng 					 1, NUVOTON_QSPI_TIMEOUT_US);
13478b16af1SChi-Wen Weng }
13578b16af1SChi-Wen Weng 
13615e9362fSMiquel Raynal static int nuvoton_qspi_set_speed(struct spi_device *spi, u32 speed_hz, bool dtr)
13778b16af1SChi-Wen Weng {
138b5671d86SMiquel Raynal 	struct nuvoton_qspi *qspi = spi_controller_get_devdata(spi->controller);
13978b16af1SChi-Wen Weng 	unsigned long clk_rate;
14078b16af1SChi-Wen Weng 	u32 div;
14178b16af1SChi-Wen Weng 
14278b16af1SChi-Wen Weng 	if (!speed_hz)
143b5671d86SMiquel Raynal 		speed_hz = spi->max_speed_hz;
144b5671d86SMiquel Raynal 
145b5671d86SMiquel Raynal 	if (!speed_hz)
14678b16af1SChi-Wen Weng 		return -EINVAL;
14778b16af1SChi-Wen Weng 
14815e9362fSMiquel Raynal 	/* Experimentally, when enabling DTR the frequency is cut in half */
14915e9362fSMiquel Raynal 	if (dtr)
15015e9362fSMiquel Raynal 		speed_hz *= 2;
15115e9362fSMiquel Raynal 
15278b16af1SChi-Wen Weng 	if (qspi->speed_hz == speed_hz)
15378b16af1SChi-Wen Weng 		return 0;
15478b16af1SChi-Wen Weng 
15578b16af1SChi-Wen Weng 	clk_rate = clk_get_rate(qspi->clk);
15678b16af1SChi-Wen Weng 	if (!clk_rate) {
15778b16af1SChi-Wen Weng 		dev_err(qspi->dev, "failed to get clock rate\n");
15878b16af1SChi-Wen Weng 		return -EINVAL;
15978b16af1SChi-Wen Weng 	}
16078b16af1SChi-Wen Weng 
16178b16af1SChi-Wen Weng 	div = DIV_ROUND_UP(clk_rate, speed_hz) - 1;
16278b16af1SChi-Wen Weng 	if (div > FIELD_MAX(NUVOTON_QSPI_CLKDIV_MASK)) {
16378b16af1SChi-Wen Weng 		dev_err(qspi->dev, "unsupported SPI clock %u Hz\n", speed_hz);
16478b16af1SChi-Wen Weng 		return -EINVAL;
16578b16af1SChi-Wen Weng 	}
16678b16af1SChi-Wen Weng 
16778b16af1SChi-Wen Weng 	nuvoton_qspi_write(qspi, FIELD_PREP(NUVOTON_QSPI_CLKDIV_MASK, div),
16878b16af1SChi-Wen Weng 			   NUVOTON_QSPI_CLKDIV_OFFSET);
16978b16af1SChi-Wen Weng 	qspi->speed_hz = speed_hz;
17078b16af1SChi-Wen Weng 
17178b16af1SChi-Wen Weng 	return 0;
17278b16af1SChi-Wen Weng }
17378b16af1SChi-Wen Weng 
17478b16af1SChi-Wen Weng static int nuvoton_qspi_set_bits_per_word(struct nuvoton_qspi *qspi, u8 bpw)
17578b16af1SChi-Wen Weng {
17678b16af1SChi-Wen Weng 	if (bpw != NUVOTON_QSPI_DEFAULT_BPW)
17778b16af1SChi-Wen Weng 		return -EINVAL;
17878b16af1SChi-Wen Weng 
17978b16af1SChi-Wen Weng 	nuvoton_qspi_update_bits(qspi, NUVOTON_QSPI_CTL_OFFSET,
18078b16af1SChi-Wen Weng 				 NUVOTON_QSPI_CTL_DWIDTH_MASK |
18178b16af1SChi-Wen Weng 				 NUVOTON_QSPI_CTL_REORDER_MASK,
18278b16af1SChi-Wen Weng 				 FIELD_PREP(NUVOTON_QSPI_CTL_DWIDTH_MASK, bpw));
18378b16af1SChi-Wen Weng 
18478b16af1SChi-Wen Weng 	return 0;
18578b16af1SChi-Wen Weng }
18678b16af1SChi-Wen Weng 
187b5671d86SMiquel Raynal static int nuvoton_qspi_setup_transfer(struct spi_device *spi, u8 bpw)
18878b16af1SChi-Wen Weng {
18978b16af1SChi-Wen Weng 	struct nuvoton_qspi *qspi = spi_controller_get_devdata(spi->controller);
19078b16af1SChi-Wen Weng 	u32 mode = spi->mode & SPI_MODE_X_MASK;
19178b16af1SChi-Wen Weng 	u32 ctl = 0;
19278b16af1SChi-Wen Weng 	int ret;
19378b16af1SChi-Wen Weng 
19478b16af1SChi-Wen Weng 	if (!bpw)
19578b16af1SChi-Wen Weng 		bpw = NUVOTON_QSPI_DEFAULT_BPW;
19678b16af1SChi-Wen Weng 
19778b16af1SChi-Wen Weng 	ret = nuvoton_qspi_set_bits_per_word(qspi, bpw);
19878b16af1SChi-Wen Weng 	if (ret)
19978b16af1SChi-Wen Weng 		return ret;
20078b16af1SChi-Wen Weng 
20178b16af1SChi-Wen Weng 	if (mode == SPI_MODE_0 || mode == SPI_MODE_3)
20278b16af1SChi-Wen Weng 		ctl |= NUVOTON_QSPI_CTL_TXNEG_MASK;
20378b16af1SChi-Wen Weng 	else
20478b16af1SChi-Wen Weng 		ctl |= NUVOTON_QSPI_CTL_RXNEG_MASK;
20578b16af1SChi-Wen Weng 
20678b16af1SChi-Wen Weng 	if (spi->mode & SPI_CPOL)
20778b16af1SChi-Wen Weng 		ctl |= NUVOTON_QSPI_CTL_CLKPOL_MASK;
20878b16af1SChi-Wen Weng 
20978b16af1SChi-Wen Weng 	if (spi->mode & SPI_LSB_FIRST)
21078b16af1SChi-Wen Weng 		ctl |= NUVOTON_QSPI_CTL_LSB_MASK;
21178b16af1SChi-Wen Weng 
21278b16af1SChi-Wen Weng 	nuvoton_qspi_update_bits(qspi, NUVOTON_QSPI_CTL_OFFSET,
21378b16af1SChi-Wen Weng 				 NUVOTON_QSPI_CTL_TXNEG_MASK |
21478b16af1SChi-Wen Weng 				 NUVOTON_QSPI_CTL_RXNEG_MASK |
21578b16af1SChi-Wen Weng 				 NUVOTON_QSPI_CTL_CLKPOL_MASK |
21678b16af1SChi-Wen Weng 				 NUVOTON_QSPI_CTL_LSB_MASK, ctl);
21778b16af1SChi-Wen Weng 
21878b16af1SChi-Wen Weng 	return 0;
21978b16af1SChi-Wen Weng }
22078b16af1SChi-Wen Weng 
221b5671d86SMiquel Raynal static int nuvoton_qspi_configure_bus(struct spi_device *spi,
22278b16af1SChi-Wen Weng 				      unsigned int buswidth,
223b5671d86SMiquel Raynal 				      enum spi_mem_data_dir dir,
22415e9362fSMiquel Raynal 				      u32 speed_hz, bool dtr)
22578b16af1SChi-Wen Weng {
226b5671d86SMiquel Raynal 	struct nuvoton_qspi *qspi = spi_controller_get_devdata(spi->controller);
22778b16af1SChi-Wen Weng 	u32 ctl = 0;
228b5671d86SMiquel Raynal 	int ret;
229b5671d86SMiquel Raynal 
23015e9362fSMiquel Raynal 	ret = nuvoton_qspi_set_speed(spi, speed_hz, dtr);
231b5671d86SMiquel Raynal 	if (ret)
232b5671d86SMiquel Raynal 		return ret;
23378b16af1SChi-Wen Weng 
23415e9362fSMiquel Raynal 	if (dtr)
23515e9362fSMiquel Raynal 		ctl |= NUVOTON_QSPI_CTL_DTREN_MASK;
23615e9362fSMiquel Raynal 
23778b16af1SChi-Wen Weng 	if (buswidth == 4)
23878b16af1SChi-Wen Weng 		ctl |= NUVOTON_QSPI_CTL_QUADIOEN_MASK;
23978b16af1SChi-Wen Weng 	else if (buswidth == 2)
24078b16af1SChi-Wen Weng 		ctl |= NUVOTON_QSPI_CTL_DUALIOEN_MASK;
24178b16af1SChi-Wen Weng 
24278b16af1SChi-Wen Weng 	if (buswidth > 1 && dir == SPI_MEM_DATA_OUT)
24378b16af1SChi-Wen Weng 		ctl |= NUVOTON_QSPI_CTL_DATDIR_MASK;
24478b16af1SChi-Wen Weng 
24578b16af1SChi-Wen Weng 	nuvoton_qspi_update_bits(qspi, NUVOTON_QSPI_CTL_OFFSET,
24615e9362fSMiquel Raynal 				 NUVOTON_QSPI_CTL_DTREN_MASK |
24778b16af1SChi-Wen Weng 				 NUVOTON_QSPI_CTL_QUADIOEN_MASK |
24878b16af1SChi-Wen Weng 				 NUVOTON_QSPI_CTL_DUALIOEN_MASK |
24978b16af1SChi-Wen Weng 				 NUVOTON_QSPI_CTL_DATDIR_MASK, ctl);
250b5671d86SMiquel Raynal 
251b5671d86SMiquel Raynal 	return 0;
25278b16af1SChi-Wen Weng }
25378b16af1SChi-Wen Weng 
25478b16af1SChi-Wen Weng static u32 nuvoton_qspi_tx_byte(const void *txbuf, unsigned int idx)
25578b16af1SChi-Wen Weng {
25678b16af1SChi-Wen Weng 	if (!txbuf)
25778b16af1SChi-Wen Weng 		return 0;
25878b16af1SChi-Wen Weng 
25978b16af1SChi-Wen Weng 	return ((const u8 *)txbuf)[idx];
26078b16af1SChi-Wen Weng }
26178b16af1SChi-Wen Weng 
26278b16af1SChi-Wen Weng static void nuvoton_qspi_rx_byte(void *rxbuf, unsigned int idx, u32 val)
26378b16af1SChi-Wen Weng {
26478b16af1SChi-Wen Weng 	if (rxbuf)
26578b16af1SChi-Wen Weng 		((u8 *)rxbuf)[idx] = val;
26678b16af1SChi-Wen Weng }
26778b16af1SChi-Wen Weng 
26878b16af1SChi-Wen Weng static int nuvoton_qspi_wait_tx_not_full(struct nuvoton_qspi *qspi)
26978b16af1SChi-Wen Weng {
27078b16af1SChi-Wen Weng 	u32 val;
27178b16af1SChi-Wen Weng 
27278b16af1SChi-Wen Weng 	return readl_poll_timeout_atomic(qspi->regs + NUVOTON_QSPI_STATUS_OFFSET,
27378b16af1SChi-Wen Weng 					 val,
27478b16af1SChi-Wen Weng 					 !(val & NUVOTON_QSPI_STATUS_TXFULL_MASK),
27578b16af1SChi-Wen Weng 					 0, NUVOTON_QSPI_TIMEOUT_US);
27678b16af1SChi-Wen Weng }
27778b16af1SChi-Wen Weng 
27878b16af1SChi-Wen Weng static int nuvoton_qspi_wait_rx_not_empty(struct nuvoton_qspi *qspi)
27978b16af1SChi-Wen Weng {
28078b16af1SChi-Wen Weng 	u32 val;
28178b16af1SChi-Wen Weng 
28278b16af1SChi-Wen Weng 	return readl_poll_timeout_atomic(qspi->regs + NUVOTON_QSPI_STATUS_OFFSET,
28378b16af1SChi-Wen Weng 					 val,
28478b16af1SChi-Wen Weng 					 !(val & NUVOTON_QSPI_STATUS_RXEMPTY_MASK),
28578b16af1SChi-Wen Weng 					 0, NUVOTON_QSPI_TIMEOUT_US);
28678b16af1SChi-Wen Weng }
28778b16af1SChi-Wen Weng 
28878b16af1SChi-Wen Weng static int nuvoton_qspi_txrx(struct nuvoton_qspi *qspi, const void *txbuf,
28978b16af1SChi-Wen Weng 			     void *rxbuf, unsigned int len)
29078b16af1SChi-Wen Weng {
29178b16af1SChi-Wen Weng 	unsigned int i;
29278b16af1SChi-Wen Weng 	u32 val;
29378b16af1SChi-Wen Weng 	int ret;
29478b16af1SChi-Wen Weng 
29578b16af1SChi-Wen Weng 	if (!len)
29678b16af1SChi-Wen Weng 		return 0;
29778b16af1SChi-Wen Weng 
29878b16af1SChi-Wen Weng 	if (len > NUVOTON_QSPI_MAX_TRANSFER_SIZE)
29978b16af1SChi-Wen Weng 		return -EMSGSIZE;
30078b16af1SChi-Wen Weng 
30178b16af1SChi-Wen Weng 	ret = nuvoton_qspi_reset_fifo(qspi);
30278b16af1SChi-Wen Weng 	if (ret) {
30378b16af1SChi-Wen Weng 		dev_err(qspi->dev, "FIFO reset timed out\n");
30478b16af1SChi-Wen Weng 		return ret;
30578b16af1SChi-Wen Weng 	}
30678b16af1SChi-Wen Weng 
30778b16af1SChi-Wen Weng 	/*
30878b16af1SChi-Wen Weng 	 * Use conservative byte-by-byte PIO access. This keeps the initial driver
30978b16af1SChi-Wen Weng 	 * simple and avoids relying on FIFO threshold interrupts or DMA support.
31078b16af1SChi-Wen Weng 	 *
31178b16af1SChi-Wen Weng 	 * The MA35D1 QSPI controller pushes one RX FIFO entry for each TX byte in
31278b16af1SChi-Wen Weng 	 * single, dual-output and quad-output modes. Drain RX after every TX byte
31378b16af1SChi-Wen Weng 	 * and discard the value for TX-only transfers to avoid RX FIFO overflow.
31478b16af1SChi-Wen Weng 	 */
31578b16af1SChi-Wen Weng 	for (i = 0; i < len; i++) {
31678b16af1SChi-Wen Weng 		ret = nuvoton_qspi_wait_tx_not_full(qspi);
31778b16af1SChi-Wen Weng 		if (ret) {
31878b16af1SChi-Wen Weng 			dev_err(qspi->dev, "TX FIFO full timeout\n");
31978b16af1SChi-Wen Weng 			return ret;
32078b16af1SChi-Wen Weng 		}
32178b16af1SChi-Wen Weng 
32278b16af1SChi-Wen Weng 		nuvoton_qspi_write(qspi, nuvoton_qspi_tx_byte(txbuf, i),
32378b16af1SChi-Wen Weng 				   NUVOTON_QSPI_TX_OFFSET);
32478b16af1SChi-Wen Weng 
32578b16af1SChi-Wen Weng 		ret = nuvoton_qspi_wait_rx_not_empty(qspi);
32678b16af1SChi-Wen Weng 		if (ret) {
32778b16af1SChi-Wen Weng 			dev_err(qspi->dev, "RX FIFO empty timeout\n");
32878b16af1SChi-Wen Weng 			return ret;
32978b16af1SChi-Wen Weng 		}
33078b16af1SChi-Wen Weng 
33178b16af1SChi-Wen Weng 		val = nuvoton_qspi_read(qspi, NUVOTON_QSPI_RX_OFFSET);
33278b16af1SChi-Wen Weng 		if (rxbuf)
33378b16af1SChi-Wen Weng 			nuvoton_qspi_rx_byte(rxbuf, i, val);
33478b16af1SChi-Wen Weng 	}
33578b16af1SChi-Wen Weng 
33678b16af1SChi-Wen Weng 	ret = nuvoton_qspi_wait_ready(qspi);
33778b16af1SChi-Wen Weng 	if (ret)
33878b16af1SChi-Wen Weng 		dev_err(qspi->dev, "controller busy timeout\n");
33978b16af1SChi-Wen Weng 
34078b16af1SChi-Wen Weng 	return ret;
34178b16af1SChi-Wen Weng }
34278b16af1SChi-Wen Weng 
34378b16af1SChi-Wen Weng static int nuvoton_qspi_hw_init(struct nuvoton_qspi *qspi)
34478b16af1SChi-Wen Weng {
34578b16af1SChi-Wen Weng 	u32 val;
34678b16af1SChi-Wen Weng 	int ret;
34778b16af1SChi-Wen Weng 
34878b16af1SChi-Wen Weng 	ret = nuvoton_qspi_set_bits_per_word(qspi, NUVOTON_QSPI_DEFAULT_BPW);
34978b16af1SChi-Wen Weng 	if (ret)
35078b16af1SChi-Wen Weng 		return ret;
35178b16af1SChi-Wen Weng 
35278b16af1SChi-Wen Weng 	nuvoton_qspi_update_bits(qspi, NUVOTON_QSPI_CTL_OFFSET,
35378b16af1SChi-Wen Weng 				 NUVOTON_QSPI_CTL_SUSPITV_MASK |
35478b16af1SChi-Wen Weng 				 NUVOTON_QSPI_CTL_TXNEG_MASK |
35578b16af1SChi-Wen Weng 				 NUVOTON_QSPI_CTL_RXNEG_MASK |
35678b16af1SChi-Wen Weng 				 NUVOTON_QSPI_CTL_CLKPOL_MASK |
35778b16af1SChi-Wen Weng 				 NUVOTON_QSPI_CTL_LSB_MASK,
35878b16af1SChi-Wen Weng 				 NUVOTON_QSPI_CTL_TXNEG_MASK);
35978b16af1SChi-Wen Weng 
360*0730bb35SMiquel Raynal 	nuvoton_qspi_update_bits(qspi, NUVOTON_QSPI_CTL_OFFSET,
361*0730bb35SMiquel Raynal 				 NUVOTON_QSPI_CTL_SPIEN_MASK,
362*0730bb35SMiquel Raynal 				 NUVOTON_QSPI_CTL_SPIEN_MASK);
36378b16af1SChi-Wen Weng 
36478b16af1SChi-Wen Weng 	ret = readl_poll_timeout(qspi->regs + NUVOTON_QSPI_STATUS_OFFSET, val,
36578b16af1SChi-Wen Weng 				 (val & NUVOTON_QSPI_STATUS_SPIENSTS_MASK),
36678b16af1SChi-Wen Weng 				 1, NUVOTON_QSPI_TIMEOUT_US);
36778b16af1SChi-Wen Weng 	if (ret) {
36878b16af1SChi-Wen Weng 		dev_err(qspi->dev, "failed to enable controller\n");
36978b16af1SChi-Wen Weng 		return ret;
37078b16af1SChi-Wen Weng 	}
37178b16af1SChi-Wen Weng 
37278b16af1SChi-Wen Weng 	ret = nuvoton_qspi_reset_fifo(qspi);
37378b16af1SChi-Wen Weng 	if (ret)
37478b16af1SChi-Wen Weng 		dev_err(qspi->dev, "FIFO reset timed out\n");
37578b16af1SChi-Wen Weng 
37678b16af1SChi-Wen Weng 	return ret;
37778b16af1SChi-Wen Weng }
37878b16af1SChi-Wen Weng 
37978b16af1SChi-Wen Weng static size_t nuvoton_qspi_max_transfer_size(struct spi_device *spi)
38078b16af1SChi-Wen Weng {
38178b16af1SChi-Wen Weng 	return NUVOTON_QSPI_MAX_TRANSFER_SIZE;
38278b16af1SChi-Wen Weng }
38378b16af1SChi-Wen Weng 
38478b16af1SChi-Wen Weng static size_t nuvoton_qspi_max_message_size(struct spi_device *spi)
38578b16af1SChi-Wen Weng {
38678b16af1SChi-Wen Weng 	return NUVOTON_QSPI_MAX_MESSAGE_SIZE;
38778b16af1SChi-Wen Weng }
38878b16af1SChi-Wen Weng 
38978b16af1SChi-Wen Weng static int nuvoton_qspi_mem_adjust_op_size(struct spi_mem *mem,
39078b16af1SChi-Wen Weng 					   struct spi_mem_op *op)
39178b16af1SChi-Wen Weng {
39278b16af1SChi-Wen Weng 	if (op->data.nbytes > NUVOTON_QSPI_MAX_TRANSFER_SIZE)
39378b16af1SChi-Wen Weng 		op->data.nbytes = NUVOTON_QSPI_MAX_TRANSFER_SIZE;
39478b16af1SChi-Wen Weng 
39578b16af1SChi-Wen Weng 	return 0;
39678b16af1SChi-Wen Weng }
39778b16af1SChi-Wen Weng 
39878b16af1SChi-Wen Weng static bool nuvoton_qspi_mem_supports_op(struct spi_mem *mem,
39978b16af1SChi-Wen Weng 					 const struct spi_mem_op *op)
40078b16af1SChi-Wen Weng {
40178b16af1SChi-Wen Weng 	if (!spi_mem_default_supports_op(mem, op))
40278b16af1SChi-Wen Weng 		return false;
40378b16af1SChi-Wen Weng 
40478b16af1SChi-Wen Weng 	if (op->cmd.buswidth > 4 || op->addr.buswidth > 4 ||
40578b16af1SChi-Wen Weng 	    op->dummy.buswidth > 4 || op->data.buswidth > 4)
40678b16af1SChi-Wen Weng 		return false;
40778b16af1SChi-Wen Weng 
40878b16af1SChi-Wen Weng 	if (op->addr.nbytes > 4)
40978b16af1SChi-Wen Weng 		return false;
41078b16af1SChi-Wen Weng 
41178b16af1SChi-Wen Weng 	return true;
41278b16af1SChi-Wen Weng }
41378b16af1SChi-Wen Weng 
41478b16af1SChi-Wen Weng static void nuvoton_qspi_set_cs_level(struct nuvoton_qspi *qspi,
41578b16af1SChi-Wen Weng 				      unsigned int cs, bool assert)
41678b16af1SChi-Wen Weng {
41778b16af1SChi-Wen Weng 	unsigned long flags;
41878b16af1SChi-Wen Weng 	u32 mask;
41978b16af1SChi-Wen Weng 	u32 val;
42078b16af1SChi-Wen Weng 
42178b16af1SChi-Wen Weng 	switch (cs) {
42278b16af1SChi-Wen Weng 	case 0:
42378b16af1SChi-Wen Weng 		mask = NUVOTON_QSPI_SSCTL_SS0_MASK;
42478b16af1SChi-Wen Weng 		break;
42578b16af1SChi-Wen Weng 	case 1:
42678b16af1SChi-Wen Weng 		mask = NUVOTON_QSPI_SSCTL_SS1_MASK;
42778b16af1SChi-Wen Weng 		break;
42878b16af1SChi-Wen Weng 	default:
42978b16af1SChi-Wen Weng 		dev_warn(qspi->dev, "invalid chip select %u\n", cs);
43078b16af1SChi-Wen Weng 		return;
43178b16af1SChi-Wen Weng 	}
43278b16af1SChi-Wen Weng 
43378b16af1SChi-Wen Weng 	spin_lock_irqsave(&qspi->ssctl_lock, flags);
43478b16af1SChi-Wen Weng 
43578b16af1SChi-Wen Weng 	val = nuvoton_qspi_read(qspi, NUVOTON_QSPI_SSCTL_OFFSET);
43678b16af1SChi-Wen Weng 	if (assert)
43778b16af1SChi-Wen Weng 		val |= mask;
43878b16af1SChi-Wen Weng 	else
43978b16af1SChi-Wen Weng 		val &= ~mask;
44078b16af1SChi-Wen Weng 	nuvoton_qspi_write(qspi, val, NUVOTON_QSPI_SSCTL_OFFSET);
44178b16af1SChi-Wen Weng 
44278b16af1SChi-Wen Weng 	spin_unlock_irqrestore(&qspi->ssctl_lock, flags);
44378b16af1SChi-Wen Weng }
44478b16af1SChi-Wen Weng 
44578b16af1SChi-Wen Weng static void nuvoton_qspi_set_cs(struct spi_device *spi, bool level)
44678b16af1SChi-Wen Weng {
44778b16af1SChi-Wen Weng 	struct nuvoton_qspi *qspi = spi_controller_get_devdata(spi->controller);
44878b16af1SChi-Wen Weng 
44978b16af1SChi-Wen Weng 	/*
45078b16af1SChi-Wen Weng 	 * The SPI core passes the physical CS level to ->set_cs(). This
45178b16af1SChi-Wen Weng 	 * initial driver only supports active-low native chip selects.
45278b16af1SChi-Wen Weng 	 */
45378b16af1SChi-Wen Weng 	nuvoton_qspi_set_cs_level(qspi, spi_get_chipselect(spi, 0), !level);
45478b16af1SChi-Wen Weng }
45578b16af1SChi-Wen Weng 
45678b16af1SChi-Wen Weng static void nuvoton_qspi_mem_set_cs(struct spi_device *spi, bool assert)
45778b16af1SChi-Wen Weng {
45878b16af1SChi-Wen Weng 	struct nuvoton_qspi *qspi = spi_controller_get_devdata(spi->controller);
45978b16af1SChi-Wen Weng 
46078b16af1SChi-Wen Weng 	/* The direct spi-mem path passes a logical assertion state. */
46178b16af1SChi-Wen Weng 	nuvoton_qspi_set_cs_level(qspi, spi_get_chipselect(spi, 0), assert);
46278b16af1SChi-Wen Weng }
46378b16af1SChi-Wen Weng 
46478b16af1SChi-Wen Weng static int nuvoton_qspi_mem_exec_op(struct spi_mem *mem,
46578b16af1SChi-Wen Weng 				    const struct spi_mem_op *op)
46678b16af1SChi-Wen Weng {
46778b16af1SChi-Wen Weng 	struct spi_device *spi = mem->spi;
46878b16af1SChi-Wen Weng 	struct nuvoton_qspi *qspi = spi_controller_get_devdata(spi->controller);
46999542d24SMiquel Raynal 	u8 cmd[2], addr[4];
47078b16af1SChi-Wen Weng 	int ret;
47178b16af1SChi-Wen Weng 	int i;
47278b16af1SChi-Wen Weng 
473b5671d86SMiquel Raynal 	ret = nuvoton_qspi_setup_transfer(spi, NUVOTON_QSPI_DEFAULT_BPW);
47478b16af1SChi-Wen Weng 	if (ret)
47578b16af1SChi-Wen Weng 		return ret;
47678b16af1SChi-Wen Weng 
47778b16af1SChi-Wen Weng 	nuvoton_qspi_mem_set_cs(spi, true);
47878b16af1SChi-Wen Weng 
47999542d24SMiquel Raynal 	for (i = 0; i < op->cmd.nbytes; i++)
48099542d24SMiquel Raynal 		cmd[i] = op->cmd.opcode >> (8 * (op->cmd.nbytes - i - 1));
48199542d24SMiquel Raynal 
482b5671d86SMiquel Raynal 	ret = nuvoton_qspi_configure_bus(spi, op->cmd.buswidth, SPI_MEM_DATA_OUT,
48315e9362fSMiquel Raynal 					 op->max_freq, op->cmd.dtr);
484b5671d86SMiquel Raynal 	if (ret)
485b5671d86SMiquel Raynal 		goto out_deassert_cs;
486b5671d86SMiquel Raynal 
48799542d24SMiquel Raynal 	ret = nuvoton_qspi_txrx(qspi, cmd, NULL, op->cmd.nbytes);
48878b16af1SChi-Wen Weng 	if (ret)
48978b16af1SChi-Wen Weng 		goto out_deassert_cs;
49078b16af1SChi-Wen Weng 
49178b16af1SChi-Wen Weng 	if (op->addr.nbytes) {
49278b16af1SChi-Wen Weng 		for (i = 0; i < op->addr.nbytes; i++)
49378b16af1SChi-Wen Weng 			addr[i] = op->addr.val >> (8 * (op->addr.nbytes - i - 1));
49478b16af1SChi-Wen Weng 
495b5671d86SMiquel Raynal 		ret = nuvoton_qspi_configure_bus(spi, op->addr.buswidth, SPI_MEM_DATA_OUT,
49615e9362fSMiquel Raynal 						 op->max_freq, op->addr.dtr);
497b5671d86SMiquel Raynal 		if (ret)
498b5671d86SMiquel Raynal 			goto out_deassert_cs;
499b5671d86SMiquel Raynal 
50078b16af1SChi-Wen Weng 		ret = nuvoton_qspi_txrx(qspi, addr, NULL, op->addr.nbytes);
50178b16af1SChi-Wen Weng 		if (ret)
50278b16af1SChi-Wen Weng 			goto out_deassert_cs;
50378b16af1SChi-Wen Weng 	}
50478b16af1SChi-Wen Weng 
50578b16af1SChi-Wen Weng 	if (op->dummy.nbytes) {
506b5671d86SMiquel Raynal 		ret = nuvoton_qspi_configure_bus(spi, op->dummy.buswidth, SPI_MEM_DATA_OUT,
50715e9362fSMiquel Raynal 						 op->max_freq, op->dummy.dtr);
508b5671d86SMiquel Raynal 		if (ret)
509b5671d86SMiquel Raynal 			goto out_deassert_cs;
510b5671d86SMiquel Raynal 
51178b16af1SChi-Wen Weng 		ret = nuvoton_qspi_txrx(qspi, NULL, NULL, op->dummy.nbytes);
51278b16af1SChi-Wen Weng 		if (ret)
51378b16af1SChi-Wen Weng 			goto out_deassert_cs;
51478b16af1SChi-Wen Weng 	}
51578b16af1SChi-Wen Weng 
51678b16af1SChi-Wen Weng 	if (op->data.nbytes) {
517b5671d86SMiquel Raynal 		ret = nuvoton_qspi_configure_bus(spi, op->data.buswidth, op->data.dir,
51815e9362fSMiquel Raynal 						 op->max_freq, op->data.dtr);
519b5671d86SMiquel Raynal 		if (ret)
520b5671d86SMiquel Raynal 			goto out_deassert_cs;
521b5671d86SMiquel Raynal 
52278b16af1SChi-Wen Weng 		ret = nuvoton_qspi_txrx(qspi,
52378b16af1SChi-Wen Weng 					op->data.dir == SPI_MEM_DATA_OUT ?
52478b16af1SChi-Wen Weng 					op->data.buf.out : NULL,
52578b16af1SChi-Wen Weng 					op->data.dir == SPI_MEM_DATA_IN ?
52678b16af1SChi-Wen Weng 					op->data.buf.in : NULL,
52778b16af1SChi-Wen Weng 					op->data.nbytes);
52878b16af1SChi-Wen Weng 	}
52978b16af1SChi-Wen Weng 
53078b16af1SChi-Wen Weng out_deassert_cs:
53178b16af1SChi-Wen Weng 	nuvoton_qspi_mem_set_cs(spi, false);
53278b16af1SChi-Wen Weng 
53378b16af1SChi-Wen Weng 	return ret;
53478b16af1SChi-Wen Weng }
53578b16af1SChi-Wen Weng 
53678b16af1SChi-Wen Weng static const struct spi_controller_mem_ops nuvoton_qspi_mem_ops = {
53778b16af1SChi-Wen Weng 	.adjust_op_size = nuvoton_qspi_mem_adjust_op_size,
53878b16af1SChi-Wen Weng 	.supports_op = nuvoton_qspi_mem_supports_op,
53978b16af1SChi-Wen Weng 	.exec_op = nuvoton_qspi_mem_exec_op,
54078b16af1SChi-Wen Weng };
54178b16af1SChi-Wen Weng 
54278b16af1SChi-Wen Weng static const struct spi_controller_mem_caps nuvoton_qspi_mem_caps = {
54378b16af1SChi-Wen Weng 	.per_op_freq = true,
54415e9362fSMiquel Raynal 	.dtr = true,
54578b16af1SChi-Wen Weng };
54678b16af1SChi-Wen Weng 
54778b16af1SChi-Wen Weng static int nuvoton_qspi_transfer_one(struct spi_controller *ctlr,
54878b16af1SChi-Wen Weng 				     struct spi_device *spi,
54978b16af1SChi-Wen Weng 				     struct spi_transfer *xfer)
55078b16af1SChi-Wen Weng {
55178b16af1SChi-Wen Weng 	struct nuvoton_qspi *qspi = spi_controller_get_devdata(ctlr);
55278b16af1SChi-Wen Weng 	unsigned int tx_nbits = xfer->tx_nbits ?: SPI_NBITS_SINGLE;
55378b16af1SChi-Wen Weng 	unsigned int rx_nbits = xfer->rx_nbits ?: SPI_NBITS_SINGLE;
55478b16af1SChi-Wen Weng 	enum spi_mem_data_dir dir = SPI_MEM_DATA_IN;
55578b16af1SChi-Wen Weng 	unsigned int buswidth = 1;
55678b16af1SChi-Wen Weng 	int ret;
55778b16af1SChi-Wen Weng 
558b5671d86SMiquel Raynal 	ret = nuvoton_qspi_setup_transfer(spi, xfer->bits_per_word);
55978b16af1SChi-Wen Weng 	if (ret)
56078b16af1SChi-Wen Weng 		return ret;
56178b16af1SChi-Wen Weng 
56278b16af1SChi-Wen Weng 	if (xfer->tx_buf && xfer->rx_buf &&
56378b16af1SChi-Wen Weng 	    (tx_nbits != SPI_NBITS_SINGLE ||
56478b16af1SChi-Wen Weng 	     rx_nbits != SPI_NBITS_SINGLE))
56578b16af1SChi-Wen Weng 		return -EOPNOTSUPP;
56678b16af1SChi-Wen Weng 
56778b16af1SChi-Wen Weng 	if (xfer->tx_buf) {
56878b16af1SChi-Wen Weng 		dir = SPI_MEM_DATA_OUT;
56978b16af1SChi-Wen Weng 
57078b16af1SChi-Wen Weng 		if (tx_nbits == SPI_NBITS_QUAD)
57178b16af1SChi-Wen Weng 			buswidth = 4;
57278b16af1SChi-Wen Weng 		else if (tx_nbits == SPI_NBITS_DUAL)
57378b16af1SChi-Wen Weng 			buswidth = 2;
57478b16af1SChi-Wen Weng 	} else if (xfer->rx_buf) {
57578b16af1SChi-Wen Weng 		if (rx_nbits == SPI_NBITS_QUAD)
57678b16af1SChi-Wen Weng 			buswidth = 4;
57778b16af1SChi-Wen Weng 		else if (rx_nbits == SPI_NBITS_DUAL)
57878b16af1SChi-Wen Weng 			buswidth = 2;
57978b16af1SChi-Wen Weng 	}
58078b16af1SChi-Wen Weng 
58115e9362fSMiquel Raynal 	ret = nuvoton_qspi_configure_bus(spi, buswidth, dir, xfer->speed_hz,
58215e9362fSMiquel Raynal 					 xfer->dtr_mode);
583b5671d86SMiquel Raynal 	if (ret)
584b5671d86SMiquel Raynal 		return ret;
585b5671d86SMiquel Raynal 
58678b16af1SChi-Wen Weng 	ret = nuvoton_qspi_txrx(qspi, xfer->tx_buf, xfer->rx_buf,
58778b16af1SChi-Wen Weng 				xfer->len);
58878b16af1SChi-Wen Weng 
58978b16af1SChi-Wen Weng 	return ret;
59078b16af1SChi-Wen Weng }
59178b16af1SChi-Wen Weng 
59278b16af1SChi-Wen Weng static int nuvoton_qspi_probe(struct platform_device *pdev)
59378b16af1SChi-Wen Weng {
59478b16af1SChi-Wen Weng 	struct device *dev = &pdev->dev;
59578b16af1SChi-Wen Weng 	struct spi_controller *ctlr;
59678b16af1SChi-Wen Weng 	struct nuvoton_qspi *qspi;
59778b16af1SChi-Wen Weng 	struct reset_control *rst;
59878b16af1SChi-Wen Weng 	u32 num_cs = NUVOTON_QSPI_DEFAULT_NUM_CS;
59978b16af1SChi-Wen Weng 	int ret;
60078b16af1SChi-Wen Weng 
60178b16af1SChi-Wen Weng 	ctlr = devm_spi_alloc_host(dev, sizeof(*qspi));
60278b16af1SChi-Wen Weng 	if (!ctlr)
60378b16af1SChi-Wen Weng 		return -ENOMEM;
60478b16af1SChi-Wen Weng 
60578b16af1SChi-Wen Weng 	platform_set_drvdata(pdev, ctlr);
60678b16af1SChi-Wen Weng 
60778b16af1SChi-Wen Weng 	qspi = spi_controller_get_devdata(ctlr);
60878b16af1SChi-Wen Weng 	qspi->dev = dev;
60978b16af1SChi-Wen Weng 	spin_lock_init(&qspi->ssctl_lock);
61078b16af1SChi-Wen Weng 
61178b16af1SChi-Wen Weng 	qspi->regs = devm_platform_ioremap_resource(pdev, 0);
61278b16af1SChi-Wen Weng 	if (IS_ERR(qspi->regs))
61378b16af1SChi-Wen Weng 		return PTR_ERR(qspi->regs);
61478b16af1SChi-Wen Weng 
61578b16af1SChi-Wen Weng 	rst = devm_reset_control_get_exclusive(dev, NULL);
61678b16af1SChi-Wen Weng 	if (IS_ERR(rst))
61778b16af1SChi-Wen Weng 		return dev_err_probe(dev, PTR_ERR(rst),
61878b16af1SChi-Wen Weng 				     "failed to get reset\n");
61978b16af1SChi-Wen Weng 
62078b16af1SChi-Wen Weng 	qspi->clk = devm_clk_get_enabled(dev, NULL);
62178b16af1SChi-Wen Weng 	if (IS_ERR(qspi->clk))
62278b16af1SChi-Wen Weng 		return dev_err_probe(dev, PTR_ERR(qspi->clk),
62378b16af1SChi-Wen Weng 				     "failed to get and enable clock\n");
62478b16af1SChi-Wen Weng 
62578b16af1SChi-Wen Weng 	ret = reset_control_assert(rst);
62678b16af1SChi-Wen Weng 	if (ret)
62778b16af1SChi-Wen Weng 		return dev_err_probe(dev, ret, "failed to assert reset\n");
62878b16af1SChi-Wen Weng 
62978b16af1SChi-Wen Weng 	udelay(2);
63078b16af1SChi-Wen Weng 
63178b16af1SChi-Wen Weng 	ret = reset_control_deassert(rst);
63278b16af1SChi-Wen Weng 	if (ret)
63378b16af1SChi-Wen Weng 		return dev_err_probe(dev, ret, "failed to deassert reset\n");
63478b16af1SChi-Wen Weng 
63578b16af1SChi-Wen Weng 	ret = device_property_read_u32(dev, "num-cs", &num_cs);
63678b16af1SChi-Wen Weng 	if (ret && ret != -EINVAL)
63778b16af1SChi-Wen Weng 		return dev_err_probe(dev, ret, "failed to read num-cs\n");
63878b16af1SChi-Wen Weng 
63978b16af1SChi-Wen Weng 	if (!num_cs || num_cs > NUVOTON_QSPI_MAX_NUM_CS)
64078b16af1SChi-Wen Weng 		return dev_err_probe(dev, -EINVAL, "invalid num-cs %u\n",
64178b16af1SChi-Wen Weng 				     num_cs);
64278b16af1SChi-Wen Weng 
64378b16af1SChi-Wen Weng 	ctlr->num_chipselect = num_cs;
64478b16af1SChi-Wen Weng 	ctlr->max_transfer_size = nuvoton_qspi_max_transfer_size;
64578b16af1SChi-Wen Weng 	ctlr->max_message_size = nuvoton_qspi_max_message_size;
64678b16af1SChi-Wen Weng 	ctlr->mem_ops = &nuvoton_qspi_mem_ops;
64778b16af1SChi-Wen Weng 	ctlr->mem_caps = &nuvoton_qspi_mem_caps;
64878b16af1SChi-Wen Weng 	ctlr->set_cs = nuvoton_qspi_set_cs;
64978b16af1SChi-Wen Weng 	ctlr->transfer_one = nuvoton_qspi_transfer_one;
65078b16af1SChi-Wen Weng 	ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
65178b16af1SChi-Wen Weng 	ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST |
65278b16af1SChi-Wen Weng 			  SPI_RX_DUAL | SPI_TX_DUAL |
65378b16af1SChi-Wen Weng 			  SPI_RX_QUAD | SPI_TX_QUAD;
65478b16af1SChi-Wen Weng 	ctlr->dev.of_node = dev->of_node;
65578b16af1SChi-Wen Weng 
65678b16af1SChi-Wen Weng 	ret = nuvoton_qspi_hw_init(qspi);
65778b16af1SChi-Wen Weng 	if (ret)
65878b16af1SChi-Wen Weng 		return ret;
65978b16af1SChi-Wen Weng 
66078b16af1SChi-Wen Weng 	ret = devm_spi_register_controller(dev, ctlr);
66178b16af1SChi-Wen Weng 	if (ret)
66278b16af1SChi-Wen Weng 		return dev_err_probe(dev, ret,
66378b16af1SChi-Wen Weng 				     "failed to register spi controller\n");
66478b16af1SChi-Wen Weng 
66578b16af1SChi-Wen Weng 	return 0;
66678b16af1SChi-Wen Weng }
66778b16af1SChi-Wen Weng 
66878b16af1SChi-Wen Weng static const struct of_device_id nuvoton_qspi_of_match[] = {
66978b16af1SChi-Wen Weng 	{ .compatible = "nuvoton,ma35d1-qspi" },
67078b16af1SChi-Wen Weng 	{ }
67178b16af1SChi-Wen Weng };
67278b16af1SChi-Wen Weng MODULE_DEVICE_TABLE(of, nuvoton_qspi_of_match);
67378b16af1SChi-Wen Weng 
67478b16af1SChi-Wen Weng static struct platform_driver nuvoton_qspi_driver = {
67578b16af1SChi-Wen Weng 	.driver = {
67678b16af1SChi-Wen Weng 		.name = "ma35d1-qspi",
67778b16af1SChi-Wen Weng 		.of_match_table = nuvoton_qspi_of_match,
67878b16af1SChi-Wen Weng 	},
67978b16af1SChi-Wen Weng 	.probe = nuvoton_qspi_probe,
68078b16af1SChi-Wen Weng };
68178b16af1SChi-Wen Weng module_platform_driver(nuvoton_qspi_driver);
68278b16af1SChi-Wen Weng 
68378b16af1SChi-Wen Weng MODULE_DESCRIPTION("Nuvoton MA35D1 QSPI controller driver");
68478b16af1SChi-Wen Weng MODULE_AUTHOR("Chi-Wen Weng <cwweng@nuvoton.com>");
68578b16af1SChi-Wen Weng MODULE_LICENSE("GPL");
686