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