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