d270451a2e53b89c9c477baf75dee078fa708c5e
[contrib/mraa.git] / src / spi / spi.c
1 /*
2  * Author: Thomas Ingleby <thomas.c.ingleby@intel.com>
3  * Author: Brendan Le Foll <brendan.le.foll@intel.com>
4  * Copyright (c) 2014, 2015 Intel Corporation.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/ioctl.h>
29 #include <linux/spi/spidev.h>
30 #include <stdio.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33
34 #include "spi.h"
35 #include "mraa_internal.h"
36
37 #define MAX_SIZE 64
38 #define SPI_MAX_LENGTH 4096
39
40 static mraa_spi_context
41 mraa_spi_init_internal(mraa_adv_func_t* func_table)
42 {
43     mraa_spi_context dev = (mraa_spi_context) calloc(1, sizeof(struct _spi));
44     if (dev == NULL) {
45         return NULL;
46     }
47     dev->advance_func = func_table;
48
49     return dev;
50 }
51
52 mraa_spi_context
53 mraa_spi_init(int bus)
54 {
55     if (plat == NULL) {
56         syslog(LOG_ERR, "spi: Platform Not Initialised");
57         return NULL;
58     }
59     if (mraa_is_sub_platform_id(bus)) {
60         syslog(LOG_ERR, "spi: Spi module doesn't support subplatforms");
61         return NULL;
62     }
63     if (plat->spi_bus_count == 0) {
64         syslog(LOG_ERR, "spi: no spi buses defined in platform");
65         return NULL;
66     }
67     if (plat->spi_bus_count == 1) {
68         bus = plat->def_spi_bus;
69     }
70     if (bus >= plat->spi_bus_count) {
71         syslog(LOG_ERR, "spi: requested bus above spi bus count");
72         return NULL;
73     }
74     if (plat->adv_func->spi_init_pre != NULL) {
75         if (plat->adv_func->spi_init_pre(bus) != MRAA_SUCCESS) {
76             return NULL;
77         }
78     }
79
80     int pos = plat->spi_bus[bus].sclk;
81     if (plat->pins[pos].spi.mux_total > 0) {
82         if (mraa_setup_mux_mapped(plat->pins[pos].spi) != MRAA_SUCCESS) {
83             syslog(LOG_ERR, "spi: failed to set-up spi sclk multiplexer");
84             return NULL;
85         }
86     }
87
88     pos = plat->spi_bus[bus].mosi;
89     if (plat->pins[pos].spi.mux_total > 0) {
90         if (mraa_setup_mux_mapped(plat->pins[pos].spi) != MRAA_SUCCESS) {
91             syslog(LOG_ERR, "spi: failed to set-up spi mosi multiplexer");
92             return NULL;
93         }
94     }
95
96     pos = plat->spi_bus[bus].miso;
97     if (plat->pins[pos].spi.mux_total > 0) {
98         if (mraa_setup_mux_mapped(plat->pins[pos].spi) != MRAA_SUCCESS) {
99             syslog(LOG_ERR, "spi: failed to set-up spi miso multiplexer");
100             return NULL;
101         }
102     }
103
104     pos = plat->spi_bus[bus].cs;
105     if (plat->pins[pos].spi.mux_total > 0) {
106         if (mraa_setup_mux_mapped(plat->pins[pos].spi) != MRAA_SUCCESS) {
107             syslog(LOG_ERR, "spi: failed to set-up spi cs multiplexer");
108             return NULL;
109         }
110     }
111     mraa_spi_context dev = mraa_spi_init_raw(plat->spi_bus[bus].bus_id, plat->spi_bus[bus].slave_s);
112
113     if (plat->adv_func->spi_init_post != NULL) {
114         mraa_result_t ret = plat->adv_func->spi_init_post(dev);
115         if (ret != MRAA_SUCCESS) {
116             free(dev);
117             return NULL;
118         }
119     }
120
121     return dev;
122 }
123
124 mraa_spi_context
125 mraa_spi_init_raw(unsigned int bus, unsigned int cs)
126 {
127     mraa_spi_context dev = mraa_spi_init_internal(plat == NULL ? NULL : plat->adv_func);
128     if (dev == NULL) {
129         syslog(LOG_CRIT, "spi: Failed to allocate memory for context");
130         return NULL;
131     }
132
133     char path[MAX_SIZE];
134     sprintf(path, "/dev/spidev%u.%u", bus, cs);
135
136     dev->devfd = open(path, O_RDWR);
137     if (dev->devfd < 0) {
138         syslog(LOG_ERR, "spi: Failed opening SPI Device. bus:%s", path);
139         free(dev);
140         return NULL;
141     }
142
143     int speed = 0;
144     if ((ioctl(dev->devfd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) != -1) && (speed < 4000000)) {
145         dev->clock = speed;
146     } else {
147         dev->clock = 4000000;
148     }
149
150     if (mraa_spi_mode(dev, MRAA_SPI_MODE0) != MRAA_SUCCESS) {
151         free(dev);
152         return NULL;
153     }
154
155     if (mraa_spi_lsbmode(dev, 0) != MRAA_SUCCESS) {
156         free(dev);
157         return NULL;
158     }
159
160     if (mraa_spi_bit_per_word(dev, 8) != MRAA_SUCCESS) {
161         free(dev);
162         return NULL;
163     }
164
165     return dev;
166 }
167
168 mraa_result_t
169 mraa_spi_mode(mraa_spi_context dev, mraa_spi_mode_t mode)
170 {
171     uint8_t spi_mode = 0;
172     switch (mode) {
173         case MRAA_SPI_MODE0:
174             spi_mode = SPI_MODE_0;
175             break;
176         case MRAA_SPI_MODE1:
177             spi_mode = SPI_MODE_1;
178             break;
179         case MRAA_SPI_MODE2:
180             spi_mode = SPI_MODE_2;
181             break;
182         case MRAA_SPI_MODE3:
183             spi_mode = SPI_MODE_3;
184             break;
185         default:
186             spi_mode = SPI_MODE_0;
187             break;
188     }
189
190     if (ioctl(dev->devfd, SPI_IOC_WR_MODE, &spi_mode) < 0) {
191         syslog(LOG_ERR, "spi: Failed to set spi mode");
192         return MRAA_ERROR_INVALID_RESOURCE;
193     }
194
195     dev->mode = spi_mode;
196     return MRAA_SUCCESS;
197 }
198
199 mraa_result_t
200 mraa_spi_frequency(mraa_spi_context dev, int hz)
201 {
202     int speed = 0;
203     dev->clock = hz;
204     if (ioctl(dev->devfd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) != -1) {
205         if (speed < hz) {
206             dev->clock = speed;
207             syslog(LOG_WARNING, "spi: Selected speed reduced to max allowed speed");
208         }
209     }
210     return MRAA_SUCCESS;
211 }
212
213 mraa_result_t
214 mraa_spi_lsbmode(mraa_spi_context dev, mraa_boolean_t lsb)
215 {
216     if (IS_FUNC_DEFINED(dev, spi_lsbmode_replace)) {
217         return dev->advance_func->spi_lsbmode_replace(dev, lsb);
218     }
219
220     uint8_t lsb_mode = (uint8_t) lsb;
221     if (ioctl(dev->devfd, SPI_IOC_WR_LSB_FIRST, &lsb_mode) < 0) {
222         syslog(LOG_ERR, "spi: Failed to set bit order");
223         return MRAA_ERROR_INVALID_RESOURCE;
224     }
225     if (ioctl(dev->devfd, SPI_IOC_RD_LSB_FIRST, &lsb_mode) < 0) {
226         syslog(LOG_ERR, "spi: Failed to set bit order");
227         return MRAA_ERROR_INVALID_RESOURCE;
228     }
229     dev->lsb = lsb;
230     return MRAA_SUCCESS;
231 }
232
233 mraa_result_t
234 mraa_spi_bit_per_word(mraa_spi_context dev, unsigned int bits)
235 {
236     if (ioctl(dev->devfd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0) {
237         syslog(LOG_ERR, "spi: Failed to set bit per word");
238         return MRAA_ERROR_INVALID_RESOURCE;
239     }
240     dev->bpw = bits;
241     return MRAA_SUCCESS;
242 }
243
244 int
245 mraa_spi_write(mraa_spi_context dev, uint8_t data)
246 {
247     struct spi_ioc_transfer msg;
248     memset(&msg, 0, sizeof(msg));
249
250     uint16_t length = 1;
251
252     unsigned long recv = 0;
253     msg.tx_buf = (unsigned long) &data;
254     msg.rx_buf = (unsigned long) &recv;
255     msg.speed_hz = dev->clock;
256     msg.bits_per_word = dev->bpw;
257     msg.delay_usecs = 0;
258     msg.len = length;
259     if (ioctl(dev->devfd, SPI_IOC_MESSAGE(1), &msg) < 0) {
260         syslog(LOG_ERR, "spi: Failed to perform dev transfer");
261         return -1;
262     }
263     return (int) recv;
264 }
265
266 uint16_t
267 mraa_spi_write_word(mraa_spi_context dev, uint16_t data)
268 {
269     struct spi_ioc_transfer msg;
270     memset(&msg, 0, sizeof(msg));
271
272     uint16_t length = 2;
273
274     uint16_t recv = 0;
275     msg.tx_buf = (unsigned long) &data;
276     msg.rx_buf = (unsigned long) &recv;
277     msg.speed_hz = dev->clock;
278     msg.bits_per_word = dev->bpw;
279     msg.delay_usecs = 0;
280     msg.len = length;
281     if (ioctl(dev->devfd, SPI_IOC_MESSAGE(1), &msg) < 0) {
282         syslog(LOG_ERR, "spi: Failed to perform dev transfer");
283         return -1;
284     }
285     return recv;
286 }
287
288 mraa_result_t
289 mraa_spi_transfer_buf(mraa_spi_context dev, uint8_t* data, uint8_t* rxbuf, int length)
290 {
291     struct spi_ioc_transfer msg;
292     memset(&msg, 0, sizeof(msg));
293
294     msg.tx_buf = (unsigned long) data;
295     msg.rx_buf = (unsigned long) rxbuf;
296     msg.speed_hz = dev->clock;
297     msg.bits_per_word = dev->bpw;
298     msg.delay_usecs = 0;
299     msg.len = length;
300     if (ioctl(dev->devfd, SPI_IOC_MESSAGE(1), &msg) < 0) {
301         syslog(LOG_ERR, "spi: Failed to perform dev transfer");
302         return MRAA_ERROR_INVALID_RESOURCE;
303     }
304     return MRAA_SUCCESS;
305 }
306
307 mraa_result_t
308 mraa_spi_transfer_buf_word(mraa_spi_context dev, uint16_t* data, uint16_t* rxbuf, int length)
309 {
310     struct spi_ioc_transfer msg;
311     memset(&msg, 0, sizeof(msg));
312
313     msg.tx_buf = (unsigned long) data;
314     msg.rx_buf = (unsigned long) rxbuf;
315     msg.speed_hz = dev->clock;
316     msg.bits_per_word = dev->bpw;
317     msg.delay_usecs = 0;
318     msg.len = length;
319     if (ioctl(dev->devfd, SPI_IOC_MESSAGE(1), &msg) < 0) {
320         syslog(LOG_ERR, "spi: Failed to perform dev transfer");
321         return MRAA_ERROR_INVALID_RESOURCE;
322     }
323     return MRAA_SUCCESS;
324 }
325
326 uint8_t*
327 mraa_spi_write_buf(mraa_spi_context dev, uint8_t* data, int length)
328 {
329     uint8_t* recv = malloc(sizeof(uint8_t) * length);
330
331     if (mraa_spi_transfer_buf(dev, data, recv, length) != MRAA_SUCCESS) {
332         free(recv);
333         return NULL;
334     }
335     return recv;
336 }
337
338 uint16_t*
339 mraa_spi_write_buf_word(mraa_spi_context dev, uint16_t* data, int length)
340 {
341     uint16_t* recv = malloc(sizeof(uint16_t) * length);
342
343     if (mraa_spi_transfer_buf_word(dev, data, recv, length) != MRAA_SUCCESS) {
344         free(recv);
345         return NULL;
346     }
347     return recv;
348 }
349
350 mraa_result_t
351 mraa_spi_stop(mraa_spi_context dev)
352 {
353     close(dev->devfd);
354     free(dev);
355     return MRAA_SUCCESS;
356 }