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 }