xref: /openbmc/linux/drivers/spi/spi-rspi.c (revision df900e67)
10b2182ddSShimoda, Yoshihiro /*
20b2182ddSShimoda, Yoshihiro  * SH RSPI driver
30b2182ddSShimoda, Yoshihiro  *
40b2182ddSShimoda, Yoshihiro  * Copyright (C) 2012  Renesas Solutions Corp.
50b2182ddSShimoda, Yoshihiro  *
60b2182ddSShimoda, Yoshihiro  * Based on spi-sh.c:
70b2182ddSShimoda, Yoshihiro  * Copyright (C) 2011 Renesas Solutions Corp.
80b2182ddSShimoda, Yoshihiro  *
90b2182ddSShimoda, Yoshihiro  * This program is free software; you can redistribute it and/or modify
100b2182ddSShimoda, Yoshihiro  * it under the terms of the GNU General Public License as published by
110b2182ddSShimoda, Yoshihiro  * the Free Software Foundation; version 2 of the License.
120b2182ddSShimoda, Yoshihiro  *
130b2182ddSShimoda, Yoshihiro  * This program is distributed in the hope that it will be useful,
140b2182ddSShimoda, Yoshihiro  * but WITHOUT ANY WARRANTY; without even the implied warranty of
150b2182ddSShimoda, Yoshihiro  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
160b2182ddSShimoda, Yoshihiro  * GNU General Public License for more details.
170b2182ddSShimoda, Yoshihiro  *
180b2182ddSShimoda, Yoshihiro  * You should have received a copy of the GNU General Public License
190b2182ddSShimoda, Yoshihiro  * along with this program; if not, write to the Free Software
200b2182ddSShimoda, Yoshihiro  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
210b2182ddSShimoda, Yoshihiro  *
220b2182ddSShimoda, Yoshihiro  */
230b2182ddSShimoda, Yoshihiro 
240b2182ddSShimoda, Yoshihiro #include <linux/module.h>
250b2182ddSShimoda, Yoshihiro #include <linux/kernel.h>
260b2182ddSShimoda, Yoshihiro #include <linux/sched.h>
270b2182ddSShimoda, Yoshihiro #include <linux/errno.h>
280b2182ddSShimoda, Yoshihiro #include <linux/list.h>
290b2182ddSShimoda, Yoshihiro #include <linux/workqueue.h>
300b2182ddSShimoda, Yoshihiro #include <linux/interrupt.h>
310b2182ddSShimoda, Yoshihiro #include <linux/platform_device.h>
320b2182ddSShimoda, Yoshihiro #include <linux/io.h>
330b2182ddSShimoda, Yoshihiro #include <linux/clk.h>
34a3633fe7SShimoda, Yoshihiro #include <linux/dmaengine.h>
35a3633fe7SShimoda, Yoshihiro #include <linux/dma-mapping.h>
36a3633fe7SShimoda, Yoshihiro #include <linux/sh_dma.h>
370b2182ddSShimoda, Yoshihiro #include <linux/spi/spi.h>
38a3633fe7SShimoda, Yoshihiro #include <linux/spi/rspi.h>
390b2182ddSShimoda, Yoshihiro 
400b2182ddSShimoda, Yoshihiro #define RSPI_SPCR		0x00
410b2182ddSShimoda, Yoshihiro #define RSPI_SSLP		0x01
420b2182ddSShimoda, Yoshihiro #define RSPI_SPPCR		0x02
430b2182ddSShimoda, Yoshihiro #define RSPI_SPSR		0x03
440b2182ddSShimoda, Yoshihiro #define RSPI_SPDR		0x04
450b2182ddSShimoda, Yoshihiro #define RSPI_SPSCR		0x08
460b2182ddSShimoda, Yoshihiro #define RSPI_SPSSR		0x09
470b2182ddSShimoda, Yoshihiro #define RSPI_SPBR		0x0a
480b2182ddSShimoda, Yoshihiro #define RSPI_SPDCR		0x0b
490b2182ddSShimoda, Yoshihiro #define RSPI_SPCKD		0x0c
500b2182ddSShimoda, Yoshihiro #define RSPI_SSLND		0x0d
510b2182ddSShimoda, Yoshihiro #define RSPI_SPND		0x0e
520b2182ddSShimoda, Yoshihiro #define RSPI_SPCR2		0x0f
530b2182ddSShimoda, Yoshihiro #define RSPI_SPCMD0		0x10
540b2182ddSShimoda, Yoshihiro #define RSPI_SPCMD1		0x12
550b2182ddSShimoda, Yoshihiro #define RSPI_SPCMD2		0x14
560b2182ddSShimoda, Yoshihiro #define RSPI_SPCMD3		0x16
570b2182ddSShimoda, Yoshihiro #define RSPI_SPCMD4		0x18
580b2182ddSShimoda, Yoshihiro #define RSPI_SPCMD5		0x1a
590b2182ddSShimoda, Yoshihiro #define RSPI_SPCMD6		0x1c
600b2182ddSShimoda, Yoshihiro #define RSPI_SPCMD7		0x1e
610b2182ddSShimoda, Yoshihiro 
625ce0ba88SHiep Cao Minh /*qspi only */
635ce0ba88SHiep Cao Minh #define QSPI_SPBFCR		0x18
645ce0ba88SHiep Cao Minh #define QSPI_SPBDCR		0x1a
655ce0ba88SHiep Cao Minh #define QSPI_SPBMUL0		0x1c
665ce0ba88SHiep Cao Minh #define QSPI_SPBMUL1		0x20
675ce0ba88SHiep Cao Minh #define QSPI_SPBMUL2		0x24
685ce0ba88SHiep Cao Minh #define QSPI_SPBMUL3		0x28
695ce0ba88SHiep Cao Minh 
700b2182ddSShimoda, Yoshihiro /* SPCR */
710b2182ddSShimoda, Yoshihiro #define SPCR_SPRIE		0x80
720b2182ddSShimoda, Yoshihiro #define SPCR_SPE		0x40
730b2182ddSShimoda, Yoshihiro #define SPCR_SPTIE		0x20
740b2182ddSShimoda, Yoshihiro #define SPCR_SPEIE		0x10
750b2182ddSShimoda, Yoshihiro #define SPCR_MSTR		0x08
760b2182ddSShimoda, Yoshihiro #define SPCR_MODFEN		0x04
770b2182ddSShimoda, Yoshihiro #define SPCR_TXMD		0x02
780b2182ddSShimoda, Yoshihiro #define SPCR_SPMS		0x01
790b2182ddSShimoda, Yoshihiro 
800b2182ddSShimoda, Yoshihiro /* SSLP */
810b2182ddSShimoda, Yoshihiro #define SSLP_SSL1P		0x02
820b2182ddSShimoda, Yoshihiro #define SSLP_SSL0P		0x01
830b2182ddSShimoda, Yoshihiro 
840b2182ddSShimoda, Yoshihiro /* SPPCR */
850b2182ddSShimoda, Yoshihiro #define SPPCR_MOIFE		0x20
860b2182ddSShimoda, Yoshihiro #define SPPCR_MOIFV		0x10
870b2182ddSShimoda, Yoshihiro #define SPPCR_SPOM		0x04
880b2182ddSShimoda, Yoshihiro #define SPPCR_SPLP2		0x02
890b2182ddSShimoda, Yoshihiro #define SPPCR_SPLP		0x01
900b2182ddSShimoda, Yoshihiro 
910b2182ddSShimoda, Yoshihiro /* SPSR */
920b2182ddSShimoda, Yoshihiro #define SPSR_SPRF		0x80
930b2182ddSShimoda, Yoshihiro #define SPSR_SPTEF		0x20
940b2182ddSShimoda, Yoshihiro #define SPSR_PERF		0x08
950b2182ddSShimoda, Yoshihiro #define SPSR_MODF		0x04
960b2182ddSShimoda, Yoshihiro #define SPSR_IDLNF		0x02
970b2182ddSShimoda, Yoshihiro #define SPSR_OVRF		0x01
980b2182ddSShimoda, Yoshihiro 
990b2182ddSShimoda, Yoshihiro /* SPSCR */
1000b2182ddSShimoda, Yoshihiro #define SPSCR_SPSLN_MASK	0x07
1010b2182ddSShimoda, Yoshihiro 
1020b2182ddSShimoda, Yoshihiro /* SPSSR */
1030b2182ddSShimoda, Yoshihiro #define SPSSR_SPECM_MASK	0x70
1040b2182ddSShimoda, Yoshihiro #define SPSSR_SPCP_MASK		0x07
1050b2182ddSShimoda, Yoshihiro 
1060b2182ddSShimoda, Yoshihiro /* SPDCR */
1070b2182ddSShimoda, Yoshihiro #define SPDCR_SPLW		0x20
1080b2182ddSShimoda, Yoshihiro #define SPDCR_SPRDTD		0x10
1090b2182ddSShimoda, Yoshihiro #define SPDCR_SLSEL1		0x08
1100b2182ddSShimoda, Yoshihiro #define SPDCR_SLSEL0		0x04
1110b2182ddSShimoda, Yoshihiro #define SPDCR_SLSEL_MASK	0x0c
1120b2182ddSShimoda, Yoshihiro #define SPDCR_SPFC1		0x02
1130b2182ddSShimoda, Yoshihiro #define SPDCR_SPFC0		0x01
1140b2182ddSShimoda, Yoshihiro 
1150b2182ddSShimoda, Yoshihiro /* SPCKD */
1160b2182ddSShimoda, Yoshihiro #define SPCKD_SCKDL_MASK	0x07
1170b2182ddSShimoda, Yoshihiro 
1180b2182ddSShimoda, Yoshihiro /* SSLND */
1190b2182ddSShimoda, Yoshihiro #define SSLND_SLNDL_MASK	0x07
1200b2182ddSShimoda, Yoshihiro 
1210b2182ddSShimoda, Yoshihiro /* SPND */
1220b2182ddSShimoda, Yoshihiro #define SPND_SPNDL_MASK		0x07
1230b2182ddSShimoda, Yoshihiro 
1240b2182ddSShimoda, Yoshihiro /* SPCR2 */
1250b2182ddSShimoda, Yoshihiro #define SPCR2_PTE		0x08
1260b2182ddSShimoda, Yoshihiro #define SPCR2_SPIE		0x04
1270b2182ddSShimoda, Yoshihiro #define SPCR2_SPOE		0x02
1280b2182ddSShimoda, Yoshihiro #define SPCR2_SPPE		0x01
1290b2182ddSShimoda, Yoshihiro 
1300b2182ddSShimoda, Yoshihiro /* SPCMDn */
1310b2182ddSShimoda, Yoshihiro #define SPCMD_SCKDEN		0x8000
1320b2182ddSShimoda, Yoshihiro #define SPCMD_SLNDEN		0x4000
1330b2182ddSShimoda, Yoshihiro #define SPCMD_SPNDEN		0x2000
1340b2182ddSShimoda, Yoshihiro #define SPCMD_LSBF		0x1000
1350b2182ddSShimoda, Yoshihiro #define SPCMD_SPB_MASK		0x0f00
1360b2182ddSShimoda, Yoshihiro #define SPCMD_SPB_8_TO_16(bit)	(((bit - 1) << 8) & SPCMD_SPB_MASK)
1375ce0ba88SHiep Cao Minh #define SPCMD_SPB_8BIT		0x0000	/* qspi only */
1385ce0ba88SHiep Cao Minh #define SPCMD_SPB_16BIT		0x0100
1390b2182ddSShimoda, Yoshihiro #define SPCMD_SPB_20BIT		0x0000
1400b2182ddSShimoda, Yoshihiro #define SPCMD_SPB_24BIT		0x0100
1410b2182ddSShimoda, Yoshihiro #define SPCMD_SPB_32BIT		0x0200
1420b2182ddSShimoda, Yoshihiro #define SPCMD_SSLKP		0x0080
1430b2182ddSShimoda, Yoshihiro #define SPCMD_SSLA_MASK		0x0030
1440b2182ddSShimoda, Yoshihiro #define SPCMD_BRDV_MASK		0x000c
1450b2182ddSShimoda, Yoshihiro #define SPCMD_CPOL		0x0002
1460b2182ddSShimoda, Yoshihiro #define SPCMD_CPHA		0x0001
1470b2182ddSShimoda, Yoshihiro 
1485ce0ba88SHiep Cao Minh /* SPBFCR */
1495ce0ba88SHiep Cao Minh #define SPBFCR_TXRST		0x80	/* qspi only */
1505ce0ba88SHiep Cao Minh #define SPBFCR_RXRST		0x40	/* qspi only */
1515ce0ba88SHiep Cao Minh 
1520b2182ddSShimoda, Yoshihiro struct rspi_data {
1530b2182ddSShimoda, Yoshihiro 	void __iomem *addr;
1540b2182ddSShimoda, Yoshihiro 	u32 max_speed_hz;
1550b2182ddSShimoda, Yoshihiro 	struct spi_master *master;
1560b2182ddSShimoda, Yoshihiro 	struct list_head queue;
1570b2182ddSShimoda, Yoshihiro 	struct work_struct ws;
1580b2182ddSShimoda, Yoshihiro 	wait_queue_head_t wait;
1590b2182ddSShimoda, Yoshihiro 	spinlock_t lock;
1600b2182ddSShimoda, Yoshihiro 	struct clk *clk;
1610b2182ddSShimoda, Yoshihiro 	unsigned char spsr;
1625ce0ba88SHiep Cao Minh 	const struct spi_ops *ops;
163a3633fe7SShimoda, Yoshihiro 
164a3633fe7SShimoda, Yoshihiro 	/* for dmaengine */
165a3633fe7SShimoda, Yoshihiro 	struct dma_chan *chan_tx;
166a3633fe7SShimoda, Yoshihiro 	struct dma_chan *chan_rx;
167a3633fe7SShimoda, Yoshihiro 	int irq;
168a3633fe7SShimoda, Yoshihiro 
169a3633fe7SShimoda, Yoshihiro 	unsigned dma_width_16bit:1;
170a3633fe7SShimoda, Yoshihiro 	unsigned dma_callbacked:1;
1710b2182ddSShimoda, Yoshihiro };
1720b2182ddSShimoda, Yoshihiro 
1730b2182ddSShimoda, Yoshihiro static void rspi_write8(struct rspi_data *rspi, u8 data, u16 offset)
1740b2182ddSShimoda, Yoshihiro {
1750b2182ddSShimoda, Yoshihiro 	iowrite8(data, rspi->addr + offset);
1760b2182ddSShimoda, Yoshihiro }
1770b2182ddSShimoda, Yoshihiro 
1780b2182ddSShimoda, Yoshihiro static void rspi_write16(struct rspi_data *rspi, u16 data, u16 offset)
1790b2182ddSShimoda, Yoshihiro {
1800b2182ddSShimoda, Yoshihiro 	iowrite16(data, rspi->addr + offset);
1810b2182ddSShimoda, Yoshihiro }
1820b2182ddSShimoda, Yoshihiro 
1835ce0ba88SHiep Cao Minh static void rspi_write32(struct rspi_data *rspi, u32 data, u16 offset)
1845ce0ba88SHiep Cao Minh {
1855ce0ba88SHiep Cao Minh 	iowrite32(data, rspi->addr + offset);
1865ce0ba88SHiep Cao Minh }
1875ce0ba88SHiep Cao Minh 
1880b2182ddSShimoda, Yoshihiro static u8 rspi_read8(struct rspi_data *rspi, u16 offset)
1890b2182ddSShimoda, Yoshihiro {
1900b2182ddSShimoda, Yoshihiro 	return ioread8(rspi->addr + offset);
1910b2182ddSShimoda, Yoshihiro }
1920b2182ddSShimoda, Yoshihiro 
1930b2182ddSShimoda, Yoshihiro static u16 rspi_read16(struct rspi_data *rspi, u16 offset)
1940b2182ddSShimoda, Yoshihiro {
1950b2182ddSShimoda, Yoshihiro 	return ioread16(rspi->addr + offset);
1960b2182ddSShimoda, Yoshihiro }
1970b2182ddSShimoda, Yoshihiro 
1985ce0ba88SHiep Cao Minh /* optional functions */
1995ce0ba88SHiep Cao Minh struct spi_ops {
2005ce0ba88SHiep Cao Minh 	int (*set_config_register)(struct rspi_data *rspi, int access_size);
201cb52c673SHiep Cao Minh 	int (*send_pio)(struct rspi_data *rspi, struct spi_message *mesg,
202cb52c673SHiep Cao Minh 			struct spi_transfer *t);
203cb52c673SHiep Cao Minh 	int (*receive_pio)(struct rspi_data *rspi, struct spi_message *mesg,
204cb52c673SHiep Cao Minh 			   struct spi_transfer *t);
205cb52c673SHiep Cao Minh 
2065ce0ba88SHiep Cao Minh };
2075ce0ba88SHiep Cao Minh 
2085ce0ba88SHiep Cao Minh /*
2095ce0ba88SHiep Cao Minh  * functions for RSPI
2105ce0ba88SHiep Cao Minh  */
2115ce0ba88SHiep Cao Minh static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
2120b2182ddSShimoda, Yoshihiro {
2135ce0ba88SHiep Cao Minh 	int spbr;
2140b2182ddSShimoda, Yoshihiro 
2155ce0ba88SHiep Cao Minh 	/* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
2165ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SPPCR);
2170b2182ddSShimoda, Yoshihiro 
2185ce0ba88SHiep Cao Minh 	/* Sets transfer bit rate */
2195ce0ba88SHiep Cao Minh 	spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
2205ce0ba88SHiep Cao Minh 	rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
2215ce0ba88SHiep Cao Minh 
2225ce0ba88SHiep Cao Minh 	/* Sets number of frames to be used: 1 frame */
2235ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SPDCR);
2245ce0ba88SHiep Cao Minh 
2255ce0ba88SHiep Cao Minh 	/* Sets RSPCK, SSL, next-access delay value */
2265ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SPCKD);
2275ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SSLND);
2285ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SPND);
2295ce0ba88SHiep Cao Minh 
2305ce0ba88SHiep Cao Minh 	/* Sets parity, interrupt mask */
2315ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SPCR2);
2325ce0ba88SHiep Cao Minh 
2335ce0ba88SHiep Cao Minh 	/* Sets SPCMD */
2345ce0ba88SHiep Cao Minh 	rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | SPCMD_SSLKP,
2355ce0ba88SHiep Cao Minh 		     RSPI_SPCMD0);
2365ce0ba88SHiep Cao Minh 
2375ce0ba88SHiep Cao Minh 	/* Sets RSPI mode */
2385ce0ba88SHiep Cao Minh 	rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
2395ce0ba88SHiep Cao Minh 
2405ce0ba88SHiep Cao Minh 	return 0;
2410b2182ddSShimoda, Yoshihiro }
2420b2182ddSShimoda, Yoshihiro 
2435ce0ba88SHiep Cao Minh /*
2445ce0ba88SHiep Cao Minh  * functions for QSPI
2455ce0ba88SHiep Cao Minh  */
2465ce0ba88SHiep Cao Minh static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
2475ce0ba88SHiep Cao Minh {
2485ce0ba88SHiep Cao Minh 	u16 spcmd;
2495ce0ba88SHiep Cao Minh 	int spbr;
2505ce0ba88SHiep Cao Minh 
2515ce0ba88SHiep Cao Minh 	/* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
2525ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SPPCR);
2535ce0ba88SHiep Cao Minh 
2545ce0ba88SHiep Cao Minh 	/* Sets transfer bit rate */
2555ce0ba88SHiep Cao Minh 	spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz);
2565ce0ba88SHiep Cao Minh 	rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
2575ce0ba88SHiep Cao Minh 
2585ce0ba88SHiep Cao Minh 	/* Sets number of frames to be used: 1 frame */
2595ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SPDCR);
2605ce0ba88SHiep Cao Minh 
2615ce0ba88SHiep Cao Minh 	/* Sets RSPCK, SSL, next-access delay value */
2625ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SPCKD);
2635ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SSLND);
2645ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, RSPI_SPND);
2655ce0ba88SHiep Cao Minh 
2665ce0ba88SHiep Cao Minh 	/* Data Length Setting */
2675ce0ba88SHiep Cao Minh 	if (access_size == 8)
2685ce0ba88SHiep Cao Minh 		spcmd = SPCMD_SPB_8BIT;
2695ce0ba88SHiep Cao Minh 	else if (access_size == 16)
2705ce0ba88SHiep Cao Minh 		spcmd = SPCMD_SPB_16BIT;
2715ce0ba88SHiep Cao Minh 	else if (access_size == 32)
2725ce0ba88SHiep Cao Minh 		spcmd = SPCMD_SPB_32BIT;
2735ce0ba88SHiep Cao Minh 
2745ce0ba88SHiep Cao Minh 	spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | SPCMD_SSLKP | SPCMD_SPNDEN;
2755ce0ba88SHiep Cao Minh 
2765ce0ba88SHiep Cao Minh 	/* Resets transfer data length */
2775ce0ba88SHiep Cao Minh 	rspi_write32(rspi, 0, QSPI_SPBMUL0);
2785ce0ba88SHiep Cao Minh 
2795ce0ba88SHiep Cao Minh 	/* Resets transmit and receive buffer */
2805ce0ba88SHiep Cao Minh 	rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR);
2815ce0ba88SHiep Cao Minh 	/* Sets buffer to allow normal operation */
2825ce0ba88SHiep Cao Minh 	rspi_write8(rspi, 0x00, QSPI_SPBFCR);
2835ce0ba88SHiep Cao Minh 
2845ce0ba88SHiep Cao Minh 	/* Sets SPCMD */
2855ce0ba88SHiep Cao Minh 	rspi_write16(rspi, spcmd, RSPI_SPCMD0);
2865ce0ba88SHiep Cao Minh 
2875ce0ba88SHiep Cao Minh 	/* Enables SPI function in a master mode */
2885ce0ba88SHiep Cao Minh 	rspi_write8(rspi, SPCR_SPE | SPCR_MSTR, RSPI_SPCR);
2895ce0ba88SHiep Cao Minh 
2905ce0ba88SHiep Cao Minh 	return 0;
2915ce0ba88SHiep Cao Minh }
2925ce0ba88SHiep Cao Minh 
2935ce0ba88SHiep Cao Minh #define set_config_register(spi, n) spi->ops->set_config_register(spi, n)
2945ce0ba88SHiep Cao Minh 
2950b2182ddSShimoda, Yoshihiro static void rspi_enable_irq(struct rspi_data *rspi, u8 enable)
2960b2182ddSShimoda, Yoshihiro {
2970b2182ddSShimoda, Yoshihiro 	rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | enable, RSPI_SPCR);
2980b2182ddSShimoda, Yoshihiro }
2990b2182ddSShimoda, Yoshihiro 
3000b2182ddSShimoda, Yoshihiro static void rspi_disable_irq(struct rspi_data *rspi, u8 disable)
3010b2182ddSShimoda, Yoshihiro {
3020b2182ddSShimoda, Yoshihiro 	rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~disable, RSPI_SPCR);
3030b2182ddSShimoda, Yoshihiro }
3040b2182ddSShimoda, Yoshihiro 
3050b2182ddSShimoda, Yoshihiro static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask,
3060b2182ddSShimoda, Yoshihiro 				   u8 enable_bit)
3070b2182ddSShimoda, Yoshihiro {
3080b2182ddSShimoda, Yoshihiro 	int ret;
3090b2182ddSShimoda, Yoshihiro 
3100b2182ddSShimoda, Yoshihiro 	rspi->spsr = rspi_read8(rspi, RSPI_SPSR);
3110b2182ddSShimoda, Yoshihiro 	rspi_enable_irq(rspi, enable_bit);
3120b2182ddSShimoda, Yoshihiro 	ret = wait_event_timeout(rspi->wait, rspi->spsr & wait_mask, HZ);
3130b2182ddSShimoda, Yoshihiro 	if (ret == 0 && !(rspi->spsr & wait_mask))
3140b2182ddSShimoda, Yoshihiro 		return -ETIMEDOUT;
3150b2182ddSShimoda, Yoshihiro 
3160b2182ddSShimoda, Yoshihiro 	return 0;
3170b2182ddSShimoda, Yoshihiro }
3180b2182ddSShimoda, Yoshihiro 
3190b2182ddSShimoda, Yoshihiro static void rspi_assert_ssl(struct rspi_data *rspi)
3200b2182ddSShimoda, Yoshihiro {
3210b2182ddSShimoda, Yoshihiro 	rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR);
3220b2182ddSShimoda, Yoshihiro }
3230b2182ddSShimoda, Yoshihiro 
3240b2182ddSShimoda, Yoshihiro static void rspi_negate_ssl(struct rspi_data *rspi)
3250b2182ddSShimoda, Yoshihiro {
3260b2182ddSShimoda, Yoshihiro 	rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
3270b2182ddSShimoda, Yoshihiro }
3280b2182ddSShimoda, Yoshihiro 
3290b2182ddSShimoda, Yoshihiro static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
3300b2182ddSShimoda, Yoshihiro 			 struct spi_transfer *t)
3310b2182ddSShimoda, Yoshihiro {
3320b2182ddSShimoda, Yoshihiro 	int remain = t->len;
3330b2182ddSShimoda, Yoshihiro 	u8 *data;
3340b2182ddSShimoda, Yoshihiro 
3350b2182ddSShimoda, Yoshihiro 	data = (u8 *)t->tx_buf;
3360b2182ddSShimoda, Yoshihiro 	while (remain > 0) {
3370b2182ddSShimoda, Yoshihiro 		rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD,
3380b2182ddSShimoda, Yoshihiro 			    RSPI_SPCR);
3390b2182ddSShimoda, Yoshihiro 
3400b2182ddSShimoda, Yoshihiro 		if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
3410b2182ddSShimoda, Yoshihiro 			dev_err(&rspi->master->dev,
3420b2182ddSShimoda, Yoshihiro 				"%s: tx empty timeout\n", __func__);
3430b2182ddSShimoda, Yoshihiro 			return -ETIMEDOUT;
3440b2182ddSShimoda, Yoshihiro 		}
3450b2182ddSShimoda, Yoshihiro 
3460b2182ddSShimoda, Yoshihiro 		rspi_write16(rspi, *data, RSPI_SPDR);
3470b2182ddSShimoda, Yoshihiro 		data++;
3480b2182ddSShimoda, Yoshihiro 		remain--;
3490b2182ddSShimoda, Yoshihiro 	}
3500b2182ddSShimoda, Yoshihiro 
3510b2182ddSShimoda, Yoshihiro 	/* Waiting for the last transmition */
3520b2182ddSShimoda, Yoshihiro 	rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
3530b2182ddSShimoda, Yoshihiro 
3540b2182ddSShimoda, Yoshihiro 	return 0;
3550b2182ddSShimoda, Yoshihiro }
3560b2182ddSShimoda, Yoshihiro 
357cb52c673SHiep Cao Minh static int qspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
358cb52c673SHiep Cao Minh 			 struct spi_transfer *t)
359cb52c673SHiep Cao Minh {
360cb52c673SHiep Cao Minh 	int remain = t->len;
361cb52c673SHiep Cao Minh 	u8 *data;
362cb52c673SHiep Cao Minh 
363cb52c673SHiep Cao Minh 	rspi_write8(rspi, SPBFCR_TXRST, QSPI_SPBFCR);
364cb52c673SHiep Cao Minh 	rspi_write8(rspi, 0x00, QSPI_SPBFCR);
365cb52c673SHiep Cao Minh 
366cb52c673SHiep Cao Minh 	data = (u8 *)t->tx_buf;
367cb52c673SHiep Cao Minh 	while (remain > 0) {
368cb52c673SHiep Cao Minh 
369cb52c673SHiep Cao Minh 		if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
370cb52c673SHiep Cao Minh 			dev_err(&rspi->master->dev,
371cb52c673SHiep Cao Minh 				"%s: tx empty timeout\n", __func__);
372cb52c673SHiep Cao Minh 			return -ETIMEDOUT;
373cb52c673SHiep Cao Minh 		}
374cb52c673SHiep Cao Minh 		rspi_write8(rspi, *data++, RSPI_SPDR);
375cb52c673SHiep Cao Minh 
376cb52c673SHiep Cao Minh 		if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
377cb52c673SHiep Cao Minh 			dev_err(&rspi->master->dev,
378cb52c673SHiep Cao Minh 				"%s: receive timeout\n", __func__);
379cb52c673SHiep Cao Minh 			return -ETIMEDOUT;
380cb52c673SHiep Cao Minh 		}
381cb52c673SHiep Cao Minh 		rspi_read8(rspi, RSPI_SPDR);
382cb52c673SHiep Cao Minh 
383cb52c673SHiep Cao Minh 		remain--;
384cb52c673SHiep Cao Minh 	}
385cb52c673SHiep Cao Minh 
386cb52c673SHiep Cao Minh 	/* Waiting for the last transmition */
387cb52c673SHiep Cao Minh 	rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
388cb52c673SHiep Cao Minh 
389cb52c673SHiep Cao Minh 	return 0;
390cb52c673SHiep Cao Minh }
391cb52c673SHiep Cao Minh 
392cb52c673SHiep Cao Minh #define send_pio(spi, mesg, t) spi->ops->send_pio(spi, mesg, t)
393cb52c673SHiep Cao Minh 
394a3633fe7SShimoda, Yoshihiro static void rspi_dma_complete(void *arg)
3950b2182ddSShimoda, Yoshihiro {
396a3633fe7SShimoda, Yoshihiro 	struct rspi_data *rspi = arg;
397a3633fe7SShimoda, Yoshihiro 
398a3633fe7SShimoda, Yoshihiro 	rspi->dma_callbacked = 1;
399a3633fe7SShimoda, Yoshihiro 	wake_up_interruptible(&rspi->wait);
400a3633fe7SShimoda, Yoshihiro }
401a3633fe7SShimoda, Yoshihiro 
402a3633fe7SShimoda, Yoshihiro static int rspi_dma_map_sg(struct scatterlist *sg, void *buf, unsigned len,
403a3633fe7SShimoda, Yoshihiro 			   struct dma_chan *chan,
404a3633fe7SShimoda, Yoshihiro 			   enum dma_transfer_direction dir)
405a3633fe7SShimoda, Yoshihiro {
406a3633fe7SShimoda, Yoshihiro 	sg_init_table(sg, 1);
407a3633fe7SShimoda, Yoshihiro 	sg_set_buf(sg, buf, len);
408a3633fe7SShimoda, Yoshihiro 	sg_dma_len(sg) = len;
409a3633fe7SShimoda, Yoshihiro 	return dma_map_sg(chan->device->dev, sg, 1, dir);
410a3633fe7SShimoda, Yoshihiro }
411a3633fe7SShimoda, Yoshihiro 
412a3633fe7SShimoda, Yoshihiro static void rspi_dma_unmap_sg(struct scatterlist *sg, struct dma_chan *chan,
413a3633fe7SShimoda, Yoshihiro 			      enum dma_transfer_direction dir)
414a3633fe7SShimoda, Yoshihiro {
415a3633fe7SShimoda, Yoshihiro 	dma_unmap_sg(chan->device->dev, sg, 1, dir);
416a3633fe7SShimoda, Yoshihiro }
417a3633fe7SShimoda, Yoshihiro 
418a3633fe7SShimoda, Yoshihiro static void rspi_memory_to_8bit(void *buf, const void *data, unsigned len)
419a3633fe7SShimoda, Yoshihiro {
420a3633fe7SShimoda, Yoshihiro 	u16 *dst = buf;
421a3633fe7SShimoda, Yoshihiro 	const u8 *src = data;
422a3633fe7SShimoda, Yoshihiro 
423a3633fe7SShimoda, Yoshihiro 	while (len) {
424a3633fe7SShimoda, Yoshihiro 		*dst++ = (u16)(*src++);
425a3633fe7SShimoda, Yoshihiro 		len--;
426a3633fe7SShimoda, Yoshihiro 	}
427a3633fe7SShimoda, Yoshihiro }
428a3633fe7SShimoda, Yoshihiro 
429a3633fe7SShimoda, Yoshihiro static void rspi_memory_from_8bit(void *buf, const void *data, unsigned len)
430a3633fe7SShimoda, Yoshihiro {
431a3633fe7SShimoda, Yoshihiro 	u8 *dst = buf;
432a3633fe7SShimoda, Yoshihiro 	const u16 *src = data;
433a3633fe7SShimoda, Yoshihiro 
434a3633fe7SShimoda, Yoshihiro 	while (len) {
435a3633fe7SShimoda, Yoshihiro 		*dst++ = (u8)*src++;
436a3633fe7SShimoda, Yoshihiro 		len--;
437a3633fe7SShimoda, Yoshihiro 	}
438a3633fe7SShimoda, Yoshihiro }
439a3633fe7SShimoda, Yoshihiro 
440a3633fe7SShimoda, Yoshihiro static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
441a3633fe7SShimoda, Yoshihiro {
442a3633fe7SShimoda, Yoshihiro 	struct scatterlist sg;
443a3633fe7SShimoda, Yoshihiro 	void *buf = NULL;
444a3633fe7SShimoda, Yoshihiro 	struct dma_async_tx_descriptor *desc;
445a3633fe7SShimoda, Yoshihiro 	unsigned len;
446a3633fe7SShimoda, Yoshihiro 	int ret = 0;
447a3633fe7SShimoda, Yoshihiro 
448a3633fe7SShimoda, Yoshihiro 	if (rspi->dma_width_16bit) {
449a3633fe7SShimoda, Yoshihiro 		/*
450a3633fe7SShimoda, Yoshihiro 		 * If DMAC bus width is 16-bit, the driver allocates a dummy
451a3633fe7SShimoda, Yoshihiro 		 * buffer. And, the driver converts original data into the
452a3633fe7SShimoda, Yoshihiro 		 * DMAC data as the following format:
453a3633fe7SShimoda, Yoshihiro 		 *  original data: 1st byte, 2nd byte ...
454a3633fe7SShimoda, Yoshihiro 		 *  DMAC data:     1st byte, dummy, 2nd byte, dummy ...
455a3633fe7SShimoda, Yoshihiro 		 */
456a3633fe7SShimoda, Yoshihiro 		len = t->len * 2;
457a3633fe7SShimoda, Yoshihiro 		buf = kmalloc(len, GFP_KERNEL);
458a3633fe7SShimoda, Yoshihiro 		if (!buf)
459a3633fe7SShimoda, Yoshihiro 			return -ENOMEM;
460a3633fe7SShimoda, Yoshihiro 		rspi_memory_to_8bit(buf, t->tx_buf, t->len);
461a3633fe7SShimoda, Yoshihiro 	} else {
462a3633fe7SShimoda, Yoshihiro 		len = t->len;
463a3633fe7SShimoda, Yoshihiro 		buf = (void *)t->tx_buf;
464a3633fe7SShimoda, Yoshihiro 	}
465a3633fe7SShimoda, Yoshihiro 
466a3633fe7SShimoda, Yoshihiro 	if (!rspi_dma_map_sg(&sg, buf, len, rspi->chan_tx, DMA_TO_DEVICE)) {
467a3633fe7SShimoda, Yoshihiro 		ret = -EFAULT;
468a3633fe7SShimoda, Yoshihiro 		goto end_nomap;
469a3633fe7SShimoda, Yoshihiro 	}
470a3633fe7SShimoda, Yoshihiro 	desc = dmaengine_prep_slave_sg(rspi->chan_tx, &sg, 1, DMA_TO_DEVICE,
471a3633fe7SShimoda, Yoshihiro 				       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
472a3633fe7SShimoda, Yoshihiro 	if (!desc) {
473a3633fe7SShimoda, Yoshihiro 		ret = -EIO;
474a3633fe7SShimoda, Yoshihiro 		goto end;
475a3633fe7SShimoda, Yoshihiro 	}
476a3633fe7SShimoda, Yoshihiro 
477a3633fe7SShimoda, Yoshihiro 	/*
478a3633fe7SShimoda, Yoshihiro 	 * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be
479a3633fe7SShimoda, Yoshihiro 	 * called. So, this driver disables the IRQ while DMA transfer.
480a3633fe7SShimoda, Yoshihiro 	 */
481a3633fe7SShimoda, Yoshihiro 	disable_irq(rspi->irq);
482a3633fe7SShimoda, Yoshihiro 
483a3633fe7SShimoda, Yoshihiro 	rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, RSPI_SPCR);
484a3633fe7SShimoda, Yoshihiro 	rspi_enable_irq(rspi, SPCR_SPTIE);
485a3633fe7SShimoda, Yoshihiro 	rspi->dma_callbacked = 0;
486a3633fe7SShimoda, Yoshihiro 
487a3633fe7SShimoda, Yoshihiro 	desc->callback = rspi_dma_complete;
488a3633fe7SShimoda, Yoshihiro 	desc->callback_param = rspi;
489a3633fe7SShimoda, Yoshihiro 	dmaengine_submit(desc);
490a3633fe7SShimoda, Yoshihiro 	dma_async_issue_pending(rspi->chan_tx);
491a3633fe7SShimoda, Yoshihiro 
492a3633fe7SShimoda, Yoshihiro 	ret = wait_event_interruptible_timeout(rspi->wait,
493a3633fe7SShimoda, Yoshihiro 					       rspi->dma_callbacked, HZ);
494a3633fe7SShimoda, Yoshihiro 	if (ret > 0 && rspi->dma_callbacked)
495a3633fe7SShimoda, Yoshihiro 		ret = 0;
496a3633fe7SShimoda, Yoshihiro 	else if (!ret)
497a3633fe7SShimoda, Yoshihiro 		ret = -ETIMEDOUT;
498a3633fe7SShimoda, Yoshihiro 	rspi_disable_irq(rspi, SPCR_SPTIE);
499a3633fe7SShimoda, Yoshihiro 
500a3633fe7SShimoda, Yoshihiro 	enable_irq(rspi->irq);
501a3633fe7SShimoda, Yoshihiro 
502a3633fe7SShimoda, Yoshihiro end:
503a3633fe7SShimoda, Yoshihiro 	rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE);
504a3633fe7SShimoda, Yoshihiro end_nomap:
505a3633fe7SShimoda, Yoshihiro 	if (rspi->dma_width_16bit)
506a3633fe7SShimoda, Yoshihiro 		kfree(buf);
507a3633fe7SShimoda, Yoshihiro 
508a3633fe7SShimoda, Yoshihiro 	return ret;
509a3633fe7SShimoda, Yoshihiro }
510a3633fe7SShimoda, Yoshihiro 
511a3633fe7SShimoda, Yoshihiro static void rspi_receive_init(struct rspi_data *rspi)
512a3633fe7SShimoda, Yoshihiro {
5130b2182ddSShimoda, Yoshihiro 	unsigned char spsr;
5140b2182ddSShimoda, Yoshihiro 
5150b2182ddSShimoda, Yoshihiro 	spsr = rspi_read8(rspi, RSPI_SPSR);
5160b2182ddSShimoda, Yoshihiro 	if (spsr & SPSR_SPRF)
5170b2182ddSShimoda, Yoshihiro 		rspi_read16(rspi, RSPI_SPDR);	/* dummy read */
5180b2182ddSShimoda, Yoshihiro 	if (spsr & SPSR_OVRF)
5190b2182ddSShimoda, Yoshihiro 		rspi_write8(rspi, rspi_read8(rspi, RSPI_SPSR) & ~SPSR_OVRF,
520df900e67SGeert Uytterhoeven 			    RSPI_SPSR);
521a3633fe7SShimoda, Yoshihiro }
522a3633fe7SShimoda, Yoshihiro 
523a3633fe7SShimoda, Yoshihiro static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
524a3633fe7SShimoda, Yoshihiro 			    struct spi_transfer *t)
525a3633fe7SShimoda, Yoshihiro {
526a3633fe7SShimoda, Yoshihiro 	int remain = t->len;
527a3633fe7SShimoda, Yoshihiro 	u8 *data;
528a3633fe7SShimoda, Yoshihiro 
529a3633fe7SShimoda, Yoshihiro 	rspi_receive_init(rspi);
5300b2182ddSShimoda, Yoshihiro 
5310b2182ddSShimoda, Yoshihiro 	data = (u8 *)t->rx_buf;
5320b2182ddSShimoda, Yoshihiro 	while (remain > 0) {
5330b2182ddSShimoda, Yoshihiro 		rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD,
5340b2182ddSShimoda, Yoshihiro 			    RSPI_SPCR);
5350b2182ddSShimoda, Yoshihiro 
5360b2182ddSShimoda, Yoshihiro 		if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
5370b2182ddSShimoda, Yoshihiro 			dev_err(&rspi->master->dev,
5380b2182ddSShimoda, Yoshihiro 				"%s: tx empty timeout\n", __func__);
5390b2182ddSShimoda, Yoshihiro 			return -ETIMEDOUT;
5400b2182ddSShimoda, Yoshihiro 		}
5410b2182ddSShimoda, Yoshihiro 		/* dummy write for generate clock */
5420b2182ddSShimoda, Yoshihiro 		rspi_write16(rspi, 0x00, RSPI_SPDR);
5430b2182ddSShimoda, Yoshihiro 
5440b2182ddSShimoda, Yoshihiro 		if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
5450b2182ddSShimoda, Yoshihiro 			dev_err(&rspi->master->dev,
5460b2182ddSShimoda, Yoshihiro 				"%s: receive timeout\n", __func__);
5470b2182ddSShimoda, Yoshihiro 			return -ETIMEDOUT;
5480b2182ddSShimoda, Yoshihiro 		}
5490b2182ddSShimoda, Yoshihiro 		/* SPDR allows 16 or 32-bit access only */
5500b2182ddSShimoda, Yoshihiro 		*data = (u8)rspi_read16(rspi, RSPI_SPDR);
5510b2182ddSShimoda, Yoshihiro 
5520b2182ddSShimoda, Yoshihiro 		data++;
5530b2182ddSShimoda, Yoshihiro 		remain--;
5540b2182ddSShimoda, Yoshihiro 	}
5550b2182ddSShimoda, Yoshihiro 
5560b2182ddSShimoda, Yoshihiro 	return 0;
5570b2182ddSShimoda, Yoshihiro }
5580b2182ddSShimoda, Yoshihiro 
559cb52c673SHiep Cao Minh static void qspi_receive_init(struct rspi_data *rspi)
560cb52c673SHiep Cao Minh {
561cb52c673SHiep Cao Minh 	unsigned char spsr;
562cb52c673SHiep Cao Minh 
563cb52c673SHiep Cao Minh 	spsr = rspi_read8(rspi, RSPI_SPSR);
564cb52c673SHiep Cao Minh 	if (spsr & SPSR_SPRF)
565cb52c673SHiep Cao Minh 		rspi_read8(rspi, RSPI_SPDR);   /* dummy read */
566cb52c673SHiep Cao Minh 	rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR);
567cb52c673SHiep Cao Minh 	rspi_write8(rspi, 0x00, QSPI_SPBFCR);
568cb52c673SHiep Cao Minh }
569cb52c673SHiep Cao Minh 
570cb52c673SHiep Cao Minh static int qspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
571cb52c673SHiep Cao Minh 			    struct spi_transfer *t)
572cb52c673SHiep Cao Minh {
573cb52c673SHiep Cao Minh 	int remain = t->len;
574cb52c673SHiep Cao Minh 	u8 *data;
575cb52c673SHiep Cao Minh 
576cb52c673SHiep Cao Minh 	qspi_receive_init(rspi);
577cb52c673SHiep Cao Minh 
578cb52c673SHiep Cao Minh 	data = (u8 *)t->rx_buf;
579cb52c673SHiep Cao Minh 	while (remain > 0) {
580cb52c673SHiep Cao Minh 
581cb52c673SHiep Cao Minh 		if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
582cb52c673SHiep Cao Minh 			dev_err(&rspi->master->dev,
583cb52c673SHiep Cao Minh 				"%s: tx empty timeout\n", __func__);
584cb52c673SHiep Cao Minh 			return -ETIMEDOUT;
585cb52c673SHiep Cao Minh 		}
586cb52c673SHiep Cao Minh 		/* dummy write for generate clock */
587cb52c673SHiep Cao Minh 		rspi_write8(rspi, 0x00, RSPI_SPDR);
588cb52c673SHiep Cao Minh 
589cb52c673SHiep Cao Minh 		if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
590cb52c673SHiep Cao Minh 			dev_err(&rspi->master->dev,
591cb52c673SHiep Cao Minh 				"%s: receive timeout\n", __func__);
592cb52c673SHiep Cao Minh 			return -ETIMEDOUT;
593cb52c673SHiep Cao Minh 		}
594cb52c673SHiep Cao Minh 		/* SPDR allows 8, 16 or 32-bit access */
595cb52c673SHiep Cao Minh 		*data++ = rspi_read8(rspi, RSPI_SPDR);
596cb52c673SHiep Cao Minh 		remain--;
597cb52c673SHiep Cao Minh 	}
598cb52c673SHiep Cao Minh 
599cb52c673SHiep Cao Minh 	return 0;
600cb52c673SHiep Cao Minh }
601cb52c673SHiep Cao Minh 
602cb52c673SHiep Cao Minh #define receive_pio(spi, mesg, t) spi->ops->receive_pio(spi, mesg, t)
603cb52c673SHiep Cao Minh 
604a3633fe7SShimoda, Yoshihiro static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
605a3633fe7SShimoda, Yoshihiro {
606a3633fe7SShimoda, Yoshihiro 	struct scatterlist sg, sg_dummy;
607a3633fe7SShimoda, Yoshihiro 	void *dummy = NULL, *rx_buf = NULL;
608a3633fe7SShimoda, Yoshihiro 	struct dma_async_tx_descriptor *desc, *desc_dummy;
609a3633fe7SShimoda, Yoshihiro 	unsigned len;
610a3633fe7SShimoda, Yoshihiro 	int ret = 0;
611a3633fe7SShimoda, Yoshihiro 
612a3633fe7SShimoda, Yoshihiro 	if (rspi->dma_width_16bit) {
613a3633fe7SShimoda, Yoshihiro 		/*
614a3633fe7SShimoda, Yoshihiro 		 * If DMAC bus width is 16-bit, the driver allocates a dummy
615a3633fe7SShimoda, Yoshihiro 		 * buffer. And, finally the driver converts the DMAC data into
616a3633fe7SShimoda, Yoshihiro 		 * actual data as the following format:
617a3633fe7SShimoda, Yoshihiro 		 *  DMAC data:   1st byte, dummy, 2nd byte, dummy ...
618a3633fe7SShimoda, Yoshihiro 		 *  actual data: 1st byte, 2nd byte ...
619a3633fe7SShimoda, Yoshihiro 		 */
620a3633fe7SShimoda, Yoshihiro 		len = t->len * 2;
621a3633fe7SShimoda, Yoshihiro 		rx_buf = kmalloc(len, GFP_KERNEL);
622a3633fe7SShimoda, Yoshihiro 		if (!rx_buf)
623a3633fe7SShimoda, Yoshihiro 			return -ENOMEM;
624a3633fe7SShimoda, Yoshihiro 	 } else {
625a3633fe7SShimoda, Yoshihiro 		len = t->len;
626a3633fe7SShimoda, Yoshihiro 		rx_buf = t->rx_buf;
627a3633fe7SShimoda, Yoshihiro 	}
628a3633fe7SShimoda, Yoshihiro 
629a3633fe7SShimoda, Yoshihiro 	/* prepare dummy transfer to generate SPI clocks */
630a3633fe7SShimoda, Yoshihiro 	dummy = kzalloc(len, GFP_KERNEL);
631a3633fe7SShimoda, Yoshihiro 	if (!dummy) {
632a3633fe7SShimoda, Yoshihiro 		ret = -ENOMEM;
633a3633fe7SShimoda, Yoshihiro 		goto end_nomap;
634a3633fe7SShimoda, Yoshihiro 	}
635a3633fe7SShimoda, Yoshihiro 	if (!rspi_dma_map_sg(&sg_dummy, dummy, len, rspi->chan_tx,
636a3633fe7SShimoda, Yoshihiro 			     DMA_TO_DEVICE)) {
637a3633fe7SShimoda, Yoshihiro 		ret = -EFAULT;
638a3633fe7SShimoda, Yoshihiro 		goto end_nomap;
639a3633fe7SShimoda, Yoshihiro 	}
640a3633fe7SShimoda, Yoshihiro 	desc_dummy = dmaengine_prep_slave_sg(rspi->chan_tx, &sg_dummy, 1,
641a3633fe7SShimoda, Yoshihiro 			DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
642a3633fe7SShimoda, Yoshihiro 	if (!desc_dummy) {
643a3633fe7SShimoda, Yoshihiro 		ret = -EIO;
644a3633fe7SShimoda, Yoshihiro 		goto end_dummy_mapped;
645a3633fe7SShimoda, Yoshihiro 	}
646a3633fe7SShimoda, Yoshihiro 
647a3633fe7SShimoda, Yoshihiro 	/* prepare receive transfer */
648a3633fe7SShimoda, Yoshihiro 	if (!rspi_dma_map_sg(&sg, rx_buf, len, rspi->chan_rx,
649a3633fe7SShimoda, Yoshihiro 			     DMA_FROM_DEVICE)) {
650a3633fe7SShimoda, Yoshihiro 		ret = -EFAULT;
651a3633fe7SShimoda, Yoshihiro 		goto end_dummy_mapped;
652a3633fe7SShimoda, Yoshihiro 
653a3633fe7SShimoda, Yoshihiro 	}
654a3633fe7SShimoda, Yoshihiro 	desc = dmaengine_prep_slave_sg(rspi->chan_rx, &sg, 1, DMA_FROM_DEVICE,
655a3633fe7SShimoda, Yoshihiro 				       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
656a3633fe7SShimoda, Yoshihiro 	if (!desc) {
657a3633fe7SShimoda, Yoshihiro 		ret = -EIO;
658a3633fe7SShimoda, Yoshihiro 		goto end;
659a3633fe7SShimoda, Yoshihiro 	}
660a3633fe7SShimoda, Yoshihiro 
661a3633fe7SShimoda, Yoshihiro 	rspi_receive_init(rspi);
662a3633fe7SShimoda, Yoshihiro 
663a3633fe7SShimoda, Yoshihiro 	/*
664a3633fe7SShimoda, Yoshihiro 	 * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be
665a3633fe7SShimoda, Yoshihiro 	 * called. So, this driver disables the IRQ while DMA transfer.
666a3633fe7SShimoda, Yoshihiro 	 */
667a3633fe7SShimoda, Yoshihiro 	disable_irq(rspi->irq);
668a3633fe7SShimoda, Yoshihiro 
669a3633fe7SShimoda, Yoshihiro 	rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, RSPI_SPCR);
670a3633fe7SShimoda, Yoshihiro 	rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
671a3633fe7SShimoda, Yoshihiro 	rspi->dma_callbacked = 0;
672a3633fe7SShimoda, Yoshihiro 
673a3633fe7SShimoda, Yoshihiro 	desc->callback = rspi_dma_complete;
674a3633fe7SShimoda, Yoshihiro 	desc->callback_param = rspi;
675a3633fe7SShimoda, Yoshihiro 	dmaengine_submit(desc);
676a3633fe7SShimoda, Yoshihiro 	dma_async_issue_pending(rspi->chan_rx);
677a3633fe7SShimoda, Yoshihiro 
678a3633fe7SShimoda, Yoshihiro 	desc_dummy->callback = NULL;	/* No callback */
679a3633fe7SShimoda, Yoshihiro 	dmaengine_submit(desc_dummy);
680a3633fe7SShimoda, Yoshihiro 	dma_async_issue_pending(rspi->chan_tx);
681a3633fe7SShimoda, Yoshihiro 
682a3633fe7SShimoda, Yoshihiro 	ret = wait_event_interruptible_timeout(rspi->wait,
683a3633fe7SShimoda, Yoshihiro 					       rspi->dma_callbacked, HZ);
684a3633fe7SShimoda, Yoshihiro 	if (ret > 0 && rspi->dma_callbacked)
685a3633fe7SShimoda, Yoshihiro 		ret = 0;
686a3633fe7SShimoda, Yoshihiro 	else if (!ret)
687a3633fe7SShimoda, Yoshihiro 		ret = -ETIMEDOUT;
688a3633fe7SShimoda, Yoshihiro 	rspi_disable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
689a3633fe7SShimoda, Yoshihiro 
690a3633fe7SShimoda, Yoshihiro 	enable_irq(rspi->irq);
691a3633fe7SShimoda, Yoshihiro 
692a3633fe7SShimoda, Yoshihiro end:
693a3633fe7SShimoda, Yoshihiro 	rspi_dma_unmap_sg(&sg, rspi->chan_rx, DMA_FROM_DEVICE);
694a3633fe7SShimoda, Yoshihiro end_dummy_mapped:
695a3633fe7SShimoda, Yoshihiro 	rspi_dma_unmap_sg(&sg_dummy, rspi->chan_tx, DMA_TO_DEVICE);
696a3633fe7SShimoda, Yoshihiro end_nomap:
697a3633fe7SShimoda, Yoshihiro 	if (rspi->dma_width_16bit) {
698a3633fe7SShimoda, Yoshihiro 		if (!ret)
699a3633fe7SShimoda, Yoshihiro 			rspi_memory_from_8bit(t->rx_buf, rx_buf, t->len);
700a3633fe7SShimoda, Yoshihiro 		kfree(rx_buf);
701a3633fe7SShimoda, Yoshihiro 	}
702a3633fe7SShimoda, Yoshihiro 	kfree(dummy);
703a3633fe7SShimoda, Yoshihiro 
704a3633fe7SShimoda, Yoshihiro 	return ret;
705a3633fe7SShimoda, Yoshihiro }
706a3633fe7SShimoda, Yoshihiro 
707a3633fe7SShimoda, Yoshihiro static int rspi_is_dma(struct rspi_data *rspi, struct spi_transfer *t)
708a3633fe7SShimoda, Yoshihiro {
709a3633fe7SShimoda, Yoshihiro 	if (t->tx_buf && rspi->chan_tx)
710a3633fe7SShimoda, Yoshihiro 		return 1;
711a3633fe7SShimoda, Yoshihiro 	/* If the module receives data by DMAC, it also needs TX DMAC */
712a3633fe7SShimoda, Yoshihiro 	if (t->rx_buf && rspi->chan_tx && rspi->chan_rx)
713a3633fe7SShimoda, Yoshihiro 		return 1;
714a3633fe7SShimoda, Yoshihiro 
715a3633fe7SShimoda, Yoshihiro 	return 0;
716a3633fe7SShimoda, Yoshihiro }
717a3633fe7SShimoda, Yoshihiro 
7180b2182ddSShimoda, Yoshihiro static void rspi_work(struct work_struct *work)
7190b2182ddSShimoda, Yoshihiro {
7200b2182ddSShimoda, Yoshihiro 	struct rspi_data *rspi = container_of(work, struct rspi_data, ws);
7210b2182ddSShimoda, Yoshihiro 	struct spi_message *mesg;
7220b2182ddSShimoda, Yoshihiro 	struct spi_transfer *t;
7230b2182ddSShimoda, Yoshihiro 	unsigned long flags;
7240b2182ddSShimoda, Yoshihiro 	int ret;
7250b2182ddSShimoda, Yoshihiro 
7268d4d08ceSShimoda, Yoshihiro 	while (1) {
7270b2182ddSShimoda, Yoshihiro 		spin_lock_irqsave(&rspi->lock, flags);
7288d4d08ceSShimoda, Yoshihiro 		if (list_empty(&rspi->queue)) {
7298d4d08ceSShimoda, Yoshihiro 			spin_unlock_irqrestore(&rspi->lock, flags);
7308d4d08ceSShimoda, Yoshihiro 			break;
7318d4d08ceSShimoda, Yoshihiro 		}
7320b2182ddSShimoda, Yoshihiro 		mesg = list_entry(rspi->queue.next, struct spi_message, queue);
7330b2182ddSShimoda, Yoshihiro 		list_del_init(&mesg->queue);
7340b2182ddSShimoda, Yoshihiro 		spin_unlock_irqrestore(&rspi->lock, flags);
7350b2182ddSShimoda, Yoshihiro 
7360b2182ddSShimoda, Yoshihiro 		rspi_assert_ssl(rspi);
7370b2182ddSShimoda, Yoshihiro 
7380b2182ddSShimoda, Yoshihiro 		list_for_each_entry(t, &mesg->transfers, transfer_list) {
7390b2182ddSShimoda, Yoshihiro 			if (t->tx_buf) {
740a3633fe7SShimoda, Yoshihiro 				if (rspi_is_dma(rspi, t))
741a3633fe7SShimoda, Yoshihiro 					ret = rspi_send_dma(rspi, t);
742a3633fe7SShimoda, Yoshihiro 				else
743cb52c673SHiep Cao Minh 					ret = send_pio(rspi, mesg, t);
7440b2182ddSShimoda, Yoshihiro 				if (ret < 0)
7450b2182ddSShimoda, Yoshihiro 					goto error;
7460b2182ddSShimoda, Yoshihiro 			}
7470b2182ddSShimoda, Yoshihiro 			if (t->rx_buf) {
748a3633fe7SShimoda, Yoshihiro 				if (rspi_is_dma(rspi, t))
749a3633fe7SShimoda, Yoshihiro 					ret = rspi_receive_dma(rspi, t);
750a3633fe7SShimoda, Yoshihiro 				else
751cb52c673SHiep Cao Minh 					ret = receive_pio(rspi, mesg, t);
7520b2182ddSShimoda, Yoshihiro 				if (ret < 0)
7530b2182ddSShimoda, Yoshihiro 					goto error;
7540b2182ddSShimoda, Yoshihiro 			}
7550b2182ddSShimoda, Yoshihiro 			mesg->actual_length += t->len;
7560b2182ddSShimoda, Yoshihiro 		}
7570b2182ddSShimoda, Yoshihiro 		rspi_negate_ssl(rspi);
7580b2182ddSShimoda, Yoshihiro 
7590b2182ddSShimoda, Yoshihiro 		mesg->status = 0;
7600b2182ddSShimoda, Yoshihiro 		mesg->complete(mesg->context);
7610b2182ddSShimoda, Yoshihiro 	}
7620b2182ddSShimoda, Yoshihiro 
7630b2182ddSShimoda, Yoshihiro 	return;
7640b2182ddSShimoda, Yoshihiro 
7650b2182ddSShimoda, Yoshihiro error:
7660b2182ddSShimoda, Yoshihiro 	mesg->status = ret;
7670b2182ddSShimoda, Yoshihiro 	mesg->complete(mesg->context);
7680b2182ddSShimoda, Yoshihiro }
7690b2182ddSShimoda, Yoshihiro 
7700b2182ddSShimoda, Yoshihiro static int rspi_setup(struct spi_device *spi)
7710b2182ddSShimoda, Yoshihiro {
7720b2182ddSShimoda, Yoshihiro 	struct rspi_data *rspi = spi_master_get_devdata(spi->master);
7730b2182ddSShimoda, Yoshihiro 
7740b2182ddSShimoda, Yoshihiro 	if (!spi->bits_per_word)
7750b2182ddSShimoda, Yoshihiro 		spi->bits_per_word = 8;
7760b2182ddSShimoda, Yoshihiro 	rspi->max_speed_hz = spi->max_speed_hz;
7770b2182ddSShimoda, Yoshihiro 
7785ce0ba88SHiep Cao Minh 	set_config_register(rspi, 8);
7790b2182ddSShimoda, Yoshihiro 
7800b2182ddSShimoda, Yoshihiro 	return 0;
7810b2182ddSShimoda, Yoshihiro }
7820b2182ddSShimoda, Yoshihiro 
7830b2182ddSShimoda, Yoshihiro static int rspi_transfer(struct spi_device *spi, struct spi_message *mesg)
7840b2182ddSShimoda, Yoshihiro {
7850b2182ddSShimoda, Yoshihiro 	struct rspi_data *rspi = spi_master_get_devdata(spi->master);
7860b2182ddSShimoda, Yoshihiro 	unsigned long flags;
7870b2182ddSShimoda, Yoshihiro 
7880b2182ddSShimoda, Yoshihiro 	mesg->actual_length = 0;
7890b2182ddSShimoda, Yoshihiro 	mesg->status = -EINPROGRESS;
7900b2182ddSShimoda, Yoshihiro 
7910b2182ddSShimoda, Yoshihiro 	spin_lock_irqsave(&rspi->lock, flags);
7920b2182ddSShimoda, Yoshihiro 	list_add_tail(&mesg->queue, &rspi->queue);
7930b2182ddSShimoda, Yoshihiro 	schedule_work(&rspi->ws);
7940b2182ddSShimoda, Yoshihiro 	spin_unlock_irqrestore(&rspi->lock, flags);
7950b2182ddSShimoda, Yoshihiro 
7960b2182ddSShimoda, Yoshihiro 	return 0;
7970b2182ddSShimoda, Yoshihiro }
7980b2182ddSShimoda, Yoshihiro 
7990b2182ddSShimoda, Yoshihiro static void rspi_cleanup(struct spi_device *spi)
8000b2182ddSShimoda, Yoshihiro {
8010b2182ddSShimoda, Yoshihiro }
8020b2182ddSShimoda, Yoshihiro 
8030b2182ddSShimoda, Yoshihiro static irqreturn_t rspi_irq(int irq, void *_sr)
8040b2182ddSShimoda, Yoshihiro {
8050b2182ddSShimoda, Yoshihiro 	struct rspi_data *rspi = (struct rspi_data *)_sr;
8060b2182ddSShimoda, Yoshihiro 	unsigned long spsr;
8070b2182ddSShimoda, Yoshihiro 	irqreturn_t ret = IRQ_NONE;
8080b2182ddSShimoda, Yoshihiro 	unsigned char disable_irq = 0;
8090b2182ddSShimoda, Yoshihiro 
8100b2182ddSShimoda, Yoshihiro 	rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR);
8110b2182ddSShimoda, Yoshihiro 	if (spsr & SPSR_SPRF)
8120b2182ddSShimoda, Yoshihiro 		disable_irq |= SPCR_SPRIE;
8130b2182ddSShimoda, Yoshihiro 	if (spsr & SPSR_SPTEF)
8140b2182ddSShimoda, Yoshihiro 		disable_irq |= SPCR_SPTIE;
8150b2182ddSShimoda, Yoshihiro 
8160b2182ddSShimoda, Yoshihiro 	if (disable_irq) {
8170b2182ddSShimoda, Yoshihiro 		ret = IRQ_HANDLED;
8180b2182ddSShimoda, Yoshihiro 		rspi_disable_irq(rspi, disable_irq);
8190b2182ddSShimoda, Yoshihiro 		wake_up(&rspi->wait);
8200b2182ddSShimoda, Yoshihiro 	}
8210b2182ddSShimoda, Yoshihiro 
8220b2182ddSShimoda, Yoshihiro 	return ret;
8230b2182ddSShimoda, Yoshihiro }
8240b2182ddSShimoda, Yoshihiro 
825fd4a319bSGrant Likely static int rspi_request_dma(struct rspi_data *rspi,
826a3633fe7SShimoda, Yoshihiro 				      struct platform_device *pdev)
827a3633fe7SShimoda, Yoshihiro {
8288074cf06SJingoo Han 	struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev);
829e2b05099SGuennadi Liakhovetski 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
830a3633fe7SShimoda, Yoshihiro 	dma_cap_mask_t mask;
8310243c536SShimoda, Yoshihiro 	struct dma_slave_config cfg;
8320243c536SShimoda, Yoshihiro 	int ret;
833a3633fe7SShimoda, Yoshihiro 
834e2b05099SGuennadi Liakhovetski 	if (!res || !rspi_pd)
8350243c536SShimoda, Yoshihiro 		return 0;	/* The driver assumes no error. */
836a3633fe7SShimoda, Yoshihiro 
837a3633fe7SShimoda, Yoshihiro 	rspi->dma_width_16bit = rspi_pd->dma_width_16bit;
838a3633fe7SShimoda, Yoshihiro 
839a3633fe7SShimoda, Yoshihiro 	/* If the module receives data by DMAC, it also needs TX DMAC */
840a3633fe7SShimoda, Yoshihiro 	if (rspi_pd->dma_rx_id && rspi_pd->dma_tx_id) {
841a3633fe7SShimoda, Yoshihiro 		dma_cap_zero(mask);
842a3633fe7SShimoda, Yoshihiro 		dma_cap_set(DMA_SLAVE, mask);
8430243c536SShimoda, Yoshihiro 		rspi->chan_rx = dma_request_channel(mask, shdma_chan_filter,
8440243c536SShimoda, Yoshihiro 						    (void *)rspi_pd->dma_rx_id);
8450243c536SShimoda, Yoshihiro 		if (rspi->chan_rx) {
8460243c536SShimoda, Yoshihiro 			cfg.slave_id = rspi_pd->dma_rx_id;
8470243c536SShimoda, Yoshihiro 			cfg.direction = DMA_DEV_TO_MEM;
848e2b05099SGuennadi Liakhovetski 			cfg.dst_addr = 0;
849e2b05099SGuennadi Liakhovetski 			cfg.src_addr = res->start + RSPI_SPDR;
8500243c536SShimoda, Yoshihiro 			ret = dmaengine_slave_config(rspi->chan_rx, &cfg);
8510243c536SShimoda, Yoshihiro 			if (!ret)
852a3633fe7SShimoda, Yoshihiro 				dev_info(&pdev->dev, "Use DMA when rx.\n");
8530243c536SShimoda, Yoshihiro 			else
8540243c536SShimoda, Yoshihiro 				return ret;
8550243c536SShimoda, Yoshihiro 		}
856a3633fe7SShimoda, Yoshihiro 	}
857a3633fe7SShimoda, Yoshihiro 	if (rspi_pd->dma_tx_id) {
858a3633fe7SShimoda, Yoshihiro 		dma_cap_zero(mask);
859a3633fe7SShimoda, Yoshihiro 		dma_cap_set(DMA_SLAVE, mask);
8600243c536SShimoda, Yoshihiro 		rspi->chan_tx = dma_request_channel(mask, shdma_chan_filter,
8610243c536SShimoda, Yoshihiro 						    (void *)rspi_pd->dma_tx_id);
8620243c536SShimoda, Yoshihiro 		if (rspi->chan_tx) {
8630243c536SShimoda, Yoshihiro 			cfg.slave_id = rspi_pd->dma_tx_id;
8640243c536SShimoda, Yoshihiro 			cfg.direction = DMA_MEM_TO_DEV;
865e2b05099SGuennadi Liakhovetski 			cfg.dst_addr = res->start + RSPI_SPDR;
866e2b05099SGuennadi Liakhovetski 			cfg.src_addr = 0;
8670243c536SShimoda, Yoshihiro 			ret = dmaengine_slave_config(rspi->chan_tx, &cfg);
8680243c536SShimoda, Yoshihiro 			if (!ret)
869a3633fe7SShimoda, Yoshihiro 				dev_info(&pdev->dev, "Use DMA when tx\n");
8700243c536SShimoda, Yoshihiro 			else
8710243c536SShimoda, Yoshihiro 				return ret;
872a3633fe7SShimoda, Yoshihiro 		}
873a3633fe7SShimoda, Yoshihiro 	}
874a3633fe7SShimoda, Yoshihiro 
8750243c536SShimoda, Yoshihiro 	return 0;
8760243c536SShimoda, Yoshihiro }
8770243c536SShimoda, Yoshihiro 
878fd4a319bSGrant Likely static void rspi_release_dma(struct rspi_data *rspi)
879a3633fe7SShimoda, Yoshihiro {
880a3633fe7SShimoda, Yoshihiro 	if (rspi->chan_tx)
881a3633fe7SShimoda, Yoshihiro 		dma_release_channel(rspi->chan_tx);
882a3633fe7SShimoda, Yoshihiro 	if (rspi->chan_rx)
883a3633fe7SShimoda, Yoshihiro 		dma_release_channel(rspi->chan_rx);
884a3633fe7SShimoda, Yoshihiro }
885a3633fe7SShimoda, Yoshihiro 
886fd4a319bSGrant Likely static int rspi_remove(struct platform_device *pdev)
8870b2182ddSShimoda, Yoshihiro {
8889d3405dbSAxel Lin 	struct rspi_data *rspi = spi_master_get(platform_get_drvdata(pdev));
8890b2182ddSShimoda, Yoshihiro 
8900b2182ddSShimoda, Yoshihiro 	spi_unregister_master(rspi->master);
891a3633fe7SShimoda, Yoshihiro 	rspi_release_dma(rspi);
8920b2182ddSShimoda, Yoshihiro 	free_irq(platform_get_irq(pdev, 0), rspi);
8930b2182ddSShimoda, Yoshihiro 	clk_put(rspi->clk);
8940b2182ddSShimoda, Yoshihiro 	iounmap(rspi->addr);
8950b2182ddSShimoda, Yoshihiro 	spi_master_put(rspi->master);
8960b2182ddSShimoda, Yoshihiro 
8970b2182ddSShimoda, Yoshihiro 	return 0;
8980b2182ddSShimoda, Yoshihiro }
8990b2182ddSShimoda, Yoshihiro 
900fd4a319bSGrant Likely static int rspi_probe(struct platform_device *pdev)
9010b2182ddSShimoda, Yoshihiro {
9020b2182ddSShimoda, Yoshihiro 	struct resource *res;
9030b2182ddSShimoda, Yoshihiro 	struct spi_master *master;
9040b2182ddSShimoda, Yoshihiro 	struct rspi_data *rspi;
9050b2182ddSShimoda, Yoshihiro 	int ret, irq;
9060b2182ddSShimoda, Yoshihiro 	char clk_name[16];
9075ce0ba88SHiep Cao Minh 	struct rspi_plat_data *rspi_pd = pdev->dev.platform_data;
9085ce0ba88SHiep Cao Minh 	const struct spi_ops *ops;
9095ce0ba88SHiep Cao Minh 	const struct platform_device_id *id_entry = pdev->id_entry;
9100b2182ddSShimoda, Yoshihiro 
9115ce0ba88SHiep Cao Minh 	ops = (struct spi_ops *)id_entry->driver_data;
9125ce0ba88SHiep Cao Minh 	/* ops parameter check */
9135ce0ba88SHiep Cao Minh 	if (!ops->set_config_register) {
9145ce0ba88SHiep Cao Minh 		dev_err(&pdev->dev, "there is no set_config_register\n");
9155ce0ba88SHiep Cao Minh 		return -ENODEV;
9165ce0ba88SHiep Cao Minh 	}
9170b2182ddSShimoda, Yoshihiro 	/* get base addr */
9180b2182ddSShimoda, Yoshihiro 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
9190b2182ddSShimoda, Yoshihiro 	if (unlikely(res == NULL)) {
9200b2182ddSShimoda, Yoshihiro 		dev_err(&pdev->dev, "invalid resource\n");
9210b2182ddSShimoda, Yoshihiro 		return -EINVAL;
9220b2182ddSShimoda, Yoshihiro 	}
9230b2182ddSShimoda, Yoshihiro 
9240b2182ddSShimoda, Yoshihiro 	irq = platform_get_irq(pdev, 0);
9250b2182ddSShimoda, Yoshihiro 	if (irq < 0) {
9260b2182ddSShimoda, Yoshihiro 		dev_err(&pdev->dev, "platform_get_irq error\n");
9270b2182ddSShimoda, Yoshihiro 		return -ENODEV;
9280b2182ddSShimoda, Yoshihiro 	}
9290b2182ddSShimoda, Yoshihiro 
9300b2182ddSShimoda, Yoshihiro 	master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data));
9310b2182ddSShimoda, Yoshihiro 	if (master == NULL) {
9320b2182ddSShimoda, Yoshihiro 		dev_err(&pdev->dev, "spi_alloc_master error.\n");
9330b2182ddSShimoda, Yoshihiro 		return -ENOMEM;
9340b2182ddSShimoda, Yoshihiro 	}
9350b2182ddSShimoda, Yoshihiro 
9360b2182ddSShimoda, Yoshihiro 	rspi = spi_master_get_devdata(master);
93724b5a82cSJingoo Han 	platform_set_drvdata(pdev, rspi);
9385ce0ba88SHiep Cao Minh 	rspi->ops = ops;
9390b2182ddSShimoda, Yoshihiro 	rspi->master = master;
9400b2182ddSShimoda, Yoshihiro 	rspi->addr = ioremap(res->start, resource_size(res));
9410b2182ddSShimoda, Yoshihiro 	if (rspi->addr == NULL) {
9420b2182ddSShimoda, Yoshihiro 		dev_err(&pdev->dev, "ioremap error.\n");
9430b2182ddSShimoda, Yoshihiro 		ret = -ENOMEM;
9440b2182ddSShimoda, Yoshihiro 		goto error1;
9450b2182ddSShimoda, Yoshihiro 	}
9460b2182ddSShimoda, Yoshihiro 
9475ce0ba88SHiep Cao Minh 	snprintf(clk_name, sizeof(clk_name), "%s%d", id_entry->name, pdev->id);
9480b2182ddSShimoda, Yoshihiro 	rspi->clk = clk_get(&pdev->dev, clk_name);
9490b2182ddSShimoda, Yoshihiro 	if (IS_ERR(rspi->clk)) {
9500b2182ddSShimoda, Yoshihiro 		dev_err(&pdev->dev, "cannot get clock\n");
9510b2182ddSShimoda, Yoshihiro 		ret = PTR_ERR(rspi->clk);
9520b2182ddSShimoda, Yoshihiro 		goto error2;
9530b2182ddSShimoda, Yoshihiro 	}
9540b2182ddSShimoda, Yoshihiro 	clk_enable(rspi->clk);
9550b2182ddSShimoda, Yoshihiro 
9560b2182ddSShimoda, Yoshihiro 	INIT_LIST_HEAD(&rspi->queue);
9570b2182ddSShimoda, Yoshihiro 	spin_lock_init(&rspi->lock);
9580b2182ddSShimoda, Yoshihiro 	INIT_WORK(&rspi->ws, rspi_work);
9590b2182ddSShimoda, Yoshihiro 	init_waitqueue_head(&rspi->wait);
9600b2182ddSShimoda, Yoshihiro 
961efd85acbSGeert Uytterhoeven 	if (rspi_pd && rspi_pd->num_chipselect)
9625ce0ba88SHiep Cao Minh 		master->num_chipselect = rspi_pd->num_chipselect;
963efd85acbSGeert Uytterhoeven 	else
9645ce0ba88SHiep Cao Minh 		master->num_chipselect = 2; /* default */
9655ce0ba88SHiep Cao Minh 
9660b2182ddSShimoda, Yoshihiro 	master->bus_num = pdev->id;
9670b2182ddSShimoda, Yoshihiro 	master->setup = rspi_setup;
9680b2182ddSShimoda, Yoshihiro 	master->transfer = rspi_transfer;
9690b2182ddSShimoda, Yoshihiro 	master->cleanup = rspi_cleanup;
9700b2182ddSShimoda, Yoshihiro 
9710b2182ddSShimoda, Yoshihiro 	ret = request_irq(irq, rspi_irq, 0, dev_name(&pdev->dev), rspi);
9720b2182ddSShimoda, Yoshihiro 	if (ret < 0) {
9730b2182ddSShimoda, Yoshihiro 		dev_err(&pdev->dev, "request_irq error\n");
9740b2182ddSShimoda, Yoshihiro 		goto error3;
9750b2182ddSShimoda, Yoshihiro 	}
9760b2182ddSShimoda, Yoshihiro 
977a3633fe7SShimoda, Yoshihiro 	rspi->irq = irq;
9780243c536SShimoda, Yoshihiro 	ret = rspi_request_dma(rspi, pdev);
9790243c536SShimoda, Yoshihiro 	if (ret < 0) {
9800243c536SShimoda, Yoshihiro 		dev_err(&pdev->dev, "rspi_request_dma failed.\n");
9810243c536SShimoda, Yoshihiro 		goto error4;
9820243c536SShimoda, Yoshihiro 	}
983a3633fe7SShimoda, Yoshihiro 
9840b2182ddSShimoda, Yoshihiro 	ret = spi_register_master(master);
9850b2182ddSShimoda, Yoshihiro 	if (ret < 0) {
9860b2182ddSShimoda, Yoshihiro 		dev_err(&pdev->dev, "spi_register_master error.\n");
9870b2182ddSShimoda, Yoshihiro 		goto error4;
9880b2182ddSShimoda, Yoshihiro 	}
9890b2182ddSShimoda, Yoshihiro 
9900b2182ddSShimoda, Yoshihiro 	dev_info(&pdev->dev, "probed\n");
9910b2182ddSShimoda, Yoshihiro 
9920b2182ddSShimoda, Yoshihiro 	return 0;
9930b2182ddSShimoda, Yoshihiro 
9940b2182ddSShimoda, Yoshihiro error4:
995a3633fe7SShimoda, Yoshihiro 	rspi_release_dma(rspi);
9960b2182ddSShimoda, Yoshihiro 	free_irq(irq, rspi);
9970b2182ddSShimoda, Yoshihiro error3:
9980b2182ddSShimoda, Yoshihiro 	clk_put(rspi->clk);
9990b2182ddSShimoda, Yoshihiro error2:
10000b2182ddSShimoda, Yoshihiro 	iounmap(rspi->addr);
10010b2182ddSShimoda, Yoshihiro error1:
10020b2182ddSShimoda, Yoshihiro 	spi_master_put(master);
10030b2182ddSShimoda, Yoshihiro 
10040b2182ddSShimoda, Yoshihiro 	return ret;
10050b2182ddSShimoda, Yoshihiro }
10060b2182ddSShimoda, Yoshihiro 
10075ce0ba88SHiep Cao Minh static struct spi_ops rspi_ops = {
10085ce0ba88SHiep Cao Minh 	.set_config_register =		rspi_set_config_register,
1009cb52c673SHiep Cao Minh 	.send_pio =			rspi_send_pio,
1010cb52c673SHiep Cao Minh 	.receive_pio =			rspi_receive_pio,
10115ce0ba88SHiep Cao Minh };
10125ce0ba88SHiep Cao Minh 
10135ce0ba88SHiep Cao Minh static struct spi_ops qspi_ops = {
10145ce0ba88SHiep Cao Minh 	.set_config_register =		qspi_set_config_register,
1015cb52c673SHiep Cao Minh 	.send_pio =			qspi_send_pio,
1016cb52c673SHiep Cao Minh 	.receive_pio =			qspi_receive_pio,
10175ce0ba88SHiep Cao Minh };
10185ce0ba88SHiep Cao Minh 
10195ce0ba88SHiep Cao Minh static struct platform_device_id spi_driver_ids[] = {
10205ce0ba88SHiep Cao Minh 	{ "rspi",	(kernel_ulong_t)&rspi_ops },
10215ce0ba88SHiep Cao Minh 	{ "qspi",	(kernel_ulong_t)&qspi_ops },
10225ce0ba88SHiep Cao Minh 	{},
10235ce0ba88SHiep Cao Minh };
10245ce0ba88SHiep Cao Minh 
10255ce0ba88SHiep Cao Minh MODULE_DEVICE_TABLE(platform, spi_driver_ids);
10265ce0ba88SHiep Cao Minh 
10270b2182ddSShimoda, Yoshihiro static struct platform_driver rspi_driver = {
10280b2182ddSShimoda, Yoshihiro 	.probe =	rspi_probe,
1029fd4a319bSGrant Likely 	.remove =	rspi_remove,
10305ce0ba88SHiep Cao Minh 	.id_table =	spi_driver_ids,
10310b2182ddSShimoda, Yoshihiro 	.driver		= {
10325ce0ba88SHiep Cao Minh 		.name = "renesas_spi",
10330b2182ddSShimoda, Yoshihiro 		.owner	= THIS_MODULE,
10340b2182ddSShimoda, Yoshihiro 	},
10350b2182ddSShimoda, Yoshihiro };
10360b2182ddSShimoda, Yoshihiro module_platform_driver(rspi_driver);
10370b2182ddSShimoda, Yoshihiro 
10380b2182ddSShimoda, Yoshihiro MODULE_DESCRIPTION("Renesas RSPI bus driver");
10390b2182ddSShimoda, Yoshihiro MODULE_LICENSE("GPL v2");
10400b2182ddSShimoda, Yoshihiro MODULE_AUTHOR("Yoshihiro Shimoda");
10410b2182ddSShimoda, Yoshihiro MODULE_ALIAS("platform:rspi");
1042