Home | History | Annotate | Download | only in spi
      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