1 #include "bflb_spi.h"
2 #include "bflb_clock.h"
3 #include "hardware/spi_reg.h"
4
5 #if defined(BL602) || defined(BL702) || defined(BL702L)
6 #define GLB_SPI_MODE_ADDRESS 0x40000080
7 #elif defined(BL606P) || defined(BL808) || defined(BL616) || defined(BL628)
8 #define GLB_SPI_MODE_ADDRESS 0x20000510
9 #endif
10
bflb_spi_init(struct bflb_device_s * dev,const struct bflb_spi_config_s * config)11 void bflb_spi_init(struct bflb_device_s *dev, const struct bflb_spi_config_s *config)
12 {
13 uint32_t reg_base;
14 uint32_t regval;
15 uint32_t div;
16
17 /* GLB select master or slave mode */
18 regval = getreg32(GLB_SPI_MODE_ADDRESS);
19 if (config->role == SPI_ROLE_MASTER) {
20 regval |= 1 << 12;
21 } else {
22 regval &= ~(1 << 12);
23 }
24 putreg32(regval, GLB_SPI_MODE_ADDRESS);
25
26 reg_base = dev->reg_base;
27 /* integer frequency segmentation by rounding */
28 div = (bflb_clk_get_peripheral_clock(BFLB_DEVICE_TYPE_SPI, dev->idx) / 2 * 10 / config->freq + 5) / 10;
29 div = (div) ? (div - 1) : 0;
30 div = (div > 0xff) ? 0xff : div;
31
32 regval = 0;
33 regval |= div << SPI_CR_SPI_PRD_D_PH_0_SHIFT;
34 regval |= div << SPI_CR_SPI_PRD_D_PH_1_SHIFT;
35 regval |= div << SPI_CR_SPI_PRD_S_SHIFT;
36 regval |= div << SPI_CR_SPI_PRD_P_SHIFT;
37 putreg32(regval, reg_base + SPI_PRD_0_OFFSET);
38
39 regval = getreg32(reg_base + SPI_PRD_1_OFFSET);
40 regval &= ~SPI_CR_SPI_PRD_I_MASK;
41 regval |= (div) << SPI_CR_SPI_PRD_I_SHIFT;
42 putreg32(regval, reg_base + SPI_PRD_1_OFFSET);
43
44 /* Disable deglitch and disenable continue function */
45 regval = getreg32(reg_base + SPI_CONFIG_OFFSET);
46 regval &= ~SPI_CR_SPI_DEG_EN;
47 regval &= ~SPI_CR_SPI_DEG_CNT_MASK;
48 regval &= ~SPI_CR_SPI_M_CONT_EN;
49 regval &= ~SPI_CR_SPI_RXD_IGNR_EN;
50
51 /* Byte-inverse and Bit-inverse */
52 if (config->byte_order == SPI_BYTE_LSB) {
53 regval &= ~SPI_CR_SPI_BYTE_INV;
54 } else {
55 regval |= SPI_CR_SPI_BYTE_INV;
56 }
57 if (config->bit_order == SPI_BIT_LSB) {
58 regval |= SPI_CR_SPI_BIT_INV;
59 } else {
60 regval &= ~SPI_CR_SPI_BIT_INV;
61 }
62
63 /* clk phase and polarity cfg */
64 switch (config->mode) {
65 case SPI_MODE0:
66 /* CPOL=0 CHPHA=0 */
67 regval &= ~SPI_CR_SPI_SCLK_POL;
68 regval |= SPI_CR_SPI_SCLK_PH;
69 break;
70 case SPI_MODE1:
71 /* CPOL=0 CHPHA=1 */
72 regval &= ~SPI_CR_SPI_SCLK_POL;
73 regval &= ~SPI_CR_SPI_SCLK_PH;
74 break;
75 case SPI_MODE2:
76 /* CPOL=1 CHPHA=0 */
77 regval |= SPI_CR_SPI_SCLK_POL;
78 regval |= SPI_CR_SPI_SCLK_PH;
79 break;
80 case SPI_MODE3:
81 /* CPOL=1 CHPHA=1 */
82 regval |= SPI_CR_SPI_SCLK_POL;
83 regval &= ~SPI_CR_SPI_SCLK_PH;
84 break;
85 default:
86 break;
87 }
88
89 /* data frame size cfg */
90 regval &= ~SPI_CR_SPI_FRAME_SIZE_MASK;
91 regval |= (config->data_width - 1) << SPI_CR_SPI_FRAME_SIZE_SHIFT;
92
93 /* disable SPI */
94 regval &= ~SPI_CR_SPI_S_EN;
95 regval &= ~SPI_CR_SPI_M_EN;
96
97 putreg32(regval, reg_base + SPI_CONFIG_OFFSET);
98
99 /* clear fifo and close dma */
100 regval = getreg32(reg_base + SPI_FIFO_CONFIG_0_OFFSET);
101 regval |= SPI_TX_FIFO_CLR;
102 regval |= SPI_RX_FIFO_CLR;
103 regval &= ~SPI_DMA_TX_EN;
104 regval &= ~SPI_DMA_RX_EN;
105 putreg32(regval, reg_base + SPI_FIFO_CONFIG_0_OFFSET);
106
107 /* fifo threshold cfg */
108 regval = getreg32(reg_base + SPI_FIFO_CONFIG_1_OFFSET);
109 regval &= ~SPI_TX_FIFO_TH_MASK;
110 regval &= ~SPI_RX_FIFO_TH_MASK;
111 regval |= (config->tx_fifo_threshold << SPI_TX_FIFO_TH_SHIFT) & SPI_TX_FIFO_TH_MASK;
112 regval |= (config->rx_fifo_threshold << SPI_RX_FIFO_TH_SHIFT) & SPI_RX_FIFO_TH_MASK;
113 putreg32(regval, reg_base + SPI_FIFO_CONFIG_1_OFFSET);
114
115 /* enable spi */
116 regval = getreg32(reg_base + SPI_CONFIG_OFFSET);
117 if (config->role == SPI_ROLE_MASTER) {
118 regval |= SPI_CR_SPI_M_EN;
119 regval &= ~SPI_CR_SPI_S_EN;
120 } else {
121 regval |= SPI_CR_SPI_S_EN;
122 regval &= ~SPI_CR_SPI_M_EN;
123 }
124 putreg32(regval, reg_base + SPI_CONFIG_OFFSET);
125 }
126
bflb_spi_deinit(struct bflb_device_s * dev)127 void bflb_spi_deinit(struct bflb_device_s *dev)
128 {
129 uint32_t regval;
130 /* disable SPI */
131 regval = getreg32(dev->reg_base + SPI_CONFIG_OFFSET);
132 regval &= ~SPI_CR_SPI_S_EN;
133 regval &= ~SPI_CR_SPI_M_EN;
134 putreg32(regval, dev->reg_base + SPI_CONFIG_OFFSET);
135 }
136
bflb_spi_link_txdma(struct bflb_device_s * dev,bool enable)137 void bflb_spi_link_txdma(struct bflb_device_s *dev, bool enable)
138 {
139 uint32_t reg_base;
140 uint32_t regval;
141
142 reg_base = dev->reg_base;
143 regval = getreg32(reg_base + SPI_FIFO_CONFIG_0_OFFSET);
144 if (enable) {
145 regval |= SPI_DMA_TX_EN;
146 } else {
147 regval &= ~SPI_DMA_TX_EN;
148 }
149 putreg32(regval, reg_base + SPI_FIFO_CONFIG_0_OFFSET);
150 }
151
bflb_spi_link_rxdma(struct bflb_device_s * dev,bool enable)152 void bflb_spi_link_rxdma(struct bflb_device_s *dev, bool enable)
153 {
154 uint32_t reg_base;
155 uint32_t regval;
156
157 reg_base = dev->reg_base;
158 regval = getreg32(reg_base + SPI_FIFO_CONFIG_0_OFFSET);
159 if (enable) {
160 regval |= SPI_DMA_RX_EN;
161 } else {
162 regval &= ~SPI_DMA_RX_EN;
163 }
164 putreg32(regval, reg_base + SPI_FIFO_CONFIG_0_OFFSET);
165 }
166
167 /* Read and write a frame of data */
bflb_spi_poll_send(struct bflb_device_s * dev,uint32_t data)168 ATTR_TCM_SECTION uint32_t bflb_spi_poll_send(struct bflb_device_s *dev, uint32_t data)
169 {
170 uint32_t reg_base = dev->reg_base;
171 uint32_t regval;
172 uint8_t fifo_cnt;
173
174 #if 0
175 /* Wait for tx FIFO to be empty */
176 #if (SPI_FIFO_WIDTH_VARIABLE_SUPPORT)
177 do {
178 regval = getreg32(reg_base + SPI_FIFO_CONFIG_1_OFFSET);
179 fifo_cnt = (regval & SPI_TX_FIFO_CNT_MASK) >> SPI_TX_FIFO_CNT_SHIFT;
180 } while (fifo_cnt < SPI_FIFO_BYTE_NUM_MAX);
181 #else
182 do {
183 regval = getreg32(reg_base + SPI_FIFO_CONFIG_1_OFFSET);
184 fifo_cnt = (regval & SPI_TX_FIFO_CNT_MASK) >> SPI_TX_FIFO_CNT_SHIFT;
185 } while (fifo_cnt < SPI_FIFO_WORD_NUM_MAX);
186 #endif
187
188 /* Wait for SPI to idle */
189 do {
190 regval = getreg32(reg_base + SPI_BUS_BUSY_OFFSET);
191 } while (regval);
192
193 /* clear fifo */
194 regval = getreg32(reg_base + SPI_FIFO_CONFIG_0_OFFSET);
195 regval |= SPI_TX_FIFO_CLR;
196 regval |= SPI_RX_FIFO_CLR;
197 putreg32(regval, reg_base + SPI_FIFO_CONFIG_0_OFFSET);
198
199 #endif
200
201 /* wtire data to fifo */
202 putreg32(data, reg_base + SPI_FIFO_WDATA_OFFSET);
203
204 #if (SPI_FIFO_WIDTH_VARIABLE_SUPPORT)
205
206 /* get frame size */
207 regval = getreg32(reg_base + SPI_CONFIG_OFFSET);
208 uint8_t frame_size = ((regval & SPI_CR_SPI_FRAME_SIZE_MASK) >> SPI_CR_SPI_FRAME_SIZE_SHIFT) + 1;
209 if (frame_size == 3) {
210 frame_size = 4;
211 }
212
213 /* Wait for rx data */
214 do {
215 regval = getreg32(reg_base + SPI_FIFO_CONFIG_1_OFFSET);
216 fifo_cnt = (regval & SPI_RX_FIFO_CNT_MASK) >> SPI_RX_FIFO_CNT_SHIFT;
217 } while (fifo_cnt < frame_size);
218 #else
219
220 /* Wait for rx data */
221 do {
222 regval = getreg32(reg_base + SPI_FIFO_CONFIG_1_OFFSET);
223 fifo_cnt = (regval & SPI_RX_FIFO_CNT_MASK) >> SPI_RX_FIFO_CNT_SHIFT;
224 } while (fifo_cnt == 0);
225 #endif
226
227 regval = getreg32(reg_base + SPI_FIFO_RDATA_OFFSET);
228
229 return regval;
230 }
231
232 /* read and write data */
bflb_spi_poll_exchange(struct bflb_device_s * dev,const void * txbuffer,void * rxbuffer,size_t nbytes)233 ATTR_TCM_SECTION int bflb_spi_poll_exchange(struct bflb_device_s *dev, const void *txbuffer, void *rxbuffer, size_t nbytes)
234 {
235 uint32_t regval;
236 uint32_t reg_base = dev->reg_base;
237 uint32_t tx_cnt;
238 uint8_t fifo_cnt, frame_size;
239
240 /* get frame size */
241 regval = getreg32(reg_base + SPI_CONFIG_OFFSET);
242 frame_size = ((regval & SPI_CR_SPI_FRAME_SIZE_MASK) >> SPI_CR_SPI_FRAME_SIZE_SHIFT) + 1;
243 if (frame_size == 3) {
244 frame_size = 4;
245 }
246
247 nbytes /= frame_size;
248 tx_cnt = nbytes;
249
250 #if 0
251 /* Wait for tx FIFO to be empty */
252 #if (SPI_FIFO_WIDTH_VARIABLE_SUPPORT)
253 do {
254 regval = getreg32(reg_base + SPI_FIFO_CONFIG_1_OFFSET);
255 fifo_cnt = (regval & SPI_TX_FIFO_CNT_MASK) >> SPI_TX_FIFO_CNT_SHIFT;
256 } while (fifo_cnt < SPI_FIFO_BYTE_NUM_MAX);
257 #else
258 do {
259 regval = getreg32(reg_base + SPI_FIFO_CONFIG_1_OFFSET);
260 fifo_cnt = (regval & SPI_TX_FIFO_CNT_MASK) >> SPI_TX_FIFO_CNT_SHIFT;
261 } while (fifo_cnt < SPI_FIFO_WORD_NUM_MAX);
262 #endif
263
264 /* Wait for SPI to idle */
265 do {
266 regval = getreg32(reg_base + SPI_BUS_BUSY_OFFSET);
267 } while (regval);
268
269 /* clear fifo */
270 regval = getreg32(reg_base + SPI_FIFO_CONFIG_0_OFFSET);
271 regval |= SPI_TX_FIFO_CLR;
272 regval |= SPI_RX_FIFO_CLR;
273 putreg32(regval, reg_base + SPI_FIFO_CONFIG_0_OFFSET);
274
275 #endif
276
277 /* clear fifo */
278 regval = getreg32(reg_base + SPI_FIFO_CONFIG_0_OFFSET);
279 regval |= SPI_TX_FIFO_CLR;
280 regval |= SPI_RX_FIFO_CLR;
281 putreg32(regval, reg_base + SPI_FIFO_CONFIG_0_OFFSET);
282
283 /* get tx fifo cnt */
284 regval = getreg32(reg_base + SPI_FIFO_CONFIG_1_OFFSET);
285 #if (SPI_FIFO_WIDTH_VARIABLE_SUPPORT)
286 fifo_cnt = ((regval & SPI_TX_FIFO_CNT_MASK) >> SPI_TX_FIFO_CNT_SHIFT) / frame_size;
287 #else
288 fifo_cnt = ((regval & SPI_TX_FIFO_CNT_MASK) >> SPI_TX_FIFO_CNT_SHIFT);
289 #endif
290
291 /* first fill tx fifo */
292 fifo_cnt = fifo_cnt > nbytes ? nbytes : fifo_cnt;
293 tx_cnt -= fifo_cnt;
294 if (txbuffer != NULL) {
295 /* Send valid data */
296 for (; fifo_cnt > 0; fifo_cnt--) {
297 switch (frame_size) {
298 case 1:
299 regval = *(uint8_t *)txbuffer;
300 putreg32(regval, reg_base + SPI_FIFO_WDATA_OFFSET);
301 txbuffer += 1;
302 break;
303 case 2:
304 regval = *(uint16_t *)txbuffer;
305 putreg32(regval, reg_base + SPI_FIFO_WDATA_OFFSET);
306 txbuffer += 2;
307 break;
308 case 3:
309 case 4:
310 regval = *(uint32_t *)txbuffer;
311 putreg32(regval, reg_base + SPI_FIFO_WDATA_OFFSET);
312 txbuffer += 4;
313 break;
314 default:
315 break;
316 }
317 }
318 } else {
319 /* Send idle Data */
320 for (; fifo_cnt > 0; fifo_cnt--) {
321 putreg32(0xFFFFFFFF, reg_base + SPI_FIFO_WDATA_OFFSET);
322 }
323 }
324
325 /* read and write rest of the data */
326 for (; nbytes > 0;) {
327 /* get rx fifo cnt */
328 regval = getreg32(reg_base + SPI_FIFO_CONFIG_1_OFFSET);
329
330 #if (SPI_FIFO_WIDTH_VARIABLE_SUPPORT)
331 fifo_cnt = ((regval & SPI_RX_FIFO_CNT_MASK) >> SPI_RX_FIFO_CNT_SHIFT) / frame_size;
332 #else
333 fifo_cnt = ((regval & SPI_RX_FIFO_CNT_MASK) >> SPI_RX_FIFO_CNT_SHIFT);
334 #endif
335 if (fifo_cnt) {
336 fifo_cnt = fifo_cnt > nbytes ? nbytes : fifo_cnt;
337 nbytes -= fifo_cnt;
338 } else {
339 }
340
341 /* read and write data */
342 for (; fifo_cnt > 0; fifo_cnt--) {
343 regval = getreg32(reg_base + SPI_FIFO_RDATA_OFFSET);
344 switch (frame_size) {
345 case 1:
346 if (rxbuffer) {
347 *((uint8_t *)rxbuffer) = (uint8_t)regval;
348 rxbuffer += 1;
349 }
350 if (tx_cnt) {
351 if (txbuffer) {
352 regval = *(uint8_t *)txbuffer;
353 putreg32(regval, reg_base + SPI_FIFO_WDATA_OFFSET);
354 txbuffer++;
355 } else {
356 putreg32(0xFFFFFFFF, reg_base + SPI_FIFO_WDATA_OFFSET);
357 }
358 tx_cnt--;
359 }
360 break;
361 case 2:
362 if (rxbuffer) {
363 *((uint16_t *)rxbuffer) = (uint16_t)regval;
364 rxbuffer += 2;
365 }
366 if (tx_cnt) {
367 if (txbuffer) {
368 regval = *(uint16_t *)txbuffer;
369 putreg32(regval, reg_base + SPI_FIFO_WDATA_OFFSET);
370 txbuffer += 2;
371 } else {
372 putreg32(0xFFFFFFFF, reg_base + SPI_FIFO_WDATA_OFFSET);
373 }
374 tx_cnt--;
375 }
376 break;
377 case 3:
378 /* discard the high 8 bits of data when 24bit-frame */
379 case 4:
380 if (rxbuffer) {
381 *((uint32_t *)rxbuffer) = (uint32_t)regval;
382 rxbuffer += 4;
383 }
384 if (tx_cnt) {
385 if (txbuffer) {
386 regval = *(uint32_t *)txbuffer;
387 putreg32(regval, reg_base + SPI_FIFO_WDATA_OFFSET);
388 txbuffer += 4;
389 } else {
390 putreg32(0xFFFFFFFF, reg_base + SPI_FIFO_WDATA_OFFSET);
391 }
392 tx_cnt--;
393 }
394 break;
395 default:
396 break;
397 }
398 }
399 }
400 return 0;
401 }
402
bflb_spi_txint_mask(struct bflb_device_s * dev,bool mask)403 void bflb_spi_txint_mask(struct bflb_device_s *dev, bool mask)
404 {
405 uint32_t regval;
406 uint32_t reg_base = dev->reg_base;
407
408 regval = getreg32(reg_base + SPI_INT_STS_OFFSET);
409 if (mask) {
410 regval |= SPI_CR_SPI_TXF_MASK;
411 } else {
412 regval &= ~SPI_CR_SPI_TXF_MASK;
413 }
414 putreg32(regval, reg_base + SPI_INT_STS_OFFSET);
415 }
416
bflb_spi_rxint_mask(struct bflb_device_s * dev,bool mask)417 void bflb_spi_rxint_mask(struct bflb_device_s *dev, bool mask)
418 {
419 uint32_t regval;
420 uint32_t reg_base = dev->reg_base;
421
422 regval = getreg32(reg_base + SPI_INT_STS_OFFSET);
423 if (mask) {
424 regval |= SPI_CR_SPI_RXF_MASK;
425 } else {
426 regval &= ~SPI_CR_SPI_RXF_MASK;
427 }
428 putreg32(regval, reg_base + SPI_INT_STS_OFFSET);
429 }
430
bflb_spi_tcint_mask(struct bflb_device_s * dev,bool mask)431 void bflb_spi_tcint_mask(struct bflb_device_s *dev, bool mask)
432 {
433 uint32_t regval;
434 uint32_t reg_base = dev->reg_base;
435
436 regval = getreg32(reg_base + SPI_INT_STS_OFFSET);
437 if (mask) {
438 regval |= SPI_CR_SPI_END_MASK;
439 } else {
440 regval &= ~SPI_CR_SPI_END_MASK;
441 }
442 putreg32(regval, reg_base + SPI_INT_STS_OFFSET);
443 }
444
bflb_spi_errint_mask(struct bflb_device_s * dev,bool mask)445 void bflb_spi_errint_mask(struct bflb_device_s *dev, bool mask)
446 {
447 uint32_t regval;
448 uint32_t reg_base = dev->reg_base;
449
450 regval = getreg32(reg_base + SPI_INT_STS_OFFSET);
451 if (mask) {
452 regval |= SPI_CR_SPI_STO_MASK;
453 regval |= SPI_CR_SPI_TXU_MASK;
454 regval |= SPI_CR_SPI_FER_MASK;
455 } else {
456 regval &= ~SPI_CR_SPI_STO_MASK;
457 regval &= ~SPI_CR_SPI_TXU_MASK;
458 regval &= ~SPI_CR_SPI_FER_MASK;
459 }
460 putreg32(regval, reg_base + SPI_INT_STS_OFFSET);
461 }
462
bflb_spi_get_intstatus(struct bflb_device_s * dev)463 uint32_t bflb_spi_get_intstatus(struct bflb_device_s *dev)
464 {
465 uint32_t reg_base;
466 uint32_t int_status;
467 uint32_t int_mask;
468
469 reg_base = dev->reg_base;
470 int_status = getreg32(reg_base + SPI_INT_STS_OFFSET) & 0x1f;
471 int_mask = getreg32(reg_base + SPI_INT_STS_OFFSET) >> 8 & 0x1f;
472 return (int_status & ~int_mask);
473 }
474
bflb_spi_int_clear(struct bflb_device_s * dev,uint32_t int_clear)475 void bflb_spi_int_clear(struct bflb_device_s *dev, uint32_t int_clear)
476 {
477 uint32_t reg_base;
478 uint32_t regval;
479
480 reg_base = dev->reg_base;
481 regval = getreg32(reg_base + SPI_INT_STS_OFFSET);
482 regval |= int_clear;
483 putreg32(regval, reg_base + SPI_INT_STS_OFFSET);
484 }
485
bflb_spi_isbusy(struct bflb_device_s * dev)486 bool bflb_spi_isbusy(struct bflb_device_s *dev)
487 {
488 uint32_t reg_base;
489 uint32_t regval;
490
491 reg_base = dev->reg_base;
492
493 /* check tx fifo */
494 regval = getreg32(reg_base + SPI_FIFO_CONFIG_1_OFFSET);
495 #if (SPI_FIFO_WIDTH_VARIABLE_SUPPORT)
496 if ((regval & SPI_TX_FIFO_CNT_MASK) >> SPI_TX_FIFO_CNT_SHIFT < SPI_FIFO_BYTE_NUM_MAX) {
497 return true;
498 }
499 #else
500 if ((regval & SPI_TX_FIFO_CNT_MASK) >> SPI_TX_FIFO_CNT_SHIFT < SPI_FIFO_WORD_NUM_MAX) {
501 return true;
502 }
503 #endif
504
505 /* check busy bit */
506 regval = getreg32(reg_base + SPI_BUS_BUSY_OFFSET);
507 if (regval) {
508 return true;
509 }
510
511 return false;
512 }
513
bflb_spi_feature_control(struct bflb_device_s * dev,int cmd,size_t arg)514 int bflb_spi_feature_control(struct bflb_device_s *dev, int cmd, size_t arg)
515 {
516 int ret = 0;
517 uint32_t reg_base;
518 uint32_t regval;
519 uint32_t div;
520
521 reg_base = dev->reg_base;
522
523 switch (cmd) {
524 case SPI_CMD_SET_DATA_WIDTH:
525 /* set data width, arg use @ref SPI_DATA_WIDTH, must clear fifo */
526 regval = getreg32(reg_base + SPI_FIFO_CONFIG_0_OFFSET);
527 regval |= SPI_TX_FIFO_CLR;
528 regval |= SPI_RX_FIFO_CLR;
529 putreg32(regval, reg_base + SPI_FIFO_CONFIG_0_OFFSET);
530
531 regval = getreg32(reg_base + SPI_CONFIG_OFFSET);
532 regval &= ~SPI_CR_SPI_FRAME_SIZE_MASK;
533 regval |= (arg - 1) << SPI_CR_SPI_FRAME_SIZE_SHIFT;
534 putreg32(regval, reg_base + SPI_CONFIG_OFFSET);
535 break;
536
537 case SPI_CMD_GET_DATA_WIDTH:
538 /* set data width, arg use @ref SPI_DATA_WIDTH */
539 regval = getreg32(reg_base + SPI_CONFIG_OFFSET);
540 regval &= SPI_CR_SPI_FRAME_SIZE_MASK;
541 regval >>= SPI_CR_SPI_FRAME_SIZE_SHIFT;
542 *(uint32_t *)arg = regval;
543 break;
544
545 case SPI_CMD_CLEAR_TX_FIFO:
546 /* clear tx fifo */
547 regval = getreg32(reg_base + SPI_FIFO_CONFIG_0_OFFSET);
548 regval |= SPI_TX_FIFO_CLR;
549 putreg32(regval, reg_base + SPI_FIFO_CONFIG_0_OFFSET);
550 break;
551
552 case SPI_CMD_CLEAR_RX_FIFO:
553 /* clear rx fifo */
554 regval = getreg32(reg_base + SPI_FIFO_CONFIG_0_OFFSET);
555 regval |= SPI_RX_FIFO_CLR;
556 putreg32(regval, reg_base + SPI_FIFO_CONFIG_0_OFFSET);
557 break;
558
559 case SPI_CMD_SET_CS_INTERVAL:
560 /* set CS continue mode, arg use true or false */
561 regval = getreg32(reg_base + SPI_CONFIG_OFFSET);
562 if (arg) {
563 regval |= SPI_CR_SPI_M_CONT_EN;
564 } else {
565 regval &= ~SPI_CR_SPI_M_CONT_EN;
566 }
567 putreg32(regval, reg_base + SPI_CONFIG_OFFSET);
568 break;
569
570 case SPI_CMD_RX_IGNORE:
571 /* set rx ignore, start: arg[20:16], stop: arg[4:0] */
572 regval = getreg32(reg_base + SPI_CONFIG_OFFSET);
573 if (arg) {
574 regval |= SPI_CR_SPI_RXD_IGNR_EN;
575 putreg32(arg, reg_base + SPI_RXD_IGNR_OFFSET);
576 } else {
577 regval &= ~SPI_CR_SPI_RXD_IGNR_EN;
578 }
579 putreg32(regval, reg_base + SPI_CONFIG_OFFSET);
580 break;
581
582 case SPI_CMD_SET_MODE:
583 /* set spi mode (clk phase and polarity), arg use @ref SPI_MODE*/
584 regval = getreg32(reg_base + SPI_CONFIG_OFFSET);
585 switch (arg) {
586 case SPI_MODE0:
587 /* CPOL=0 CHPHA=0 */
588 regval &= ~SPI_CR_SPI_SCLK_POL;
589 regval |= SPI_CR_SPI_SCLK_PH;
590 break;
591 case SPI_MODE1:
592 /* CPOL=0 CHPHA=1 */
593 regval &= ~SPI_CR_SPI_SCLK_POL;
594 regval &= ~SPI_CR_SPI_SCLK_PH;
595 break;
596 case SPI_MODE2:
597 /* CPOL=1 CHPHA=0 */
598 regval |= SPI_CR_SPI_SCLK_POL;
599 regval |= SPI_CR_SPI_SCLK_PH;
600 break;
601 case SPI_MODE3:
602 /* CPOL=1 CHPHA=1 */
603 regval |= SPI_CR_SPI_SCLK_POL;
604 regval &= ~SPI_CR_SPI_SCLK_PH;
605 break;
606 default:
607 break;
608 }
609 putreg32(regval, reg_base + SPI_CONFIG_OFFSET);
610 break;
611
612 case SPI_CMD_GET_MODE:
613 /* get spi mode (clk phase and polarity), ret @ref SPI_MODE*/
614 regval = getreg32(reg_base + SPI_CONFIG_OFFSET);
615 if (regval & SPI_CR_SPI_SCLK_POL) {
616 if (regval & SPI_CR_SPI_SCLK_PH) {
617 ret = SPI_MODE2;
618 } else {
619 ret = SPI_MODE3;
620 }
621 } else {
622 if (regval & SPI_CR_SPI_SCLK_PH) {
623 ret = SPI_MODE0;
624 } else {
625 ret = SPI_MODE1;
626 }
627 }
628 break;
629
630 case SPI_CMD_SET_FREQ:
631 /* set clk frequence, should be less than spi_clk/2*/
632 /* integer frequency segmentation by rounding */
633 div = (bflb_clk_get_peripheral_clock(BFLB_DEVICE_TYPE_SPI, dev->idx) / 2 * 10 / arg + 5) / 10;
634 div = (div) ? (div - 1) : 0;
635 div = (div > 0xff) ? 0xff : div;
636
637 regval = 0;
638 regval |= div << SPI_CR_SPI_PRD_D_PH_0_SHIFT;
639 regval |= div << SPI_CR_SPI_PRD_D_PH_1_SHIFT;
640 regval |= div << SPI_CR_SPI_PRD_S_SHIFT;
641 regval |= div << SPI_CR_SPI_PRD_P_SHIFT;
642 putreg32(regval, reg_base + SPI_PRD_0_OFFSET);
643 break;
644
645 case SPI_CMD_GET_FREQ:
646 /* get clk frequence */
647 regval = getreg32(reg_base + SPI_PRD_0_OFFSET);
648 div = (regval & SPI_CR_SPI_PRD_D_PH_0_MASK) >> SPI_CR_SPI_PRD_D_PH_0_SHIFT;
649 div += (regval & SPI_CR_SPI_PRD_D_PH_1_MASK) >> SPI_CR_SPI_PRD_D_PH_1_SHIFT;
650
651 ret = bflb_clk_get_peripheral_clock(BFLB_DEVICE_TYPE_SPI, dev->idx) / div;
652 break;
653
654 case SPI_CMD_SET_BIT_ORDER:
655 /* set bit order, arg use @ref SPI_BIT_ORDER */
656 regval = getreg32(reg_base + SPI_CONFIG_OFFSET);
657 if (arg == SPI_BIT_LSB) {
658 regval |= SPI_CR_SPI_BIT_INV;
659 } else {
660 regval &= ~SPI_CR_SPI_BIT_INV;
661 }
662 putreg32(regval, reg_base + SPI_CONFIG_OFFSET);
663 break;
664
665 case SPI_CMD_GET_BIT_ORDER:
666 regval = getreg32(reg_base + SPI_CONFIG_OFFSET);
667 if (regval & SPI_CR_SPI_BIT_INV) {
668 ret = SPI_BIT_LSB;
669 } else {
670 ret = !SPI_BIT_LSB;
671 }
672 break;
673
674 case SPI_CMD_SET_BYTE_ORDER:
675 /* set byte order, arg use @ref SPI_BYTE_ORDER */
676 regval = getreg32(reg_base + SPI_CONFIG_OFFSET);
677 if (arg == SPI_BYTE_LSB) {
678 regval &= ~SPI_CR_SPI_BYTE_INV;
679 } else {
680 regval |= SPI_CR_SPI_BYTE_INV;
681 }
682 putreg32(regval, reg_base + SPI_CONFIG_OFFSET);
683 break;
684
685 case SPI_CMD_GET_BYTE_ORDER:
686 regval = getreg32(reg_base + SPI_CONFIG_OFFSET);
687 if (regval & SPI_CR_SPI_BYTE_INV) {
688 ret = !SPI_BYTE_LSB;
689 } else {
690 ret = SPI_BYTE_LSB;
691 }
692 break;
693
694 default:
695 ret = -EPERM;
696 break;
697 }
698
699 return ret;
700 }