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
mraa_spi_init_internal(mraa_adv_func_t * func_table)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
mraa_spi_init(int bus)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 if (!plat->no_bus_mux) {
81 int pos = plat->spi_bus[bus].sclk;
82 if (plat->pins[pos].spi.mux_total > 0) {
83 if (mraa_setup_mux_mapped(plat->pins[pos].spi) != MRAA_SUCCESS) {
84 syslog(LOG_ERR, "spi: failed to set-up spi sclk multiplexer");
85 return NULL;
86 }
87 }
88
89 pos = plat->spi_bus[bus].mosi;
90 if (plat->pins[pos].spi.mux_total > 0) {
91 if (mraa_setup_mux_mapped(plat->pins[pos].spi) != MRAA_SUCCESS) {
92 syslog(LOG_ERR, "spi: failed to set-up spi mosi multiplexer");
93 return NULL;
94 }
95 }
96
97 pos = plat->spi_bus[bus].miso;
98 if (plat->pins[pos].spi.mux_total > 0) {
99 if (mraa_setup_mux_mapped(plat->pins[pos].spi) != MRAA_SUCCESS) {
100 syslog(LOG_ERR, "spi: failed to set-up spi miso multiplexer");
101 return NULL;
102 }
103 }
104
105 pos = plat->spi_bus[bus].cs;
106 if (plat->pins[pos].spi.mux_total > 0) {
107 if (mraa_setup_mux_mapped(plat->pins[pos].spi) != MRAA_SUCCESS) {
108 syslog(LOG_ERR, "spi: failed to set-up spi cs multiplexer");
109 return NULL;
110 }
111 }
112 }
113 mraa_spi_context dev = mraa_spi_init_raw(plat->spi_bus[bus].bus_id, plat->spi_bus[bus].slave_s);
114
115 if (plat->adv_func->spi_init_post != NULL) {
116 mraa_result_t ret = plat->adv_func->spi_init_post(dev);
117 if (ret != MRAA_SUCCESS) {
118 free(dev);
119 return NULL;
120 }
121 }
122
123 return dev;
124 }
125
126 mraa_spi_context
mraa_spi_init_raw(unsigned int bus,unsigned int cs)127 mraa_spi_init_raw(unsigned int bus, unsigned int cs)
128 {
129 mraa_spi_context dev = mraa_spi_init_internal(plat == NULL ? NULL : plat->adv_func);
130 if (dev == NULL) {
131 syslog(LOG_CRIT, "spi: Failed to allocate memory for context");
132 return NULL;
133 }
134
135 char path[MAX_SIZE];
136 sprintf(path, "/dev/spidev%u.%u", bus, cs);
137
138 dev->devfd = open(path, O_RDWR);
139 if (dev->devfd < 0) {
140 syslog(LOG_ERR, "spi: Failed opening SPI Device. bus:%s", path);
141 free(dev);
142 return NULL;
143 }
144
145 int speed = 0;
146 if ((ioctl(dev->devfd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) != -1) && (speed < 4000000)) {
147 dev->clock = speed;
148 } else {
149 dev->clock = 4000000;
150 }
151
152 if (mraa_spi_mode(dev, MRAA_SPI_MODE0) != MRAA_SUCCESS) {
153 free(dev);
154 return NULL;
155 }
156
157 if (mraa_spi_lsbmode(dev, 0) != MRAA_SUCCESS) {
158 free(dev);
159 return NULL;
160 }
161
162 if (mraa_spi_bit_per_word(dev, 8) != MRAA_SUCCESS) {
163 free(dev);
164 return NULL;
165 }
166
167 return dev;
168 }
169
170 mraa_result_t
mraa_spi_mode(mraa_spi_context dev,mraa_spi_mode_t mode)171 mraa_spi_mode(mraa_spi_context dev, mraa_spi_mode_t mode)
172 {
173 uint8_t spi_mode = 0;
174 switch (mode) {
175 case MRAA_SPI_MODE0:
176 spi_mode = SPI_MODE_0;
177 break;
178 case MRAA_SPI_MODE1:
179 spi_mode = SPI_MODE_1;
180 break;
181 case MRAA_SPI_MODE2:
182 spi_mode = SPI_MODE_2;
183 break;
184 case MRAA_SPI_MODE3:
185 spi_mode = SPI_MODE_3;
186 break;
187 default:
188 spi_mode = SPI_MODE_0;
189 break;
190 }
191
192 if (ioctl(dev->devfd, SPI_IOC_WR_MODE, &spi_mode) < 0) {
193 syslog(LOG_ERR, "spi: Failed to set spi mode");
194 return MRAA_ERROR_INVALID_RESOURCE;
195 }
196
197 dev->mode = spi_mode;
198 return MRAA_SUCCESS;
199 }
200
201 mraa_result_t
mraa_spi_frequency(mraa_spi_context dev,int hz)202 mraa_spi_frequency(mraa_spi_context dev, int hz)
203 {
204 int speed = 0;
205 dev->clock = hz;
206 if (ioctl(dev->devfd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) != -1) {
207 if (speed < hz) {
208 dev->clock = speed;
209 syslog(LOG_WARNING, "spi: Selected speed reduced to max allowed speed");
210 }
211 }
212 return MRAA_SUCCESS;
213 }
214
215 mraa_result_t
mraa_spi_lsbmode(mraa_spi_context dev,mraa_boolean_t lsb)216 mraa_spi_lsbmode(mraa_spi_context dev, mraa_boolean_t lsb)
217 {
218 if (IS_FUNC_DEFINED(dev, spi_lsbmode_replace)) {
219 return dev->advance_func->spi_lsbmode_replace(dev, lsb);
220 }
221
222 uint8_t lsb_mode = (uint8_t) lsb;
223 if (ioctl(dev->devfd, SPI_IOC_WR_LSB_FIRST, &lsb_mode) < 0) {
224 syslog(LOG_ERR, "spi: Failed to set bit order");
225 return MRAA_ERROR_INVALID_RESOURCE;
226 }
227 if (ioctl(dev->devfd, SPI_IOC_RD_LSB_FIRST, &lsb_mode) < 0) {
228 syslog(LOG_ERR, "spi: Failed to set bit order");
229 return MRAA_ERROR_INVALID_RESOURCE;
230 }
231 dev->lsb = lsb;
232 return MRAA_SUCCESS;
233 }
234
235 mraa_result_t
mraa_spi_bit_per_word(mraa_spi_context dev,unsigned int bits)236 mraa_spi_bit_per_word(mraa_spi_context dev, unsigned int bits)
237 {
238 if (ioctl(dev->devfd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0) {
239 syslog(LOG_ERR, "spi: Failed to set bit per word");
240 return MRAA_ERROR_INVALID_RESOURCE;
241 }
242 dev->bpw = bits;
243 return MRAA_SUCCESS;
244 }
245
246 int
mraa_spi_write(mraa_spi_context dev,uint8_t data)247 mraa_spi_write(mraa_spi_context dev, uint8_t data)
248 {
249 struct spi_ioc_transfer msg;
250 memset(&msg, 0, sizeof(msg));
251
252 uint16_t length = 1;
253
254 unsigned long recv = 0;
255 msg.tx_buf = (unsigned long) &data;
256 msg.rx_buf = (unsigned long) &recv;
257 msg.speed_hz = dev->clock;
258 msg.bits_per_word = dev->bpw;
259 msg.delay_usecs = 0;
260 msg.len = length;
261 if (ioctl(dev->devfd, SPI_IOC_MESSAGE(1), &msg) < 0) {
262 syslog(LOG_ERR, "spi: Failed to perform dev transfer");
263 return -1;
264 }
265 return (int) recv;
266 }
267
268 uint16_t
mraa_spi_write_word(mraa_spi_context dev,uint16_t data)269 mraa_spi_write_word(mraa_spi_context dev, uint16_t data)
270 {
271 struct spi_ioc_transfer msg;
272 memset(&msg, 0, sizeof(msg));
273
274 uint16_t length = 2;
275
276 uint16_t recv = 0;
277 msg.tx_buf = (unsigned long) &data;
278 msg.rx_buf = (unsigned long) &recv;
279 msg.speed_hz = dev->clock;
280 msg.bits_per_word = dev->bpw;
281 msg.delay_usecs = 0;
282 msg.len = length;
283 if (ioctl(dev->devfd, SPI_IOC_MESSAGE(1), &msg) < 0) {
284 syslog(LOG_ERR, "spi: Failed to perform dev transfer");
285 return -1;
286 }
287 return recv;
288 }
289
290 mraa_result_t
mraa_spi_transfer_buf(mraa_spi_context dev,uint8_t * data,uint8_t * rxbuf,int length)291 mraa_spi_transfer_buf(mraa_spi_context dev, uint8_t* data, uint8_t* rxbuf, int length)
292 {
293 struct spi_ioc_transfer msg;
294 memset(&msg, 0, sizeof(msg));
295
296 msg.tx_buf = (unsigned long) data;
297 msg.rx_buf = (unsigned long) rxbuf;
298 msg.speed_hz = dev->clock;
299 msg.bits_per_word = dev->bpw;
300 msg.delay_usecs = 0;
301 msg.len = length;
302 if (ioctl(dev->devfd, SPI_IOC_MESSAGE(1), &msg) < 0) {
303 syslog(LOG_ERR, "spi: Failed to perform dev transfer");
304 return MRAA_ERROR_INVALID_RESOURCE;
305 }
306 return MRAA_SUCCESS;
307 }
308
309 mraa_result_t
mraa_spi_transfer_buf_word(mraa_spi_context dev,uint16_t * data,uint16_t * rxbuf,int length)310 mraa_spi_transfer_buf_word(mraa_spi_context dev, uint16_t* data, uint16_t* rxbuf, int length)
311 {
312 struct spi_ioc_transfer msg;
313 memset(&msg, 0, sizeof(msg));
314
315 msg.tx_buf = (unsigned long) data;
316 msg.rx_buf = (unsigned long) rxbuf;
317 msg.speed_hz = dev->clock;
318 msg.bits_per_word = dev->bpw;
319 msg.delay_usecs = 0;
320 msg.len = length;
321 if (ioctl(dev->devfd, SPI_IOC_MESSAGE(1), &msg) < 0) {
322 syslog(LOG_ERR, "spi: Failed to perform dev transfer");
323 return MRAA_ERROR_INVALID_RESOURCE;
324 }
325 return MRAA_SUCCESS;
326 }
327
328 uint8_t*
mraa_spi_write_buf(mraa_spi_context dev,uint8_t * data,int length)329 mraa_spi_write_buf(mraa_spi_context dev, uint8_t* data, int length)
330 {
331 uint8_t* recv = malloc(sizeof(uint8_t) * length);
332
333 if (mraa_spi_transfer_buf(dev, data, recv, length) != MRAA_SUCCESS) {
334 free(recv);
335 return NULL;
336 }
337 return recv;
338 }
339
340 uint16_t*
mraa_spi_write_buf_word(mraa_spi_context dev,uint16_t * data,int length)341 mraa_spi_write_buf_word(mraa_spi_context dev, uint16_t* data, int length)
342 {
343 uint16_t* recv = malloc(sizeof(uint16_t) * length);
344
345 if (mraa_spi_transfer_buf_word(dev, data, recv, length) != MRAA_SUCCESS) {
346 free(recv);
347 return NULL;
348 }
349 return recv;
350 }
351
352 mraa_result_t
mraa_spi_stop(mraa_spi_context dev)353 mraa_spi_stop(mraa_spi_context dev)
354 {
355 close(dev->devfd);
356 free(dev);
357 return MRAA_SUCCESS;
358 }
359