1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2024-04-08 QT-one first version
9 */
10
11 #include <rtdbg.h>
12 #include "drv_spi.h"
13
14 #ifdef RT_USING_SPI
15 #if !defined(BSP_USING_SPI0) && !defined(BSP_USING_SPI1)
16 #error "Please define at least one BSP_USING_SPIx"
17 #endif
18
19 struct ht32_spi_config
20 {
21 HT_SPI_TypeDef *spi_x;
22 const char *spi_name;
23 IRQn_Type irq;
24 };
25
26 struct ht32_spi
27 {
28 struct ht32_spi_config *config;
29 struct rt_spi_bus spi_bus;
30 };
31
32 struct ht32_spi_cs
33 {
34 HT_GPIO_TypeDef *gpio_x;
35 uint32_t gpio_pin;
36 };
37
38 enum
39 {
40 #ifdef BSP_USING_SPI0
41 SPI0_INDEX,
42 #endif
43 #ifdef BSP_USING_SPI1
44 SPI1_INDEX,
45 #endif
46 };
47
48 static struct ht32_spi_config spi_config[] =
49 {
50 #ifdef BSP_USING_SPI0
51 {
52 .spi_x = HT_SPI0,
53 .spi_name = BSP_USING_SPI0_NAME,
54 .irq = SPI0_IRQn
55 },
56 #endif
57 #ifdef BSP_USING_SPI1
58 {
59 .spi_x = HT_SPI1,
60 .spi_name = BSP_USING_SPI1_NAME,
61 .irq = SPI1_IRQn
62 },
63 #endif
64 };
65
66 static struct ht32_spi spis[sizeof(spi_config) / sizeof(spi_config[0])] = {0};
67
68 /* attach the spi device to spi bus, this function must be used after initialization */
rt_hw_spi_device_attach(const char * bus_name,const char * device_name,HT_GPIO_TypeDef * cs_gpiox,uint16_t cs_gpio_pin)69 rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, HT_GPIO_TypeDef *cs_gpiox, uint16_t cs_gpio_pin)
70 {
71 CKCU_PeripClockConfig_TypeDef CKCUClock = {{0}};
72
73 RT_ASSERT(bus_name != RT_NULL);
74 RT_ASSERT(device_name != RT_NULL);
75
76 rt_err_t result;
77 struct rt_spi_device *spi_device;
78 struct ht32_spi_cs *cs_pin;
79
80 if ((cs_gpiox) == HT_GPIOA)
81 {
82 CKCUClock.Bit.PA = 1;
83 CKCU_PeripClockConfig(CKCUClock, ENABLE);
84 AFIO_GPxConfig(GPIO_PA, cs_gpio_pin, AFIO_FUN_GPIO);
85 }
86 else if ((cs_gpiox) == HT_GPIOB)
87 {
88 CKCUClock.Bit.PB = 1;
89 CKCU_PeripClockConfig(CKCUClock, ENABLE);
90 AFIO_GPxConfig(GPIO_PB, cs_gpio_pin, AFIO_FUN_GPIO);
91 }
92 #if defined(HT_GPIOC)
93 else if ((cs_gpiox) == HT_GPIOC)
94 {
95 CKCUClock.Bit.PC = 1;
96 CKCU_PeripClockConfig(CKCUClock, ENABLE);
97 AFIO_GPxConfig(GPIO_PC, cs_gpio_pin, AFIO_FUN_GPIO);
98 }
99 #endif
100 #if defined(HT_GPIOD)
101 else if ((cs_gpiox) == HT_GPIOD)
102 {
103 CKCUClock.Bit.PD = 1;
104 CKCU_PeripClockConfig(CKCUClock, ENABLE);
105 AFIO_GPxConfig(GPIO_PD, cs_gpio_pin, AFIO_FUN_GPIO);
106 }
107 #endif
108 #if defined(HT_GPIOE)
109 else if ((cs_gpiox) == HT_GPIOE)
110 {
111 CKCUClock.Bit.PE = 1;
112 CKCU_PeripClockConfig(CKCUClock, ENABLE);
113 AFIO_GPxConfig(GPIO_PE, cs_gpio_pin, AFIO_FUN_GPIO);
114 }
115 #endif
116 #if defined(HT_GPIOF)
117 else if ((cs_gpiox) == HT_GPIOF)
118 {
119 CKCUClock.Bit.PF = 1;
120 CKCU_PeripClockConfig(CKCUClock, ENABLE);
121 AFIO_GPxConfig(GPIO_PF, cs_gpio_pin, AFIO_FUN_GPIO);
122 }
123 #endif
124 GPIO_PullResistorConfig(cs_gpiox, cs_gpio_pin, GPIO_PR_DISABLE);
125 GPIO_WriteOutBits(cs_gpiox, cs_gpio_pin, SET);
126 GPIO_DirectionConfig(cs_gpiox, cs_gpio_pin, GPIO_DIR_OUT);
127
128 /* attach the device to spi bus */
129 spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
130 RT_ASSERT(spi_device != RT_NULL);
131 cs_pin = (struct ht32_spi_cs *)rt_malloc(sizeof(struct ht32_spi_cs));
132 RT_ASSERT(cs_pin != RT_NULL);
133 cs_pin->gpio_x = cs_gpiox;
134 cs_pin->gpio_pin = cs_gpio_pin;
135 result = rt_spi_bus_attach_device(spi_device, device_name, bus_name, (void *)cs_pin);
136
137 if (result != RT_EOK)
138 {
139 LOG_D("%s attach to %s faild, %d\n", device_name, bus_name, result);
140 }
141
142 RT_ASSERT(result == RT_EOK);
143
144 LOG_D("%s attach to %s done", device_name, bus_name);
145
146 return result;
147 }
148
ht32_configure(struct rt_spi_device * device,struct rt_spi_configuration * configuration)149 static rt_err_t ht32_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration)
150 {
151 struct rt_spi_bus *spi_bus = (struct rt_spi_bus *)device->bus;
152 struct ht32_spi *spi_instance = (struct ht32_spi *)spi_bus->parent.user_data;
153
154 SPI_InitTypeDef SPI_InitStructure;
155 CKCU_PeripClockConfig_TypeDef CKCUClock = {{0}};
156
157 RT_ASSERT(device != RT_NULL);
158 RT_ASSERT(configuration != RT_NULL);
159 #ifdef BSP_USING_SPI0
160 if (HT_SPI0 == spi_instance->config->spi_x)
161 {
162 CKCUClock.Bit.SPI0 = 1;
163 }
164 #endif
165 #ifdef BSP_USING_SPI1
166 if (HT_SPI1 == spi_instance->config->spi_x)
167 {
168 CKCUClock.Bit.SPI1 = 1;
169 }
170 #endif
171 CKCUClock.Bit.AFIO = 1;
172 CKCU_PeripClockConfig(CKCUClock, ENABLE);
173
174 ht32_spi_gpio_init(spi_instance->config->spi_x);
175
176 /* data_width */
177 if (configuration->data_width <= 8)
178 {
179 SPI_InitStructure.SPI_DataLength = SPI_DATALENGTH_8;
180 }
181 else if (configuration->data_width <= 16)
182 {
183 SPI_InitStructure.SPI_DataLength = SPI_DATALENGTH_16;
184 }
185 else
186 {
187 return -RT_ERROR;
188 }
189
190 /* Set the polarity and phase of the SPI */
191 switch (configuration->mode & RT_SPI_MODE_3)
192 {
193 case RT_SPI_MODE_0:
194 SPI_InitStructure.SPI_CPOL = SPI_CPOL_LOW;
195 SPI_InitStructure.SPI_CPHA = SPI_CPHA_FIRST;
196 break;
197 case RT_SPI_MODE_1:
198 SPI_InitStructure.SPI_CPOL = SPI_CPOL_LOW;
199 SPI_InitStructure.SPI_CPHA = SPI_CPHA_SECOND;
200 break;
201 case RT_SPI_MODE_2:
202 SPI_InitStructure.SPI_CPOL = SPI_CPOL_HIGH;
203 SPI_InitStructure.SPI_CPHA = SPI_CPHA_FIRST;
204 break;
205 case RT_SPI_MODE_3:
206 SPI_InitStructure.SPI_CPOL = SPI_CPOL_HIGH;
207 SPI_InitStructure.SPI_CPHA = SPI_CPHA_SECOND;
208 break;
209 }
210
211 /* Set the SPI as a master or slave */
212 SPI_InitStructure.SPI_Mode = (configuration->mode & RT_SPI_SLAVE) ? (SPI_SLAVE) : (SPI_MASTER);
213
214 /* Set the data high or low first */
215 SPI_InitStructure.SPI_FirstBit = (configuration->mode & RT_SPI_MSB) ? (SPI_FIRSTBIT_MSB) : (SPI_FIRSTBIT_LSB);
216
217 /* SEL uses software by default */
218 SPI_InitStructure.SPI_SELMode = SPI_SEL_SOFTWARE;
219
220 /* SEL effective level */
221 SPI_InitStructure.SPI_SELPolarity = (configuration->mode & RT_SPI_CS_HIGH) ? (SPI_SELPOLARITY_HIGH) : (SPI_SELPOLARITY_LOW);
222
223 /* Configure the SCK clock frequency of the SPI */
224 if (configuration->max_hz < 0xFFFF)
225 {
226 SPI_InitStructure.SPI_ClockPrescaler = ((configuration->max_hz) & 0xFFFF);
227 }
228 else
229 {
230 return -RT_ERROR;
231 }
232
233 SPI_InitStructure.SPI_FIFO = SPI_FIFO_DISABLE;
234 SPI_InitStructure.SPI_RxFIFOTriggerLevel = 0;
235 SPI_InitStructure.SPI_TxFIFOTriggerLevel = 0;
236 SPI_Init(spi_instance->config->spi_x, &SPI_InitStructure);
237 #if (!LIBCFG_SPI_NO_MULTI_MASTER)
238 SPI_SELOutputCmd(spi_instance->config->spi_x, ENABLE);
239 #endif
240
241 SPI_Cmd(spi_instance->config->spi_x, ENABLE);
242 return RT_EOK;
243 }
244
ht32_xfer(struct rt_spi_device * device,struct rt_spi_message * message)245 static rt_ssize_t ht32_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
246 {
247 struct rt_spi_bus *ht32_spi_bus = (struct rt_spi_bus *)device->bus;
248 struct ht32_spi *spi_instance = (struct ht32_spi *)ht32_spi_bus->parent.user_data;
249 struct rt_spi_configuration *config = &device->config;
250 struct ht32_spi_cs *ht32_spi_cs = device->parent.user_data;
251
252 RT_ASSERT(device != NULL);
253 RT_ASSERT(message != NULL);
254
255 /* take cs */
256 if (message->cs_take)
257 {
258 GPIO_ClearOutBits(ht32_spi_cs->gpio_x, ht32_spi_cs->gpio_pin);
259 LOG_D("spi take cs\n");
260 }
261
262 if (config->data_width <= 8)
263 {
264 const rt_uint8_t *send_ptr = message->send_buf;
265 rt_uint8_t *recv_ptr = message->recv_buf;
266 rt_uint32_t size = message->length;
267
268 LOG_D("spi poll transfer start: %d\n", size);
269
270 while (size--)
271 {
272 rt_uint8_t data = 0xFF;
273
274 if (send_ptr != RT_NULL)
275 {
276 data = *send_ptr++;
277 }
278
279 /* wait until the transmit buffer is empty */
280 while (SPI_GetFlagStatus(spi_instance->config->spi_x, SPI_FLAG_TXE) == RESET);
281 /* send the byte */
282 SPI_SendData(spi_instance->config->spi_x, data);
283
284 /* wait until a data is received */
285 while (SPI_GetFlagStatus(spi_instance->config->spi_x, SPI_INT_RXBNE) == RESET);
286 /* get the received data */
287 data = SPI_ReceiveData(spi_instance->config->spi_x);
288
289 if (recv_ptr != RT_NULL)
290 {
291 *recv_ptr++ = data;
292 }
293 }
294 LOG_D("spi poll transfer finsh\n");
295 }
296 else if (config->data_width <= 16)
297 {
298 const rt_uint16_t *send_ptr = message->send_buf;
299 rt_uint16_t *recv_ptr = message->recv_buf;
300 rt_uint32_t size = message->length;
301
302 while (size--)
303 {
304 rt_uint16_t data = 0xFF;
305
306 if (send_ptr != RT_NULL)
307 {
308 data = *send_ptr++;
309 }
310
311 /* wait until the transmit buffer is empty */
312 while (SPI_GetFlagStatus(spi_instance->config->spi_x, SPI_FLAG_TXE) == RESET);
313 /* send the byte */
314 SPI_SendData(spi_instance->config->spi_x, data);
315
316 /* wait until a data is received */
317 while (SPI_GetFlagStatus(spi_instance->config->spi_x, SPI_INT_RXBNE) == RESET);
318 /* get the received data */
319 data = SPI_ReceiveData(spi_instance->config->spi_x);
320
321 if (recv_ptr != RT_NULL)
322 {
323 *recv_ptr++ = data;
324 }
325 }
326 }
327
328 /* release cs */
329 if (message->cs_release)
330 {
331 GPIO_SetOutBits(ht32_spi_cs->gpio_x, ht32_spi_cs->gpio_pin);
332 LOG_D("spi release cs\n");
333 }
334
335 return message->length;
336 }
337
338 static struct rt_spi_ops ht32_spi_ops =
339 {
340 .configure = ht32_configure,
341 .xfer = ht32_xfer
342 };
343
rt_hw_spi_init(void)344 int rt_hw_spi_init(void)
345 {
346 int i;
347 rt_err_t result;
348 rt_size_t obj_num = sizeof(spis) / sizeof(struct ht32_spi);
349
350 for (i = 0; i < obj_num; i++)
351 {
352 spis[i].config = &spi_config[i];
353 spis[i].spi_bus.parent.user_data = (void *)&spis[i];
354 result = rt_spi_bus_register(&spis[i].spi_bus, spis[i].config->spi_name, &ht32_spi_ops);
355 }
356 return result;
357 }
358 INIT_BOARD_EXPORT(rt_hw_spi_init);
359
360 #endif /* RT_USING_SPI */
361