xref: /openbmc/linux/drivers/spi/spi-rspi.c (revision afcc98de)
10b2182ddSShimoda, Yoshihiro /*
20b2182ddSShimoda, Yoshihiro  * SH RSPI driver
30b2182ddSShimoda, Yoshihiro  *
493722206SGeert Uytterhoeven  * Copyright (C) 2012, 2013  Renesas Solutions Corp.
5880c6d11SGeert Uytterhoeven  * Copyright (C) 2014 Glider bvba
60b2182ddSShimoda, Yoshihiro  *
70b2182ddSShimoda, Yoshihiro  * Based on spi-sh.c:
80b2182ddSShimoda, Yoshihiro  * Copyright (C) 2011 Renesas Solutions Corp.
90b2182ddSShimoda, Yoshihiro  *
100b2182ddSShimoda, Yoshihiro  * This program is free software; you can redistribute it and/or modify
110b2182ddSShimoda, Yoshihiro  * it under the terms of the GNU General Public License as published by
120b2182ddSShimoda, Yoshihiro  * the Free Software Foundation; version 2 of the License.
130b2182ddSShimoda, Yoshihiro  *
140b2182ddSShimoda, Yoshihiro  * This program is distributed in the hope that it will be useful,
150b2182ddSShimoda, Yoshihiro  * but WITHOUT ANY WARRANTY; without even the implied warranty of
160b2182ddSShimoda, Yoshihiro  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
170b2182ddSShimoda, Yoshihiro  * GNU General Public License for more details.
180b2182ddSShimoda, Yoshihiro  *
190b2182ddSShimoda, Yoshihiro  * You should have received a copy of the GNU General Public License
200b2182ddSShimoda, Yoshihiro  * along with this program; if not, write to the Free Software
210b2182ddSShimoda, Yoshihiro  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
220b2182ddSShimoda, Yoshihiro  *
230b2182ddSShimoda, Yoshihiro  */
240b2182ddSShimoda, Yoshihiro 
250b2182ddSShimoda, Yoshihiro #include <linux/module.h>
260b2182ddSShimoda, Yoshihiro #include <linux/kernel.h>
270b2182ddSShimoda, Yoshihiro #include <linux/sched.h>
280b2182ddSShimoda, Yoshihiro #include <linux/errno.h>
290b2182ddSShimoda, Yoshihiro #include <linux/interrupt.h>
300b2182ddSShimoda, Yoshihiro #include <linux/platform_device.h>
310b2182ddSShimoda, Yoshihiro #include <linux/io.h>
320b2182ddSShimoda, Yoshihiro #include <linux/clk.h>
33a3633fe7SShimoda, Yoshihiro #include <linux/dmaengine.h>
34a3633fe7SShimoda, Yoshihiro #include <linux/dma-mapping.h>
35426ef76dSGeert Uytterhoeven #include <linux/of_device.h>
36490c9774SGeert Uytterhoeven #include <linux/pm_runtime.h>
37a3633fe7SShimoda, Yoshihiro #include <linux/sh_dma.h>
380b2182ddSShimoda, Yoshihiro #include <linux/spi/spi.h>
39a3633fe7SShimoda, Yoshihiro #include <linux/spi/rspi.h>
400b2182ddSShimoda, Yoshihiro 
416ab4865bSGeert Uytterhoeven #define RSPI_SPCR		0x00	/* Control Register */
426ab4865bSGeert Uytterhoeven #define RSPI_SSLP		0x01	/* Slave Select Polarity Register */
436ab4865bSGeert Uytterhoeven #define RSPI_SPPCR		0x02	/* Pin Control Register */
446ab4865bSGeert Uytterhoeven #define RSPI_SPSR		0x03	/* Status Register */
456ab4865bSGeert Uytterhoeven #define RSPI_SPDR		0x04	/* Data Register */
466ab4865bSGeert Uytterhoeven #define RSPI_SPSCR		0x08	/* Sequence Control Register */
476ab4865bSGeert Uytterhoeven #define RSPI_SPSSR		0x09	/* Sequence Status Register */
486ab4865bSGeert Uytterhoeven #define RSPI_SPBR		0x0a	/* Bit Rate Register */
496ab4865bSGeert Uytterhoeven #define RSPI_SPDCR		0x0b	/* Data Control Register */
506ab4865bSGeert Uytterhoeven #define RSPI_SPCKD		0x0c	/* Clock Delay Register */
516ab4865bSGeert Uytterhoeven #define RSPI_SSLND		0x0d	/* Slave Select Negation Delay Register */
526ab4865bSGeert Uytterhoeven #define RSPI_SPND		0x0e	/* Next-Access Delay Register */
53862d357fSGeert Uytterhoeven #define RSPI_SPCR2		0x0f	/* Control Register 2 (SH only) */
546ab4865bSGeert Uytterhoeven #define RSPI_SPCMD0		0x10	/* Command Register 0 */
556ab4865bSGeert Uytterhoeven #define RSPI_SPCMD1		0x12	/* Command Register 1 */
566ab4865bSGeert Uytterhoeven #define RSPI_SPCMD2		0x14	/* Command Register 2 */
576ab4865bSGeert Uytterhoeven #define RSPI_SPCMD3		0x16	/* Command Register 3 */
586ab4865bSGeert Uytterhoeven #define RSPI_SPCMD4		0x18	/* Command Register 4 */
596ab4865bSGeert Uytterhoeven #define RSPI_SPCMD5		0x1a	/* Command Register 5 */
606ab4865bSGeert Uytterhoeven #define RSPI_SPCMD6		0x1c	/* Command Register 6 */
616ab4865bSGeert Uytterhoeven #define RSPI_SPCMD7		0x1e	/* Command Register 7 */
62880c6d11SGeert Uytterhoeven #define RSPI_SPCMD(i)		(RSPI_SPCMD0 + (i) * 2)
63880c6d11SGeert Uytterhoeven #define RSPI_NUM_SPCMD		8
64880c6d11SGeert Uytterhoeven #define RSPI_RZ_NUM_SPCMD	4
65880c6d11SGeert Uytterhoeven #define QSPI_NUM_SPCMD		4
66862d357fSGeert Uytterhoeven 
67862d357fSGeert Uytterhoeven /* RSPI on RZ only */
686ab4865bSGeert Uytterhoeven #define RSPI_SPBFCR		0x20	/* Buffer Control Register */
696ab4865bSGeert Uytterhoeven #define RSPI_SPBFDR		0x22	/* Buffer Data Count Setting Register */
700b2182ddSShimoda, Yoshihiro 
71862d357fSGeert Uytterhoeven /* QSPI only */
72fbe5072bSGeert Uytterhoeven #define QSPI_SPBFCR		0x18	/* Buffer Control Register */
73fbe5072bSGeert Uytterhoeven #define QSPI_SPBDCR		0x1a	/* Buffer Data Count Register */
74fbe5072bSGeert Uytterhoeven #define QSPI_SPBMUL0		0x1c	/* Transfer Data Length Multiplier Setting Register 0 */
75fbe5072bSGeert Uytterhoeven #define QSPI_SPBMUL1		0x20	/* Transfer Data Length Multiplier Setting Register 1 */
76fbe5072bSGeert Uytterhoeven #define QSPI_SPBMUL2		0x24	/* Transfer Data Length Multiplier Setting Register 2 */
77fbe5072bSGeert Uytterhoeven #define QSPI_SPBMUL3		0x28	/* Transfer Data Length Multiplier Setting Register 3 */
78880c6d11SGeert Uytterhoeven #define QSPI_SPBMUL(i)		(QSPI_SPBMUL0 + (i) * 4)
795ce0ba88SHiep Cao Minh 
806ab4865bSGeert Uytterhoeven /* SPCR - Control Register */
816ab4865bSGeert Uytterhoeven #define SPCR_SPRIE		0x80	/* Receive Interrupt Enable */
826ab4865bSGeert Uytterhoeven #define SPCR_SPE		0x40	/* Function Enable */
836ab4865bSGeert Uytterhoeven #define SPCR_SPTIE		0x20	/* Transmit Interrupt Enable */
846ab4865bSGeert Uytterhoeven #define SPCR_SPEIE		0x10	/* Error Interrupt Enable */
856ab4865bSGeert Uytterhoeven #define SPCR_MSTR		0x08	/* Master/Slave Mode Select */
866ab4865bSGeert Uytterhoeven #define SPCR_MODFEN		0x04	/* Mode Fault Error Detection Enable */
876ab4865bSGeert Uytterhoeven /* RSPI on SH only */
886ab4865bSGeert Uytterhoeven #define SPCR_TXMD		0x02	/* TX Only Mode (vs. Full Duplex) */
896ab4865bSGeert Uytterhoeven #define SPCR_SPMS		0x01	/* 3-wire Mode (vs. 4-wire) */
90fbe5072bSGeert Uytterhoeven /* QSPI on R-Car M2 only */
91fbe5072bSGeert Uytterhoeven #define SPCR_WSWAP		0x02	/* Word Swap of read-data for DMAC */
92fbe5072bSGeert Uytterhoeven #define SPCR_BSWAP		0x01	/* Byte Swap of read-data for DMAC */
930b2182ddSShimoda, Yoshihiro 
946ab4865bSGeert Uytterhoeven /* SSLP - Slave Select Polarity Register */
956ab4865bSGeert Uytterhoeven #define SSLP_SSL1P		0x02	/* SSL1 Signal Polarity Setting */
966ab4865bSGeert Uytterhoeven #define SSLP_SSL0P		0x01	/* SSL0 Signal Polarity Setting */
970b2182ddSShimoda, Yoshihiro 
986ab4865bSGeert Uytterhoeven /* SPPCR - Pin Control Register */
996ab4865bSGeert Uytterhoeven #define SPPCR_MOIFE		0x20	/* MOSI Idle Value Fixing Enable */
1006ab4865bSGeert Uytterhoeven #define SPPCR_MOIFV		0x10	/* MOSI Idle Fixed Value */
1010b2182ddSShimoda, Yoshihiro #define SPPCR_SPOM		0x04
1026ab4865bSGeert Uytterhoeven #define SPPCR_SPLP2		0x02	/* Loopback Mode 2 (non-inverting) */
1036ab4865bSGeert Uytterhoeven #define SPPCR_SPLP		0x01	/* Loopback Mode (inverting) */
1040b2182ddSShimoda, Yoshihiro 
105fbe5072bSGeert Uytterhoeven #define SPPCR_IO3FV		0x04	/* Single-/Dual-SPI Mode IO3 Output Fixed Value */
106fbe5072bSGeert Uytterhoeven #define SPPCR_IO2FV		0x04	/* Single-/Dual-SPI Mode IO2 Output Fixed Value */
107fbe5072bSGeert Uytterhoeven 
1086ab4865bSGeert Uytterhoeven /* SPSR - Status Register */
1096ab4865bSGeert Uytterhoeven #define SPSR_SPRF		0x80	/* Receive Buffer Full Flag */
1106ab4865bSGeert Uytterhoeven #define SPSR_TEND		0x40	/* Transmit End */
1116ab4865bSGeert Uytterhoeven #define SPSR_SPTEF		0x20	/* Transmit Buffer Empty Flag */
1126ab4865bSGeert Uytterhoeven #define SPSR_PERF		0x08	/* Parity Error Flag */
1136ab4865bSGeert Uytterhoeven #define SPSR_MODF		0x04	/* Mode Fault Error Flag */
1146ab4865bSGeert Uytterhoeven #define SPSR_IDLNF		0x02	/* RSPI Idle Flag */
115862d357fSGeert Uytterhoeven #define SPSR_OVRF		0x01	/* Overrun Error Flag (RSPI only) */
1160b2182ddSShimoda, Yoshihiro 
1176ab4865bSGeert Uytterhoeven /* SPSCR - Sequence Control Register */
1186ab4865bSGeert Uytterhoeven #define SPSCR_SPSLN_MASK	0x07	/* Sequence Length Specification */
1190b2182ddSShimoda, Yoshihiro 
1206ab4865bSGeert Uytterhoeven /* SPSSR - Sequence Status Register */
1216ab4865bSGeert Uytterhoeven #define SPSSR_SPECM_MASK	0x70	/* Command Error Mask */
1226ab4865bSGeert Uytterhoeven #define SPSSR_SPCP_MASK		0x07	/* Command Pointer Mask */
1230b2182ddSShimoda, Yoshihiro 
1246ab4865bSGeert Uytterhoeven /* SPDCR - Data Control Register */
1256ab4865bSGeert Uytterhoeven #define SPDCR_TXDMY		0x80	/* Dummy Data Transmission Enable */
1266ab4865bSGeert Uytterhoeven #define SPDCR_SPLW1		0x40	/* Access Width Specification (RZ) */
1276ab4865bSGeert Uytterhoeven #define SPDCR_SPLW0		0x20	/* Access Width Specification (RZ) */
1286ab4865bSGeert Uytterhoeven #define SPDCR_SPLLWORD		(SPDCR_SPLW1 | SPDCR_SPLW0)
1296ab4865bSGeert Uytterhoeven #define SPDCR_SPLWORD		SPDCR_SPLW1
1306ab4865bSGeert Uytterhoeven #define SPDCR_SPLBYTE		SPDCR_SPLW0
1316ab4865bSGeert Uytterhoeven #define SPDCR_SPLW		0x20	/* Access Width Specification (SH) */
132862d357fSGeert Uytterhoeven #define SPDCR_SPRDTD		0x10	/* Receive Transmit Data Select (SH) */
1330b2182ddSShimoda, Yoshihiro #define SPDCR_SLSEL1		0x08
1340b2182ddSShimoda, Yoshihiro #define SPDCR_SLSEL0		0x04
135862d357fSGeert Uytterhoeven #define SPDCR_SLSEL_MASK	0x0c	/* SSL1 Output Select (SH) */
1360b2182ddSShimoda, Yoshihiro #define SPDCR_SPFC1		0x02
1370b2182ddSShimoda, Yoshihiro #define SPDCR_SPFC0		0x01
138862d357fSGeert Uytterhoeven #define SPDCR_SPFC_MASK		0x03	/* Frame Count Setting (1-4) (SH) */
1390b2182ddSShimoda, Yoshihiro 
1406ab4865bSGeert Uytterhoeven /* SPCKD - Clock Delay Register */
1416ab4865bSGeert Uytterhoeven #define SPCKD_SCKDL_MASK	0x07	/* Clock Delay Setting (1-8) */
1420b2182ddSShimoda, Yoshihiro 
1436ab4865bSGeert Uytterhoeven /* SSLND - Slave Select Negation Delay Register */
1446ab4865bSGeert Uytterhoeven #define SSLND_SLNDL_MASK	0x07	/* SSL Negation Delay Setting (1-8) */
1450b2182ddSShimoda, Yoshihiro 
1466ab4865bSGeert Uytterhoeven /* SPND - Next-Access Delay Register */
1476ab4865bSGeert Uytterhoeven #define SPND_SPNDL_MASK		0x07	/* Next-Access Delay Setting (1-8) */
1480b2182ddSShimoda, Yoshihiro 
1496ab4865bSGeert Uytterhoeven /* SPCR2 - Control Register 2 */
1506ab4865bSGeert Uytterhoeven #define SPCR2_PTE		0x08	/* Parity Self-Test Enable */
1516ab4865bSGeert Uytterhoeven #define SPCR2_SPIE		0x04	/* Idle Interrupt Enable */
1526ab4865bSGeert Uytterhoeven #define SPCR2_SPOE		0x02	/* Odd Parity Enable (vs. Even) */
1536ab4865bSGeert Uytterhoeven #define SPCR2_SPPE		0x01	/* Parity Enable */
1540b2182ddSShimoda, Yoshihiro 
1556ab4865bSGeert Uytterhoeven /* SPCMDn - Command Registers */
1566ab4865bSGeert Uytterhoeven #define SPCMD_SCKDEN		0x8000	/* Clock Delay Setting Enable */
1576ab4865bSGeert Uytterhoeven #define SPCMD_SLNDEN		0x4000	/* SSL Negation Delay Setting Enable */
1586ab4865bSGeert Uytterhoeven #define SPCMD_SPNDEN		0x2000	/* Next-Access Delay Enable */
1596ab4865bSGeert Uytterhoeven #define SPCMD_LSBF		0x1000	/* LSB First */
1606ab4865bSGeert Uytterhoeven #define SPCMD_SPB_MASK		0x0f00	/* Data Length Setting */
1610b2182ddSShimoda, Yoshihiro #define SPCMD_SPB_8_TO_16(bit)	(((bit - 1) << 8) & SPCMD_SPB_MASK)
162880c6d11SGeert Uytterhoeven #define SPCMD_SPB_8BIT		0x0000	/* QSPI only */
1635ce0ba88SHiep Cao Minh #define SPCMD_SPB_16BIT		0x0100
1640b2182ddSShimoda, Yoshihiro #define SPCMD_SPB_20BIT		0x0000
1650b2182ddSShimoda, Yoshihiro #define SPCMD_SPB_24BIT		0x0100
1660b2182ddSShimoda, Yoshihiro #define SPCMD_SPB_32BIT		0x0200
1676ab4865bSGeert Uytterhoeven #define SPCMD_SSLKP		0x0080	/* SSL Signal Level Keeping */
168fbe5072bSGeert Uytterhoeven #define SPCMD_SPIMOD_MASK	0x0060	/* SPI Operating Mode (QSPI only) */
169fbe5072bSGeert Uytterhoeven #define SPCMD_SPIMOD1		0x0040
170fbe5072bSGeert Uytterhoeven #define SPCMD_SPIMOD0		0x0020
171fbe5072bSGeert Uytterhoeven #define SPCMD_SPIMOD_SINGLE	0
172fbe5072bSGeert Uytterhoeven #define SPCMD_SPIMOD_DUAL	SPCMD_SPIMOD0
173fbe5072bSGeert Uytterhoeven #define SPCMD_SPIMOD_QUAD	SPCMD_SPIMOD1
174fbe5072bSGeert Uytterhoeven #define SPCMD_SPRW		0x0010	/* SPI Read/Write Access (Dual/Quad) */
1756ab4865bSGeert Uytterhoeven #define SPCMD_SSLA_MASK		0x0030	/* SSL Assert Signal Setting (RSPI) */
1766ab4865bSGeert Uytterhoeven #define SPCMD_BRDV_MASK		0x000c	/* Bit Rate Division Setting */
1776ab4865bSGeert Uytterhoeven #define SPCMD_CPOL		0x0002	/* Clock Polarity Setting */
1786ab4865bSGeert Uytterhoeven #define SPCMD_CPHA		0x0001	/* Clock Phase Setting */
1790b2182ddSShimoda, Yoshihiro 
1806ab4865bSGeert Uytterhoeven /* SPBFCR - Buffer Control Register */
181862d357fSGeert Uytterhoeven #define SPBFCR_TXRST		0x80	/* Transmit Buffer Data Reset */
182862d357fSGeert Uytterhoeven #define SPBFCR_RXRST		0x40	/* Receive Buffer Data Reset */
1836ab4865bSGeert Uytterhoeven #define SPBFCR_TXTRG_MASK	0x30	/* Transmit Buffer Data Triggering Number */
1846ab4865bSGeert Uytterhoeven #define SPBFCR_RXTRG_MASK	0x07	/* Receive Buffer Data Triggering Number */
1855ce0ba88SHiep Cao Minh 
1860b2182ddSShimoda, Yoshihiro struct rspi_data {
1870b2182ddSShimoda, Yoshihiro 	void __iomem *addr;
1880b2182ddSShimoda, Yoshihiro 	u32 max_speed_hz;
1890b2182ddSShimoda, Yoshihiro 	struct spi_master *master;
1900b2182ddSShimoda, Yoshihiro 	wait_queue_head_t wait;
1910b2182ddSShimoda, Yoshihiro 	struct clk *clk;
192348e5153SGeert Uytterhoeven 	u16 spcmd;
19306a7a3cfSGeert Uytterhoeven 	u8 spsr;
19406a7a3cfSGeert Uytterhoeven 	u8 sppcr;
19593722206SGeert Uytterhoeven 	int rx_irq, tx_irq;
1965ce0ba88SHiep Cao Minh 	const struct spi_ops *ops;
197a3633fe7SShimoda, Yoshihiro 
198a3633fe7SShimoda, Yoshihiro 	unsigned dma_callbacked:1;
19974da7686SGeert Uytterhoeven 	unsigned byte_access:1;
2000b2182ddSShimoda, Yoshihiro };
2010b2182ddSShimoda, Yoshihiro 
202baf588f4SGeert Uytterhoeven static void rspi_write8(const struct rspi_data *rspi, u8 data, u16 offset)
2030b2182ddSShimoda, Yoshihiro {
2040b2182ddSShimoda, Yoshihiro 	iowrite8(data, rspi->addr + offset);
2050b2182ddSShimoda, Yoshihiro }
2060b2182ddSShimoda, Yoshihiro 
207baf588f4SGeert Uytterhoeven static void rspi_write16(const struct rspi_data *rspi, u16 data, u16 offset)
2080b2182ddSShimoda, Yoshihiro {
2090b2182ddSShimoda, Yoshihiro 	iowrite16(data, rspi->addr + offset);
2100b2182ddSShimoda, Yoshihiro }
2110b2182ddSShimoda, Yoshihiro 
212baf588f4SGeert Uytterhoeven static void rspi_write32(const struct rspi_data *rspi, u32 data, u16 offset)
2135ce0ba88SHiep Cao Minh {
2145ce0ba88SHiep Cao Minh 	iowrite32(data, rspi->addr + offset);
2155ce0ba88SHiep Cao Minh }
2165ce0ba88SHiep Cao Minh 
217baf588f4SGeert Uytterhoeven static u8 rspi_read8(const struct rspi_data *rspi, u16 offset)
2180b2182ddSShimoda, Yoshihiro {
2190b2182ddSShimoda, Yoshihiro 	return ioread8(rspi->addr + offset);
2200b2182ddSShimoda, Yoshihiro }
2210b2182ddSShimoda, Yoshihiro 
222baf588f4SGeert Uytterhoeven static u16 rspi_read16(const struct rspi_data *rspi, u16 offset)
2230b2182ddSShimoda, Yoshihiro {
2240b2182ddSShimoda, Yoshihiro 	return ioread16(rspi->addr + offset);
2250b2182ddSShimoda, Yoshihiro }
2260b2182ddSShimoda, Yoshihiro 
22774da7686SGeert Uytterhoeven static void rspi_write_data(const struct rspi_data *rspi, u16 data)
22874da7686SGeert Uytterhoeven {
22974da7686SGeert Uytterhoeven 	if (rspi->byte_access)
23074da7686SGeert Uytterhoeven 		rspi_write8(rspi, data, RSPI_SPDR);
23174da7686SGeert Uytterhoeven 	else /* 16 bit */
23274da7686SGeert Uytterhoeven 		rspi_write16(rspi, data, RSPI_SPDR);
23374da7686SGeert Uytterhoeven }
23474da7686SGeert Uytterhoeven 
23574da7686SGeert Uytterhoeven static u16 rspi_read_data(const struct rspi_data *rspi)
23674da7686SGeert Uytterhoeven {
23774da7686SGeert Uytterhoeven 	if (rspi->byte_access)
23874da7686SGeert Uytterhoeven 		return rspi_read8(rspi, RSPI_SPDR);
23974da7686SGeert Uytterhoeven 	else /* 16 bit */
24074da7686SGeert Uytterhoeven 		return rspi_read16(rspi, RSPI_SPDR);
24174da7686SGeert Uytterhoeven }
24274da7686SGeert Uytterhoeven 
2435ce0ba88SHiep Cao Minh /* optional functions */
2445ce0ba88SHiep Cao Minh struct spi_ops {
24574da7686SGeert Uytterhoeven 	int (*set_config_register)(struct rspi_data *rspi, int access_size);
246eb557f75SGeert Uytterhoeven 	int (*transfer_one)(struct spi_master *master, struct spi_device *spi,
247eb557f75SGeert Uytterhoeven 			    struct spi_transfer *xfer);
248880c6d11SGeert Uytterhoeven 	u16 mode_bits;
249b42e0359SGeert Uytterhoeven 	u16 flags;
2502f777ec9SGeert Uytterhoeven 	u16 fifo_size;
2515ce0ba88SHiep Cao Minh };
2525ce0ba88SHiep Cao Minh 
2535ce0ba88SHiep Cao Minh /*
254862d357fSGeert Uytterhoeven  * functions for RSPI on legacy SH
2555ce0ba88SHiep Cao Minh  */
25674da7686SGeert Uytterhoeven static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
2570b2182ddSShimoda, Yoshihiro {
2585ce0ba88SHiep Cao Minh 	int spbr;
2590b2182ddSShimoda, Yoshihiro 
26006a7a3cfSGeert Uytterhoeven 	/* Sets output mode, MOSI signal, and (optionally) loopback */
26106a7a3cfSGeert Uytterhoeven 	rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
2620b2182ddSShimoda, Yoshihiro 
2635ce0ba88SHiep Cao Minh 	/* Sets transfer bit rate */
2643beb61dbSGeert Uytterhoeven 	spbr = DIV_ROUND_UP(clk_get_rate(rspi->clk),
2653beb61dbSGeert Uytterhoeven 			    2 * rspi->max_speed_hz) - 1;
2665ce0ba88SHiep Cao Minh 	rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
2675ce0ba88SHiep Cao Minh 
26874da7686SGeert Uytterhoeven 	/* Disable dummy transmission, set 16-bit word access, 1 frame */
26974da7686SGeert Uytterhoeven 	rspi_write8(rspi, 0, RSPI_SPDCR);
27074da7686SGeert Uytterhoeven 	rspi->byte_access = 0;
2715ce0ba88SHiep Cao Minh 
2725ce0ba88SHiep Cao Minh 	/* Sets RSPCK, SSL, next-access delay value */
2735ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SPCKD);
2745ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SSLND);
2755ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SPND);
2765ce0ba88SHiep Cao Minh 
2775ce0ba88SHiep Cao Minh 	/* Sets parity, interrupt mask */
2785ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SPCR2);
2795ce0ba88SHiep Cao Minh 
2805ce0ba88SHiep Cao Minh 	/* Sets SPCMD */
281880c6d11SGeert Uytterhoeven 	rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
282880c6d11SGeert Uytterhoeven 	rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
2835ce0ba88SHiep Cao Minh 
2845ce0ba88SHiep Cao Minh 	/* Sets RSPI mode */
2855ce0ba88SHiep Cao Minh 	rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
2865ce0ba88SHiep Cao Minh 
2875ce0ba88SHiep Cao Minh 	return 0;
2880b2182ddSShimoda, Yoshihiro }
2890b2182ddSShimoda, Yoshihiro 
2905ce0ba88SHiep Cao Minh /*
291862d357fSGeert Uytterhoeven  * functions for RSPI on RZ
292862d357fSGeert Uytterhoeven  */
293862d357fSGeert Uytterhoeven static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size)
294862d357fSGeert Uytterhoeven {
295862d357fSGeert Uytterhoeven 	int spbr;
296862d357fSGeert Uytterhoeven 
29706a7a3cfSGeert Uytterhoeven 	/* Sets output mode, MOSI signal, and (optionally) loopback */
29806a7a3cfSGeert Uytterhoeven 	rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
299862d357fSGeert Uytterhoeven 
300862d357fSGeert Uytterhoeven 	/* Sets transfer bit rate */
3013beb61dbSGeert Uytterhoeven 	spbr = DIV_ROUND_UP(clk_get_rate(rspi->clk),
3023beb61dbSGeert Uytterhoeven 			    2 * rspi->max_speed_hz) - 1;
303862d357fSGeert Uytterhoeven 	rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
304862d357fSGeert Uytterhoeven 
305862d357fSGeert Uytterhoeven 	/* Disable dummy transmission, set byte access */
306862d357fSGeert Uytterhoeven 	rspi_write8(rspi, SPDCR_SPLBYTE, RSPI_SPDCR);
307862d357fSGeert Uytterhoeven 	rspi->byte_access = 1;
308862d357fSGeert Uytterhoeven 
309862d357fSGeert Uytterhoeven 	/* Sets RSPCK, SSL, next-access delay value */
310862d357fSGeert Uytterhoeven 	rspi_write8(rspi, 0x00, RSPI_SPCKD);
311862d357fSGeert Uytterhoeven 	rspi_write8(rspi, 0x00, RSPI_SSLND);
312862d357fSGeert Uytterhoeven 	rspi_write8(rspi, 0x00, RSPI_SPND);
313862d357fSGeert Uytterhoeven 
314862d357fSGeert Uytterhoeven 	/* Sets SPCMD */
315862d357fSGeert Uytterhoeven 	rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
316862d357fSGeert Uytterhoeven 	rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
317862d357fSGeert Uytterhoeven 
318862d357fSGeert Uytterhoeven 	/* Sets RSPI mode */
319862d357fSGeert Uytterhoeven 	rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
320862d357fSGeert Uytterhoeven 
321862d357fSGeert Uytterhoeven 	return 0;
322862d357fSGeert Uytterhoeven }
323862d357fSGeert Uytterhoeven 
324862d357fSGeert Uytterhoeven /*
3255ce0ba88SHiep Cao Minh  * functions for QSPI
3265ce0ba88SHiep Cao Minh  */
32774da7686SGeert Uytterhoeven static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
3285ce0ba88SHiep Cao Minh {
3295ce0ba88SHiep Cao Minh 	int spbr;
3305ce0ba88SHiep Cao Minh 
33106a7a3cfSGeert Uytterhoeven 	/* Sets output mode, MOSI signal, and (optionally) loopback */
33206a7a3cfSGeert Uytterhoeven 	rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
3335ce0ba88SHiep Cao Minh 
3345ce0ba88SHiep Cao Minh 	/* Sets transfer bit rate */
3353beb61dbSGeert Uytterhoeven 	spbr = DIV_ROUND_UP(clk_get_rate(rspi->clk), 2 * rspi->max_speed_hz);
3365ce0ba88SHiep Cao Minh 	rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
3375ce0ba88SHiep Cao Minh 
33874da7686SGeert Uytterhoeven 	/* Disable dummy transmission, set byte access */
33974da7686SGeert Uytterhoeven 	rspi_write8(rspi, 0, RSPI_SPDCR);
34074da7686SGeert Uytterhoeven 	rspi->byte_access = 1;
3415ce0ba88SHiep Cao Minh 
3425ce0ba88SHiep Cao Minh 	/* Sets RSPCK, SSL, next-access delay value */
3435ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SPCKD);
3445ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SSLND);
3455ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SPND);
3465ce0ba88SHiep Cao Minh 
3475ce0ba88SHiep Cao Minh 	/* Data Length Setting */
3485ce0ba88SHiep Cao Minh 	if (access_size == 8)
349880c6d11SGeert Uytterhoeven 		rspi->spcmd |= SPCMD_SPB_8BIT;
3505ce0ba88SHiep Cao Minh 	else if (access_size == 16)
351880c6d11SGeert Uytterhoeven 		rspi->spcmd |= SPCMD_SPB_16BIT;
3528e1c8096SLaurent Pinchart 	else
353880c6d11SGeert Uytterhoeven 		rspi->spcmd |= SPCMD_SPB_32BIT;
3545ce0ba88SHiep Cao Minh 
355880c6d11SGeert Uytterhoeven 	rspi->spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | SPCMD_SPNDEN;
3565ce0ba88SHiep Cao Minh 
3575ce0ba88SHiep Cao Minh 	/* Resets transfer data length */
3585ce0ba88SHiep Cao Minh 	rspi_write32(rspi, 0, QSPI_SPBMUL0);
3595ce0ba88SHiep Cao Minh 
3605ce0ba88SHiep Cao Minh 	/* Resets transmit and receive buffer */
3615ce0ba88SHiep Cao Minh 	rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR);
3625ce0ba88SHiep Cao Minh 	/* Sets buffer to allow normal operation */
3635ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, QSPI_SPBFCR);
3645ce0ba88SHiep Cao Minh 
3655ce0ba88SHiep Cao Minh 	/* Sets SPCMD */
366880c6d11SGeert Uytterhoeven 	rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
3675ce0ba88SHiep Cao Minh 
368880c6d11SGeert Uytterhoeven 	/* Enables SPI function in master mode */
3695ce0ba88SHiep Cao Minh 	rspi_write8(rspi, SPCR_SPE | SPCR_MSTR, RSPI_SPCR);
3705ce0ba88SHiep Cao Minh 
3715ce0ba88SHiep Cao Minh 	return 0;
3725ce0ba88SHiep Cao Minh }
3735ce0ba88SHiep Cao Minh 
3745ce0ba88SHiep Cao Minh #define set_config_register(spi, n) spi->ops->set_config_register(spi, n)
3755ce0ba88SHiep Cao Minh 
376baf588f4SGeert Uytterhoeven static void rspi_enable_irq(const struct rspi_data *rspi, u8 enable)
3770b2182ddSShimoda, Yoshihiro {
3780b2182ddSShimoda, Yoshihiro 	rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | enable, RSPI_SPCR);
3790b2182ddSShimoda, Yoshihiro }
3800b2182ddSShimoda, Yoshihiro 
381baf588f4SGeert Uytterhoeven static void rspi_disable_irq(const struct rspi_data *rspi, u8 disable)
3820b2182ddSShimoda, Yoshihiro {
3830b2182ddSShimoda, Yoshihiro 	rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~disable, RSPI_SPCR);
3840b2182ddSShimoda, Yoshihiro }
3850b2182ddSShimoda, Yoshihiro 
3860b2182ddSShimoda, Yoshihiro static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask,
3870b2182ddSShimoda, Yoshihiro 				   u8 enable_bit)
3880b2182ddSShimoda, Yoshihiro {
3890b2182ddSShimoda, Yoshihiro 	int ret;
3900b2182ddSShimoda, Yoshihiro 
3910b2182ddSShimoda, Yoshihiro 	rspi->spsr = rspi_read8(rspi, RSPI_SPSR);
3925dd1ad23SGeert Uytterhoeven 	if (rspi->spsr & wait_mask)
3935dd1ad23SGeert Uytterhoeven 		return 0;
3945dd1ad23SGeert Uytterhoeven 
3950b2182ddSShimoda, Yoshihiro 	rspi_enable_irq(rspi, enable_bit);
3960b2182ddSShimoda, Yoshihiro 	ret = wait_event_timeout(rspi->wait, rspi->spsr & wait_mask, HZ);
3970b2182ddSShimoda, Yoshihiro 	if (ret == 0 && !(rspi->spsr & wait_mask))
3980b2182ddSShimoda, Yoshihiro 		return -ETIMEDOUT;
3990b2182ddSShimoda, Yoshihiro 
4000b2182ddSShimoda, Yoshihiro 	return 0;
4010b2182ddSShimoda, Yoshihiro }
4020b2182ddSShimoda, Yoshihiro 
4035f684c34SGeert Uytterhoeven static inline int rspi_wait_for_tx_empty(struct rspi_data *rspi)
4045f684c34SGeert Uytterhoeven {
4055f684c34SGeert Uytterhoeven 	return rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
4065f684c34SGeert Uytterhoeven }
4075f684c34SGeert Uytterhoeven 
4085f684c34SGeert Uytterhoeven static inline int rspi_wait_for_rx_full(struct rspi_data *rspi)
4095f684c34SGeert Uytterhoeven {
4105f684c34SGeert Uytterhoeven 	return rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE);
4115f684c34SGeert Uytterhoeven }
4125f684c34SGeert Uytterhoeven 
41335301c99SGeert Uytterhoeven static int rspi_data_out(struct rspi_data *rspi, u8 data)
41435301c99SGeert Uytterhoeven {
4155f684c34SGeert Uytterhoeven 	int error = rspi_wait_for_tx_empty(rspi);
4165f684c34SGeert Uytterhoeven 	if (error < 0) {
41735301c99SGeert Uytterhoeven 		dev_err(&rspi->master->dev, "transmit timeout\n");
4185f684c34SGeert Uytterhoeven 		return error;
41935301c99SGeert Uytterhoeven 	}
42035301c99SGeert Uytterhoeven 	rspi_write_data(rspi, data);
42135301c99SGeert Uytterhoeven 	return 0;
42235301c99SGeert Uytterhoeven }
42335301c99SGeert Uytterhoeven 
42435301c99SGeert Uytterhoeven static int rspi_data_in(struct rspi_data *rspi)
42535301c99SGeert Uytterhoeven {
4265f684c34SGeert Uytterhoeven 	int error;
42735301c99SGeert Uytterhoeven 	u8 data;
42835301c99SGeert Uytterhoeven 
4295f684c34SGeert Uytterhoeven 	error = rspi_wait_for_rx_full(rspi);
4305f684c34SGeert Uytterhoeven 	if (error < 0) {
43135301c99SGeert Uytterhoeven 		dev_err(&rspi->master->dev, "receive timeout\n");
4325f684c34SGeert Uytterhoeven 		return error;
43335301c99SGeert Uytterhoeven 	}
43435301c99SGeert Uytterhoeven 	data = rspi_read_data(rspi);
43535301c99SGeert Uytterhoeven 	return data;
43635301c99SGeert Uytterhoeven }
43735301c99SGeert Uytterhoeven 
4386837b8e9SGeert Uytterhoeven static int rspi_pio_transfer(struct rspi_data *rspi, const u8 *tx, u8 *rx,
4396837b8e9SGeert Uytterhoeven 			     unsigned int n)
44035301c99SGeert Uytterhoeven {
4416837b8e9SGeert Uytterhoeven 	while (n-- > 0) {
4426837b8e9SGeert Uytterhoeven 		if (tx) {
4436837b8e9SGeert Uytterhoeven 			int ret = rspi_data_out(rspi, *tx++);
44435301c99SGeert Uytterhoeven 			if (ret < 0)
44535301c99SGeert Uytterhoeven 				return ret;
4466837b8e9SGeert Uytterhoeven 		}
4476837b8e9SGeert Uytterhoeven 		if (rx) {
4486837b8e9SGeert Uytterhoeven 			int ret = rspi_data_in(rspi);
4496837b8e9SGeert Uytterhoeven 			if (ret < 0)
4506837b8e9SGeert Uytterhoeven 				return ret;
4516837b8e9SGeert Uytterhoeven 			*rx++ = ret;
4526837b8e9SGeert Uytterhoeven 		}
4536837b8e9SGeert Uytterhoeven 	}
45435301c99SGeert Uytterhoeven 
4556837b8e9SGeert Uytterhoeven 	return 0;
45635301c99SGeert Uytterhoeven }
45735301c99SGeert Uytterhoeven 
458a3633fe7SShimoda, Yoshihiro static void rspi_dma_complete(void *arg)
4590b2182ddSShimoda, Yoshihiro {
460a3633fe7SShimoda, Yoshihiro 	struct rspi_data *rspi = arg;
461a3633fe7SShimoda, Yoshihiro 
462a3633fe7SShimoda, Yoshihiro 	rspi->dma_callbacked = 1;
463a3633fe7SShimoda, Yoshihiro 	wake_up_interruptible(&rspi->wait);
464a3633fe7SShimoda, Yoshihiro }
465a3633fe7SShimoda, Yoshihiro 
466c52fb6d6SGeert Uytterhoeven static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
467c52fb6d6SGeert Uytterhoeven 			     struct sg_table *rx)
468a3633fe7SShimoda, Yoshihiro {
469c52fb6d6SGeert Uytterhoeven 	struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL;
470c52fb6d6SGeert Uytterhoeven 	u8 irq_mask = 0;
471c52fb6d6SGeert Uytterhoeven 	unsigned int other_irq = 0;
472c52fb6d6SGeert Uytterhoeven 	dma_cookie_t cookie;
4732f777ec9SGeert Uytterhoeven 	int ret;
474a3633fe7SShimoda, Yoshihiro 
475c52fb6d6SGeert Uytterhoeven 	if (tx) {
476c52fb6d6SGeert Uytterhoeven 		desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx,
477c52fb6d6SGeert Uytterhoeven 					tx->sgl, tx->nents, DMA_TO_DEVICE,
478a3633fe7SShimoda, Yoshihiro 					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
479c52fb6d6SGeert Uytterhoeven 		if (!desc_tx)
4802f777ec9SGeert Uytterhoeven 			return -EIO;
481a3633fe7SShimoda, Yoshihiro 
482c52fb6d6SGeert Uytterhoeven 		irq_mask |= SPCR_SPTIE;
483c52fb6d6SGeert Uytterhoeven 	}
484c52fb6d6SGeert Uytterhoeven 	if (rx) {
485c52fb6d6SGeert Uytterhoeven 		desc_rx = dmaengine_prep_slave_sg(rspi->master->dma_rx,
486c52fb6d6SGeert Uytterhoeven 					rx->sgl, rx->nents, DMA_FROM_DEVICE,
487c52fb6d6SGeert Uytterhoeven 					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
488c52fb6d6SGeert Uytterhoeven 		if (!desc_rx)
489c52fb6d6SGeert Uytterhoeven 			return -EIO;
490c52fb6d6SGeert Uytterhoeven 
491c52fb6d6SGeert Uytterhoeven 		irq_mask |= SPCR_SPRIE;
492c52fb6d6SGeert Uytterhoeven 	}
493c52fb6d6SGeert Uytterhoeven 
494a3633fe7SShimoda, Yoshihiro 	/*
495c52fb6d6SGeert Uytterhoeven 	 * DMAC needs SPxIE, but if SPxIE is set, the IRQ routine will be
496a3633fe7SShimoda, Yoshihiro 	 * called. So, this driver disables the IRQ while DMA transfer.
497a3633fe7SShimoda, Yoshihiro 	 */
498c52fb6d6SGeert Uytterhoeven 	if (tx)
499c52fb6d6SGeert Uytterhoeven 		disable_irq(other_irq = rspi->tx_irq);
500c52fb6d6SGeert Uytterhoeven 	if (rx && rspi->rx_irq != other_irq)
501c52fb6d6SGeert Uytterhoeven 		disable_irq(rspi->rx_irq);
502a3633fe7SShimoda, Yoshihiro 
503c52fb6d6SGeert Uytterhoeven 	rspi_enable_irq(rspi, irq_mask);
504a3633fe7SShimoda, Yoshihiro 	rspi->dma_callbacked = 0;
505a3633fe7SShimoda, Yoshihiro 
506c52fb6d6SGeert Uytterhoeven 	if (rx) {
507c52fb6d6SGeert Uytterhoeven 		desc_rx->callback = rspi_dma_complete;
508c52fb6d6SGeert Uytterhoeven 		desc_rx->callback_param = rspi;
509c52fb6d6SGeert Uytterhoeven 		cookie = dmaengine_submit(desc_rx);
510c52fb6d6SGeert Uytterhoeven 		if (dma_submit_error(cookie))
511c52fb6d6SGeert Uytterhoeven 			return cookie;
512c52fb6d6SGeert Uytterhoeven 		dma_async_issue_pending(rspi->master->dma_rx);
513c52fb6d6SGeert Uytterhoeven 	}
514c52fb6d6SGeert Uytterhoeven 	if (tx) {
515c52fb6d6SGeert Uytterhoeven 		if (rx) {
516c52fb6d6SGeert Uytterhoeven 			/* No callback */
517c52fb6d6SGeert Uytterhoeven 			desc_tx->callback = NULL;
518c52fb6d6SGeert Uytterhoeven 		} else {
519c52fb6d6SGeert Uytterhoeven 			desc_tx->callback = rspi_dma_complete;
520c52fb6d6SGeert Uytterhoeven 			desc_tx->callback_param = rspi;
521c52fb6d6SGeert Uytterhoeven 		}
522c52fb6d6SGeert Uytterhoeven 		cookie = dmaengine_submit(desc_tx);
523c52fb6d6SGeert Uytterhoeven 		if (dma_submit_error(cookie))
524c52fb6d6SGeert Uytterhoeven 			return cookie;
5252f777ec9SGeert Uytterhoeven 		dma_async_issue_pending(rspi->master->dma_tx);
526c52fb6d6SGeert Uytterhoeven 	}
527a3633fe7SShimoda, Yoshihiro 
528a3633fe7SShimoda, Yoshihiro 	ret = wait_event_interruptible_timeout(rspi->wait,
529a3633fe7SShimoda, Yoshihiro 					       rspi->dma_callbacked, HZ);
530a3633fe7SShimoda, Yoshihiro 	if (ret > 0 && rspi->dma_callbacked)
531a3633fe7SShimoda, Yoshihiro 		ret = 0;
532a3633fe7SShimoda, Yoshihiro 	else if (!ret)
533a3633fe7SShimoda, Yoshihiro 		ret = -ETIMEDOUT;
534a3633fe7SShimoda, Yoshihiro 
535c52fb6d6SGeert Uytterhoeven 	rspi_disable_irq(rspi, irq_mask);
536c52fb6d6SGeert Uytterhoeven 
537c52fb6d6SGeert Uytterhoeven 	if (tx)
53893722206SGeert Uytterhoeven 		enable_irq(rspi->tx_irq);
539c52fb6d6SGeert Uytterhoeven 	if (rx && rspi->rx_irq != other_irq)
540c52fb6d6SGeert Uytterhoeven 		enable_irq(rspi->rx_irq);
541c52fb6d6SGeert Uytterhoeven 
542a3633fe7SShimoda, Yoshihiro 	return ret;
543a3633fe7SShimoda, Yoshihiro }
544a3633fe7SShimoda, Yoshihiro 
545baf588f4SGeert Uytterhoeven static void rspi_receive_init(const struct rspi_data *rspi)
546a3633fe7SShimoda, Yoshihiro {
54797b95c11SGeert Uytterhoeven 	u8 spsr;
5480b2182ddSShimoda, Yoshihiro 
5490b2182ddSShimoda, Yoshihiro 	spsr = rspi_read8(rspi, RSPI_SPSR);
5500b2182ddSShimoda, Yoshihiro 	if (spsr & SPSR_SPRF)
55174da7686SGeert Uytterhoeven 		rspi_read_data(rspi);	/* dummy read */
5520b2182ddSShimoda, Yoshihiro 	if (spsr & SPSR_OVRF)
5530b2182ddSShimoda, Yoshihiro 		rspi_write8(rspi, rspi_read8(rspi, RSPI_SPSR) & ~SPSR_OVRF,
554df900e67SGeert Uytterhoeven 			    RSPI_SPSR);
555a3633fe7SShimoda, Yoshihiro }
556a3633fe7SShimoda, Yoshihiro 
557862d357fSGeert Uytterhoeven static void rspi_rz_receive_init(const struct rspi_data *rspi)
558862d357fSGeert Uytterhoeven {
559862d357fSGeert Uytterhoeven 	rspi_receive_init(rspi);
560862d357fSGeert Uytterhoeven 	rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, RSPI_SPBFCR);
561862d357fSGeert Uytterhoeven 	rspi_write8(rspi, 0, RSPI_SPBFCR);
562862d357fSGeert Uytterhoeven }
563862d357fSGeert Uytterhoeven 
564baf588f4SGeert Uytterhoeven static void qspi_receive_init(const struct rspi_data *rspi)
565cb52c673SHiep Cao Minh {
56697b95c11SGeert Uytterhoeven 	u8 spsr;
567cb52c673SHiep Cao Minh 
568cb52c673SHiep Cao Minh 	spsr = rspi_read8(rspi, RSPI_SPSR);
569cb52c673SHiep Cao Minh 	if (spsr & SPSR_SPRF)
57074da7686SGeert Uytterhoeven 		rspi_read_data(rspi);   /* dummy read */
571cb52c673SHiep Cao Minh 	rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR);
572340a15e6SGeert Uytterhoeven 	rspi_write8(rspi, 0, QSPI_SPBFCR);
573cb52c673SHiep Cao Minh }
574cb52c673SHiep Cao Minh 
5752f777ec9SGeert Uytterhoeven static bool __rspi_can_dma(const struct rspi_data *rspi,
5762f777ec9SGeert Uytterhoeven 			   const struct spi_transfer *xfer)
577a3633fe7SShimoda, Yoshihiro {
5782f777ec9SGeert Uytterhoeven 	return xfer->len > rspi->ops->fifo_size;
5792f777ec9SGeert Uytterhoeven }
580a3633fe7SShimoda, Yoshihiro 
5812f777ec9SGeert Uytterhoeven static bool rspi_can_dma(struct spi_master *master, struct spi_device *spi,
5822f777ec9SGeert Uytterhoeven 			 struct spi_transfer *xfer)
5832f777ec9SGeert Uytterhoeven {
5842f777ec9SGeert Uytterhoeven 	struct rspi_data *rspi = spi_master_get_devdata(master);
5852f777ec9SGeert Uytterhoeven 
5862f777ec9SGeert Uytterhoeven 	return __rspi_can_dma(rspi, xfer);
587a3633fe7SShimoda, Yoshihiro }
588a3633fe7SShimoda, Yoshihiro 
5898b983e90SGeert Uytterhoeven static int rspi_common_transfer(struct rspi_data *rspi,
5908b983e90SGeert Uytterhoeven 				struct spi_transfer *xfer)
5918b983e90SGeert Uytterhoeven {
5928b983e90SGeert Uytterhoeven 	int ret;
5938b983e90SGeert Uytterhoeven 
5948b983e90SGeert Uytterhoeven 	if (rspi->master->can_dma && __rspi_can_dma(rspi, xfer)) {
5958b983e90SGeert Uytterhoeven 		/* rx_buf can be NULL on RSPI on SH in TX-only Mode */
5968b983e90SGeert Uytterhoeven 		return rspi_dma_transfer(rspi, &xfer->tx_sg,
5978b983e90SGeert Uytterhoeven 					 xfer->rx_buf ? &xfer->rx_sg : NULL);
5988b983e90SGeert Uytterhoeven 	}
5998b983e90SGeert Uytterhoeven 
6008b983e90SGeert Uytterhoeven 	ret = rspi_pio_transfer(rspi, xfer->tx_buf, xfer->rx_buf, xfer->len);
6018b983e90SGeert Uytterhoeven 	if (ret < 0)
6028b983e90SGeert Uytterhoeven 		return ret;
6038b983e90SGeert Uytterhoeven 
6048b983e90SGeert Uytterhoeven 	/* Wait for the last transmission */
6058b983e90SGeert Uytterhoeven 	rspi_wait_for_tx_empty(rspi);
6068b983e90SGeert Uytterhoeven 
6078b983e90SGeert Uytterhoeven 	return 0;
6088b983e90SGeert Uytterhoeven }
6098b983e90SGeert Uytterhoeven 
6108393fa78SGeert Uytterhoeven static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi,
6118449fd76SGeert Uytterhoeven 			     struct spi_transfer *xfer)
6128449fd76SGeert Uytterhoeven {
6138393fa78SGeert Uytterhoeven 	struct rspi_data *rspi = spi_master_get_devdata(master);
614b42e0359SGeert Uytterhoeven 	u8 spcr;
6158449fd76SGeert Uytterhoeven 
6168449fd76SGeert Uytterhoeven 	spcr = rspi_read8(rspi, RSPI_SPCR);
6176837b8e9SGeert Uytterhoeven 	if (xfer->rx_buf) {
61832c64261SGeert Uytterhoeven 		rspi_receive_init(rspi);
6198449fd76SGeert Uytterhoeven 		spcr &= ~SPCR_TXMD;
62032c64261SGeert Uytterhoeven 	} else {
6218449fd76SGeert Uytterhoeven 		spcr |= SPCR_TXMD;
62232c64261SGeert Uytterhoeven 	}
6238449fd76SGeert Uytterhoeven 	rspi_write8(rspi, spcr, RSPI_SPCR);
6248449fd76SGeert Uytterhoeven 
6258b983e90SGeert Uytterhoeven 	return rspi_common_transfer(rspi, xfer);
6268449fd76SGeert Uytterhoeven }
6278449fd76SGeert Uytterhoeven 
62803e627c5SGeert Uytterhoeven static int rspi_rz_transfer_one(struct spi_master *master,
62903e627c5SGeert Uytterhoeven 				struct spi_device *spi,
630862d357fSGeert Uytterhoeven 				struct spi_transfer *xfer)
631862d357fSGeert Uytterhoeven {
63203e627c5SGeert Uytterhoeven 	struct rspi_data *rspi = spi_master_get_devdata(master);
633862d357fSGeert Uytterhoeven 
634862d357fSGeert Uytterhoeven 	rspi_rz_receive_init(rspi);
635862d357fSGeert Uytterhoeven 
6368b983e90SGeert Uytterhoeven 	return rspi_common_transfer(rspi, xfer);
637862d357fSGeert Uytterhoeven }
638862d357fSGeert Uytterhoeven 
639340a15e6SGeert Uytterhoeven static int qspi_transfer_out_in(struct rspi_data *rspi,
640340a15e6SGeert Uytterhoeven 				struct spi_transfer *xfer)
641340a15e6SGeert Uytterhoeven {
642340a15e6SGeert Uytterhoeven 	qspi_receive_init(rspi);
643340a15e6SGeert Uytterhoeven 
6448b983e90SGeert Uytterhoeven 	return rspi_common_transfer(rspi, xfer);
645340a15e6SGeert Uytterhoeven }
646340a15e6SGeert Uytterhoeven 
647880c6d11SGeert Uytterhoeven static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer)
648880c6d11SGeert Uytterhoeven {
649880c6d11SGeert Uytterhoeven 	int ret;
650880c6d11SGeert Uytterhoeven 
6514f12b5e5SGeert Uytterhoeven 	if (rspi->master->can_dma && __rspi_can_dma(rspi, xfer))
6524f12b5e5SGeert Uytterhoeven 		return rspi_dma_transfer(rspi, &xfer->tx_sg, NULL);
6534f12b5e5SGeert Uytterhoeven 
6546837b8e9SGeert Uytterhoeven 	ret = rspi_pio_transfer(rspi, xfer->tx_buf, NULL, xfer->len);
655880c6d11SGeert Uytterhoeven 	if (ret < 0)
656880c6d11SGeert Uytterhoeven 		return ret;
657880c6d11SGeert Uytterhoeven 
658880c6d11SGeert Uytterhoeven 	/* Wait for the last transmission */
6595f684c34SGeert Uytterhoeven 	rspi_wait_for_tx_empty(rspi);
660880c6d11SGeert Uytterhoeven 
661880c6d11SGeert Uytterhoeven 	return 0;
662880c6d11SGeert Uytterhoeven }
663880c6d11SGeert Uytterhoeven 
664880c6d11SGeert Uytterhoeven static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer)
665880c6d11SGeert Uytterhoeven {
6664f12b5e5SGeert Uytterhoeven 	if (rspi->master->can_dma && __rspi_can_dma(rspi, xfer))
6674f12b5e5SGeert Uytterhoeven 		return rspi_dma_transfer(rspi, NULL, &xfer->rx_sg);
6684f12b5e5SGeert Uytterhoeven 
6696837b8e9SGeert Uytterhoeven 	return rspi_pio_transfer(rspi, NULL, xfer->rx_buf, xfer->len);
670880c6d11SGeert Uytterhoeven }
671880c6d11SGeert Uytterhoeven 
672eb557f75SGeert Uytterhoeven static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi,
673eb557f75SGeert Uytterhoeven 			     struct spi_transfer *xfer)
674eb557f75SGeert Uytterhoeven {
675eb557f75SGeert Uytterhoeven 	struct rspi_data *rspi = spi_master_get_devdata(master);
676eb557f75SGeert Uytterhoeven 
677ba824d49SGeert Uytterhoeven 	if (spi->mode & SPI_LOOP) {
678ba824d49SGeert Uytterhoeven 		return qspi_transfer_out_in(rspi, xfer);
679b42e0359SGeert Uytterhoeven 	} else if (xfer->tx_nbits > SPI_NBITS_SINGLE) {
680880c6d11SGeert Uytterhoeven 		/* Quad or Dual SPI Write */
681880c6d11SGeert Uytterhoeven 		return qspi_transfer_out(rspi, xfer);
682b42e0359SGeert Uytterhoeven 	} else if (xfer->rx_nbits > SPI_NBITS_SINGLE) {
683880c6d11SGeert Uytterhoeven 		/* Quad or Dual SPI Read */
684880c6d11SGeert Uytterhoeven 		return qspi_transfer_in(rspi, xfer);
685880c6d11SGeert Uytterhoeven 	} else {
686880c6d11SGeert Uytterhoeven 		/* Single SPI Transfer */
687340a15e6SGeert Uytterhoeven 		return qspi_transfer_out_in(rspi, xfer);
688eb557f75SGeert Uytterhoeven 	}
689880c6d11SGeert Uytterhoeven }
690eb557f75SGeert Uytterhoeven 
6910b2182ddSShimoda, Yoshihiro static int rspi_setup(struct spi_device *spi)
6920b2182ddSShimoda, Yoshihiro {
6930b2182ddSShimoda, Yoshihiro 	struct rspi_data *rspi = spi_master_get_devdata(spi->master);
6940b2182ddSShimoda, Yoshihiro 
6950b2182ddSShimoda, Yoshihiro 	rspi->max_speed_hz = spi->max_speed_hz;
6960b2182ddSShimoda, Yoshihiro 
697348e5153SGeert Uytterhoeven 	rspi->spcmd = SPCMD_SSLKP;
698348e5153SGeert Uytterhoeven 	if (spi->mode & SPI_CPOL)
699348e5153SGeert Uytterhoeven 		rspi->spcmd |= SPCMD_CPOL;
700348e5153SGeert Uytterhoeven 	if (spi->mode & SPI_CPHA)
701348e5153SGeert Uytterhoeven 		rspi->spcmd |= SPCMD_CPHA;
702348e5153SGeert Uytterhoeven 
70306a7a3cfSGeert Uytterhoeven 	/* CMOS output mode and MOSI signal from previous transfer */
70406a7a3cfSGeert Uytterhoeven 	rspi->sppcr = 0;
70506a7a3cfSGeert Uytterhoeven 	if (spi->mode & SPI_LOOP)
70606a7a3cfSGeert Uytterhoeven 		rspi->sppcr |= SPPCR_SPLP;
70706a7a3cfSGeert Uytterhoeven 
7085ce0ba88SHiep Cao Minh 	set_config_register(rspi, 8);
7090b2182ddSShimoda, Yoshihiro 
7100b2182ddSShimoda, Yoshihiro 	return 0;
7110b2182ddSShimoda, Yoshihiro }
7120b2182ddSShimoda, Yoshihiro 
713880c6d11SGeert Uytterhoeven static u16 qspi_transfer_mode(const struct spi_transfer *xfer)
714880c6d11SGeert Uytterhoeven {
715880c6d11SGeert Uytterhoeven 	if (xfer->tx_buf)
716880c6d11SGeert Uytterhoeven 		switch (xfer->tx_nbits) {
717880c6d11SGeert Uytterhoeven 		case SPI_NBITS_QUAD:
718880c6d11SGeert Uytterhoeven 			return SPCMD_SPIMOD_QUAD;
719880c6d11SGeert Uytterhoeven 		case SPI_NBITS_DUAL:
720880c6d11SGeert Uytterhoeven 			return SPCMD_SPIMOD_DUAL;
721880c6d11SGeert Uytterhoeven 		default:
722880c6d11SGeert Uytterhoeven 			return 0;
723880c6d11SGeert Uytterhoeven 		}
724880c6d11SGeert Uytterhoeven 	if (xfer->rx_buf)
725880c6d11SGeert Uytterhoeven 		switch (xfer->rx_nbits) {
726880c6d11SGeert Uytterhoeven 		case SPI_NBITS_QUAD:
727880c6d11SGeert Uytterhoeven 			return SPCMD_SPIMOD_QUAD | SPCMD_SPRW;
728880c6d11SGeert Uytterhoeven 		case SPI_NBITS_DUAL:
729880c6d11SGeert Uytterhoeven 			return SPCMD_SPIMOD_DUAL | SPCMD_SPRW;
730880c6d11SGeert Uytterhoeven 		default:
731880c6d11SGeert Uytterhoeven 			return 0;
732880c6d11SGeert Uytterhoeven 		}
733880c6d11SGeert Uytterhoeven 
734880c6d11SGeert Uytterhoeven 	return 0;
735880c6d11SGeert Uytterhoeven }
736880c6d11SGeert Uytterhoeven 
737880c6d11SGeert Uytterhoeven static int qspi_setup_sequencer(struct rspi_data *rspi,
738880c6d11SGeert Uytterhoeven 				const struct spi_message *msg)
739880c6d11SGeert Uytterhoeven {
740880c6d11SGeert Uytterhoeven 	const struct spi_transfer *xfer;
741880c6d11SGeert Uytterhoeven 	unsigned int i = 0, len = 0;
742880c6d11SGeert Uytterhoeven 	u16 current_mode = 0xffff, mode;
743880c6d11SGeert Uytterhoeven 
744880c6d11SGeert Uytterhoeven 	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
745880c6d11SGeert Uytterhoeven 		mode = qspi_transfer_mode(xfer);
746880c6d11SGeert Uytterhoeven 		if (mode == current_mode) {
747880c6d11SGeert Uytterhoeven 			len += xfer->len;
748880c6d11SGeert Uytterhoeven 			continue;
749880c6d11SGeert Uytterhoeven 		}
750880c6d11SGeert Uytterhoeven 
751880c6d11SGeert Uytterhoeven 		/* Transfer mode change */
752880c6d11SGeert Uytterhoeven 		if (i) {
753880c6d11SGeert Uytterhoeven 			/* Set transfer data length of previous transfer */
754880c6d11SGeert Uytterhoeven 			rspi_write32(rspi, len, QSPI_SPBMUL(i - 1));
755880c6d11SGeert Uytterhoeven 		}
756880c6d11SGeert Uytterhoeven 
757880c6d11SGeert Uytterhoeven 		if (i >= QSPI_NUM_SPCMD) {
758880c6d11SGeert Uytterhoeven 			dev_err(&msg->spi->dev,
759880c6d11SGeert Uytterhoeven 				"Too many different transfer modes");
760880c6d11SGeert Uytterhoeven 			return -EINVAL;
761880c6d11SGeert Uytterhoeven 		}
762880c6d11SGeert Uytterhoeven 
763880c6d11SGeert Uytterhoeven 		/* Program transfer mode for this transfer */
764880c6d11SGeert Uytterhoeven 		rspi_write16(rspi, rspi->spcmd | mode, RSPI_SPCMD(i));
765880c6d11SGeert Uytterhoeven 		current_mode = mode;
766880c6d11SGeert Uytterhoeven 		len = xfer->len;
767880c6d11SGeert Uytterhoeven 		i++;
768880c6d11SGeert Uytterhoeven 	}
769880c6d11SGeert Uytterhoeven 	if (i) {
770880c6d11SGeert Uytterhoeven 		/* Set final transfer data length and sequence length */
771880c6d11SGeert Uytterhoeven 		rspi_write32(rspi, len, QSPI_SPBMUL(i - 1));
772880c6d11SGeert Uytterhoeven 		rspi_write8(rspi, i - 1, RSPI_SPSCR);
773880c6d11SGeert Uytterhoeven 	}
774880c6d11SGeert Uytterhoeven 
775880c6d11SGeert Uytterhoeven 	return 0;
776880c6d11SGeert Uytterhoeven }
777880c6d11SGeert Uytterhoeven 
77879d23495SGeert Uytterhoeven static int rspi_prepare_message(struct spi_master *master,
779880c6d11SGeert Uytterhoeven 				struct spi_message *msg)
78079d23495SGeert Uytterhoeven {
78179d23495SGeert Uytterhoeven 	struct rspi_data *rspi = spi_master_get_devdata(master);
782880c6d11SGeert Uytterhoeven 	int ret;
7830b2182ddSShimoda, Yoshihiro 
784880c6d11SGeert Uytterhoeven 	if (msg->spi->mode &
785880c6d11SGeert Uytterhoeven 	    (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)) {
786880c6d11SGeert Uytterhoeven 		/* Setup sequencer for messages with multiple transfer modes */
787880c6d11SGeert Uytterhoeven 		ret = qspi_setup_sequencer(rspi, msg);
788880c6d11SGeert Uytterhoeven 		if (ret < 0)
789880c6d11SGeert Uytterhoeven 			return ret;
790880c6d11SGeert Uytterhoeven 	}
791880c6d11SGeert Uytterhoeven 
792880c6d11SGeert Uytterhoeven 	/* Enable SPI function in master mode */
79379d23495SGeert Uytterhoeven 	rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR);
7940b2182ddSShimoda, Yoshihiro 	return 0;
7950b2182ddSShimoda, Yoshihiro }
7960b2182ddSShimoda, Yoshihiro 
79779d23495SGeert Uytterhoeven static int rspi_unprepare_message(struct spi_master *master,
798880c6d11SGeert Uytterhoeven 				  struct spi_message *msg)
7990b2182ddSShimoda, Yoshihiro {
80079d23495SGeert Uytterhoeven 	struct rspi_data *rspi = spi_master_get_devdata(master);
80179d23495SGeert Uytterhoeven 
802880c6d11SGeert Uytterhoeven 	/* Disable SPI function */
80379d23495SGeert Uytterhoeven 	rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
804880c6d11SGeert Uytterhoeven 
805880c6d11SGeert Uytterhoeven 	/* Reset sequencer for Single SPI Transfers */
806880c6d11SGeert Uytterhoeven 	rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
807880c6d11SGeert Uytterhoeven 	rspi_write8(rspi, 0, RSPI_SPSCR);
80879d23495SGeert Uytterhoeven 	return 0;
8090b2182ddSShimoda, Yoshihiro }
8100b2182ddSShimoda, Yoshihiro 
81193722206SGeert Uytterhoeven static irqreturn_t rspi_irq_mux(int irq, void *_sr)
8120b2182ddSShimoda, Yoshihiro {
813c132f094SGeert Uytterhoeven 	struct rspi_data *rspi = _sr;
81497b95c11SGeert Uytterhoeven 	u8 spsr;
8150b2182ddSShimoda, Yoshihiro 	irqreturn_t ret = IRQ_NONE;
81697b95c11SGeert Uytterhoeven 	u8 disable_irq = 0;
8170b2182ddSShimoda, Yoshihiro 
8180b2182ddSShimoda, Yoshihiro 	rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR);
8190b2182ddSShimoda, Yoshihiro 	if (spsr & SPSR_SPRF)
8200b2182ddSShimoda, Yoshihiro 		disable_irq |= SPCR_SPRIE;
8210b2182ddSShimoda, Yoshihiro 	if (spsr & SPSR_SPTEF)
8220b2182ddSShimoda, Yoshihiro 		disable_irq |= SPCR_SPTIE;
8230b2182ddSShimoda, Yoshihiro 
8240b2182ddSShimoda, Yoshihiro 	if (disable_irq) {
8250b2182ddSShimoda, Yoshihiro 		ret = IRQ_HANDLED;
8260b2182ddSShimoda, Yoshihiro 		rspi_disable_irq(rspi, disable_irq);
8270b2182ddSShimoda, Yoshihiro 		wake_up(&rspi->wait);
8280b2182ddSShimoda, Yoshihiro 	}
8290b2182ddSShimoda, Yoshihiro 
8300b2182ddSShimoda, Yoshihiro 	return ret;
8310b2182ddSShimoda, Yoshihiro }
8320b2182ddSShimoda, Yoshihiro 
83393722206SGeert Uytterhoeven static irqreturn_t rspi_irq_rx(int irq, void *_sr)
83493722206SGeert Uytterhoeven {
83593722206SGeert Uytterhoeven 	struct rspi_data *rspi = _sr;
83693722206SGeert Uytterhoeven 	u8 spsr;
83793722206SGeert Uytterhoeven 
83893722206SGeert Uytterhoeven 	rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR);
83993722206SGeert Uytterhoeven 	if (spsr & SPSR_SPRF) {
84093722206SGeert Uytterhoeven 		rspi_disable_irq(rspi, SPCR_SPRIE);
84193722206SGeert Uytterhoeven 		wake_up(&rspi->wait);
84293722206SGeert Uytterhoeven 		return IRQ_HANDLED;
84393722206SGeert Uytterhoeven 	}
84493722206SGeert Uytterhoeven 
84593722206SGeert Uytterhoeven 	return 0;
84693722206SGeert Uytterhoeven }
84793722206SGeert Uytterhoeven 
84893722206SGeert Uytterhoeven static irqreturn_t rspi_irq_tx(int irq, void *_sr)
84993722206SGeert Uytterhoeven {
85093722206SGeert Uytterhoeven 	struct rspi_data *rspi = _sr;
85193722206SGeert Uytterhoeven 	u8 spsr;
85293722206SGeert Uytterhoeven 
85393722206SGeert Uytterhoeven 	rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR);
85493722206SGeert Uytterhoeven 	if (spsr & SPSR_SPTEF) {
85593722206SGeert Uytterhoeven 		rspi_disable_irq(rspi, SPCR_SPTIE);
85693722206SGeert Uytterhoeven 		wake_up(&rspi->wait);
85793722206SGeert Uytterhoeven 		return IRQ_HANDLED;
85893722206SGeert Uytterhoeven 	}
85993722206SGeert Uytterhoeven 
86093722206SGeert Uytterhoeven 	return 0;
86193722206SGeert Uytterhoeven }
86293722206SGeert Uytterhoeven 
86365bf2205SGeert Uytterhoeven static struct dma_chan *rspi_request_dma_chan(struct device *dev,
86465bf2205SGeert Uytterhoeven 					      enum dma_transfer_direction dir,
86565bf2205SGeert Uytterhoeven 					      unsigned int id,
86665bf2205SGeert Uytterhoeven 					      dma_addr_t port_addr)
86765bf2205SGeert Uytterhoeven {
86865bf2205SGeert Uytterhoeven 	dma_cap_mask_t mask;
86965bf2205SGeert Uytterhoeven 	struct dma_chan *chan;
87065bf2205SGeert Uytterhoeven 	struct dma_slave_config cfg;
87165bf2205SGeert Uytterhoeven 	int ret;
87265bf2205SGeert Uytterhoeven 
87365bf2205SGeert Uytterhoeven 	dma_cap_zero(mask);
87465bf2205SGeert Uytterhoeven 	dma_cap_set(DMA_SLAVE, mask);
87565bf2205SGeert Uytterhoeven 
87665bf2205SGeert Uytterhoeven 	chan = dma_request_channel(mask, shdma_chan_filter,
87765bf2205SGeert Uytterhoeven 				   (void *)(unsigned long)id);
87865bf2205SGeert Uytterhoeven 	if (!chan) {
87965bf2205SGeert Uytterhoeven 		dev_warn(dev, "dma_request_channel failed\n");
88065bf2205SGeert Uytterhoeven 		return NULL;
88165bf2205SGeert Uytterhoeven 	}
88265bf2205SGeert Uytterhoeven 
88365bf2205SGeert Uytterhoeven 	memset(&cfg, 0, sizeof(cfg));
88465bf2205SGeert Uytterhoeven 	cfg.slave_id = id;
88565bf2205SGeert Uytterhoeven 	cfg.direction = dir;
88665bf2205SGeert Uytterhoeven 	if (dir == DMA_MEM_TO_DEV)
88765bf2205SGeert Uytterhoeven 		cfg.dst_addr = port_addr;
88865bf2205SGeert Uytterhoeven 	else
88965bf2205SGeert Uytterhoeven 		cfg.src_addr = port_addr;
89065bf2205SGeert Uytterhoeven 
89165bf2205SGeert Uytterhoeven 	ret = dmaengine_slave_config(chan, &cfg);
89265bf2205SGeert Uytterhoeven 	if (ret) {
89365bf2205SGeert Uytterhoeven 		dev_warn(dev, "dmaengine_slave_config failed %d\n", ret);
89465bf2205SGeert Uytterhoeven 		dma_release_channel(chan);
89565bf2205SGeert Uytterhoeven 		return NULL;
89665bf2205SGeert Uytterhoeven 	}
89765bf2205SGeert Uytterhoeven 
89865bf2205SGeert Uytterhoeven 	return chan;
89965bf2205SGeert Uytterhoeven }
90065bf2205SGeert Uytterhoeven 
9012f777ec9SGeert Uytterhoeven static int rspi_request_dma(struct device *dev, struct spi_master *master,
902fcdc49aeSGeert Uytterhoeven 			    const struct resource *res)
903a3633fe7SShimoda, Yoshihiro {
904fcdc49aeSGeert Uytterhoeven 	const struct rspi_plat_data *rspi_pd = dev_get_platdata(dev);
905a3633fe7SShimoda, Yoshihiro 
9065f338d0cSGeert Uytterhoeven 	if (!rspi_pd || !rspi_pd->dma_rx_id || !rspi_pd->dma_tx_id)
9070243c536SShimoda, Yoshihiro 		return 0;	/* The driver assumes no error. */
908a3633fe7SShimoda, Yoshihiro 
9092f777ec9SGeert Uytterhoeven 	master->dma_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM,
91065bf2205SGeert Uytterhoeven 					       rspi_pd->dma_rx_id,
91165bf2205SGeert Uytterhoeven 					       res->start + RSPI_SPDR);
9122f777ec9SGeert Uytterhoeven 	if (!master->dma_rx)
91365bf2205SGeert Uytterhoeven 		return -ENODEV;
91465bf2205SGeert Uytterhoeven 
9152f777ec9SGeert Uytterhoeven 	master->dma_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV,
91665bf2205SGeert Uytterhoeven 					       rspi_pd->dma_tx_id,
91765bf2205SGeert Uytterhoeven 					       res->start + RSPI_SPDR);
9182f777ec9SGeert Uytterhoeven 	if (!master->dma_tx) {
9192f777ec9SGeert Uytterhoeven 		dma_release_channel(master->dma_rx);
9202f777ec9SGeert Uytterhoeven 		master->dma_rx = NULL;
92165bf2205SGeert Uytterhoeven 		return -ENODEV;
922a3633fe7SShimoda, Yoshihiro 	}
923a3633fe7SShimoda, Yoshihiro 
9242f777ec9SGeert Uytterhoeven 	master->can_dma = rspi_can_dma;
9255f338d0cSGeert Uytterhoeven 	dev_info(dev, "DMA available");
9260243c536SShimoda, Yoshihiro 	return 0;
9270243c536SShimoda, Yoshihiro }
9280243c536SShimoda, Yoshihiro 
929afcc98deSGeert Uytterhoeven static void rspi_release_dma(struct spi_master *master)
930a3633fe7SShimoda, Yoshihiro {
931afcc98deSGeert Uytterhoeven 	if (master->dma_tx)
932afcc98deSGeert Uytterhoeven 		dma_release_channel(master->dma_tx);
933afcc98deSGeert Uytterhoeven 	if (master->dma_rx)
934afcc98deSGeert Uytterhoeven 		dma_release_channel(master->dma_rx);
935a3633fe7SShimoda, Yoshihiro }
936a3633fe7SShimoda, Yoshihiro 
937fd4a319bSGrant Likely static int rspi_remove(struct platform_device *pdev)
9380b2182ddSShimoda, Yoshihiro {
9395ffbe2d9SLaurent Pinchart 	struct rspi_data *rspi = platform_get_drvdata(pdev);
9400b2182ddSShimoda, Yoshihiro 
941afcc98deSGeert Uytterhoeven 	rspi_release_dma(rspi->master);
942490c9774SGeert Uytterhoeven 	pm_runtime_disable(&pdev->dev);
9430b2182ddSShimoda, Yoshihiro 
9440b2182ddSShimoda, Yoshihiro 	return 0;
9450b2182ddSShimoda, Yoshihiro }
9460b2182ddSShimoda, Yoshihiro 
947426ef76dSGeert Uytterhoeven static const struct spi_ops rspi_ops = {
948426ef76dSGeert Uytterhoeven 	.set_config_register =	rspi_set_config_register,
949426ef76dSGeert Uytterhoeven 	.transfer_one =		rspi_transfer_one,
950880c6d11SGeert Uytterhoeven 	.mode_bits =		SPI_CPHA | SPI_CPOL | SPI_LOOP,
951b42e0359SGeert Uytterhoeven 	.flags =		SPI_MASTER_MUST_TX,
9522f777ec9SGeert Uytterhoeven 	.fifo_size =		8,
953426ef76dSGeert Uytterhoeven };
954426ef76dSGeert Uytterhoeven 
955426ef76dSGeert Uytterhoeven static const struct spi_ops rspi_rz_ops = {
956426ef76dSGeert Uytterhoeven 	.set_config_register =	rspi_rz_set_config_register,
957426ef76dSGeert Uytterhoeven 	.transfer_one =		rspi_rz_transfer_one,
958880c6d11SGeert Uytterhoeven 	.mode_bits =		SPI_CPHA | SPI_CPOL | SPI_LOOP,
959b42e0359SGeert Uytterhoeven 	.flags =		SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX,
9602f777ec9SGeert Uytterhoeven 	.fifo_size =		8,	/* 8 for TX, 32 for RX */
961426ef76dSGeert Uytterhoeven };
962426ef76dSGeert Uytterhoeven 
963426ef76dSGeert Uytterhoeven static const struct spi_ops qspi_ops = {
964426ef76dSGeert Uytterhoeven 	.set_config_register =	qspi_set_config_register,
965426ef76dSGeert Uytterhoeven 	.transfer_one =		qspi_transfer_one,
966880c6d11SGeert Uytterhoeven 	.mode_bits =		SPI_CPHA | SPI_CPOL | SPI_LOOP |
967880c6d11SGeert Uytterhoeven 				SPI_TX_DUAL | SPI_TX_QUAD |
968880c6d11SGeert Uytterhoeven 				SPI_RX_DUAL | SPI_RX_QUAD,
969b42e0359SGeert Uytterhoeven 	.flags =		SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX,
9702f777ec9SGeert Uytterhoeven 	.fifo_size =		32,
971426ef76dSGeert Uytterhoeven };
972426ef76dSGeert Uytterhoeven 
973426ef76dSGeert Uytterhoeven #ifdef CONFIG_OF
974426ef76dSGeert Uytterhoeven static const struct of_device_id rspi_of_match[] = {
975426ef76dSGeert Uytterhoeven 	/* RSPI on legacy SH */
976426ef76dSGeert Uytterhoeven 	{ .compatible = "renesas,rspi", .data = &rspi_ops },
977426ef76dSGeert Uytterhoeven 	/* RSPI on RZ/A1H */
978426ef76dSGeert Uytterhoeven 	{ .compatible = "renesas,rspi-rz", .data = &rspi_rz_ops },
979426ef76dSGeert Uytterhoeven 	/* QSPI on R-Car Gen2 */
980426ef76dSGeert Uytterhoeven 	{ .compatible = "renesas,qspi", .data = &qspi_ops },
981426ef76dSGeert Uytterhoeven 	{ /* sentinel */ }
982426ef76dSGeert Uytterhoeven };
983426ef76dSGeert Uytterhoeven 
984426ef76dSGeert Uytterhoeven MODULE_DEVICE_TABLE(of, rspi_of_match);
985426ef76dSGeert Uytterhoeven 
986426ef76dSGeert Uytterhoeven static int rspi_parse_dt(struct device *dev, struct spi_master *master)
987426ef76dSGeert Uytterhoeven {
988426ef76dSGeert Uytterhoeven 	u32 num_cs;
989426ef76dSGeert Uytterhoeven 	int error;
990426ef76dSGeert Uytterhoeven 
991426ef76dSGeert Uytterhoeven 	/* Parse DT properties */
992426ef76dSGeert Uytterhoeven 	error = of_property_read_u32(dev->of_node, "num-cs", &num_cs);
993426ef76dSGeert Uytterhoeven 	if (error) {
994426ef76dSGeert Uytterhoeven 		dev_err(dev, "of_property_read_u32 num-cs failed %d\n", error);
995426ef76dSGeert Uytterhoeven 		return error;
996426ef76dSGeert Uytterhoeven 	}
997426ef76dSGeert Uytterhoeven 
998426ef76dSGeert Uytterhoeven 	master->num_chipselect = num_cs;
999426ef76dSGeert Uytterhoeven 	return 0;
1000426ef76dSGeert Uytterhoeven }
1001426ef76dSGeert Uytterhoeven #else
100264b67defSShimoda, Yoshihiro #define rspi_of_match	NULL
1003426ef76dSGeert Uytterhoeven static inline int rspi_parse_dt(struct device *dev, struct spi_master *master)
1004426ef76dSGeert Uytterhoeven {
1005426ef76dSGeert Uytterhoeven 	return -EINVAL;
1006426ef76dSGeert Uytterhoeven }
1007426ef76dSGeert Uytterhoeven #endif /* CONFIG_OF */
1008426ef76dSGeert Uytterhoeven 
100993722206SGeert Uytterhoeven static int rspi_request_irq(struct device *dev, unsigned int irq,
101093722206SGeert Uytterhoeven 			    irq_handler_t handler, const char *suffix,
101193722206SGeert Uytterhoeven 			    void *dev_id)
101293722206SGeert Uytterhoeven {
101393722206SGeert Uytterhoeven 	const char *base = dev_name(dev);
101493722206SGeert Uytterhoeven 	size_t len = strlen(base) + strlen(suffix) + 2;
101593722206SGeert Uytterhoeven 	char *name = devm_kzalloc(dev, len, GFP_KERNEL);
101693722206SGeert Uytterhoeven 	if (!name)
101793722206SGeert Uytterhoeven 		return -ENOMEM;
101893722206SGeert Uytterhoeven 	snprintf(name, len, "%s:%s", base, suffix);
101993722206SGeert Uytterhoeven 	return devm_request_irq(dev, irq, handler, 0, name, dev_id);
102093722206SGeert Uytterhoeven }
102193722206SGeert Uytterhoeven 
1022fd4a319bSGrant Likely static int rspi_probe(struct platform_device *pdev)
10230b2182ddSShimoda, Yoshihiro {
10240b2182ddSShimoda, Yoshihiro 	struct resource *res;
10250b2182ddSShimoda, Yoshihiro 	struct spi_master *master;
10260b2182ddSShimoda, Yoshihiro 	struct rspi_data *rspi;
102793722206SGeert Uytterhoeven 	int ret;
1028426ef76dSGeert Uytterhoeven 	const struct of_device_id *of_id;
1029426ef76dSGeert Uytterhoeven 	const struct rspi_plat_data *rspi_pd;
10305ce0ba88SHiep Cao Minh 	const struct spi_ops *ops;
10310b2182ddSShimoda, Yoshihiro 
10320b2182ddSShimoda, Yoshihiro 	master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data));
10330b2182ddSShimoda, Yoshihiro 	if (master == NULL) {
10340b2182ddSShimoda, Yoshihiro 		dev_err(&pdev->dev, "spi_alloc_master error.\n");
10350b2182ddSShimoda, Yoshihiro 		return -ENOMEM;
10360b2182ddSShimoda, Yoshihiro 	}
10370b2182ddSShimoda, Yoshihiro 
1038426ef76dSGeert Uytterhoeven 	of_id = of_match_device(rspi_of_match, &pdev->dev);
1039426ef76dSGeert Uytterhoeven 	if (of_id) {
1040426ef76dSGeert Uytterhoeven 		ops = of_id->data;
1041426ef76dSGeert Uytterhoeven 		ret = rspi_parse_dt(&pdev->dev, master);
1042426ef76dSGeert Uytterhoeven 		if (ret)
1043426ef76dSGeert Uytterhoeven 			goto error1;
1044426ef76dSGeert Uytterhoeven 	} else {
1045426ef76dSGeert Uytterhoeven 		ops = (struct spi_ops *)pdev->id_entry->driver_data;
1046426ef76dSGeert Uytterhoeven 		rspi_pd = dev_get_platdata(&pdev->dev);
1047426ef76dSGeert Uytterhoeven 		if (rspi_pd && rspi_pd->num_chipselect)
1048426ef76dSGeert Uytterhoeven 			master->num_chipselect = rspi_pd->num_chipselect;
1049426ef76dSGeert Uytterhoeven 		else
1050426ef76dSGeert Uytterhoeven 			master->num_chipselect = 2; /* default */
1051426ef76dSGeert Uytterhoeven 	};
1052426ef76dSGeert Uytterhoeven 
1053426ef76dSGeert Uytterhoeven 	/* ops parameter check */
1054426ef76dSGeert Uytterhoeven 	if (!ops->set_config_register) {
1055426ef76dSGeert Uytterhoeven 		dev_err(&pdev->dev, "there is no set_config_register\n");
1056426ef76dSGeert Uytterhoeven 		ret = -ENODEV;
1057426ef76dSGeert Uytterhoeven 		goto error1;
1058426ef76dSGeert Uytterhoeven 	}
1059426ef76dSGeert Uytterhoeven 
10600b2182ddSShimoda, Yoshihiro 	rspi = spi_master_get_devdata(master);
106124b5a82cSJingoo Han 	platform_set_drvdata(pdev, rspi);
10625ce0ba88SHiep Cao Minh 	rspi->ops = ops;
10630b2182ddSShimoda, Yoshihiro 	rspi->master = master;
10645d79e9acSLaurent Pinchart 
10655d79e9acSLaurent Pinchart 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
10665d79e9acSLaurent Pinchart 	rspi->addr = devm_ioremap_resource(&pdev->dev, res);
10675d79e9acSLaurent Pinchart 	if (IS_ERR(rspi->addr)) {
10685d79e9acSLaurent Pinchart 		ret = PTR_ERR(rspi->addr);
10690b2182ddSShimoda, Yoshihiro 		goto error1;
10700b2182ddSShimoda, Yoshihiro 	}
10710b2182ddSShimoda, Yoshihiro 
107229f397b7SGeert Uytterhoeven 	rspi->clk = devm_clk_get(&pdev->dev, NULL);
10730b2182ddSShimoda, Yoshihiro 	if (IS_ERR(rspi->clk)) {
10740b2182ddSShimoda, Yoshihiro 		dev_err(&pdev->dev, "cannot get clock\n");
10750b2182ddSShimoda, Yoshihiro 		ret = PTR_ERR(rspi->clk);
10765d79e9acSLaurent Pinchart 		goto error1;
10770b2182ddSShimoda, Yoshihiro 	}
107817fe0d9aSGeert Uytterhoeven 
1079490c9774SGeert Uytterhoeven 	pm_runtime_enable(&pdev->dev);
10800b2182ddSShimoda, Yoshihiro 
10810b2182ddSShimoda, Yoshihiro 	init_waitqueue_head(&rspi->wait);
10820b2182ddSShimoda, Yoshihiro 
10830b2182ddSShimoda, Yoshihiro 	master->bus_num = pdev->id;
10840b2182ddSShimoda, Yoshihiro 	master->setup = rspi_setup;
1085490c9774SGeert Uytterhoeven 	master->auto_runtime_pm = true;
1086eb557f75SGeert Uytterhoeven 	master->transfer_one = ops->transfer_one;
108779d23495SGeert Uytterhoeven 	master->prepare_message = rspi_prepare_message;
108879d23495SGeert Uytterhoeven 	master->unprepare_message = rspi_unprepare_message;
1089880c6d11SGeert Uytterhoeven 	master->mode_bits = ops->mode_bits;
1090b42e0359SGeert Uytterhoeven 	master->flags = ops->flags;
1091426ef76dSGeert Uytterhoeven 	master->dev.of_node = pdev->dev.of_node;
10920b2182ddSShimoda, Yoshihiro 
109393722206SGeert Uytterhoeven 	ret = platform_get_irq_byname(pdev, "rx");
109493722206SGeert Uytterhoeven 	if (ret < 0) {
109593722206SGeert Uytterhoeven 		ret = platform_get_irq_byname(pdev, "mux");
109693722206SGeert Uytterhoeven 		if (ret < 0)
109793722206SGeert Uytterhoeven 			ret = platform_get_irq(pdev, 0);
109893722206SGeert Uytterhoeven 		if (ret >= 0)
109993722206SGeert Uytterhoeven 			rspi->rx_irq = rspi->tx_irq = ret;
110093722206SGeert Uytterhoeven 	} else {
110193722206SGeert Uytterhoeven 		rspi->rx_irq = ret;
110293722206SGeert Uytterhoeven 		ret = platform_get_irq_byname(pdev, "tx");
110393722206SGeert Uytterhoeven 		if (ret >= 0)
110493722206SGeert Uytterhoeven 			rspi->tx_irq = ret;
110593722206SGeert Uytterhoeven 	}
110693722206SGeert Uytterhoeven 	if (ret < 0) {
110793722206SGeert Uytterhoeven 		dev_err(&pdev->dev, "platform_get_irq error\n");
110893722206SGeert Uytterhoeven 		goto error2;
110993722206SGeert Uytterhoeven 	}
111093722206SGeert Uytterhoeven 
111193722206SGeert Uytterhoeven 	if (rspi->rx_irq == rspi->tx_irq) {
111293722206SGeert Uytterhoeven 		/* Single multiplexed interrupt */
111393722206SGeert Uytterhoeven 		ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_mux,
111493722206SGeert Uytterhoeven 				       "mux", rspi);
111593722206SGeert Uytterhoeven 	} else {
111693722206SGeert Uytterhoeven 		/* Multi-interrupt mode, only SPRI and SPTI are used */
111793722206SGeert Uytterhoeven 		ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_rx,
111893722206SGeert Uytterhoeven 				       "rx", rspi);
111993722206SGeert Uytterhoeven 		if (!ret)
112093722206SGeert Uytterhoeven 			ret = rspi_request_irq(&pdev->dev, rspi->tx_irq,
112193722206SGeert Uytterhoeven 					       rspi_irq_tx, "tx", rspi);
112293722206SGeert Uytterhoeven 	}
11230b2182ddSShimoda, Yoshihiro 	if (ret < 0) {
11240b2182ddSShimoda, Yoshihiro 		dev_err(&pdev->dev, "request_irq error\n");
1125fcb4ed74SGeert Uytterhoeven 		goto error2;
11260b2182ddSShimoda, Yoshihiro 	}
11270b2182ddSShimoda, Yoshihiro 
11282f777ec9SGeert Uytterhoeven 	ret = rspi_request_dma(&pdev->dev, master, res);
112927e105a6SGeert Uytterhoeven 	if (ret < 0)
113027e105a6SGeert Uytterhoeven 		dev_warn(&pdev->dev, "DMA not available, using PIO\n");
1131a3633fe7SShimoda, Yoshihiro 
11329e03d05eSJingoo Han 	ret = devm_spi_register_master(&pdev->dev, master);
11330b2182ddSShimoda, Yoshihiro 	if (ret < 0) {
11340b2182ddSShimoda, Yoshihiro 		dev_err(&pdev->dev, "spi_register_master error.\n");
1135fcb4ed74SGeert Uytterhoeven 		goto error3;
11360b2182ddSShimoda, Yoshihiro 	}
11370b2182ddSShimoda, Yoshihiro 
11380b2182ddSShimoda, Yoshihiro 	dev_info(&pdev->dev, "probed\n");
11390b2182ddSShimoda, Yoshihiro 
11400b2182ddSShimoda, Yoshihiro 	return 0;
11410b2182ddSShimoda, Yoshihiro 
1142fcb4ed74SGeert Uytterhoeven error3:
1143afcc98deSGeert Uytterhoeven 	rspi_release_dma(master);
1144fcb4ed74SGeert Uytterhoeven error2:
1145490c9774SGeert Uytterhoeven 	pm_runtime_disable(&pdev->dev);
11460b2182ddSShimoda, Yoshihiro error1:
11470b2182ddSShimoda, Yoshihiro 	spi_master_put(master);
11480b2182ddSShimoda, Yoshihiro 
11490b2182ddSShimoda, Yoshihiro 	return ret;
11500b2182ddSShimoda, Yoshihiro }
11510b2182ddSShimoda, Yoshihiro 
11525ce0ba88SHiep Cao Minh static struct platform_device_id spi_driver_ids[] = {
11535ce0ba88SHiep Cao Minh 	{ "rspi",	(kernel_ulong_t)&rspi_ops },
1154862d357fSGeert Uytterhoeven 	{ "rspi-rz",	(kernel_ulong_t)&rspi_rz_ops },
11555ce0ba88SHiep Cao Minh 	{ "qspi",	(kernel_ulong_t)&qspi_ops },
11565ce0ba88SHiep Cao Minh 	{},
11575ce0ba88SHiep Cao Minh };
11585ce0ba88SHiep Cao Minh 
11595ce0ba88SHiep Cao Minh MODULE_DEVICE_TABLE(platform, spi_driver_ids);
11605ce0ba88SHiep Cao Minh 
11610b2182ddSShimoda, Yoshihiro static struct platform_driver rspi_driver = {
11620b2182ddSShimoda, Yoshihiro 	.probe =	rspi_probe,
1163fd4a319bSGrant Likely 	.remove =	rspi_remove,
11645ce0ba88SHiep Cao Minh 	.id_table =	spi_driver_ids,
11650b2182ddSShimoda, Yoshihiro 	.driver		= {
11665ce0ba88SHiep Cao Minh 		.name = "renesas_spi",
11670b2182ddSShimoda, Yoshihiro 		.owner	= THIS_MODULE,
1168426ef76dSGeert Uytterhoeven 		.of_match_table = of_match_ptr(rspi_of_match),
11690b2182ddSShimoda, Yoshihiro 	},
11700b2182ddSShimoda, Yoshihiro };
11710b2182ddSShimoda, Yoshihiro module_platform_driver(rspi_driver);
11720b2182ddSShimoda, Yoshihiro 
11730b2182ddSShimoda, Yoshihiro MODULE_DESCRIPTION("Renesas RSPI bus driver");
11740b2182ddSShimoda, Yoshihiro MODULE_LICENSE("GPL v2");
11750b2182ddSShimoda, Yoshihiro MODULE_AUTHOR("Yoshihiro Shimoda");
11760b2182ddSShimoda, Yoshihiro MODULE_ALIAS("platform:rspi");
1177