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); 6336837b8e9SGeert Uytterhoeven int ret; 634862d357fSGeert Uytterhoeven 635862d357fSGeert Uytterhoeven rspi_rz_receive_init(rspi); 636862d357fSGeert Uytterhoeven 6378b983e90SGeert Uytterhoeven return rspi_common_transfer(rspi, xfer); 638862d357fSGeert Uytterhoeven } 639862d357fSGeert Uytterhoeven 640340a15e6SGeert Uytterhoeven static int qspi_transfer_out_in(struct rspi_data *rspi, 641340a15e6SGeert Uytterhoeven struct spi_transfer *xfer) 642340a15e6SGeert Uytterhoeven { 643340a15e6SGeert Uytterhoeven qspi_receive_init(rspi); 644340a15e6SGeert Uytterhoeven 6458b983e90SGeert Uytterhoeven return rspi_common_transfer(rspi, xfer); 646340a15e6SGeert Uytterhoeven } 647340a15e6SGeert Uytterhoeven 648880c6d11SGeert Uytterhoeven static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer) 649880c6d11SGeert Uytterhoeven { 650880c6d11SGeert Uytterhoeven int ret; 651880c6d11SGeert Uytterhoeven 6524f12b5e5SGeert Uytterhoeven if (rspi->master->can_dma && __rspi_can_dma(rspi, xfer)) 6534f12b5e5SGeert Uytterhoeven return rspi_dma_transfer(rspi, &xfer->tx_sg, NULL); 6544f12b5e5SGeert Uytterhoeven 6556837b8e9SGeert Uytterhoeven ret = rspi_pio_transfer(rspi, xfer->tx_buf, NULL, xfer->len); 656880c6d11SGeert Uytterhoeven if (ret < 0) 657880c6d11SGeert Uytterhoeven return ret; 658880c6d11SGeert Uytterhoeven 659880c6d11SGeert Uytterhoeven /* Wait for the last transmission */ 6605f684c34SGeert Uytterhoeven rspi_wait_for_tx_empty(rspi); 661880c6d11SGeert Uytterhoeven 662880c6d11SGeert Uytterhoeven return 0; 663880c6d11SGeert Uytterhoeven } 664880c6d11SGeert Uytterhoeven 665880c6d11SGeert Uytterhoeven static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer) 666880c6d11SGeert Uytterhoeven { 6674f12b5e5SGeert Uytterhoeven if (rspi->master->can_dma && __rspi_can_dma(rspi, xfer)) 6684f12b5e5SGeert Uytterhoeven return rspi_dma_transfer(rspi, NULL, &xfer->rx_sg); 6694f12b5e5SGeert Uytterhoeven 6706837b8e9SGeert Uytterhoeven return rspi_pio_transfer(rspi, NULL, xfer->rx_buf, xfer->len); 671880c6d11SGeert Uytterhoeven } 672880c6d11SGeert Uytterhoeven 673eb557f75SGeert Uytterhoeven static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi, 674eb557f75SGeert Uytterhoeven struct spi_transfer *xfer) 675eb557f75SGeert Uytterhoeven { 676eb557f75SGeert Uytterhoeven struct rspi_data *rspi = spi_master_get_devdata(master); 677eb557f75SGeert Uytterhoeven 678ba824d49SGeert Uytterhoeven if (spi->mode & SPI_LOOP) { 679ba824d49SGeert Uytterhoeven return qspi_transfer_out_in(rspi, xfer); 680b42e0359SGeert Uytterhoeven } else if (xfer->tx_nbits > SPI_NBITS_SINGLE) { 681880c6d11SGeert Uytterhoeven /* Quad or Dual SPI Write */ 682880c6d11SGeert Uytterhoeven return qspi_transfer_out(rspi, xfer); 683b42e0359SGeert Uytterhoeven } else if (xfer->rx_nbits > SPI_NBITS_SINGLE) { 684880c6d11SGeert Uytterhoeven /* Quad or Dual SPI Read */ 685880c6d11SGeert Uytterhoeven return qspi_transfer_in(rspi, xfer); 686880c6d11SGeert Uytterhoeven } else { 687880c6d11SGeert Uytterhoeven /* Single SPI Transfer */ 688340a15e6SGeert Uytterhoeven return qspi_transfer_out_in(rspi, xfer); 689eb557f75SGeert Uytterhoeven } 690880c6d11SGeert Uytterhoeven } 691eb557f75SGeert Uytterhoeven 6920b2182ddSShimoda, Yoshihiro static int rspi_setup(struct spi_device *spi) 6930b2182ddSShimoda, Yoshihiro { 6940b2182ddSShimoda, Yoshihiro struct rspi_data *rspi = spi_master_get_devdata(spi->master); 6950b2182ddSShimoda, Yoshihiro 6960b2182ddSShimoda, Yoshihiro rspi->max_speed_hz = spi->max_speed_hz; 6970b2182ddSShimoda, Yoshihiro 698348e5153SGeert Uytterhoeven rspi->spcmd = SPCMD_SSLKP; 699348e5153SGeert Uytterhoeven if (spi->mode & SPI_CPOL) 700348e5153SGeert Uytterhoeven rspi->spcmd |= SPCMD_CPOL; 701348e5153SGeert Uytterhoeven if (spi->mode & SPI_CPHA) 702348e5153SGeert Uytterhoeven rspi->spcmd |= SPCMD_CPHA; 703348e5153SGeert Uytterhoeven 70406a7a3cfSGeert Uytterhoeven /* CMOS output mode and MOSI signal from previous transfer */ 70506a7a3cfSGeert Uytterhoeven rspi->sppcr = 0; 70606a7a3cfSGeert Uytterhoeven if (spi->mode & SPI_LOOP) 70706a7a3cfSGeert Uytterhoeven rspi->sppcr |= SPPCR_SPLP; 70806a7a3cfSGeert Uytterhoeven 7095ce0ba88SHiep Cao Minh set_config_register(rspi, 8); 7100b2182ddSShimoda, Yoshihiro 7110b2182ddSShimoda, Yoshihiro return 0; 7120b2182ddSShimoda, Yoshihiro } 7130b2182ddSShimoda, Yoshihiro 714880c6d11SGeert Uytterhoeven static u16 qspi_transfer_mode(const struct spi_transfer *xfer) 715880c6d11SGeert Uytterhoeven { 716880c6d11SGeert Uytterhoeven if (xfer->tx_buf) 717880c6d11SGeert Uytterhoeven switch (xfer->tx_nbits) { 718880c6d11SGeert Uytterhoeven case SPI_NBITS_QUAD: 719880c6d11SGeert Uytterhoeven return SPCMD_SPIMOD_QUAD; 720880c6d11SGeert Uytterhoeven case SPI_NBITS_DUAL: 721880c6d11SGeert Uytterhoeven return SPCMD_SPIMOD_DUAL; 722880c6d11SGeert Uytterhoeven default: 723880c6d11SGeert Uytterhoeven return 0; 724880c6d11SGeert Uytterhoeven } 725880c6d11SGeert Uytterhoeven if (xfer->rx_buf) 726880c6d11SGeert Uytterhoeven switch (xfer->rx_nbits) { 727880c6d11SGeert Uytterhoeven case SPI_NBITS_QUAD: 728880c6d11SGeert Uytterhoeven return SPCMD_SPIMOD_QUAD | SPCMD_SPRW; 729880c6d11SGeert Uytterhoeven case SPI_NBITS_DUAL: 730880c6d11SGeert Uytterhoeven return SPCMD_SPIMOD_DUAL | SPCMD_SPRW; 731880c6d11SGeert Uytterhoeven default: 732880c6d11SGeert Uytterhoeven return 0; 733880c6d11SGeert Uytterhoeven } 734880c6d11SGeert Uytterhoeven 735880c6d11SGeert Uytterhoeven return 0; 736880c6d11SGeert Uytterhoeven } 737880c6d11SGeert Uytterhoeven 738880c6d11SGeert Uytterhoeven static int qspi_setup_sequencer(struct rspi_data *rspi, 739880c6d11SGeert Uytterhoeven const struct spi_message *msg) 740880c6d11SGeert Uytterhoeven { 741880c6d11SGeert Uytterhoeven const struct spi_transfer *xfer; 742880c6d11SGeert Uytterhoeven unsigned int i = 0, len = 0; 743880c6d11SGeert Uytterhoeven u16 current_mode = 0xffff, mode; 744880c6d11SGeert Uytterhoeven 745880c6d11SGeert Uytterhoeven list_for_each_entry(xfer, &msg->transfers, transfer_list) { 746880c6d11SGeert Uytterhoeven mode = qspi_transfer_mode(xfer); 747880c6d11SGeert Uytterhoeven if (mode == current_mode) { 748880c6d11SGeert Uytterhoeven len += xfer->len; 749880c6d11SGeert Uytterhoeven continue; 750880c6d11SGeert Uytterhoeven } 751880c6d11SGeert Uytterhoeven 752880c6d11SGeert Uytterhoeven /* Transfer mode change */ 753880c6d11SGeert Uytterhoeven if (i) { 754880c6d11SGeert Uytterhoeven /* Set transfer data length of previous transfer */ 755880c6d11SGeert Uytterhoeven rspi_write32(rspi, len, QSPI_SPBMUL(i - 1)); 756880c6d11SGeert Uytterhoeven } 757880c6d11SGeert Uytterhoeven 758880c6d11SGeert Uytterhoeven if (i >= QSPI_NUM_SPCMD) { 759880c6d11SGeert Uytterhoeven dev_err(&msg->spi->dev, 760880c6d11SGeert Uytterhoeven "Too many different transfer modes"); 761880c6d11SGeert Uytterhoeven return -EINVAL; 762880c6d11SGeert Uytterhoeven } 763880c6d11SGeert Uytterhoeven 764880c6d11SGeert Uytterhoeven /* Program transfer mode for this transfer */ 765880c6d11SGeert Uytterhoeven rspi_write16(rspi, rspi->spcmd | mode, RSPI_SPCMD(i)); 766880c6d11SGeert Uytterhoeven current_mode = mode; 767880c6d11SGeert Uytterhoeven len = xfer->len; 768880c6d11SGeert Uytterhoeven i++; 769880c6d11SGeert Uytterhoeven } 770880c6d11SGeert Uytterhoeven if (i) { 771880c6d11SGeert Uytterhoeven /* Set final transfer data length and sequence length */ 772880c6d11SGeert Uytterhoeven rspi_write32(rspi, len, QSPI_SPBMUL(i - 1)); 773880c6d11SGeert Uytterhoeven rspi_write8(rspi, i - 1, RSPI_SPSCR); 774880c6d11SGeert Uytterhoeven } 775880c6d11SGeert Uytterhoeven 776880c6d11SGeert Uytterhoeven return 0; 777880c6d11SGeert Uytterhoeven } 778880c6d11SGeert Uytterhoeven 77979d23495SGeert Uytterhoeven static int rspi_prepare_message(struct spi_master *master, 780880c6d11SGeert Uytterhoeven struct spi_message *msg) 78179d23495SGeert Uytterhoeven { 78279d23495SGeert Uytterhoeven struct rspi_data *rspi = spi_master_get_devdata(master); 783880c6d11SGeert Uytterhoeven int ret; 7840b2182ddSShimoda, Yoshihiro 785880c6d11SGeert Uytterhoeven if (msg->spi->mode & 786880c6d11SGeert Uytterhoeven (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)) { 787880c6d11SGeert Uytterhoeven /* Setup sequencer for messages with multiple transfer modes */ 788880c6d11SGeert Uytterhoeven ret = qspi_setup_sequencer(rspi, msg); 789880c6d11SGeert Uytterhoeven if (ret < 0) 790880c6d11SGeert Uytterhoeven return ret; 791880c6d11SGeert Uytterhoeven } 792880c6d11SGeert Uytterhoeven 793880c6d11SGeert Uytterhoeven /* Enable SPI function in master mode */ 79479d23495SGeert Uytterhoeven rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR); 7950b2182ddSShimoda, Yoshihiro return 0; 7960b2182ddSShimoda, Yoshihiro } 7970b2182ddSShimoda, Yoshihiro 79879d23495SGeert Uytterhoeven static int rspi_unprepare_message(struct spi_master *master, 799880c6d11SGeert Uytterhoeven struct spi_message *msg) 8000b2182ddSShimoda, Yoshihiro { 80179d23495SGeert Uytterhoeven struct rspi_data *rspi = spi_master_get_devdata(master); 80279d23495SGeert Uytterhoeven 803880c6d11SGeert Uytterhoeven /* Disable SPI function */ 80479d23495SGeert Uytterhoeven rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR); 805880c6d11SGeert Uytterhoeven 806880c6d11SGeert Uytterhoeven /* Reset sequencer for Single SPI Transfers */ 807880c6d11SGeert Uytterhoeven rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0); 808880c6d11SGeert Uytterhoeven rspi_write8(rspi, 0, RSPI_SPSCR); 80979d23495SGeert Uytterhoeven return 0; 8100b2182ddSShimoda, Yoshihiro } 8110b2182ddSShimoda, Yoshihiro 81293722206SGeert Uytterhoeven static irqreturn_t rspi_irq_mux(int irq, void *_sr) 8130b2182ddSShimoda, Yoshihiro { 814c132f094SGeert Uytterhoeven struct rspi_data *rspi = _sr; 81597b95c11SGeert Uytterhoeven u8 spsr; 8160b2182ddSShimoda, Yoshihiro irqreturn_t ret = IRQ_NONE; 81797b95c11SGeert Uytterhoeven u8 disable_irq = 0; 8180b2182ddSShimoda, Yoshihiro 8190b2182ddSShimoda, Yoshihiro rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR); 8200b2182ddSShimoda, Yoshihiro if (spsr & SPSR_SPRF) 8210b2182ddSShimoda, Yoshihiro disable_irq |= SPCR_SPRIE; 8220b2182ddSShimoda, Yoshihiro if (spsr & SPSR_SPTEF) 8230b2182ddSShimoda, Yoshihiro disable_irq |= SPCR_SPTIE; 8240b2182ddSShimoda, Yoshihiro 8250b2182ddSShimoda, Yoshihiro if (disable_irq) { 8260b2182ddSShimoda, Yoshihiro ret = IRQ_HANDLED; 8270b2182ddSShimoda, Yoshihiro rspi_disable_irq(rspi, disable_irq); 8280b2182ddSShimoda, Yoshihiro wake_up(&rspi->wait); 8290b2182ddSShimoda, Yoshihiro } 8300b2182ddSShimoda, Yoshihiro 8310b2182ddSShimoda, Yoshihiro return ret; 8320b2182ddSShimoda, Yoshihiro } 8330b2182ddSShimoda, Yoshihiro 83493722206SGeert Uytterhoeven static irqreturn_t rspi_irq_rx(int irq, void *_sr) 83593722206SGeert Uytterhoeven { 83693722206SGeert Uytterhoeven struct rspi_data *rspi = _sr; 83793722206SGeert Uytterhoeven u8 spsr; 83893722206SGeert Uytterhoeven 83993722206SGeert Uytterhoeven rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR); 84093722206SGeert Uytterhoeven if (spsr & SPSR_SPRF) { 84193722206SGeert Uytterhoeven rspi_disable_irq(rspi, SPCR_SPRIE); 84293722206SGeert Uytterhoeven wake_up(&rspi->wait); 84393722206SGeert Uytterhoeven return IRQ_HANDLED; 84493722206SGeert Uytterhoeven } 84593722206SGeert Uytterhoeven 84693722206SGeert Uytterhoeven return 0; 84793722206SGeert Uytterhoeven } 84893722206SGeert Uytterhoeven 84993722206SGeert Uytterhoeven static irqreturn_t rspi_irq_tx(int irq, void *_sr) 85093722206SGeert Uytterhoeven { 85193722206SGeert Uytterhoeven struct rspi_data *rspi = _sr; 85293722206SGeert Uytterhoeven u8 spsr; 85393722206SGeert Uytterhoeven 85493722206SGeert Uytterhoeven rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR); 85593722206SGeert Uytterhoeven if (spsr & SPSR_SPTEF) { 85693722206SGeert Uytterhoeven rspi_disable_irq(rspi, SPCR_SPTIE); 85793722206SGeert Uytterhoeven wake_up(&rspi->wait); 85893722206SGeert Uytterhoeven return IRQ_HANDLED; 85993722206SGeert Uytterhoeven } 86093722206SGeert Uytterhoeven 86193722206SGeert Uytterhoeven return 0; 86293722206SGeert Uytterhoeven } 86393722206SGeert Uytterhoeven 86465bf2205SGeert Uytterhoeven static struct dma_chan *rspi_request_dma_chan(struct device *dev, 86565bf2205SGeert Uytterhoeven enum dma_transfer_direction dir, 86665bf2205SGeert Uytterhoeven unsigned int id, 86765bf2205SGeert Uytterhoeven dma_addr_t port_addr) 86865bf2205SGeert Uytterhoeven { 86965bf2205SGeert Uytterhoeven dma_cap_mask_t mask; 87065bf2205SGeert Uytterhoeven struct dma_chan *chan; 87165bf2205SGeert Uytterhoeven struct dma_slave_config cfg; 87265bf2205SGeert Uytterhoeven int ret; 87365bf2205SGeert Uytterhoeven 87465bf2205SGeert Uytterhoeven dma_cap_zero(mask); 87565bf2205SGeert Uytterhoeven dma_cap_set(DMA_SLAVE, mask); 87665bf2205SGeert Uytterhoeven 87765bf2205SGeert Uytterhoeven chan = dma_request_channel(mask, shdma_chan_filter, 87865bf2205SGeert Uytterhoeven (void *)(unsigned long)id); 87965bf2205SGeert Uytterhoeven if (!chan) { 88065bf2205SGeert Uytterhoeven dev_warn(dev, "dma_request_channel failed\n"); 88165bf2205SGeert Uytterhoeven return NULL; 88265bf2205SGeert Uytterhoeven } 88365bf2205SGeert Uytterhoeven 88465bf2205SGeert Uytterhoeven memset(&cfg, 0, sizeof(cfg)); 88565bf2205SGeert Uytterhoeven cfg.slave_id = id; 88665bf2205SGeert Uytterhoeven cfg.direction = dir; 88765bf2205SGeert Uytterhoeven if (dir == DMA_MEM_TO_DEV) 88865bf2205SGeert Uytterhoeven cfg.dst_addr = port_addr; 88965bf2205SGeert Uytterhoeven else 89065bf2205SGeert Uytterhoeven cfg.src_addr = port_addr; 89165bf2205SGeert Uytterhoeven 89265bf2205SGeert Uytterhoeven ret = dmaengine_slave_config(chan, &cfg); 89365bf2205SGeert Uytterhoeven if (ret) { 89465bf2205SGeert Uytterhoeven dev_warn(dev, "dmaengine_slave_config failed %d\n", ret); 89565bf2205SGeert Uytterhoeven dma_release_channel(chan); 89665bf2205SGeert Uytterhoeven return NULL; 89765bf2205SGeert Uytterhoeven } 89865bf2205SGeert Uytterhoeven 89965bf2205SGeert Uytterhoeven return chan; 90065bf2205SGeert Uytterhoeven } 90165bf2205SGeert Uytterhoeven 9022f777ec9SGeert Uytterhoeven static int rspi_request_dma(struct device *dev, struct spi_master *master, 903fcdc49aeSGeert Uytterhoeven const struct resource *res) 904a3633fe7SShimoda, Yoshihiro { 905fcdc49aeSGeert Uytterhoeven const struct rspi_plat_data *rspi_pd = dev_get_platdata(dev); 906a3633fe7SShimoda, Yoshihiro 9075f338d0cSGeert Uytterhoeven if (!rspi_pd || !rspi_pd->dma_rx_id || !rspi_pd->dma_tx_id) 9080243c536SShimoda, Yoshihiro return 0; /* The driver assumes no error. */ 909a3633fe7SShimoda, Yoshihiro 9102f777ec9SGeert Uytterhoeven master->dma_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM, 91165bf2205SGeert Uytterhoeven rspi_pd->dma_rx_id, 91265bf2205SGeert Uytterhoeven res->start + RSPI_SPDR); 9132f777ec9SGeert Uytterhoeven if (!master->dma_rx) 91465bf2205SGeert Uytterhoeven return -ENODEV; 91565bf2205SGeert Uytterhoeven 9162f777ec9SGeert Uytterhoeven master->dma_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV, 91765bf2205SGeert Uytterhoeven rspi_pd->dma_tx_id, 91865bf2205SGeert Uytterhoeven res->start + RSPI_SPDR); 9192f777ec9SGeert Uytterhoeven if (!master->dma_tx) { 9202f777ec9SGeert Uytterhoeven dma_release_channel(master->dma_rx); 9212f777ec9SGeert Uytterhoeven master->dma_rx = NULL; 92265bf2205SGeert Uytterhoeven return -ENODEV; 923a3633fe7SShimoda, Yoshihiro } 924a3633fe7SShimoda, Yoshihiro 9252f777ec9SGeert Uytterhoeven master->can_dma = rspi_can_dma; 9265f338d0cSGeert Uytterhoeven dev_info(dev, "DMA available"); 9270243c536SShimoda, Yoshihiro return 0; 9280243c536SShimoda, Yoshihiro } 9290243c536SShimoda, Yoshihiro 930fd4a319bSGrant Likely static void rspi_release_dma(struct rspi_data *rspi) 931a3633fe7SShimoda, Yoshihiro { 9322f777ec9SGeert Uytterhoeven if (rspi->master->dma_tx) 9332f777ec9SGeert Uytterhoeven dma_release_channel(rspi->master->dma_tx); 9342f777ec9SGeert Uytterhoeven if (rspi->master->dma_rx) 9352f777ec9SGeert Uytterhoeven dma_release_channel(rspi->master->dma_rx); 936a3633fe7SShimoda, Yoshihiro } 937a3633fe7SShimoda, Yoshihiro 938fd4a319bSGrant Likely static int rspi_remove(struct platform_device *pdev) 9390b2182ddSShimoda, Yoshihiro { 9405ffbe2d9SLaurent Pinchart struct rspi_data *rspi = platform_get_drvdata(pdev); 9410b2182ddSShimoda, Yoshihiro 942a3633fe7SShimoda, Yoshihiro rspi_release_dma(rspi); 943490c9774SGeert Uytterhoeven pm_runtime_disable(&pdev->dev); 9440b2182ddSShimoda, Yoshihiro 9450b2182ddSShimoda, Yoshihiro return 0; 9460b2182ddSShimoda, Yoshihiro } 9470b2182ddSShimoda, Yoshihiro 948426ef76dSGeert Uytterhoeven static const struct spi_ops rspi_ops = { 949426ef76dSGeert Uytterhoeven .set_config_register = rspi_set_config_register, 950426ef76dSGeert Uytterhoeven .transfer_one = rspi_transfer_one, 951880c6d11SGeert Uytterhoeven .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, 952b42e0359SGeert Uytterhoeven .flags = SPI_MASTER_MUST_TX, 9532f777ec9SGeert Uytterhoeven .fifo_size = 8, 954426ef76dSGeert Uytterhoeven }; 955426ef76dSGeert Uytterhoeven 956426ef76dSGeert Uytterhoeven static const struct spi_ops rspi_rz_ops = { 957426ef76dSGeert Uytterhoeven .set_config_register = rspi_rz_set_config_register, 958426ef76dSGeert Uytterhoeven .transfer_one = rspi_rz_transfer_one, 959880c6d11SGeert Uytterhoeven .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, 960b42e0359SGeert Uytterhoeven .flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX, 9612f777ec9SGeert Uytterhoeven .fifo_size = 8, /* 8 for TX, 32 for RX */ 962426ef76dSGeert Uytterhoeven }; 963426ef76dSGeert Uytterhoeven 964426ef76dSGeert Uytterhoeven static const struct spi_ops qspi_ops = { 965426ef76dSGeert Uytterhoeven .set_config_register = qspi_set_config_register, 966426ef76dSGeert Uytterhoeven .transfer_one = qspi_transfer_one, 967880c6d11SGeert Uytterhoeven .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP | 968880c6d11SGeert Uytterhoeven SPI_TX_DUAL | SPI_TX_QUAD | 969880c6d11SGeert Uytterhoeven SPI_RX_DUAL | SPI_RX_QUAD, 970b42e0359SGeert Uytterhoeven .flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX, 9712f777ec9SGeert Uytterhoeven .fifo_size = 32, 972426ef76dSGeert Uytterhoeven }; 973426ef76dSGeert Uytterhoeven 974426ef76dSGeert Uytterhoeven #ifdef CONFIG_OF 975426ef76dSGeert Uytterhoeven static const struct of_device_id rspi_of_match[] = { 976426ef76dSGeert Uytterhoeven /* RSPI on legacy SH */ 977426ef76dSGeert Uytterhoeven { .compatible = "renesas,rspi", .data = &rspi_ops }, 978426ef76dSGeert Uytterhoeven /* RSPI on RZ/A1H */ 979426ef76dSGeert Uytterhoeven { .compatible = "renesas,rspi-rz", .data = &rspi_rz_ops }, 980426ef76dSGeert Uytterhoeven /* QSPI on R-Car Gen2 */ 981426ef76dSGeert Uytterhoeven { .compatible = "renesas,qspi", .data = &qspi_ops }, 982426ef76dSGeert Uytterhoeven { /* sentinel */ } 983426ef76dSGeert Uytterhoeven }; 984426ef76dSGeert Uytterhoeven 985426ef76dSGeert Uytterhoeven MODULE_DEVICE_TABLE(of, rspi_of_match); 986426ef76dSGeert Uytterhoeven 987426ef76dSGeert Uytterhoeven static int rspi_parse_dt(struct device *dev, struct spi_master *master) 988426ef76dSGeert Uytterhoeven { 989426ef76dSGeert Uytterhoeven u32 num_cs; 990426ef76dSGeert Uytterhoeven int error; 991426ef76dSGeert Uytterhoeven 992426ef76dSGeert Uytterhoeven /* Parse DT properties */ 993426ef76dSGeert Uytterhoeven error = of_property_read_u32(dev->of_node, "num-cs", &num_cs); 994426ef76dSGeert Uytterhoeven if (error) { 995426ef76dSGeert Uytterhoeven dev_err(dev, "of_property_read_u32 num-cs failed %d\n", error); 996426ef76dSGeert Uytterhoeven return error; 997426ef76dSGeert Uytterhoeven } 998426ef76dSGeert Uytterhoeven 999426ef76dSGeert Uytterhoeven master->num_chipselect = num_cs; 1000426ef76dSGeert Uytterhoeven return 0; 1001426ef76dSGeert Uytterhoeven } 1002426ef76dSGeert Uytterhoeven #else 100364b67defSShimoda, Yoshihiro #define rspi_of_match NULL 1004426ef76dSGeert Uytterhoeven static inline int rspi_parse_dt(struct device *dev, struct spi_master *master) 1005426ef76dSGeert Uytterhoeven { 1006426ef76dSGeert Uytterhoeven return -EINVAL; 1007426ef76dSGeert Uytterhoeven } 1008426ef76dSGeert Uytterhoeven #endif /* CONFIG_OF */ 1009426ef76dSGeert Uytterhoeven 101093722206SGeert Uytterhoeven static int rspi_request_irq(struct device *dev, unsigned int irq, 101193722206SGeert Uytterhoeven irq_handler_t handler, const char *suffix, 101293722206SGeert Uytterhoeven void *dev_id) 101393722206SGeert Uytterhoeven { 101493722206SGeert Uytterhoeven const char *base = dev_name(dev); 101593722206SGeert Uytterhoeven size_t len = strlen(base) + strlen(suffix) + 2; 101693722206SGeert Uytterhoeven char *name = devm_kzalloc(dev, len, GFP_KERNEL); 101793722206SGeert Uytterhoeven if (!name) 101893722206SGeert Uytterhoeven return -ENOMEM; 101993722206SGeert Uytterhoeven snprintf(name, len, "%s:%s", base, suffix); 102093722206SGeert Uytterhoeven return devm_request_irq(dev, irq, handler, 0, name, dev_id); 102193722206SGeert Uytterhoeven } 102293722206SGeert Uytterhoeven 1023fd4a319bSGrant Likely static int rspi_probe(struct platform_device *pdev) 10240b2182ddSShimoda, Yoshihiro { 10250b2182ddSShimoda, Yoshihiro struct resource *res; 10260b2182ddSShimoda, Yoshihiro struct spi_master *master; 10270b2182ddSShimoda, Yoshihiro struct rspi_data *rspi; 102893722206SGeert Uytterhoeven int ret; 1029426ef76dSGeert Uytterhoeven const struct of_device_id *of_id; 1030426ef76dSGeert Uytterhoeven const struct rspi_plat_data *rspi_pd; 10315ce0ba88SHiep Cao Minh const struct spi_ops *ops; 10320b2182ddSShimoda, Yoshihiro 10330b2182ddSShimoda, Yoshihiro master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data)); 10340b2182ddSShimoda, Yoshihiro if (master == NULL) { 10350b2182ddSShimoda, Yoshihiro dev_err(&pdev->dev, "spi_alloc_master error.\n"); 10360b2182ddSShimoda, Yoshihiro return -ENOMEM; 10370b2182ddSShimoda, Yoshihiro } 10380b2182ddSShimoda, Yoshihiro 1039426ef76dSGeert Uytterhoeven of_id = of_match_device(rspi_of_match, &pdev->dev); 1040426ef76dSGeert Uytterhoeven if (of_id) { 1041426ef76dSGeert Uytterhoeven ops = of_id->data; 1042426ef76dSGeert Uytterhoeven ret = rspi_parse_dt(&pdev->dev, master); 1043426ef76dSGeert Uytterhoeven if (ret) 1044426ef76dSGeert Uytterhoeven goto error1; 1045426ef76dSGeert Uytterhoeven } else { 1046426ef76dSGeert Uytterhoeven ops = (struct spi_ops *)pdev->id_entry->driver_data; 1047426ef76dSGeert Uytterhoeven rspi_pd = dev_get_platdata(&pdev->dev); 1048426ef76dSGeert Uytterhoeven if (rspi_pd && rspi_pd->num_chipselect) 1049426ef76dSGeert Uytterhoeven master->num_chipselect = rspi_pd->num_chipselect; 1050426ef76dSGeert Uytterhoeven else 1051426ef76dSGeert Uytterhoeven master->num_chipselect = 2; /* default */ 1052426ef76dSGeert Uytterhoeven }; 1053426ef76dSGeert Uytterhoeven 1054426ef76dSGeert Uytterhoeven /* ops parameter check */ 1055426ef76dSGeert Uytterhoeven if (!ops->set_config_register) { 1056426ef76dSGeert Uytterhoeven dev_err(&pdev->dev, "there is no set_config_register\n"); 1057426ef76dSGeert Uytterhoeven ret = -ENODEV; 1058426ef76dSGeert Uytterhoeven goto error1; 1059426ef76dSGeert Uytterhoeven } 1060426ef76dSGeert Uytterhoeven 10610b2182ddSShimoda, Yoshihiro rspi = spi_master_get_devdata(master); 106224b5a82cSJingoo Han platform_set_drvdata(pdev, rspi); 10635ce0ba88SHiep Cao Minh rspi->ops = ops; 10640b2182ddSShimoda, Yoshihiro rspi->master = master; 10655d79e9acSLaurent Pinchart 10665d79e9acSLaurent Pinchart res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 10675d79e9acSLaurent Pinchart rspi->addr = devm_ioremap_resource(&pdev->dev, res); 10685d79e9acSLaurent Pinchart if (IS_ERR(rspi->addr)) { 10695d79e9acSLaurent Pinchart ret = PTR_ERR(rspi->addr); 10700b2182ddSShimoda, Yoshihiro goto error1; 10710b2182ddSShimoda, Yoshihiro } 10720b2182ddSShimoda, Yoshihiro 107329f397b7SGeert Uytterhoeven rspi->clk = devm_clk_get(&pdev->dev, NULL); 10740b2182ddSShimoda, Yoshihiro if (IS_ERR(rspi->clk)) { 10750b2182ddSShimoda, Yoshihiro dev_err(&pdev->dev, "cannot get clock\n"); 10760b2182ddSShimoda, Yoshihiro ret = PTR_ERR(rspi->clk); 10775d79e9acSLaurent Pinchart goto error1; 10780b2182ddSShimoda, Yoshihiro } 107917fe0d9aSGeert Uytterhoeven 1080490c9774SGeert Uytterhoeven pm_runtime_enable(&pdev->dev); 10810b2182ddSShimoda, Yoshihiro 10820b2182ddSShimoda, Yoshihiro init_waitqueue_head(&rspi->wait); 10830b2182ddSShimoda, Yoshihiro 10840b2182ddSShimoda, Yoshihiro master->bus_num = pdev->id; 10850b2182ddSShimoda, Yoshihiro master->setup = rspi_setup; 1086490c9774SGeert Uytterhoeven master->auto_runtime_pm = true; 1087eb557f75SGeert Uytterhoeven master->transfer_one = ops->transfer_one; 108879d23495SGeert Uytterhoeven master->prepare_message = rspi_prepare_message; 108979d23495SGeert Uytterhoeven master->unprepare_message = rspi_unprepare_message; 1090880c6d11SGeert Uytterhoeven master->mode_bits = ops->mode_bits; 1091b42e0359SGeert Uytterhoeven master->flags = ops->flags; 1092426ef76dSGeert Uytterhoeven master->dev.of_node = pdev->dev.of_node; 10930b2182ddSShimoda, Yoshihiro 109493722206SGeert Uytterhoeven ret = platform_get_irq_byname(pdev, "rx"); 109593722206SGeert Uytterhoeven if (ret < 0) { 109693722206SGeert Uytterhoeven ret = platform_get_irq_byname(pdev, "mux"); 109793722206SGeert Uytterhoeven if (ret < 0) 109893722206SGeert Uytterhoeven ret = platform_get_irq(pdev, 0); 109993722206SGeert Uytterhoeven if (ret >= 0) 110093722206SGeert Uytterhoeven rspi->rx_irq = rspi->tx_irq = ret; 110193722206SGeert Uytterhoeven } else { 110293722206SGeert Uytterhoeven rspi->rx_irq = ret; 110393722206SGeert Uytterhoeven ret = platform_get_irq_byname(pdev, "tx"); 110493722206SGeert Uytterhoeven if (ret >= 0) 110593722206SGeert Uytterhoeven rspi->tx_irq = ret; 110693722206SGeert Uytterhoeven } 110793722206SGeert Uytterhoeven if (ret < 0) { 110893722206SGeert Uytterhoeven dev_err(&pdev->dev, "platform_get_irq error\n"); 110993722206SGeert Uytterhoeven goto error2; 111093722206SGeert Uytterhoeven } 111193722206SGeert Uytterhoeven 111293722206SGeert Uytterhoeven if (rspi->rx_irq == rspi->tx_irq) { 111393722206SGeert Uytterhoeven /* Single multiplexed interrupt */ 111493722206SGeert Uytterhoeven ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_mux, 111593722206SGeert Uytterhoeven "mux", rspi); 111693722206SGeert Uytterhoeven } else { 111793722206SGeert Uytterhoeven /* Multi-interrupt mode, only SPRI and SPTI are used */ 111893722206SGeert Uytterhoeven ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_rx, 111993722206SGeert Uytterhoeven "rx", rspi); 112093722206SGeert Uytterhoeven if (!ret) 112193722206SGeert Uytterhoeven ret = rspi_request_irq(&pdev->dev, rspi->tx_irq, 112293722206SGeert Uytterhoeven rspi_irq_tx, "tx", rspi); 112393722206SGeert Uytterhoeven } 11240b2182ddSShimoda, Yoshihiro if (ret < 0) { 11250b2182ddSShimoda, Yoshihiro dev_err(&pdev->dev, "request_irq error\n"); 1126fcb4ed74SGeert Uytterhoeven goto error2; 11270b2182ddSShimoda, Yoshihiro } 11280b2182ddSShimoda, Yoshihiro 11292f777ec9SGeert Uytterhoeven ret = rspi_request_dma(&pdev->dev, master, res); 113027e105a6SGeert Uytterhoeven if (ret < 0) 113127e105a6SGeert Uytterhoeven dev_warn(&pdev->dev, "DMA not available, using PIO\n"); 1132a3633fe7SShimoda, Yoshihiro 11339e03d05eSJingoo Han ret = devm_spi_register_master(&pdev->dev, master); 11340b2182ddSShimoda, Yoshihiro if (ret < 0) { 11350b2182ddSShimoda, Yoshihiro dev_err(&pdev->dev, "spi_register_master error.\n"); 1136fcb4ed74SGeert Uytterhoeven goto error3; 11370b2182ddSShimoda, Yoshihiro } 11380b2182ddSShimoda, Yoshihiro 11390b2182ddSShimoda, Yoshihiro dev_info(&pdev->dev, "probed\n"); 11400b2182ddSShimoda, Yoshihiro 11410b2182ddSShimoda, Yoshihiro return 0; 11420b2182ddSShimoda, Yoshihiro 1143fcb4ed74SGeert Uytterhoeven error3: 11445d79e9acSLaurent Pinchart rspi_release_dma(rspi); 1145fcb4ed74SGeert Uytterhoeven error2: 1146490c9774SGeert Uytterhoeven pm_runtime_disable(&pdev->dev); 11470b2182ddSShimoda, Yoshihiro error1: 11480b2182ddSShimoda, Yoshihiro spi_master_put(master); 11490b2182ddSShimoda, Yoshihiro 11500b2182ddSShimoda, Yoshihiro return ret; 11510b2182ddSShimoda, Yoshihiro } 11520b2182ddSShimoda, Yoshihiro 11535ce0ba88SHiep Cao Minh static struct platform_device_id spi_driver_ids[] = { 11545ce0ba88SHiep Cao Minh { "rspi", (kernel_ulong_t)&rspi_ops }, 1155862d357fSGeert Uytterhoeven { "rspi-rz", (kernel_ulong_t)&rspi_rz_ops }, 11565ce0ba88SHiep Cao Minh { "qspi", (kernel_ulong_t)&qspi_ops }, 11575ce0ba88SHiep Cao Minh {}, 11585ce0ba88SHiep Cao Minh }; 11595ce0ba88SHiep Cao Minh 11605ce0ba88SHiep Cao Minh MODULE_DEVICE_TABLE(platform, spi_driver_ids); 11615ce0ba88SHiep Cao Minh 11620b2182ddSShimoda, Yoshihiro static struct platform_driver rspi_driver = { 11630b2182ddSShimoda, Yoshihiro .probe = rspi_probe, 1164fd4a319bSGrant Likely .remove = rspi_remove, 11655ce0ba88SHiep Cao Minh .id_table = spi_driver_ids, 11660b2182ddSShimoda, Yoshihiro .driver = { 11675ce0ba88SHiep Cao Minh .name = "renesas_spi", 11680b2182ddSShimoda, Yoshihiro .owner = THIS_MODULE, 1169426ef76dSGeert Uytterhoeven .of_match_table = of_match_ptr(rspi_of_match), 11700b2182ddSShimoda, Yoshihiro }, 11710b2182ddSShimoda, Yoshihiro }; 11720b2182ddSShimoda, Yoshihiro module_platform_driver(rspi_driver); 11730b2182ddSShimoda, Yoshihiro 11740b2182ddSShimoda, Yoshihiro MODULE_DESCRIPTION("Renesas RSPI bus driver"); 11750b2182ddSShimoda, Yoshihiro MODULE_LICENSE("GPL v2"); 11760b2182ddSShimoda, Yoshihiro MODULE_AUTHOR("Yoshihiro Shimoda"); 11770b2182ddSShimoda, Yoshihiro MODULE_ALIAS("platform:rspi"); 1178