• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 ASR Microelectronics (Shanghai) Co., Ltd. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "duet_spi.h"
17 
18 duet_spi_callback_func g_duet_spi_callback_handler[DUET_SPI_NUM] = {0};
19 
duet_spi_struct_init(duet_spi_dev_t * init_struct)20 void duet_spi_struct_init(duet_spi_dev_t *init_struct)
21 {
22     init_struct->config.freq = 1000000; // 1M
23     init_struct->config.mode = SPI_ROLE_MASTER;
24     init_struct->priv = NULL;
25 }
26 
duet_spi_interrupt_config(SPI_TypeDef * SPIx,uint8_t spi_interrupt,uint8_t new_state)27 void duet_spi_interrupt_config(SPI_TypeDef *SPIx, uint8_t spi_interrupt, uint8_t new_state)
28 {
29     if (new_state == ENABLE) {
30         SPIx->IMSC |= spi_interrupt;
31     } else {
32         SPIx->IMSC &= ~spi_interrupt;
33     }
34 }
35 
duet_spi_dma_config(duet_spi_dev_t * spi,uint8_t dma_tx_rx_sel,uint8_t new_state)36 int32_t duet_spi_dma_config(duet_spi_dev_t *spi, uint8_t dma_tx_rx_sel, uint8_t new_state)
37 {
38     SPI_TypeDef *SPIx = NULL;
39     if (DUET_SPI0_INDEX == spi->port) {
40         SPIx = SPI0;
41     } else if (DUET_SPI1_INDEX == spi->port) {
42         SPIx = SPI1;
43     } else if (DUET_SPI2_INDEX == spi->port) {
44         SPIx = SPI2;
45     } else {
46         return EIO;
47     }
48     if (new_state == ENABLE) {
49         SPIx->DMA_CR |= dma_tx_rx_sel;
50     } else {
51         SPIx->DMA_CR &= ~dma_tx_rx_sel;
52     }
53     return 0;
54 }
55 
duet_spi_cmd(SPI_TypeDef * SPIx,uint8_t new_state)56 void duet_spi_cmd(SPI_TypeDef *SPIx, uint8_t new_state)
57 {
58     if (new_state == ENABLE) {
59         SPIx->CR1 |= (0x1 << 1);
60     } else {
61         SPIx->CR1 &= ~(0x1 << 1);
62     }
63 }
duet_spi_cpol_cpha_config(duet_spi_dev_t * spi,uint8_t mode)64 int32_t duet_spi_cpol_cpha_config(duet_spi_dev_t *spi, uint8_t mode)
65 {
66     uint8_t cpol, cpha;
67     SPI_TypeDef *SPIx = NULL;
68     if (DUET_SPI0_INDEX == spi->port) {
69         SPIx = SPI0;
70     } else if (DUET_SPI1_INDEX == spi->port) {
71         SPIx = SPI1;
72     } else if (DUET_SPI2_INDEX == spi->port) {
73         SPIx = SPI2;
74     } else {
75         return EIO;
76     }
77     switch (mode) {
78         case 0:
79             cpol = 0;
80             cpha = 0;
81             break;
82         case 1:
83             cpol = 0;
84             cpha = 1;
85             break;
86         case 2:
87             cpol = 1;
88             cpha = 0;
89             break;
90         case 3:
91             cpol = 1;
92             cpha = 1;
93             break;
94         default:
95             cpol = 0;
96             cpha = 0;
97             break;
98     }
99     SPIx->CR0 &= ~(0x3 << 6);  // reset SPI clk phase/polarity setting to mode 0
100     SPIx->CR0 |= (cpol << SPI_CLK_POLARITY_POS) | (cpha << SPI_CLK_PHASE_POS);
101     return 0;
102 }
103 
duet_spi_init(duet_spi_dev_t * spi)104 int32_t duet_spi_init(duet_spi_dev_t *spi)
105 {
106     uint32_t tmp_value, spi_clk = SPI_CLK;
107     uint8_t cpol, cpha;
108     SPI_TypeDef *SPIx = NULL;
109     if (DUET_SPI0_INDEX == spi->port) {
110         SPIx = SPI0;
111     } else if (DUET_SPI1_INDEX == spi->port) {
112         SPIx = SPI1;
113     } else if (DUET_SPI2_INDEX == spi->port) {
114         SPIx = SPI2;
115     } else {
116         return EIO;
117     }
118     // enable spi clk
119     if (SPIx == SPI0) {
120         tmp_value = REG_RD(PERI_CLK_EN_REG1) & (~(SPI0_BUS_CLK_EN | SPI0_PERI_CLK_EN));
121         REG_WR(PERI_CLK_EN_REG1, (tmp_value | (SPI0_BUS_CLK_EN | SPI0_PERI_CLK_EN)));
122     } else if (SPIx == SPI1) {
123         tmp_value = REG_RD(PERI_CLK_EN_REG1) & (~(SPI1_BUS_CLK_EN | SPI1_PERI_CLK_EN));
124         REG_WR(PERI_CLK_EN_REG1, (tmp_value | (SPI1_BUS_CLK_EN | SPI1_PERI_CLK_EN)));
125     } else {
126         tmp_value = REG_RD(PERI_CLK_EN_REG1) & (~(SPI2_BUS_CLK_EN | SPI2_PERI_CLK_EN));
127         REG_WR(PERI_CLK_EN_REG1, (tmp_value | (SPI2_BUS_CLK_EN | SPI2_PERI_CLK_EN)));
128     }
129     // fpga no effect, soc need
130     duet_spi_cmd(SPIx, DISABLE);
131     duet_spi_interrupt_config(SPIx, SPI_INTERRUPT_ALL, DISABLE);
132     duet_spi_interrupt_clear(SPIx, SPI_INTERRUPT_ALL);
133 
134     /* set frame format */
135     SPIx->CR0 &= ~(0x3 << 4);  // reset FRF to 0
136     SPIx->CR0 |= SPI_FRAME_FORMAT_SPI;
137     /* set sclk divider */
138     SPIx->CPSR &= ~0xff; // reset CPSR to 0
139     SPIx->CPSR |= 0x2;   // set CPSR to 2, shoule be even number between 2-254
140     SPIx->CR0 &= (0x00ff); // reset SCR to 0
141     SPIx->CR0 |= (spi_clk / 2 / spi->config.freq - 1) << 8; // set SCR to 0x7, serial clk = 16M/2/(1+7) = 1M
142     switch (SPI_CPOL_CPHA_MODE) {
143         case 0:
144             cpol = 0;
145             cpha = 0;
146             break;
147         case 1:
148             cpol = 0;
149             cpha = 1;
150             break;
151         case 2:
152             cpol = 1;
153             cpha = 0;
154             break;
155         case 3:
156             cpol = 1;
157             cpha = 1;
158             break;
159         default:
160             cpol = 0;
161             cpha = 0;
162             break;
163     }
164     /* set sclk polarity & phase */
165     SPIx->CR0 &= ~(0x3 << 6);  // reset SPI clk phase/polarity setting to mode 0
166     SPIx->CR0 |= (cpol << SPI_CLK_POLARITY_POS) | (cpha << SPI_CLK_PHASE_POS);
167 
168     /* set data size */
169     SPIx->CR0 &= ~(0xf);   // reset data size to 0
170     SPIx->CR0 |= SPI_DATA_SIZE_8BIT;
171 
172     if (spi->config.mode == SPI_ROLE_MASTER) {
173         SPIx->CR1 &= ~(0x1 << 2);  // reset master/slave select to 0, which is master mode
174     } else {
175         SPIx->CR1 &= ~(0x1 << 2);  // reset master/slave select to 0, which is master mode
176         SPIx->CR1 |= SPI_ROLE_SLAVE; // set to slave role
177     }
178 
179     /* dma handshake config,
180     should be enabled after dmac has been configured and ready */
181     //    if(SPI_DMA_TX_CONFIG == ENABLE)
182     //    {
183     //        SPIx->DMA_CR |= SPI_DMA_TX_EN;
184     //    }
185     //    else
186     //    {
187     //        SPIx->DMA_CR &= ~SPI_DMA_TX_EN;
188     //    }
189     //    if(SPI_DMA_RX_CONFIG == ENABLE)
190     //    {
191     //        SPIx->DMA_CR |= SPI_DMA_RX_EN;
192     //    }
193     //    else
194     //    {
195     //        SPIx->DMA_CR &= ~SPI_DMA_RX_EN;
196     //    }
197     if (spi->priv) {
198         // enable rx interrupt
199         SPIx->IMSC |= (SPI_INTERRUPT_RX_TIMEOUT | SPI_INTERRUPT_RX_FIFO_TRIGGER);
200         // enable cm4 interrupt
201         if (SPIx == SPI0) {
202             tmp_value = REG_RD(DUTE_IRQ_EN_REG) & (~SPI0_IRQ_BIT);
203             REG_WR(DUTE_IRQ_EN_REG, (tmp_value | (SPI0_IRQ_BIT)));
204             NVIC_EnableIRQ(SPI0_IRQn);
205         } else if (SPIx == SPI1) {
206             tmp_value = REG_RD(DUTE_IRQ_EN_REG) & (~SPI1_IRQ_BIT);
207             REG_WR(DUTE_IRQ_EN_REG, (tmp_value | (SPI1_IRQ_BIT)));
208             NVIC_EnableIRQ(SPI1_IRQn);
209         } else {
210             tmp_value = REG_RD(DUTE_IRQ_EN_REG) & (~SPI2_IRQ_BIT);
211             REG_WR(DUTE_IRQ_EN_REG, (tmp_value | (SPI2_IRQ_BIT)));
212             NVIC_EnableIRQ(SPI2_IRQn);
213         }
214         g_duet_spi_callback_handler[spi->port] = (duet_spi_callback_func)(spi->priv);
215     }
216     SPIx->CR1 |= (0x1 << 1);
217     return 0;
218 }
219 
220 /**
221  * De-initialises a SPI interface
222  *
223  *
224  * @param[in]  spi the SPI device to be de-initialised
225  *
226  * @return  0 : on success, EIO : if an error occurred
227  */
duet_spi_finalize(duet_spi_dev_t * spi)228 int32_t duet_spi_finalize(duet_spi_dev_t *spi)
229 {
230     SPI_TypeDef *SPIx;
231     unsigned int tmp_value;
232 
233     if (NULL == spi) {
234         return EIO;
235     }
236 
237     if (DUET_SPI0_INDEX == spi->port) {
238         SPIx = SPI0;
239     } else if (DUET_SPI1_INDEX == spi->port) {
240         SPIx = SPI1;
241     } else if (DUET_SPI2_INDEX == spi->port) {
242         SPIx = SPI2;
243     } else {
244         return EIO;
245     }
246 
247     // disable all spi interrupt
248     SPIx->IMSC  = SPI_DISABLE_INTERRUPT_ALL;
249     // disable all spi config
250     SPIx->CR0 = 0;
251     SPIx->CR1 = 0;
252 
253     // disable cm4 interrupt
254     if (SPI0 == SPIx) {
255         tmp_value = REG_RD(DUTE_IRQ_DIS_REG) & (~SPI0_IRQ_BIT);
256         REG_WR(DUTE_IRQ_DIS_REG, (tmp_value | (SPI0_IRQ_BIT)));
257         NVIC_DisableIRQ(SPI0_IRQn);
258     } else if (SPI1 == SPIx) {
259         tmp_value = REG_RD(DUTE_IRQ_DIS_REG) & (~SPI1_IRQ_BIT);
260         REG_WR(DUTE_IRQ_DIS_REG, (tmp_value | (SPI1_IRQ_BIT)));
261         NVIC_DisableIRQ(SPI1_IRQn);
262     } else {
263         tmp_value = REG_RD(DUTE_IRQ_DIS_REG) & (~SPI2_IRQ_BIT);
264         REG_WR(DUTE_IRQ_DIS_REG, (tmp_value | (SPI2_IRQ_BIT)));
265         NVIC_DisableIRQ(SPI2_IRQn);
266     }
267 
268     // spi sclk disable, fpga no effect, soc need
269     if (SPI0 == SPIx) {
270         tmp_value = REG_RD(PERI_CLK_DIS_REG1) & (~(SPI0_BUS_CLK_EN | SPI0_PERI_CLK_EN));
271         REG_WR(PERI_CLK_DIS_REG1, (tmp_value | (SPI0_BUS_CLK_EN | SPI0_PERI_CLK_EN)));
272     } else if (SPI1 == SPIx) {
273         tmp_value = REG_RD(PERI_CLK_DIS_REG1) & (~(SPI0_BUS_CLK_EN | SPI0_PERI_CLK_EN));
274         REG_WR(PERI_CLK_DIS_REG1, (tmp_value | (SPI0_BUS_CLK_EN | SPI0_PERI_CLK_EN)));
275     } else {
276         tmp_value = REG_RD(PERI_CLK_DIS_REG1) & (~(SPI0_BUS_CLK_EN | SPI0_PERI_CLK_EN));
277         REG_WR(PERI_CLK_DIS_REG1, (tmp_value | (SPI0_BUS_CLK_EN | SPI0_PERI_CLK_EN)));
278     }
279 
280     g_duet_spi_callback_handler[spi->port] = NULL;
281     return 0;
282 }
283 
duet_spi_send(duet_spi_dev_t * spi,const uint8_t * data,uint16_t size,uint32_t timeout)284 int32_t duet_spi_send(duet_spi_dev_t *spi, const uint8_t *data, uint16_t size, uint32_t timeout)
285 {
286     SPI_TypeDef *SPIx = NULL;
287     if (DUET_SPI0_INDEX == spi->port) {
288         SPIx = SPI0;
289     } else if (DUET_SPI1_INDEX == spi->port) {
290         SPIx = SPI1;
291     } else if (DUET_SPI2_INDEX == spi->port) {
292         SPIx = SPI2;
293     } else {
294         return EIO;
295     }
296     while (size--) {
297         while (!(duet_spi_get_flag_status(SPIx, SPI_FLAG_TX_FIFO_NOT_FULL))); // wait till tx fifo is not full
298         SPIx->DR = *data++;
299     }
300     return 0;
301 }
302 
303 // void duet_spi_receive(SPI_TypeDef * SPIx, void * rx_data, uint16_t len)
304 // {
305 //    while (len--)
306 //    {
307 //        while (!(spi_get_flag_status(SPIx, SPI_FLAG_RX_FIFO_NOT_EMPTY))); // wait till rx fifo is not empty, change to timeout mechanism???
308 
309 //        *rx_data++ = SPIx->DR ;
310 //    }
311 // }
312 
getSpixViaIdx(uint8_t spi_idx)313 SPI_TypeDef *getSpixViaIdx(uint8_t spi_idx)
314 {
315     switch (spi_idx) {
316         case DUET_SPI0_INDEX:
317             return SPI0;
318         case DUET_SPI1_INDEX:
319             return SPI1;
320         case DUET_SPI2_INDEX:
321             return SPI2;
322         default:
323             return NULL;
324     }
325 }
326 
327 /* spi interrupt handler */
SPIX_IRQHandler(uint8_t spi_idx)328 void SPIX_IRQHandler(uint8_t spi_idx)
329 {
330     uint16_t tmp;
331     SPI_TypeDef *SPIx = getSpixViaIdx(spi_idx);
332     if (duet_spi_get_interrupt_status(SPIx, SPI_INTERRUPT_TX_FIFO_TRIGGER)) {
333         duet_spi_interrupt_config(SPIx, SPI_INTERRUPT_TX_FIFO_TRIGGER, DISABLE); // disable
334         duet_spi_interrupt_clear(SPIx, SPI_INTERRUPT_TX_FIFO_TRIGGER); // clear
335         duet_spi_interrupt_config(SPIx, SPI_INTERRUPT_TX_FIFO_TRIGGER, ENABLE); // enable
336     }
337     if (duet_spi_get_interrupt_status(SPIx, SPI_INTERRUPT_RX_FIFO_TRIGGER)
338          || duet_spi_get_interrupt_status(SPIx, SPI_INTERRUPT_RX_TIMEOUT)) {
339         duet_spi_interrupt_config(SPIx, SPI_INTERRUPT_RX_FIFO_TRIGGER | SPI_INTERRUPT_RX_TIMEOUT, DISABLE); // disable
340         duet_spi_interrupt_clear(SPIx, SPI_INTERRUPT_RX_FIFO_TRIGGER | SPI_INTERRUPT_RX_TIMEOUT); // clear
341         while (SPIx->SR & SPI_FLAG_RX_FIFO_NOT_EMPTY) {
342             tmp = (uint16_t)(SPIx->DR);
343             if (g_duet_spi_callback_handler[spi_idx] != NULL) {
344                 g_duet_spi_callback_handler[spi_idx](tmp);
345             }
346         }
347         duet_spi_interrupt_config(SPIx, SPI_INTERRUPT_RX_FIFO_TRIGGER | SPI_INTERRUPT_RX_TIMEOUT, ENABLE); // enable
348     }
349 }
350 
SPI0_IRQHandler(void)351 void SPI0_IRQHandler(void)
352 {
353     duet_intrpt_enter();
354     SPIX_IRQHandler(0);
355     duet_intrpt_exit();
356 }
357 
SPI1_IRQHandler(void)358 void SPI1_IRQHandler(void)
359 {
360     duet_intrpt_enter();
361     SPIX_IRQHandler(1);
362     duet_intrpt_exit();
363 }
364 
SPI2_IRQHandler(void)365 void SPI2_IRQHandler(void)
366 {
367     duet_intrpt_enter();
368     SPIX_IRQHandler(2);
369     duet_intrpt_exit();
370 }
371 
duet_spi_set_callback(uint8_t spi_idx,duet_spi_callback_func func)372 void duet_spi_set_callback(uint8_t spi_idx, duet_spi_callback_func func)
373 {
374     if (spi_idx >= DUET_SPI_NUM) {
375         return;
376     }
377     g_duet_spi_callback_handler[spi_idx] = func;
378 
379 }