18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef DW_SPI_HEADER_H 38c2ecf20Sopenharmony_ci#define DW_SPI_HEADER_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/bits.h> 68c2ecf20Sopenharmony_ci#include <linux/completion.h> 78c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 88c2ecf20Sopenharmony_ci#include <linux/irqreturn.h> 98c2ecf20Sopenharmony_ci#include <linux/io.h> 108c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 118c2ecf20Sopenharmony_ci#include <linux/spi/spi-mem.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* Register offsets */ 148c2ecf20Sopenharmony_ci#define DW_SPI_CTRLR0 0x00 158c2ecf20Sopenharmony_ci#define DW_SPI_CTRLR1 0x04 168c2ecf20Sopenharmony_ci#define DW_SPI_SSIENR 0x08 178c2ecf20Sopenharmony_ci#define DW_SPI_MWCR 0x0c 188c2ecf20Sopenharmony_ci#define DW_SPI_SER 0x10 198c2ecf20Sopenharmony_ci#define DW_SPI_BAUDR 0x14 208c2ecf20Sopenharmony_ci#define DW_SPI_TXFTLR 0x18 218c2ecf20Sopenharmony_ci#define DW_SPI_RXFTLR 0x1c 228c2ecf20Sopenharmony_ci#define DW_SPI_TXFLR 0x20 238c2ecf20Sopenharmony_ci#define DW_SPI_RXFLR 0x24 248c2ecf20Sopenharmony_ci#define DW_SPI_SR 0x28 258c2ecf20Sopenharmony_ci#define DW_SPI_IMR 0x2c 268c2ecf20Sopenharmony_ci#define DW_SPI_ISR 0x30 278c2ecf20Sopenharmony_ci#define DW_SPI_RISR 0x34 288c2ecf20Sopenharmony_ci#define DW_SPI_TXOICR 0x38 298c2ecf20Sopenharmony_ci#define DW_SPI_RXOICR 0x3c 308c2ecf20Sopenharmony_ci#define DW_SPI_RXUICR 0x40 318c2ecf20Sopenharmony_ci#define DW_SPI_MSTICR 0x44 328c2ecf20Sopenharmony_ci#define DW_SPI_ICR 0x48 338c2ecf20Sopenharmony_ci#define DW_SPI_DMACR 0x4c 348c2ecf20Sopenharmony_ci#define DW_SPI_DMATDLR 0x50 358c2ecf20Sopenharmony_ci#define DW_SPI_DMARDLR 0x54 368c2ecf20Sopenharmony_ci#define DW_SPI_IDR 0x58 378c2ecf20Sopenharmony_ci#define DW_SPI_VERSION 0x5c 388c2ecf20Sopenharmony_ci#define DW_SPI_DR 0x60 398c2ecf20Sopenharmony_ci#define DW_SPI_RX_SAMPLE_DLY 0xf0 408c2ecf20Sopenharmony_ci#define DW_SPI_CS_OVERRIDE 0xf4 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Bit fields in CTRLR0 */ 438c2ecf20Sopenharmony_ci#define SPI_DFS_OFFSET 0 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define SPI_FRF_OFFSET 4 468c2ecf20Sopenharmony_ci#define SPI_FRF_SPI 0x0 478c2ecf20Sopenharmony_ci#define SPI_FRF_SSP 0x1 488c2ecf20Sopenharmony_ci#define SPI_FRF_MICROWIRE 0x2 498c2ecf20Sopenharmony_ci#define SPI_FRF_RESV 0x3 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define SPI_MODE_OFFSET 6 528c2ecf20Sopenharmony_ci#define SPI_SCPH_OFFSET 6 538c2ecf20Sopenharmony_ci#define SPI_SCOL_OFFSET 7 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define SPI_TMOD_OFFSET 8 568c2ecf20Sopenharmony_ci#define SPI_TMOD_MASK (0x3 << SPI_TMOD_OFFSET) 578c2ecf20Sopenharmony_ci#define SPI_TMOD_TR 0x0 /* xmit & recv */ 588c2ecf20Sopenharmony_ci#define SPI_TMOD_TO 0x1 /* xmit only */ 598c2ecf20Sopenharmony_ci#define SPI_TMOD_RO 0x2 /* recv only */ 608c2ecf20Sopenharmony_ci#define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */ 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define SPI_SLVOE_OFFSET 10 638c2ecf20Sopenharmony_ci#define SPI_SRL_OFFSET 11 648c2ecf20Sopenharmony_ci#define SPI_CFS_OFFSET 12 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* Bit fields in CTRLR0 based on DWC_ssi_databook.pdf v1.01a */ 678c2ecf20Sopenharmony_ci#define DWC_SSI_CTRLR0_SRL_OFFSET 13 688c2ecf20Sopenharmony_ci#define DWC_SSI_CTRLR0_TMOD_OFFSET 10 698c2ecf20Sopenharmony_ci#define DWC_SSI_CTRLR0_TMOD_MASK GENMASK(11, 10) 708c2ecf20Sopenharmony_ci#define DWC_SSI_CTRLR0_SCPOL_OFFSET 9 718c2ecf20Sopenharmony_ci#define DWC_SSI_CTRLR0_SCPH_OFFSET 8 728c2ecf20Sopenharmony_ci#define DWC_SSI_CTRLR0_FRF_OFFSET 6 738c2ecf20Sopenharmony_ci#define DWC_SSI_CTRLR0_DFS_OFFSET 0 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* 768c2ecf20Sopenharmony_ci * For Keem Bay, CTRLR0[31] is used to select controller mode. 778c2ecf20Sopenharmony_ci * 0: SSI is slave 788c2ecf20Sopenharmony_ci * 1: SSI is master 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci#define DWC_SSI_CTRLR0_KEEMBAY_MST BIT(31) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* Bit fields in CTRLR1 */ 838c2ecf20Sopenharmony_ci#define SPI_NDF_MASK GENMASK(15, 0) 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* Bit fields in SR, 7 bits */ 868c2ecf20Sopenharmony_ci#define SR_MASK 0x7f /* cover 7 bits */ 878c2ecf20Sopenharmony_ci#define SR_BUSY (1 << 0) 888c2ecf20Sopenharmony_ci#define SR_TF_NOT_FULL (1 << 1) 898c2ecf20Sopenharmony_ci#define SR_TF_EMPT (1 << 2) 908c2ecf20Sopenharmony_ci#define SR_RF_NOT_EMPT (1 << 3) 918c2ecf20Sopenharmony_ci#define SR_RF_FULL (1 << 4) 928c2ecf20Sopenharmony_ci#define SR_TX_ERR (1 << 5) 938c2ecf20Sopenharmony_ci#define SR_DCOL (1 << 6) 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/* Bit fields in ISR, IMR, RISR, 7 bits */ 968c2ecf20Sopenharmony_ci#define SPI_INT_TXEI (1 << 0) 978c2ecf20Sopenharmony_ci#define SPI_INT_TXOI (1 << 1) 988c2ecf20Sopenharmony_ci#define SPI_INT_RXUI (1 << 2) 998c2ecf20Sopenharmony_ci#define SPI_INT_RXOI (1 << 3) 1008c2ecf20Sopenharmony_ci#define SPI_INT_RXFI (1 << 4) 1018c2ecf20Sopenharmony_ci#define SPI_INT_MSTI (1 << 5) 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* Bit fields in DMACR */ 1048c2ecf20Sopenharmony_ci#define SPI_DMA_RDMAE (1 << 0) 1058c2ecf20Sopenharmony_ci#define SPI_DMA_TDMAE (1 << 1) 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci#define SPI_WAIT_RETRIES 5 1088c2ecf20Sopenharmony_ci#define SPI_BUF_SIZE \ 1098c2ecf20Sopenharmony_ci (sizeof_field(struct spi_mem_op, cmd.opcode) + \ 1108c2ecf20Sopenharmony_ci sizeof_field(struct spi_mem_op, addr.val) + 256) 1118c2ecf20Sopenharmony_ci#define SPI_GET_BYTE(_val, _idx) \ 1128c2ecf20Sopenharmony_ci ((_val) >> (BITS_PER_BYTE * (_idx)) & 0xff) 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cienum dw_ssi_type { 1158c2ecf20Sopenharmony_ci SSI_MOTO_SPI = 0, 1168c2ecf20Sopenharmony_ci SSI_TI_SSP, 1178c2ecf20Sopenharmony_ci SSI_NS_MICROWIRE, 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* DW SPI capabilities */ 1218c2ecf20Sopenharmony_ci#define DW_SPI_CAP_CS_OVERRIDE BIT(0) 1228c2ecf20Sopenharmony_ci#define DW_SPI_CAP_KEEMBAY_MST BIT(1) 1238c2ecf20Sopenharmony_ci#define DW_SPI_CAP_DWC_SSI BIT(2) 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/* Slave spi_transfer/spi_mem_op related */ 1268c2ecf20Sopenharmony_cistruct dw_spi_cfg { 1278c2ecf20Sopenharmony_ci u8 tmode; 1288c2ecf20Sopenharmony_ci u8 dfs; 1298c2ecf20Sopenharmony_ci u32 ndf; 1308c2ecf20Sopenharmony_ci u32 freq; 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistruct dw_spi; 1348c2ecf20Sopenharmony_cistruct dw_spi_dma_ops { 1358c2ecf20Sopenharmony_ci int (*dma_init)(struct device *dev, struct dw_spi *dws); 1368c2ecf20Sopenharmony_ci void (*dma_exit)(struct dw_spi *dws); 1378c2ecf20Sopenharmony_ci int (*dma_setup)(struct dw_spi *dws, struct spi_transfer *xfer); 1388c2ecf20Sopenharmony_ci bool (*can_dma)(struct spi_controller *master, struct spi_device *spi, 1398c2ecf20Sopenharmony_ci struct spi_transfer *xfer); 1408c2ecf20Sopenharmony_ci int (*dma_transfer)(struct dw_spi *dws, struct spi_transfer *xfer); 1418c2ecf20Sopenharmony_ci void (*dma_stop)(struct dw_spi *dws); 1428c2ecf20Sopenharmony_ci}; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistruct dw_spi { 1458c2ecf20Sopenharmony_ci struct spi_controller *master; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci void __iomem *regs; 1488c2ecf20Sopenharmony_ci unsigned long paddr; 1498c2ecf20Sopenharmony_ci int irq; 1508c2ecf20Sopenharmony_ci u32 fifo_len; /* depth of the FIFO buffer */ 1518c2ecf20Sopenharmony_ci u32 max_mem_freq; /* max mem-ops bus freq */ 1528c2ecf20Sopenharmony_ci u32 max_freq; /* max bus freq supported */ 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci u32 caps; /* DW SPI capabilities */ 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci u32 reg_io_width; /* DR I/O width in bytes */ 1578c2ecf20Sopenharmony_ci u16 bus_num; 1588c2ecf20Sopenharmony_ci u16 num_cs; /* supported slave numbers */ 1598c2ecf20Sopenharmony_ci void (*set_cs)(struct spi_device *spi, bool enable); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* Current message transfer state info */ 1628c2ecf20Sopenharmony_ci void *tx; 1638c2ecf20Sopenharmony_ci unsigned int tx_len; 1648c2ecf20Sopenharmony_ci void *rx; 1658c2ecf20Sopenharmony_ci unsigned int rx_len; 1668c2ecf20Sopenharmony_ci u8 buf[SPI_BUF_SIZE]; 1678c2ecf20Sopenharmony_ci int dma_mapped; 1688c2ecf20Sopenharmony_ci u8 n_bytes; /* current is a 1/2 bytes op */ 1698c2ecf20Sopenharmony_ci irqreturn_t (*transfer_handler)(struct dw_spi *dws); 1708c2ecf20Sopenharmony_ci u32 current_freq; /* frequency in hz */ 1718c2ecf20Sopenharmony_ci u32 cur_rx_sample_dly; 1728c2ecf20Sopenharmony_ci u32 def_rx_sample_dly_ns; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* Custom memory operations */ 1758c2ecf20Sopenharmony_ci struct spi_controller_mem_ops mem_ops; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* DMA info */ 1788c2ecf20Sopenharmony_ci struct dma_chan *txchan; 1798c2ecf20Sopenharmony_ci u32 txburst; 1808c2ecf20Sopenharmony_ci struct dma_chan *rxchan; 1818c2ecf20Sopenharmony_ci u32 rxburst; 1828c2ecf20Sopenharmony_ci u32 dma_sg_burst; 1838c2ecf20Sopenharmony_ci unsigned long dma_chan_busy; 1848c2ecf20Sopenharmony_ci dma_addr_t dma_addr; /* phy address of the Data register */ 1858c2ecf20Sopenharmony_ci const struct dw_spi_dma_ops *dma_ops; 1868c2ecf20Sopenharmony_ci struct completion dma_completion; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 1898c2ecf20Sopenharmony_ci struct dentry *debugfs; 1908c2ecf20Sopenharmony_ci struct debugfs_regset32 regset; 1918c2ecf20Sopenharmony_ci#endif 1928c2ecf20Sopenharmony_ci}; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic inline u32 dw_readl(struct dw_spi *dws, u32 offset) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci return __raw_readl(dws->regs + offset); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic inline void dw_writel(struct dw_spi *dws, u32 offset, u32 val) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci __raw_writel(val, dws->regs + offset); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic inline u32 dw_read_io_reg(struct dw_spi *dws, u32 offset) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci switch (dws->reg_io_width) { 2078c2ecf20Sopenharmony_ci case 2: 2088c2ecf20Sopenharmony_ci return readw_relaxed(dws->regs + offset); 2098c2ecf20Sopenharmony_ci case 4: 2108c2ecf20Sopenharmony_ci default: 2118c2ecf20Sopenharmony_ci return readl_relaxed(dws->regs + offset); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic inline void dw_write_io_reg(struct dw_spi *dws, u32 offset, u32 val) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci switch (dws->reg_io_width) { 2188c2ecf20Sopenharmony_ci case 2: 2198c2ecf20Sopenharmony_ci writew_relaxed(val, dws->regs + offset); 2208c2ecf20Sopenharmony_ci break; 2218c2ecf20Sopenharmony_ci case 4: 2228c2ecf20Sopenharmony_ci default: 2238c2ecf20Sopenharmony_ci writel_relaxed(val, dws->regs + offset); 2248c2ecf20Sopenharmony_ci break; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic inline void spi_enable_chip(struct dw_spi *dws, int enable) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0)); 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic inline void spi_set_clk(struct dw_spi *dws, u16 div) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci dw_writel(dws, DW_SPI_BAUDR, div); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci/* Disable IRQ bits */ 2398c2ecf20Sopenharmony_cistatic inline void spi_mask_intr(struct dw_spi *dws, u32 mask) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci u32 new_mask; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci new_mask = dw_readl(dws, DW_SPI_IMR) & ~mask; 2448c2ecf20Sopenharmony_ci dw_writel(dws, DW_SPI_IMR, new_mask); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci/* Enable IRQ bits */ 2488c2ecf20Sopenharmony_cistatic inline void spi_umask_intr(struct dw_spi *dws, u32 mask) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci u32 new_mask; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci new_mask = dw_readl(dws, DW_SPI_IMR) | mask; 2538c2ecf20Sopenharmony_ci dw_writel(dws, DW_SPI_IMR, new_mask); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/* 2578c2ecf20Sopenharmony_ci * This disables the SPI controller, interrupts, clears the interrupts status 2588c2ecf20Sopenharmony_ci * and CS, then re-enables the controller back. Transmit and receive FIFO 2598c2ecf20Sopenharmony_ci * buffers are cleared when the device is disabled. 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_cistatic inline void spi_reset_chip(struct dw_spi *dws) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci spi_enable_chip(dws, 0); 2648c2ecf20Sopenharmony_ci spi_mask_intr(dws, 0xff); 2658c2ecf20Sopenharmony_ci dw_readl(dws, DW_SPI_ICR); 2668c2ecf20Sopenharmony_ci dw_writel(dws, DW_SPI_SER, 0); 2678c2ecf20Sopenharmony_ci spi_enable_chip(dws, 1); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic inline void spi_shutdown_chip(struct dw_spi *dws) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci spi_enable_chip(dws, 0); 2738c2ecf20Sopenharmony_ci spi_set_clk(dws, 0); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ciextern void dw_spi_set_cs(struct spi_device *spi, bool enable); 2778c2ecf20Sopenharmony_ciextern void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi, 2788c2ecf20Sopenharmony_ci struct dw_spi_cfg *cfg); 2798c2ecf20Sopenharmony_ciextern int dw_spi_check_status(struct dw_spi *dws, bool raw); 2808c2ecf20Sopenharmony_ciextern int dw_spi_add_host(struct device *dev, struct dw_spi *dws); 2818c2ecf20Sopenharmony_ciextern void dw_spi_remove_host(struct dw_spi *dws); 2828c2ecf20Sopenharmony_ciextern int dw_spi_suspend_host(struct dw_spi *dws); 2838c2ecf20Sopenharmony_ciextern int dw_spi_resume_host(struct dw_spi *dws); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci#ifdef CONFIG_SPI_DW_DMA 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ciextern void dw_spi_dma_setup_mfld(struct dw_spi *dws); 2888c2ecf20Sopenharmony_ciextern void dw_spi_dma_setup_generic(struct dw_spi *dws); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci#else 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic inline void dw_spi_dma_setup_mfld(struct dw_spi *dws) {} 2938c2ecf20Sopenharmony_cistatic inline void dw_spi_dma_setup_generic(struct dw_spi *dws) {} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci#endif /* !CONFIG_SPI_DW_DMA */ 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci#endif /* DW_SPI_HEADER_H */ 298