spi.c: make use of no_bus_mux flag
[contrib/mraa.git] / src / spi / spi.c
index c5d7997..384cc20 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Author: Thomas Ingleby <thomas.c.ingleby@intel.com>
- * Copyright (c) 2014 Intel Corporation.
+ * Author: Brendan Le Foll <brendan.le.foll@intel.com>
+ * Copyright (c) 2014, 2015 Intel Corporation.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
 #define MAX_SIZE 64
 #define SPI_MAX_LENGTH 4096
 
-/**
- * A structure representing the SPI device
- */
-struct _spi {
-    /*@{*/
-    int devfd; /**< File descriptor to SPI Device */
-    int 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 */
-    /*@}*/
-};
+static mraa_spi_context
+mraa_spi_init_internal(mraa_adv_func_t* func_table)
+{
+    mraa_spi_context dev = (mraa_spi_context) calloc(1, sizeof(struct _spi));
+    if (dev == NULL) {
+        return NULL;
+    }
+    dev->advance_func = func_table;
+
+    return dev;
+}
 
 mraa_spi_context
 mraa_spi_init(int bus)
@@ -56,6 +56,10 @@ mraa_spi_init(int bus)
         syslog(LOG_ERR, "spi: Platform Not Initialised");
         return NULL;
     }
+    if (mraa_is_sub_platform_id(bus)) {
+        syslog(LOG_ERR, "spi: Spi module doesn't support subplatforms");
+        return NULL;
+    }
     if (plat->spi_bus_count == 0) {
         syslog(LOG_ERR, "spi: no spi buses defined in platform");
         return NULL;
@@ -67,46 +71,49 @@ mraa_spi_init(int bus)
         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)
+    if (plat->adv_func->spi_init_pre != NULL) {
+        if (plat->adv_func->spi_init_pre(bus) != MRAA_SUCCESS) {
             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;
+    if (!plat->no_bus_mux) {
+        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].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].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;
+        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 (plat->adv_func->spi_init_post != NULL) {
+        mraa_result_t ret = plat->adv_func->spi_init_post(dev);
         if (ret != MRAA_SUCCESS) {
             free(dev);
             return NULL;
@@ -119,12 +126,11 @@ mraa_spi_init(int bus)
 mraa_spi_context
 mraa_spi_init_raw(unsigned int bus, unsigned int cs)
 {
-    mraa_spi_context dev = (mraa_spi_context) malloc(sizeof(struct _spi));
+    mraa_spi_context dev = mraa_spi_init_internal(plat == NULL ? NULL : plat->adv_func);
     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", bus, cs);
@@ -139,25 +145,24 @@ mraa_spi_init_raw(unsigned int bus, unsigned int cs)
     int speed = 0;
     if ((ioctl(dev->devfd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) != -1) && (speed < 4000000)) {
         dev->clock = speed;
-    }
-    else {
+    } 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;
 }
@@ -184,7 +189,7 @@ mraa_spi_mode(mraa_spi_context dev, mraa_spi_mode_t mode)
             break;
     }
 
-    if (ioctl (dev->devfd, SPI_IOC_WR_MODE, &spi_mode) < 0) {
+    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;
     }
@@ -210,12 +215,16 @@ mraa_spi_frequency(mraa_spi_context dev, int hz)
 mraa_result_t
 mraa_spi_lsbmode(mraa_spi_context dev, mraa_boolean_t lsb)
 {
+    if (IS_FUNC_DEFINED(dev, spi_lsbmode_replace)) {
+        return dev->advance_func->spi_lsbmode_replace(dev, lsb);
+    }
+
     uint8_t lsb_mode = (uint8_t) lsb;
-    if (ioctl (dev->devfd, SPI_IOC_WR_LSB_FIRST, &lsb_mode) < 0) {
+    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_RD_LSB_FIRST, &lsb_mode) < 0) {
+    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;
     }
@@ -234,7 +243,7 @@ mraa_spi_bit_per_word(mraa_spi_context dev, unsigned int bits)
     return MRAA_SUCCESS;
 }
 
-uint8_t
+int
 mraa_spi_write(mraa_spi_context dev, uint8_t data)
 {
     struct spi_ioc_transfer msg;
@@ -242,7 +251,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;
@@ -275,6 +306,25 @@ mraa_spi_transfer_buf(mraa_spi_context dev, uint8_t* data, uint8_t* rxbuf, int l
     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) 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;
+}
+
 uint8_t*
 mraa_spi_write_buf(mraa_spi_context dev, uint8_t* data, int length)
 {
@@ -287,6 +337,18 @@ mraa_spi_write_buf(mraa_spi_context dev, uint8_t* data, int length)
     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;
+}
+
 mraa_result_t
 mraa_spi_stop(mraa_spi_context dev)
 {