1 /*
2 * Copyright (c) 2006-2022, Synwit Technology Co.,Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2021-07-01 lik first version
9 */
10
11 #include "drv_spi.h"
12
13 #ifdef RT_USING_SPI
14 #ifdef BSP_USING_SPI
15
16 //#define DRV_DEBUG
17 #define LOG_TAG "drv.spi"
18 #include <drv_log.h>
19
20 #if !defined(BSP_USING_SPI0) && !defined(BSP_USING_SPI1)
21 #error "Please define at least one BSP_USING_SPIx"
22 /* this driver can be disabled at menuconfig ? RT-Thread Components ? Device Drivers */
23 #endif
24
25 struct swm_spi_cs
26 {
27 GPIO_TypeDef *GPIOx;
28 uint32_t gpio_pin;
29 };
30
31 struct swm_spi_cfg
32 {
33 const char *name;
34 SPI_TypeDef *SPIx;
35 SPI_InitStructure spi_initstruct;
36 };
37
38 /* swm spi dirver class */
39 struct swm_spi_device
40 {
41 struct swm_spi_cfg *spi_cfg;
42 struct rt_spi_configuration *configure;
43 struct rt_spi_bus spi_bus;
44 };
45
46 #ifdef BSP_USING_SPI0
47 #ifndef SPI0_BUS_CONFIG
48 #define SPI0_BUS_CONFIG \
49 { \
50 .name = "spi0", \
51 .SPIx = SPI0, \
52 .spi_initstruct.clkDiv = SPI_CLKDIV_16, \
53 .spi_initstruct.FrameFormat = SPI_FORMAT_SPI, \
54 .spi_initstruct.SampleEdge = SPI_SECOND_EDGE, \
55 .spi_initstruct.IdleLevel = SPI_HIGH_LEVEL, \
56 .spi_initstruct.WordSize = 8, \
57 .spi_initstruct.Master = 1, \
58 .spi_initstruct.RXThreshold = 0, \
59 .spi_initstruct.RXThresholdIEn = 0, \
60 .spi_initstruct.TXThreshold = 0, \
61 .spi_initstruct.TXThresholdIEn = 0, \
62 .spi_initstruct.TXCompleteIEn = 0, \
63 }
64 #endif /* SPI0_BUS_CONFIG */
65 #endif /* BSP_USING_SPI0 */
66
67 #ifdef BSP_USING_SPI1
68 #ifndef SPI1_BUS_CONFIG
69 #define SPI1_BUS_CONFIG \
70 { \
71 .name = "spi1", \
72 .SPIx = SPI1, \
73 .spi_initstruct.clkDiv = SPI_CLKDIV_16, \
74 .spi_initstruct.FrameFormat = SPI_FORMAT_SPI, \
75 .spi_initstruct.SampleEdge = SPI_SECOND_EDGE, \
76 .spi_initstruct.IdleLevel = SPI_HIGH_LEVEL, \
77 .spi_initstruct.WordSize = 8, \
78 .spi_initstruct.Master = 1, \
79 .spi_initstruct.RXThreshold = 0, \
80 .spi_initstruct.RXThresholdIEn = 0, \
81 .spi_initstruct.TXThreshold = 0, \
82 .spi_initstruct.TXThresholdIEn = 0, \
83 .spi_initstruct.TXCompleteIEn = 0, \
84 }
85 #endif /* SPI1_BUS_CONFIG */
86 #endif /* BSP_USING_SPI1 */
87
88 static struct swm_spi_cfg swm_spi_cfg[] =
89 {
90 #ifdef BSP_USING_SPI0
91 SPI0_BUS_CONFIG,
92 #endif
93 #ifdef BSP_USING_SPI1
94 SPI1_BUS_CONFIG,
95 #endif
96 };
97
98 static struct swm_spi_device spi_bus_obj[sizeof(swm_spi_cfg) / sizeof(swm_spi_cfg[0])] = {0};
99
swm_spi_configure(struct rt_spi_device * device,struct rt_spi_configuration * configure)100 static rt_err_t swm_spi_configure(struct rt_spi_device *device,
101 struct rt_spi_configuration *configure)
102 {
103 RT_ASSERT(device != RT_NULL);
104 RT_ASSERT(configure != RT_NULL);
105
106 struct swm_spi_device *spi_drv = rt_container_of(device->bus, struct swm_spi_device, spi_bus);
107 spi_drv->configure = configure;
108 struct swm_spi_cfg *spi_cfg = spi_drv->spi_cfg;
109
110 if (configure->mode & RT_SPI_SLAVE)
111 {
112 spi_cfg->spi_initstruct.Master = 0;
113 }
114 else
115 {
116 spi_cfg->spi_initstruct.Master = 1;
117 }
118
119 if (configure->mode & RT_SPI_3WIRE)
120 {
121 return -RT_EINVAL;
122 }
123
124 if (configure->data_width == 8)
125 {
126 spi_cfg->spi_initstruct.WordSize = 8;
127 }
128 else if (configure->data_width == 16)
129 {
130 spi_cfg->spi_initstruct.WordSize = 16;
131 }
132 else
133 {
134 return -RT_EIO;
135 }
136
137 if (configure->mode & RT_SPI_CPHA)
138 {
139 spi_cfg->spi_initstruct.SampleEdge = SPI_SECOND_EDGE;
140 }
141 else
142 {
143 spi_cfg->spi_initstruct.SampleEdge = SPI_FIRST_EDGE;
144 }
145
146 if (configure->mode & RT_SPI_CPOL)
147 {
148 spi_cfg->spi_initstruct.IdleLevel = SPI_HIGH_LEVEL;
149 }
150 else
151 {
152 spi_cfg->spi_initstruct.IdleLevel = SPI_LOW_LEVEL;
153 }
154
155 if (configure->max_hz >= SystemCoreClock / 2)
156 {
157 spi_cfg->spi_initstruct.clkDiv = SPI_CLKDIV_2;
158 }
159 else if (configure->max_hz >= SystemCoreClock / 4)
160 {
161 spi_cfg->spi_initstruct.clkDiv = SPI_CLKDIV_4;
162 }
163 else if (configure->max_hz >= SystemCoreClock / 8)
164 {
165 spi_cfg->spi_initstruct.clkDiv = SPI_CLKDIV_8;
166 }
167 else if (configure->max_hz >= SystemCoreClock / 16)
168 {
169 spi_cfg->spi_initstruct.clkDiv = SPI_CLKDIV_16;
170 }
171 else if (configure->max_hz >= SystemCoreClock / 32)
172 {
173 spi_cfg->spi_initstruct.clkDiv = SPI_CLKDIV_32;
174 }
175 else if (configure->max_hz >= SystemCoreClock / 64)
176 {
177 spi_cfg->spi_initstruct.clkDiv = SPI_CLKDIV_64;
178 }
179 else if (configure->max_hz >= SystemCoreClock / 128)
180 {
181 spi_cfg->spi_initstruct.clkDiv = SPI_CLKDIV_128;
182 }
183 else if (configure->max_hz >= SystemCoreClock / 256)
184 {
185 spi_cfg->spi_initstruct.clkDiv = SPI_CLKDIV_256;
186 }
187 else
188 {
189 /* min prescaler 512 */
190 spi_cfg->spi_initstruct.clkDiv = SPI_CLKDIV_512;
191 }
192
193 SPI_Init(spi_cfg->SPIx, &(spi_cfg->spi_initstruct));
194 SPI_Open(spi_cfg->SPIx);
195 LOG_D("%s init done", spi_cfg->name);
196 return RT_EOK;
197 }
198
199 #define SPISTEP(datalen) (((datalen) == 8) ? 1 : 2)
200 #define SPISEND_1(reg, ptr, datalen) \
201 do \
202 { \
203 if (datalen == 8) \
204 { \
205 (reg) = *(rt_uint8_t *)(ptr); \
206 } \
207 else \
208 { \
209 (reg) = *(rt_uint16_t *)(ptr); \
210 } \
211 } while (0)
212 #define SPIRECV_1(reg, ptr, datalen) \
213 do \
214 { \
215 if (datalen == 8) \
216 { \
217 *(rt_uint8_t *)(ptr) = (reg); \
218 } \
219 else \
220 { \
221 *(rt_uint16_t *)(ptr) = reg; \
222 } \
223 } while (0)
224
swm_spi_txrx1b(struct swm_spi_device * spi_drv,void * rcvb,const void * sndb)225 static rt_err_t swm_spi_txrx1b(struct swm_spi_device *spi_drv, void *rcvb, const void *sndb)
226 {
227 rt_uint32_t padrcv = 0;
228 rt_uint32_t padsnd = 0xFF;
229 if (!rcvb && !sndb)
230 {
231 return -RT_ERROR;
232 }
233 if (!rcvb)
234 {
235 rcvb = &padrcv;
236 }
237 if (!sndb)
238 {
239 sndb = &padsnd;
240 }
241 while (SPI_IsTXFull(spi_drv->spi_cfg->SPIx))
242 ;
243 SPISEND_1(spi_drv->spi_cfg->SPIx->DATA, sndb, spi_drv->spi_cfg->spi_initstruct.WordSize);
244 while (SPI_IsRXEmpty(spi_drv->spi_cfg->SPIx))
245 ;
246 SPIRECV_1(spi_drv->spi_cfg->SPIx->DATA, rcvb, spi_drv->spi_cfg->spi_initstruct.WordSize);
247 return RT_EOK;
248 }
249
swm_spi_xfer(struct rt_spi_device * device,struct rt_spi_message * message)250 static rt_uint32_t swm_spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
251 {
252 rt_err_t res;
253
254 RT_ASSERT(device != RT_NULL);
255 RT_ASSERT(device->bus != RT_NULL);
256 RT_ASSERT(device->bus->parent.user_data != RT_NULL);
257 RT_ASSERT(message != RT_NULL);
258
259 struct swm_spi_device *spi_drv = rt_container_of(device->bus, struct swm_spi_device, spi_bus);
260 struct swm_spi_cfg *spi_cfg = spi_drv->spi_cfg;
261 struct swm_spi_cs *cs = device->parent.user_data;
262
263 if (message->cs_take)
264 {
265 GPIO_ClrBit(cs->GPIOx, cs->gpio_pin);
266 }
267
268 LOG_D("%s transfer prepare and start", spi_cfg->name);
269 LOG_D("%s sendbuf: %X, recvbuf: %X, length: %d",
270 spi_cfg->name, (uint32_t)message->send_buf, (uint32_t)message->recv_buf, message->length);
271
272 const rt_uint8_t *sndb = message->send_buf;
273 rt_uint8_t *rcvb = message->recv_buf;
274 rt_int32_t length = message->length;
275
276 while (length)
277 {
278 res = swm_spi_txrx1b(spi_drv, rcvb, sndb);
279 if (rcvb)
280 {
281 rcvb += SPISTEP(spi_cfg->spi_initstruct.WordSize);
282 }
283 if (sndb)
284 {
285 sndb += SPISTEP(spi_cfg->spi_initstruct.WordSize);
286 }
287 if (res != RT_EOK)
288 {
289 break;
290 }
291 length--;
292 }
293 /* Wait until Busy flag is reset before disabling SPI */
294 while (!SPI_IsTXEmpty(spi_cfg->SPIx) && !SPI_IsRXEmpty(spi_cfg->SPIx))
295 ;
296 if (message->cs_release)
297 {
298 GPIO_SetBit(cs->GPIOx, cs->gpio_pin);
299 }
300 return message->length - length;
301 }
302
303 static const struct rt_spi_ops swm_spi_ops =
304 {
305 .configure = swm_spi_configure,
306 .xfer = swm_spi_xfer,
307 };
308
309 //cannot be used before completion init
rt_hw_spi_device_attach(const char * bus_name,const char * device_name,GPIO_TypeDef * cs_gpiox,uint32_t cs_gpio_pin)310 rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, GPIO_TypeDef *cs_gpiox, uint32_t cs_gpio_pin)
311 {
312 RT_ASSERT(bus_name != RT_NULL);
313 RT_ASSERT(device_name != RT_NULL);
314
315 rt_err_t result;
316 struct rt_spi_device *spi_device;
317 struct swm_spi_cs *cs_pin;
318
319 GPIO_Init(cs_gpiox, cs_gpio_pin, 1, 1, 0, 0);
320 GPIO_SetBit(cs_gpiox, cs_gpio_pin);
321
322 spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
323 RT_ASSERT(spi_device != RT_NULL);
324 cs_pin = (struct swm_spi_cs *)rt_malloc(sizeof(struct swm_spi_cs));
325 RT_ASSERT(cs_pin != RT_NULL);
326 cs_pin->GPIOx = cs_gpiox;
327 cs_pin->gpio_pin = cs_gpio_pin;
328
329 result = rt_spi_bus_attach_device(spi_device, device_name, bus_name, (void *)cs_pin);
330 if (result != RT_EOK)
331 {
332 LOG_E("%s attach to %s faild, %d\n", device_name, bus_name, result);
333 }
334 RT_ASSERT(result == RT_EOK);
335 LOG_D("%s attach to %s done", device_name, bus_name);
336 return result;
337 }
338
swm_spi_init(void)339 int swm_spi_init(void)
340 {
341 rt_err_t result;
342
343 #ifdef BSP_USING_SPI0
344 PORT_Init(PORTM, PIN2, PORTM_PIN2_SPI0_SCLK, 0);
345 PORT_Init(PORTM, PIN4, PORTM_PIN4_SPI0_MISO, 1);
346 PORT_Init(PORTM, PIN5, PORTM_PIN5_SPI0_MOSI, 0);
347 #endif //BSP_USING_SPI0
348
349 #ifdef BSP_USING_SPI1
350 PORT_Init(PORTB, PIN2, PORTB_PIN2_SPI1_SCLK, 0);
351 PORT_Init(PORTB, PIN3, PORTB_PIN3_SPI1_MISO, 1);
352 PORT_Init(PORTB, PIN4, PORTB_PIN4_SPI1_MOSI, 0);
353 #endif //BSP_USING_SPI1
354
355 for (int i = 0; i < sizeof(swm_spi_cfg) / sizeof(swm_spi_cfg[0]); i++)
356 {
357 spi_bus_obj[i].spi_cfg = &swm_spi_cfg[i];
358 spi_bus_obj[i].spi_bus.parent.user_data = &swm_spi_cfg[i];
359 result = rt_spi_bus_register(&spi_bus_obj[i].spi_bus, swm_spi_cfg[i].name, &swm_spi_ops);
360 if (result != RT_EOK)
361 {
362 LOG_E("%s bus register fail.", swm_spi_cfg[i].name);
363 }
364 else
365 {
366 LOG_D("%s bus register success.", swm_spi_cfg[i].name);
367 }
368 }
369
370 return result;
371 }
372 INIT_BOARD_EXPORT(swm_spi_init);
373
374 #endif /* BSP_USING_SPI */
375 #endif /* RT_USING_SPI */
376