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