| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Support for asr spi controller |
| * |
| * Copyright (C) 2019 ASR Micro Limited |
| * |
| * Tim Wang <timwang@asrmicro.com> |
| */ |
| |
| #ifndef _SPI_ASR_H |
| #define _SPI_ASR_H |
| |
| #include <linux/atomic.h> |
| #include <linux/dmaengine.h> |
| #include <linux/errno.h> |
| #include <linux/io.h> |
| #include <linux/interrupt.h> |
| #include <linux/platform_device.h> |
| #include <linux/scatterlist.h> |
| #include <linux/sizes.h> |
| #include <linux/spi/spi.h> |
| #include <linux/pm_qos.h> |
| #include <linux/list.h> |
| #include <linux/io.h> |
| #include <linux/of.h> |
| #include <linux/spi/spi-mem.h> |
| |
| /* ASR 180x/190x SPI Registers */ |
| #define TOP_CTRL 0x00 /* SSP Top Control Register */ |
| #define FIFO_CTRL 0x04 /* SSP FIFO Control Register */ |
| #define INT_EN 0x08 /* SSP Interrupt Enable Register */ |
| #define TO 0x0C /* SSP Time Out Register */ |
| #define DATAR 0x10 /* SSP Data Register */ |
| #define STATUS 0x14 /* SSP Stauts Register */ |
| #define PSP_CTRL 0x18 /* SSP Programmable Serial Protocal Control Register */ |
| #define NET_WORK_CTRL 0x1C /* SSP NET Work Control Register */ |
| #define NET_WORK_STATUS 0x20 /* SSP Net Work Status Register */ |
| #define RWOT_CTRL 0x24 /* SSP RWOT Control Register */ |
| #define RWOT_CCM 0x28 /* SSP RWOT Counter Cycles Match Register */ |
| #define RWOT_CVWRn 0x2C /* SSP RWOT Counter Value Write for Read Request Register */ |
| #define MISC_CTRL 0x30 |
| |
| /* 0x00 TOP_CTRL */ |
| #define TOP_TTELP (1 << 18) |
| #define TOP_TTE (1 << 17) |
| #define TOP_SCFR (1 << 16) |
| #define TOP_IFS (1 << 15) |
| #define TOP_HOLD_FRAME_LOW (1 << 14) |
| #define TOP_TRAIL (1 << 13) |
| #define TOP_LBM (1 << 12) |
| #define TOP_SPH (1 << 11) |
| #define TOP_SPO (1 << 10) |
| #define TOP_DSS(x) ((x - 1) << 5) |
| #define TOP_DSS_MASK (0x1F << 5) |
| #define TOP_SFRMDIR (1 << 4) |
| #define TOP_SCLKDIR (1 << 3) |
| #define TOP_FRF_MASK (0x3 << 1) |
| #define TOP_FRF_Motorola (0x0 << 1) /* Motorola's Serial Peripheral Interface (SPI) */ |
| #define TOP_FRF_TI (0x1 << 1) /* Texas Instruments' Synchronous Serial Protocol (SSP) */ |
| #define TOP_FRF_National (0x2 << 1) /* National Microwire */ |
| #define TOP_FRF_PSP (0x3 << 1) /* Programmable Serial Protocol(PSP) */ |
| #define TOP_SSE (1 << 0) |
| |
| /* 0x04 FIFO_CTRL */ |
| #define FIFO_STRF (1 << 19) |
| #define FIFO_EFWR (1 << 18) |
| #define FIFO_RXFIFO_AUTO_FULL_CTRL (1 << 17) |
| #define FIFO_FPCKE (1 << 16) |
| #define FIFO_TXFIFO_WR_ENDIAN_MASK (0x3 << 14) |
| #define FIFO_RXFIFO_RD_ENDIAN_MASK (0x3 << 12) |
| #define FIFO_WR_ENDIAN_16BITS (1 << 14) /* Swap first 16 bits and last 16 bits */ |
| #define FIFO_WR_ENDIAN_8BITS (2 << 14) /* Swap all 4 bytes */ |
| #define FIFO_RD_ENDIAN_16BITS (1 << 12) /* Swap first 16 bits and last 16 bits */ |
| #define FIFO_RD_ENDIAN_8BITS (2 << 12) /* Swap all 4 bytes */ |
| #define FIFO_RSRE (1 << 11) |
| #define FIFO_TSRE (1 << 10) |
| |
| /* 0x08 INT_EN */ |
| #define INT_EN_EBCEI (1 << 6) |
| #define INT_EN_TIM (1 << 5) |
| #define INT_EN_RIM (1 << 4) |
| #define INT_EN_TIE (1 << 3) |
| #define INT_EN_RIE (1 << 2) |
| #define INT_EN_TINTE (1 << 1) |
| #define INT_EN_PINTE (1 << 0) |
| |
| /* 0x0C TO */ |
| #define TIMEOUT(x) ((x) << 0) |
| |
| /* 0x10 DATAR */ |
| #define DATA(x) ((x) << 0) |
| |
| /* 0x14 STATUS */ |
| #define STATUS_OSS (1 << 23) |
| #define STATUS_TX_OSS (1 << 22) |
| #define STATUS_BCE (1 << 21) |
| #define STATUS_ROR (1 << 20) |
| #define STATUS_RNE (1 << 14) |
| #define STATUS_RFS (1 << 13) |
| #define STATUS_TUR (1 << 12) |
| #define STATUS_TNF (1 << 6) |
| #define STATUS_TFS (1 << 5) |
| #define STATUS_EOC (1 << 4) |
| #define STATUS_TINT (1 << 3) |
| #define STATUS_PINT (1 << 2) |
| #define STATUS_CSS (1 << 1) |
| #define STATUS_BSY (1 << 0) |
| |
| /* 0x18 PSP_CTRL */ |
| #define PSP_EDMYSTOP(x) ((x) << 27) |
| #define PSP_EMYSTOP(x) ((x) << 25) |
| #define PSP_EDMYSTRT(x) ((x) << 23) |
| #define PSP_DMYSTRT(x) ((x) << 21) |
| #define PSP_STRTDLY(x) ((x) << 18) |
| #define PSP_SFRMWDTH(x) ((x) << 12) |
| #define PSP_SFRMDLY(x) ((x) << 5) |
| #define PSP_SFRMP (1 << 4) |
| #define PSP_FSRT (1 << 3) |
| #define PSP_ETDS (1 << 2) |
| #define PSP_SCMODE(x) ((x) << 0) |
| |
| /* 0x1C NET_WORK_CTRL */ |
| #define RTSA(x) ((x) << 12) |
| #define RTSA_MASK (0xFF << 12) |
| #define TTSA(x) ((x) << 4) |
| #define TTSA_MASK (0xFF << 4) |
| #define NET_FRDC(x) ((x) << 1) |
| #define NET_WORK_MODE (1 << 0) |
| |
| /* 0x20 NET_WORK_STATUS */ |
| #define NET_SATUS_NMBSY (1 << 3) |
| #define NET_STATUS_TSS(x) ((x) << 0) |
| |
| /* 0x24 RWOT_CTRL */ |
| #define RWOT_MASK_RWOT_LAST_SAMPLE (1 << 4) |
| #define RWOT_CLR_RWOT_CYCLE (1 << 3) |
| #define RWOT_SET_RWOT_CYCLE (1 << 2) |
| #define RWOT_CYCLE_RWOT_EN (1 << 1) |
| #define RWOT_RWOT (1 << 0) |
| |
| #define PIO_FIFO_ENTRY_NUM (32) |
| |
| enum asr_ssp_type { |
| SSP_UNDEFINED = 0, |
| ASR_SSP, |
| }; |
| |
| struct spi_driver_data { |
| /* Driver model hookup */ |
| struct platform_device *pdev; |
| |
| /* SSP Info */ |
| struct ssp_device *ssp; |
| |
| /* SPI framework hookup */ |
| enum asr_ssp_type ssp_type; |
| struct spi_master *master; |
| |
| /* ASR hookup */ |
| struct asr_spi_master *master_info; |
| |
| /* SSP register addresses */ |
| void __iomem *ioaddr; |
| u32 ssdr_physical; |
| |
| /* SSP masks*/ |
| u32 dma_fifo_ctrl; |
| u32 dma_top_ctrl; |
| u32 int_cr; |
| u32 dma_cr; |
| u32 clear_sr; |
| u32 mask_sr; |
| |
| /* SPI feature control */ |
| u8 pio_cs_auto_deasert; |
| u8 pio_interval_us; |
| u8 one_cycle_delay; |
| u8 cs_comb_ctrl; |
| u32 hold_frame_low; |
| u32 master_rxfifo_timeout; |
| u32 slave_rxfifo_timeout; |
| u32 slave_rxtimer_to_ms; |
| |
| /* Message Transfer pump */ |
| struct tasklet_struct pump_transfers; |
| |
| /* DMA engine support */ |
| struct dma_chan *rx_chan; |
| struct dma_chan *tx_chan; |
| struct sg_table rx_sgt; |
| struct sg_table tx_sgt; |
| int rx_nents; |
| int tx_nents; |
| void *dummy; |
| atomic_t dma_running; |
| |
| /* Current message transfer state info */ |
| struct spi_message *cur_msg; |
| struct spi_transfer *cur_transfer; |
| struct chip_data *cur_chip; |
| size_t len; |
| void *tx; |
| void *tx_end; |
| void *rx; |
| void *rx_end; |
| int dma_mapped; |
| dma_addr_t rx_dma; |
| dma_addr_t tx_dma; |
| size_t rx_map_len; |
| size_t tx_map_len; |
| u8 n_bytes; |
| int (*write)(struct spi_driver_data *drv_data); |
| int (*read)(struct spi_driver_data *drv_data); |
| irqreturn_t (*transfer_handler)(struct spi_driver_data *drv_data); |
| void (*cs_control)(u32 command); |
| struct pm_qos_request qos_idle; |
| int qos_idle_value; |
| struct clk *clk; |
| int irq; |
| u8 unqueued_transfer; |
| u8 no_tasklet; |
| u8 xfer_way; |
| u8 cs_assert; |
| struct completion dma_completion; |
| /* Support RX FIFO auto full control and endian swap */ |
| unsigned int ssp_enhancement; |
| unsigned char slave_mode; |
| struct timer_list slave_rx_timer; |
| }; |
| |
| enum { |
| XFER_NONE = 0, |
| XFER_PUMP = 1, |
| XFER_UNQUEUE = 2, |
| XFER_SPIMEM = 3, |
| }; |
| |
| struct chip_data { |
| u32 top_ctrl; |
| u32 fifo_ctrl; |
| u32 timeout; |
| u8 n_bytes; |
| u32 dma_burst_size; |
| u32 threshold; |
| u32 dma_threshold; |
| u8 enable_dma; |
| union { |
| int gpio_cs; |
| unsigned int frm; |
| }; |
| int gpio_cs_inverted; |
| int (*write)(struct spi_driver_data *drv_data); |
| int (*read)(struct spi_driver_data *drv_data); |
| void (*cs_control)(u32 command); |
| }; |
| |
| static inline u32 asr_spi_read(const struct spi_driver_data *drv_data, |
| unsigned reg) |
| { |
| return __raw_readl(drv_data->ioaddr + reg); |
| } |
| |
| static inline void asr_spi_write(const struct spi_driver_data *drv_data, |
| unsigned reg, u32 val) |
| { |
| __raw_writel(val, drv_data->ioaddr + reg); |
| } |
| |
| #define START_STATE ((void *)0) |
| #define RUNNING_STATE ((void *)1) |
| #define DONE_STATE ((void *)2) |
| #define ERROR_STATE ((void *)-1) |
| |
| #define IS_DMA_ALIGNED(x) IS_ALIGNED((unsigned long)(x), DMA_ALIGNMENT) |
| #define DMA_ALIGNMENT 64 |
| |
| extern int asr_spi_flush(struct spi_driver_data *drv_data); |
| extern void *asr_spi_next_transfer(struct spi_driver_data *drv_data); |
| extern void asr_spi_pump_transfers(struct spi_driver_data *drv_data); |
| |
| /* |
| * Select the right DMA implementation. |
| */ |
| #define MAX_DMA_LEN SZ_512K |
| #define DEFAULT_DMA_FIFO_CTRL (FIFO_TSRE | FIFO_RSRE) |
| #define DEFAULT_DMA_TOP_CTRL (TOP_TRAIL) |
| |
| extern bool asr_spi_dma_is_possible(size_t len); |
| extern int asr_spi_map_dma_buffers(struct spi_driver_data *drv_data); |
| extern irqreturn_t asr_spi_dma_transfer(struct spi_driver_data *drv_data); |
| extern void asr_spi_slave_sw_timeout_callback(struct spi_driver_data *drv_data); |
| extern int asr_spi_dma_prepare(struct spi_driver_data *drv_data, u32 dma_burst); |
| extern void asr_spi_dma_start(struct spi_driver_data *drv_data); |
| extern int asr_spi_dma_setup(struct spi_driver_data *drv_data); |
| extern void asr_spi_dma_release(struct spi_driver_data *drv_data); |
| extern int asr_spi_set_dma_burst_and_threshold(struct chip_data *chip, |
| struct spi_device *spi, |
| u8 bits_per_word, |
| u32 *burst_code, |
| u32 *threshold); |
| |
| #define RX_THRESH_DFLT 8 |
| #define TX_THRESH_DFLT 8 |
| /* 0x14 */ |
| #define STATUS_TFL_MASK (0x1f << 7) /* Transmit FIFO Level mask */ |
| #define STATUS_TFL_BASE (7) |
| #define STATUS_RFL_MASK (0x1f << 15) /* Receive FIFO Level mask */ |
| #define STATUS_RFL_BASE (15) |
| /* 0x4 */ |
| #define FIFO_TFT (0x0000001F) /* Transmit FIFO Threshold (mask) */ |
| #define FIFO_TxTresh(x) (((x) - 1) << 0) /* level [1..32] */ |
| #define FIFO_RFT (0x000003E0) /* Receive FIFO Threshold (mask) */ |
| #define FIFO_RxTresh(x) (((x) - 1) << 5) /* level [1..32] */ |
| |
| struct ssp_device { |
| struct platform_device *pdev; |
| struct list_head node; |
| |
| struct clk *clk; |
| void __iomem *mmio_base; |
| unsigned long phys_base; |
| |
| const char *label; |
| int port_id; |
| int type; |
| int use_count; |
| int irq; |
| int drcmr_rx; |
| int drcmr_tx; |
| |
| struct device_node *of_node; |
| }; |
| |
| /** |
| * asr_ssp_write_reg - Write to a SSP register |
| * |
| * @dev: SSP device to access |
| * @reg: Register to write to |
| * @val: Value to be written. |
| */ |
| static inline void asr_ssp_write_reg(struct ssp_device *dev, u32 reg, u32 val) |
| { |
| __raw_writel(val, dev->mmio_base + reg); |
| } |
| |
| /** |
| * asr_ssp_read_reg - Read from a SSP register |
| * |
| * @dev: SSP device to access |
| * @reg: Register to read from |
| */ |
| static inline u32 asr_ssp_read_reg(struct ssp_device *dev, u32 reg) |
| { |
| return __raw_readl(dev->mmio_base + reg); |
| } |
| |
| static inline void asr_ssp_free(struct ssp_device *ssp) {} |
| #define ASR_CS_ASSERT (0x01) |
| #define ASR_CS_DEASSERT (0x02) |
| |
| struct dma_chan; |
| |
| /* device.platform_data for SSP controller devices */ |
| struct asr_spi_master { |
| u16 num_chipselect; |
| u8 enable_dma; |
| |
| /* DMA engine specific config */ |
| bool (*dma_filter)(struct dma_chan *chan, void *param); |
| void *tx_param; |
| void *rx_param; |
| |
| /* For sound ssp controller */ |
| struct ssp_device ssp; |
| }; |
| |
| /* spi_board_info.controller_data for SPI slave devices, |
| * copied to spi_device.platform_data ... mostly for dma tuning |
| */ |
| struct asr_spi_chip { |
| u8 tx_threshold; |
| u8 tx_hi_threshold; |
| u8 rx_threshold; |
| u8 dma_burst_size; |
| u32 timeout; |
| u8 enable_loopback; |
| int gpio_cs; |
| int using_gpio_cs; |
| void (*cs_control)(u32 command); |
| }; |
| #endif /* _SPI_ASR_H */ |