1 /* 2 * Author: Thomas Ingleby <thomas.c.ingleby (at) intel.com> 3 * Author: Brendan Le Foll <brendan.le.foll (at) 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 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 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 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 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 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 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 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 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 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 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* 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* 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 353 mraa_spi_stop(mraa_spi_context dev) 354 { 355 close(dev->devfd); 356 free(dev); 357 return MRAA_SUCCESS; 358 } 359