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 }