clang-format: run clang-format on C/C++ code
[contrib/mraa.git] / src / spi / spi.c
index 45f4e76..c478e7f 100644 (file)
  */
 struct _spi {
     /*@{*/
-    int devfd; /**< File descriptor to SPI Device */
-    int mode; /**< Spi mode see spidev.h */
-    int clock; /**< clock to run transactions at */
+    int devfd;          /**< File descriptor to SPI Device */
+    uint32_t mode;      /**< Spi mode see spidev.h */
+    int clock;          /**< clock to run transactions at */
     mraa_boolean_t lsb; /**< least significant bit mode */
-    unsigned int bpw; /**< Bits per word */
+    unsigned int bpw;   /**< Bits per word */
     /*@}*/
 };
 
 mraa_spi_context
 mraa_spi_init(int bus)
 {
+    if (plat == NULL) {
+        syslog(LOG_ERR, "spi: Platform Not Initialised");
+        return NULL;
+    }
+    if (plat->spi_bus_count == 0) {
+        syslog(LOG_ERR, "spi: no spi buses defined in platform");
+        return NULL;
+    }
+    if (plat->spi_bus_count == 1) {
+        bus = plat->def_spi_bus;
+    }
+    if (bus >= plat->spi_bus_count) {
+        syslog(LOG_ERR, "spi: requested bus above spi bus count");
+        return NULL;
+    }
     if (advance_func->spi_init_pre != NULL) {
         if (advance_func->spi_init_pre(bus) != MRAA_SUCCESS)
             return NULL;
     }
 
-    mraa_spi_bus_t *spi = mraa_setup_spi(bus);
-    if(bus < 0) {
-        fprintf(stderr, "Failed. SPI platform Error\n");
-        return NULL;
+    int pos = plat->spi_bus[bus].sclk;
+    if (plat->pins[pos].spi.mux_total > 0) {
+        if (mraa_setup_mux_mapped(plat->pins[pos].spi) != MRAA_SUCCESS) {
+            syslog(LOG_ERR, "spi: failed to set-up spi sclk multiplexer");
+            return NULL;
+        }
     }
+
+    pos = plat->spi_bus[bus].mosi;
+    if (plat->pins[pos].spi.mux_total > 0) {
+        if (mraa_setup_mux_mapped(plat->pins[pos].spi) != MRAA_SUCCESS) {
+            syslog(LOG_ERR, "spi: failed to set-up spi mosi multiplexer");
+            return NULL;
+        }
+    }
+
+    pos = plat->spi_bus[bus].miso;
+    if (plat->pins[pos].spi.mux_total > 0) {
+        if (mraa_setup_mux_mapped(plat->pins[pos].spi) != MRAA_SUCCESS) {
+            syslog(LOG_ERR, "spi: failed to set-up spi miso multiplexer");
+            return NULL;
+        }
+    }
+
+    pos = plat->spi_bus[bus].cs;
+    if (plat->pins[pos].spi.mux_total > 0) {
+        if (mraa_setup_mux_mapped(plat->pins[pos].spi) != MRAA_SUCCESS) {
+            syslog(LOG_ERR, "spi: failed to set-up spi cs multiplexer");
+            return NULL;
+        }
+    }
+    mraa_spi_context dev = mraa_spi_init_raw(plat->spi_bus[bus].bus_id, plat->spi_bus[bus].slave_s);
+
+    if (advance_func->spi_init_post != NULL) {
+        mraa_result_t ret = advance_func->spi_init_post(dev);
+        if (ret != MRAA_SUCCESS) {
+            free(dev);
+            return NULL;
+        }
+    }
+
+    return dev;
+}
+
+mraa_spi_context
+mraa_spi_init_raw(unsigned int bus, unsigned int cs)
+{
     mraa_spi_context dev = (mraa_spi_context) malloc(sizeof(struct _spi));
+    if (dev == NULL) {
+        syslog(LOG_CRIT, "spi: Failed to allocate memory for context");
+        return NULL;
+    }
     memset(dev, 0, sizeof(struct _spi));
 
     char path[MAX_SIZE];
-    sprintf(path, "/dev/spidev%u.%u", spi->bus_id, spi->slave_s);
+    sprintf(path, "/dev/spidev%u.%u", bus, cs);
 
     dev->devfd = open(path, O_RDWR);
     if (dev->devfd < 0) {
-        fprintf(stderr, "Failed opening SPI Device. bus:%s\n", path);
+        syslog(LOG_ERR, "spi: Failed opening SPI Device. bus:%s", path);
         free(dev);
         return NULL;
     }
-    dev->bpw = 8;
-    dev->clock = 4000000;
-    dev->lsb = 0;
-    dev->mode = 0;
 
-    if (advance_func->spi_init_post != NULL) {
-        mraa_result_t ret = advance_func->spi_init_post(dev);
-        if (ret != MRAA_SUCCESS) {
-            free(dev);
-            return NULL;
-        }
+    int speed = 0;
+    if ((ioctl(dev->devfd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) != -1) && (speed < 4000000)) {
+        dev->clock = speed;
+    } else {
+        dev->clock = 4000000;
+    }
+
+    if (mraa_spi_mode(dev, MRAA_SPI_MODE0) != MRAA_SUCCESS) {
+        free(dev);
+        return NULL;
+    }
+
+    if (mraa_spi_lsbmode(dev, 0) != MRAA_SUCCESS) {
+        free(dev);
+        return NULL;
+    }
+
+    if (mraa_spi_bit_per_word(dev, 8) != MRAA_SUCCESS) {
+        free(dev);
+        return NULL;
     }
 
     return dev;
@@ -112,8 +183,8 @@ mraa_spi_mode(mraa_spi_context dev, mraa_spi_mode_t mode)
             break;
     }
 
-    if (ioctl (dev->devfd, SPI_IOC_WR_MODE, &spi_mode) < 0) {
-        fprintf(stderr, "Failed to set spi mode\n");
+    if (ioctl(dev->devfd, SPI_IOC_WR_MODE, &spi_mode) < 0) {
+        syslog(LOG_ERR, "spi: Failed to set spi mode");
         return MRAA_ERROR_INVALID_RESOURCE;
     }
 
@@ -124,19 +195,27 @@ mraa_spi_mode(mraa_spi_context dev, mraa_spi_mode_t mode)
 mraa_result_t
 mraa_spi_frequency(mraa_spi_context dev, int hz)
 {
+    int speed = 0;
     dev->clock = hz;
+    if (ioctl(dev->devfd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) != -1) {
+        if (speed < hz) {
+            dev->clock = speed;
+            syslog(LOG_WARNING, "spi: Selected speed reduced to max allowed speed");
+        }
+    }
     return MRAA_SUCCESS;
 }
 
 mraa_result_t
 mraa_spi_lsbmode(mraa_spi_context dev, mraa_boolean_t lsb)
 {
-    uint8_t lsb_mode = 0;
-    if (lsb == 1) {
-        lsb_mode = 1;
+    uint8_t lsb_mode = (uint8_t) lsb;
+    if (ioctl(dev->devfd, SPI_IOC_WR_LSB_FIRST, &lsb_mode) < 0) {
+        syslog(LOG_ERR, "spi: Failed to set bit order");
+        return MRAA_ERROR_INVALID_RESOURCE;
     }
-    if (ioctl (dev->devfd, SPI_IOC_WR_LSB_FIRST, &lsb_mode) < 0) {
-        fprintf(stderr, "Failed to set bit order\n");
+    if (ioctl(dev->devfd, SPI_IOC_RD_LSB_FIRST, &lsb_mode) < 0) {
+        syslog(LOG_ERR, "spi: Failed to set bit order");
         return MRAA_ERROR_INVALID_RESOURCE;
     }
     dev->lsb = lsb;
@@ -146,11 +225,15 @@ mraa_spi_lsbmode(mraa_spi_context dev, mraa_boolean_t lsb)
 mraa_result_t
 mraa_spi_bit_per_word(mraa_spi_context dev, unsigned int bits)
 {
+    if (ioctl(dev->devfd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0) {
+        syslog(LOG_ERR, "spi: Failed to set bit per word");
+        return MRAA_ERROR_INVALID_RESOURCE;
+    }
     dev->bpw = bits;
     return MRAA_SUCCESS;
 }
 
-uint8_t
+int
 mraa_spi_write(mraa_spi_context dev, uint8_t data)
 {
     struct spi_ioc_transfer msg;
@@ -158,7 +241,29 @@ mraa_spi_write(mraa_spi_context dev, uint8_t data)
 
     uint16_t length = 1;
 
-    uint8_t recv = 0;
+    unsigned long recv = 0;
+    msg.tx_buf = (unsigned long) &data;
+    msg.rx_buf = (unsigned long) &recv;
+    msg.speed_hz = dev->clock;
+    msg.bits_per_word = dev->bpw;
+    msg.delay_usecs = 0;
+    msg.len = length;
+    if (ioctl(dev->devfd, SPI_IOC_MESSAGE(1), &msg) < 0) {
+        syslog(LOG_ERR, "spi: Failed to perform dev transfer");
+        return -1;
+    }
+    return (int) recv;
+}
+
+uint16_t
+mraa_spi_write_word(mraa_spi_context dev, uint16_t data)
+{
+    struct spi_ioc_transfer msg;
+    memset(&msg, 0, sizeof(msg));
+
+    uint16_t length = 2;
+
+    uint16_t recv = 0;
     msg.tx_buf = (unsigned long) &data;
     msg.rx_buf = (unsigned long) &recv;
     msg.speed_hz = dev->clock;
@@ -166,28 +271,69 @@ mraa_spi_write(mraa_spi_context dev, uint8_t data)
     msg.delay_usecs = 0;
     msg.len = length;
     if (ioctl(dev->devfd, SPI_IOC_MESSAGE(1), &msg) < 0) {
-        fprintf(stderr, "Failed to perform dev transfer\n");
+        syslog(LOG_ERR, "spi: Failed to perform dev transfer");
         return -1;
     }
     return recv;
 }
 
-uint8_t*
-mraa_spi_write_buf(mraa_spi_context dev, uint8_t* data, int length)
+mraa_result_t
+mraa_spi_transfer_buf(mraa_spi_context dev, uint8_t* data, uint8_t* rxbuf, int length)
 {
     struct spi_ioc_transfer msg;
     memset(&msg, 0, sizeof(msg));
 
-    uint8_t* recv = malloc(sizeof(uint8_t) * length);
+    msg.tx_buf = (unsigned long) data;
+    msg.rx_buf = (unsigned long) rxbuf;
+    msg.speed_hz = dev->clock;
+    msg.bits_per_word = dev->bpw;
+    msg.delay_usecs = 0;
+    msg.len = length;
+    if (ioctl(dev->devfd, SPI_IOC_MESSAGE(1), &msg) < 0) {
+        syslog(LOG_ERR, "spi: Failed to perform dev transfer");
+        return MRAA_ERROR_INVALID_RESOURCE;
+    }
+    return MRAA_SUCCESS;
+}
+
+mraa_result_t
+mraa_spi_transfer_buf_word(mraa_spi_context dev, uint16_t* data, uint16_t* rxbuf, int length)
+{
+    struct spi_ioc_transfer msg;
+    memset(&msg, 0, sizeof(msg));
 
     msg.tx_buf = (unsigned long) data;
-    msg.rx_buf = (unsigned long) recv;
+    msg.rx_buf = (unsigned long) rxbuf;
     msg.speed_hz = dev->clock;
     msg.bits_per_word = dev->bpw;
     msg.delay_usecs = 0;
     msg.len = length;
     if (ioctl(dev->devfd, SPI_IOC_MESSAGE(1), &msg) < 0) {
-        fprintf(stderr, "Failed to perform dev transfer\n");
+        syslog(LOG_ERR, "spi: Failed to perform dev transfer");
+        return MRAA_ERROR_INVALID_RESOURCE;
+    }
+    return MRAA_SUCCESS;
+}
+
+uint8_t*
+mraa_spi_write_buf(mraa_spi_context dev, uint8_t* data, int length)
+{
+    uint8_t* recv = malloc(sizeof(uint8_t) * length);
+
+    if (mraa_spi_transfer_buf(dev, data, recv, length) != MRAA_SUCCESS) {
+        free(recv);
+        return NULL;
+    }
+    return recv;
+}
+
+uint16_t*
+mraa_spi_write_buf_word(mraa_spi_context dev, uint16_t* data, int length)
+{
+    uint16_t* recv = malloc(sizeof(uint16_t) * length);
+
+    if (mraa_spi_transfer_buf_word(dev, data, recv, length) != MRAA_SUCCESS) {
+        free(recv);
         return NULL;
     }
     return recv;