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