xref: /nrf52832-nimble/rt-thread/components/drivers/spi/spi_core.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2  * Copyright (c) 2006-2018, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2012-01-08     bernard      first version.
9  * 2012-02-03     bernard      add const attribute to the ops.
10  * 2012-05-15     dzzxzz       fixed the return value in attach_device.
11  * 2012-05-18     bernard      Changed SPI message to message list.
12  *                             Added take/release SPI device/bus interface.
13  * 2012-09-28     aozima       fixed rt_spi_release_bus assert error.
14  */
15 
16 #include <drivers/spi.h>
17 
18 extern rt_err_t rt_spi_bus_device_init(struct rt_spi_bus *bus, const char *name);
19 extern rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name);
20 
rt_spi_bus_register(struct rt_spi_bus * bus,const char * name,const struct rt_spi_ops * ops)21 rt_err_t rt_spi_bus_register(struct rt_spi_bus       *bus,
22                              const char              *name,
23                              const struct rt_spi_ops *ops)
24 {
25     rt_err_t result;
26 
27     result = rt_spi_bus_device_init(bus, name);
28     if (result != RT_EOK)
29         return result;
30 
31     /* initialize mutex lock */
32     rt_mutex_init(&(bus->lock), name, RT_IPC_FLAG_FIFO);
33     /* set ops */
34     bus->ops = ops;
35     /* initialize owner */
36     bus->owner = RT_NULL;
37     /* set bus mode */
38     bus->mode = RT_SPI_BUS_MODE_SPI;
39 
40     return RT_EOK;
41 }
42 
rt_spi_bus_attach_device(struct rt_spi_device * device,const char * name,const char * bus_name,void * user_data)43 rt_err_t rt_spi_bus_attach_device(struct rt_spi_device *device,
44                                   const char           *name,
45                                   const char           *bus_name,
46                                   void                 *user_data)
47 {
48     rt_err_t result;
49     rt_device_t bus;
50 
51     /* get physical spi bus */
52     bus = rt_device_find(bus_name);
53     if (bus != RT_NULL && bus->type == RT_Device_Class_SPIBUS)
54     {
55         device->bus = (struct rt_spi_bus *)bus;
56 
57         /* initialize spidev device */
58         result = rt_spidev_device_init(device, name);
59         if (result != RT_EOK)
60             return result;
61 
62         rt_memset(&device->config, 0, sizeof(device->config));
63         device->parent.user_data = user_data;
64 
65         return RT_EOK;
66     }
67 
68     /* not found the host bus */
69     return -RT_ERROR;
70 }
71 
rt_spi_configure(struct rt_spi_device * device,struct rt_spi_configuration * cfg)72 rt_err_t rt_spi_configure(struct rt_spi_device        *device,
73                           struct rt_spi_configuration *cfg)
74 {
75     rt_err_t result;
76 
77     RT_ASSERT(device != RT_NULL);
78 
79     /* set configuration */
80     device->config.data_width = cfg->data_width;
81     device->config.mode       = cfg->mode & RT_SPI_MODE_MASK ;
82     device->config.max_hz     = cfg->max_hz ;
83 
84     if (device->bus != RT_NULL)
85     {
86         result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
87         if (result == RT_EOK)
88         {
89             if (device->bus->owner == device)
90             {
91                 device->bus->ops->configure(device, &device->config);
92             }
93 
94             /* release lock */
95             rt_mutex_release(&(device->bus->lock));
96         }
97     }
98 
99     return RT_EOK;
100 }
101 
rt_spi_send_then_send(struct rt_spi_device * device,const void * send_buf1,rt_size_t send_length1,const void * send_buf2,rt_size_t send_length2)102 rt_err_t rt_spi_send_then_send(struct rt_spi_device *device,
103                                const void           *send_buf1,
104                                rt_size_t             send_length1,
105                                const void           *send_buf2,
106                                rt_size_t             send_length2)
107 {
108     rt_err_t result;
109     struct rt_spi_message message;
110 
111     RT_ASSERT(device != RT_NULL);
112     RT_ASSERT(device->bus != RT_NULL);
113 
114     result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
115     if (result == RT_EOK)
116     {
117         if (device->bus->owner != device)
118         {
119             /* not the same owner as current, re-configure SPI bus */
120             result = device->bus->ops->configure(device, &device->config);
121             if (result == RT_EOK)
122             {
123                 /* set SPI bus owner */
124                 device->bus->owner = device;
125             }
126             else
127             {
128                 /* configure SPI bus failed */
129                 result = -RT_EIO;
130                 goto __exit;
131             }
132         }
133 
134         /* send data1 */
135         message.send_buf   = send_buf1;
136         message.recv_buf   = RT_NULL;
137         message.length     = send_length1;
138         message.cs_take    = 1;
139         message.cs_release = 0;
140         message.next       = RT_NULL;
141 
142         result = device->bus->ops->xfer(device, &message);
143         if (result == 0)
144         {
145             result = -RT_EIO;
146             goto __exit;
147         }
148 
149         /* send data2 */
150         message.send_buf   = send_buf2;
151         message.recv_buf   = RT_NULL;
152         message.length     = send_length2;
153         message.cs_take    = 0;
154         message.cs_release = 1;
155         message.next       = RT_NULL;
156 
157         result = device->bus->ops->xfer(device, &message);
158         if (result == 0)
159         {
160             result = -RT_EIO;
161             goto __exit;
162         }
163 
164         result = RT_EOK;
165     }
166     else
167     {
168         return -RT_EIO;
169     }
170 
171 __exit:
172     rt_mutex_release(&(device->bus->lock));
173 
174     return result;
175 }
176 
rt_spi_send_then_recv(struct rt_spi_device * device,const void * send_buf,rt_size_t send_length,void * recv_buf,rt_size_t recv_length)177 rt_err_t rt_spi_send_then_recv(struct rt_spi_device *device,
178                                const void           *send_buf,
179                                rt_size_t             send_length,
180                                void                 *recv_buf,
181                                rt_size_t             recv_length)
182 {
183     rt_err_t result;
184     struct rt_spi_message message;
185 
186     RT_ASSERT(device != RT_NULL);
187     RT_ASSERT(device->bus != RT_NULL);
188 
189     result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
190     if (result == RT_EOK)
191     {
192         if (device->bus->owner != device)
193         {
194             /* not the same owner as current, re-configure SPI bus */
195             result = device->bus->ops->configure(device, &device->config);
196             if (result == RT_EOK)
197             {
198                 /* set SPI bus owner */
199                 device->bus->owner = device;
200             }
201             else
202             {
203                 /* configure SPI bus failed */
204                 result = -RT_EIO;
205                 goto __exit;
206             }
207         }
208 
209         /* send data */
210         message.send_buf   = send_buf;
211         message.recv_buf   = RT_NULL;
212         message.length     = send_length;
213         message.cs_take    = 1;
214         message.cs_release = 0;
215         message.next       = RT_NULL;
216 
217         result = device->bus->ops->xfer(device, &message);
218         if (result == 0)
219         {
220             result = -RT_EIO;
221             goto __exit;
222         }
223 
224         /* recv data */
225         message.send_buf   = RT_NULL;
226         message.recv_buf   = recv_buf;
227         message.length     = recv_length;
228         message.cs_take    = 0;
229         message.cs_release = 1;
230         message.next       = RT_NULL;
231 
232         result = device->bus->ops->xfer(device, &message);
233         if (result == 0)
234         {
235             result = -RT_EIO;
236             goto __exit;
237         }
238 
239         result = RT_EOK;
240     }
241     else
242     {
243         return -RT_EIO;
244     }
245 
246 __exit:
247     rt_mutex_release(&(device->bus->lock));
248 
249     return result;
250 }
251 
rt_spi_transfer(struct rt_spi_device * device,const void * send_buf,void * recv_buf,rt_size_t length)252 rt_size_t rt_spi_transfer(struct rt_spi_device *device,
253                           const void           *send_buf,
254                           void                 *recv_buf,
255                           rt_size_t             length)
256 {
257     rt_err_t result;
258     struct rt_spi_message message;
259 
260     RT_ASSERT(device != RT_NULL);
261     RT_ASSERT(device->bus != RT_NULL);
262 
263     result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
264     if (result == RT_EOK)
265     {
266         if (device->bus->owner != device)
267         {
268             /* not the same owner as current, re-configure SPI bus */
269             result = device->bus->ops->configure(device, &device->config);
270             if (result == RT_EOK)
271             {
272                 /* set SPI bus owner */
273                 device->bus->owner = device;
274             }
275             else
276             {
277                 /* configure SPI bus failed */
278                 rt_set_errno(-RT_EIO);
279                 result = 0;
280                 goto __exit;
281             }
282         }
283 
284         /* initial message */
285         message.send_buf   = send_buf;
286         message.recv_buf   = recv_buf;
287         message.length     = length;
288         message.cs_take    = 1;
289         message.cs_release = 1;
290         message.next       = RT_NULL;
291 
292         /* transfer message */
293         result = device->bus->ops->xfer(device, &message);
294         if (result == 0)
295         {
296             rt_set_errno(-RT_EIO);
297             goto __exit;
298         }
299     }
300     else
301     {
302         rt_set_errno(-RT_EIO);
303 
304         return 0;
305     }
306 
307 __exit:
308     rt_mutex_release(&(device->bus->lock));
309 
310     return result;
311 }
312 
rt_spi_transfer_message(struct rt_spi_device * device,struct rt_spi_message * message)313 struct rt_spi_message *rt_spi_transfer_message(struct rt_spi_device  *device,
314                                                struct rt_spi_message *message)
315 {
316     rt_err_t result;
317     struct rt_spi_message *index;
318 
319     RT_ASSERT(device != RT_NULL);
320 
321     /* get first message */
322     index = message;
323     if (index == RT_NULL)
324         return index;
325 
326     result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
327     if (result != RT_EOK)
328     {
329         rt_set_errno(-RT_EBUSY);
330 
331         return index;
332     }
333 
334     /* reset errno */
335     rt_set_errno(RT_EOK);
336 
337     /* configure SPI bus */
338     if (device->bus->owner != device)
339     {
340         /* not the same owner as current, re-configure SPI bus */
341         result = device->bus->ops->configure(device, &device->config);
342         if (result == RT_EOK)
343         {
344             /* set SPI bus owner */
345             device->bus->owner = device;
346         }
347         else
348         {
349             /* configure SPI bus failed */
350             rt_set_errno(-RT_EIO);
351             goto __exit;
352         }
353     }
354 
355     /* transmit each SPI message */
356     while (index != RT_NULL)
357     {
358         /* transmit SPI message */
359         result = device->bus->ops->xfer(device, index);
360         if (result == 0)
361         {
362             rt_set_errno(-RT_EIO);
363             break;
364         }
365 
366         index = index->next;
367     }
368 
369 __exit:
370     /* release bus lock */
371     rt_mutex_release(&(device->bus->lock));
372 
373     return index;
374 }
375 
rt_spi_take_bus(struct rt_spi_device * device)376 rt_err_t rt_spi_take_bus(struct rt_spi_device *device)
377 {
378     rt_err_t result = RT_EOK;
379 
380     RT_ASSERT(device != RT_NULL);
381     RT_ASSERT(device->bus != RT_NULL);
382 
383     result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
384     if (result != RT_EOK)
385     {
386         rt_set_errno(-RT_EBUSY);
387 
388         return -RT_EBUSY;
389     }
390 
391     /* reset errno */
392     rt_set_errno(RT_EOK);
393 
394     /* configure SPI bus */
395     if (device->bus->owner != device)
396     {
397         /* not the same owner as current, re-configure SPI bus */
398         result = device->bus->ops->configure(device, &device->config);
399         if (result == RT_EOK)
400         {
401             /* set SPI bus owner */
402             device->bus->owner = device;
403         }
404         else
405         {
406             /* configure SPI bus failed */
407             rt_set_errno(-RT_EIO);
408             /* release lock */
409             rt_mutex_release(&(device->bus->lock));
410 
411             return -RT_EIO;
412         }
413     }
414 
415     return result;
416 }
417 
rt_spi_release_bus(struct rt_spi_device * device)418 rt_err_t rt_spi_release_bus(struct rt_spi_device *device)
419 {
420     RT_ASSERT(device != RT_NULL);
421     RT_ASSERT(device->bus != RT_NULL);
422     RT_ASSERT(device->bus->owner == device);
423 
424     /* release lock */
425     rt_mutex_release(&(device->bus->lock));
426 
427     return RT_EOK;
428 }
429 
rt_spi_take(struct rt_spi_device * device)430 rt_err_t rt_spi_take(struct rt_spi_device *device)
431 {
432     rt_err_t result;
433     struct rt_spi_message message;
434 
435     RT_ASSERT(device != RT_NULL);
436     RT_ASSERT(device->bus != RT_NULL);
437 
438     rt_memset(&message, 0, sizeof(message));
439     message.cs_take = 1;
440 
441     result = device->bus->ops->xfer(device, &message);
442 
443     return result;
444 }
445 
rt_spi_release(struct rt_spi_device * device)446 rt_err_t rt_spi_release(struct rt_spi_device *device)
447 {
448     rt_err_t result;
449     struct rt_spi_message message;
450 
451     RT_ASSERT(device != RT_NULL);
452     RT_ASSERT(device->bus != RT_NULL);
453 
454     rt_memset(&message, 0, sizeof(message));
455     message.cs_release = 1;
456 
457     result = device->bus->ops->xfer(device, &message);
458 
459     return result;
460 }
461