Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __SPI_DW_H__ #define __SPI_DW_H__ #include <linux/bits.h> #include <linux/completion.h> #include <linux/debugfs.h> #include <linux/irqreturn.h> #include <linux/io.h> #include <linux/scatterlist.h> #include <linux/spi/spi-mem.h> #include <linux/bitfield.h> /* Synopsys DW SSI IP-core virtual IDs */ #define DW_PSSI_ID 0 #define DW_HSSI_ID 1 /* Synopsys DW SSI component versions (FourCC sequence) */ #define DW_HSSI_102A 0x3130322a /* DW SSI IP-core ID and version check helpers */ #define dw_spi_ip_is(_dws, _ip) \ ((_dws)->ip == DW_ ## _ip ## _ID) #define __dw_spi_ver_cmp(_dws, _ip, _ver, _op) \ (dw_spi_ip_is(_dws, _ip) && (_dws)->ver _op DW_ ## _ip ## _ver) #define dw_spi_ver_is(_dws, _ip, _ver) __dw_spi_ver_cmp(_dws, _ip, _ver, ==) #define dw_spi_ver_is_ge(_dws, _ip, _ver) __dw_spi_ver_cmp(_dws, _ip, _ver, >=) /* DW SPI controller capabilities */ #define DW_SPI_CAP_CS_OVERRIDE BIT(0) #define DW_SPI_CAP_KEEMBAY_MST BIT(1) #define DW_SPI_CAP_DFS32 BIT(2) /* Register offsets (Generic for both DWC APB SSI and DWC SSI IP-cores) */ #define DW_SPI_CTRLR0 0x00 #define DW_SPI_CTRLR1 0x04 #define DW_SPI_SSIENR 0x08 #define DW_SPI_MWCR 0x0c #define DW_SPI_SER 0x10 #define DW_SPI_BAUDR 0x14 #define DW_SPI_TXFTLR 0x18 #define DW_SPI_RXFTLR 0x1c #define DW_SPI_TXFLR 0x20 #define DW_SPI_RXFLR 0x24 #define DW_SPI_SR 0x28 #define DW_SPI_IMR 0x2c #define DW_SPI_ISR 0x30 #define DW_SPI_RISR 0x34 #define DW_SPI_TXOICR 0x38 #define DW_SPI_RXOICR 0x3c #define DW_SPI_RXUICR 0x40 #define DW_SPI_MSTICR 0x44 #define DW_SPI_ICR 0x48 #define DW_SPI_DMACR 0x4c #define DW_SPI_DMATDLR 0x50 #define DW_SPI_DMARDLR 0x54 #define DW_SPI_IDR 0x58 #define DW_SPI_VERSION 0x5c #define DW_SPI_DR 0x60 #define DW_SPI_RX_SAMPLE_DLY 0xf0 #define DW_SPI_CS_OVERRIDE 0xf4 /* Bit fields in CTRLR0 (DWC APB SSI) */ #define DW_PSSI_CTRLR0_DFS_MASK GENMASK(3, 0) #define DW_PSSI_CTRLR0_DFS32_MASK GENMASK(20, 16) #define DW_PSSI_CTRLR0_FRF_MASK GENMASK(5, 4) #define DW_SPI_CTRLR0_FRF_MOTO_SPI 0x0 #define DW_SPI_CTRLR0_FRF_TI_SSP 0x1 #define DW_SPI_CTRLR0_FRF_NS_MICROWIRE 0x2 #define DW_SPI_CTRLR0_FRF_RESV 0x3 #define DW_PSSI_CTRLR0_MODE_MASK GENMASK(7, 6) #define DW_PSSI_CTRLR0_SCPHA BIT(6) #define DW_PSSI_CTRLR0_SCPOL BIT(7) #define DW_PSSI_CTRLR0_TMOD_MASK GENMASK(9, 8) #define DW_SPI_CTRLR0_TMOD_TR 0x0 /* xmit & recv */ #define DW_SPI_CTRLR0_TMOD_TO 0x1 /* xmit only */ #define DW_SPI_CTRLR0_TMOD_RO 0x2 /* recv only */ #define DW_SPI_CTRLR0_TMOD_EPROMREAD 0x3 /* eeprom read mode */ #define DW_PSSI_CTRLR0_SLV_OE BIT(10) #define DW_PSSI_CTRLR0_SRL BIT(11) #define DW_PSSI_CTRLR0_CFS BIT(12) /* Bit fields in CTRLR0 (DWC SSI with AHB interface) */ #define DW_HSSI_CTRLR0_DFS_MASK GENMASK(4, 0) #define DW_HSSI_CTRLR0_FRF_MASK GENMASK(7, 6) #define DW_HSSI_CTRLR0_SCPHA BIT(8) #define DW_HSSI_CTRLR0_SCPOL BIT(9) #define DW_HSSI_CTRLR0_TMOD_MASK GENMASK(11, 10) #define DW_HSSI_CTRLR0_SRL BIT(13) /* * For Keem Bay, CTRLR0[31] is used to select controller mode. * 0: SSI is slave * 1: SSI is master */ #define DW_HSSI_CTRLR0_KEEMBAY_MST BIT(31) /* Bit fields in CTRLR1 */ #define DW_SPI_NDF_MASK GENMASK(15, 0) /* Bit fields in SR, 7 bits */ #define DW_SPI_SR_MASK GENMASK(6, 0) #define DW_SPI_SR_BUSY BIT(0) #define DW_SPI_SR_TF_NOT_FULL BIT(1) #define DW_SPI_SR_TF_EMPT BIT(2) #define DW_SPI_SR_RF_NOT_EMPT BIT(3) #define DW_SPI_SR_RF_FULL BIT(4) #define DW_SPI_SR_TX_ERR BIT(5) #define DW_SPI_SR_DCOL BIT(6) /* Bit fields in ISR, IMR, RISR, 7 bits */ #define DW_SPI_INT_MASK GENMASK(5, 0) #define DW_SPI_INT_TXEI BIT(0) #define DW_SPI_INT_TXOI BIT(1) #define DW_SPI_INT_RXUI BIT(2) #define DW_SPI_INT_RXOI BIT(3) #define DW_SPI_INT_RXFI BIT(4) #define DW_SPI_INT_MSTI BIT(5) /* Bit fields in DMACR */ #define DW_SPI_DMACR_RDMAE BIT(0) #define DW_SPI_DMACR_TDMAE BIT(1) /* Mem/DMA operations helpers */ #define DW_SPI_WAIT_RETRIES 5 #define DW_SPI_BUF_SIZE \ (sizeof_field(struct spi_mem_op, cmd.opcode) + \ sizeof_field(struct spi_mem_op, addr.val) + 256) #define DW_SPI_GET_BYTE(_val, _idx) \ ((_val) >> (BITS_PER_BYTE * (_idx)) & 0xff) /* Slave spi_transfer/spi_mem_op related */ struct dw_spi_cfg { u8 tmode; u8 dfs; u32 ndf; u32 freq; }; struct dw_spi; struct dw_spi_dma_ops { int (*dma_init)(struct device *dev, struct dw_spi *dws); void (*dma_exit)(struct dw_spi *dws); int (*dma_setup)(struct dw_spi *dws, struct spi_transfer *xfer); bool (*can_dma)(struct spi_controller *master, struct spi_device *spi, struct spi_transfer *xfer); int (*dma_transfer)(struct dw_spi *dws, struct spi_transfer *xfer); void (*dma_stop)(struct dw_spi *dws); }; struct dw_spi { struct spi_controller *master; u32 ip; /* Synopsys DW SSI IP-core ID */ u32 ver; /* Synopsys component version */ u32 caps; /* DW SPI capabilities */ void __iomem *regs; unsigned long paddr; int irq; u32 fifo_len; /* depth of the FIFO buffer */ unsigned int dfs_offset; /* CTRLR0 DFS field offset */ u32 max_mem_freq; /* max mem-ops bus freq */ u32 max_freq; /* max bus freq supported */ u32 reg_io_width; /* DR I/O width in bytes */ u16 bus_num; u16 num_cs; /* supported slave numbers */ void (*set_cs)(struct spi_device *spi, bool enable); /* Current message transfer state info */ void *tx; unsigned int tx_len; void *rx; unsigned int rx_len; u8 buf[DW_SPI_BUF_SIZE]; int dma_mapped; u8 n_bytes; /* current is a 1/2 bytes op */ irqreturn_t (*transfer_handler)(struct dw_spi *dws); u32 current_freq; /* frequency in hz */ u32 cur_rx_sample_dly; u32 def_rx_sample_dly_ns; /* Custom memory operations */ struct spi_controller_mem_ops mem_ops; /* DMA info */ struct dma_chan *txchan; u32 txburst; struct dma_chan *rxchan; u32 rxburst; u32 dma_sg_burst; unsigned long dma_chan_busy; dma_addr_t dma_addr; /* phy address of the Data register */ const struct dw_spi_dma_ops *dma_ops; struct completion dma_completion; #ifdef CONFIG_DEBUG_FS struct dentry *debugfs; struct debugfs_regset32 regset; #endif }; static inline u32 dw_readl(struct dw_spi *dws, u32 offset) { return __raw_readl(dws->regs + offset); } static inline void dw_writel(struct dw_spi *dws, u32 offset, u32 val) { __raw_writel(val, dws->regs + offset); } static inline u32 dw_read_io_reg(struct dw_spi *dws, u32 offset) { switch (dws->reg_io_width) { case 2: return readw_relaxed(dws->regs + offset); case 4: default: return readl_relaxed(dws->regs + offset); } } static inline void dw_write_io_reg(struct dw_spi *dws, u32 offset, u32 val) { switch (dws->reg_io_width) { case 2: writew_relaxed(val, dws->regs + offset); break; case 4: default: writel_relaxed(val, dws->regs + offset); break; } } static inline void dw_spi_enable_chip(struct dw_spi *dws, int enable) { dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0)); } static inline void dw_spi_set_clk(struct dw_spi *dws, u16 div) { dw_writel(dws, DW_SPI_BAUDR, div); } /* Disable IRQ bits */ static inline void dw_spi_mask_intr(struct dw_spi *dws, u32 mask) { u32 new_mask; new_mask = dw_readl(dws, DW_SPI_IMR) & ~mask; dw_writel(dws, DW_SPI_IMR, new_mask); } /* Enable IRQ bits */ static inline void dw_spi_umask_intr(struct dw_spi *dws, u32 mask) { u32 new_mask; new_mask = dw_readl(dws, DW_SPI_IMR) | mask; dw_writel(dws, DW_SPI_IMR, new_mask); } /* * This disables the SPI controller, interrupts, clears the interrupts status * and CS, then re-enables the controller back. Transmit and receive FIFO * buffers are cleared when the device is disabled. */ static inline void dw_spi_reset_chip(struct dw_spi *dws) { dw_spi_enable_chip(dws, 0); dw_spi_mask_intr(dws, 0xff); dw_readl(dws, DW_SPI_ICR); dw_writel(dws, DW_SPI_SER, 0); dw_spi_enable_chip(dws, 1); } static inline void dw_spi_shutdown_chip(struct dw_spi *dws) { dw_spi_enable_chip(dws, 0); dw_spi_set_clk(dws, 0); } extern void dw_spi_set_cs(struct spi_device *spi, bool enable); extern void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi, struct dw_spi_cfg *cfg); extern int dw_spi_check_status(struct dw_spi *dws, bool raw); extern int dw_spi_add_host(struct device *dev, struct dw_spi *dws); extern void dw_spi_remove_host(struct dw_spi *dws); extern int dw_spi_suspend_host(struct dw_spi *dws); extern int dw_spi_resume_host(struct dw_spi *dws); #ifdef CONFIG_SPI_DW_DMA extern void dw_spi_dma_setup_mfld(struct dw_spi *dws); extern void dw_spi_dma_setup_generic(struct dw_spi *dws); #else static inline void dw_spi_dma_setup_mfld(struct dw_spi *dws) {} static inline void dw_spi_dma_setup_generic(struct dw_spi *dws) {} #endif /* !CONFIG_SPI_DW_DMA */ #endif /* __SPI_DW_H__ */ |