intel_edison_fab_c.c: Remove dependency on debugfs
[contrib/mraa.git] / src / x86 / intel_edison_fab_c.c
index ee9df88..decf624 100644 (file)
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <linux/spi/spidev.h>
 
 #include "common.h"
 #include "x86/intel_edison_fab_c.h"
 
 #define PLATFORM_NAME "Intel Edison"
 #define SYSFS_CLASS_GPIO "/sys/class/gpio"
-#define SYSFS_PINMODE_PATH "/sys/kernel/debug/gpio_debug/gpio"
+#define DEBUGFS_PINMODE_PATH "/sys/kernel/debug/gpio_debug/gpio"
 #define MAX_SIZE 64
 #define MAX_MODE_SIZE 8
 
@@ -72,6 +74,29 @@ static int mmap_fd = 0;
 static int mmap_size;
 static unsigned int mmap_count = 0;
 
+mraa_result_t
+mraa_intel_edison_spi_lsbmode_replace(mraa_spi_context dev, mraa_boolean_t lsb)
+{
+    uint8_t lsb_mode = (uint8_t) lsb;
+
+    // Edison doesn't support LSB_FIRST, we need to react appropriately
+    if (!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_RD_LSB_FIRST, &lsb_mode) < 0) {
+            syslog(LOG_ERR, "spi: Failed to set bit order");
+            return MRAA_ERROR_INVALID_RESOURCE;
+        }
+    } else {
+        return MRAA_ERROR_FEATURE_NOT_SUPPORTED;
+    }
+
+    dev->lsb = lsb;
+    return MRAA_SUCCESS;
+}
+
 static mraa_result_t
 mraa_intel_edison_pinmode_change(int sysfs, int mode)
 {
@@ -80,26 +105,42 @@ mraa_intel_edison_pinmode_change(int sysfs, int mode)
     }
 
     char buffer[MAX_SIZE];
-    snprintf(buffer, MAX_SIZE, SYSFS_PINMODE_PATH "%i/current_pinmux", sysfs);
+    int useDebugFS = 0;
+
+    mraa_gpio_context mode_gpio = mraa_gpio_init_raw(sysfs);
+    if (mode_gpio == NULL) {
+        return MRAA_ERROR_NO_RESOURCES;
+    }
+
+    // first try SYSFS_CLASS_GPIO path
+    snprintf(buffer, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%i/pinmux", sysfs);
     int modef = open(buffer, O_WRONLY);
     if (modef == -1) {
+        snprintf(buffer, MAX_SIZE, DEBUGFS_PINMODE_PATH "%i/current_pinmux", sysfs);
+        modef = open(buffer, O_WRONLY);
+        useDebugFS = 1;
+    }
+
+    if (modef == -1) {
         syslog(LOG_ERR, "edison: Failed to open SoC pinmode for opening");
+        mraa_gpio_close(mode_gpio);
         return MRAA_ERROR_INVALID_RESOURCE;
     }
 
     mraa_result_t ret = MRAA_SUCCESS;
     char mode_buf[MAX_MODE_SIZE];
-    int length = sprintf(mode_buf, "mode%u", mode);
+    int length = sprintf(mode_buf, "%s%u", useDebugFS ? "mode" : "", mode);
     if (write(modef, mode_buf, length * sizeof(char)) == -1) {
         ret = MRAA_ERROR_INVALID_RESOURCE;
     }
     close(modef);
+    mraa_gpio_close(mode_gpio);
 
     return ret;
 }
 
 mraa_result_t
-mraa_intel_edison_gpio_dir_pre(mraa_gpio_context dev, gpio_dir_t dir)
+mraa_intel_edison_gpio_dir_pre(mraa_gpio_context dev, mraa_gpio_dir_t dir)
 {
 
     if (dev->phy_pin >= 0) {
@@ -132,7 +173,7 @@ mraa_intel_edison_gpio_dir_pre(mraa_gpio_context dev, gpio_dir_t dir)
 }
 
 mraa_result_t
-mraa_intel_edison_gpio_dir_post(mraa_gpio_context dev, gpio_dir_t dir)
+mraa_intel_edison_gpio_dir_post(mraa_gpio_context dev, mraa_gpio_dir_t dir)
 {
     if (dev->phy_pin >= 0) {
         return mraa_gpio_write(tristate, 1);
@@ -225,39 +266,39 @@ mraa_intel_edison_i2c_init_pre(unsigned int bus)
 static mraa_result_t
 mraa_intel_edison_misc_spi()
 {
-    mraa_gpio_write(tristate, 0);
+    // These arrays must have same length
+    static const int gpio_pin_list[] = {263, 240, 262, 241, 242, 243};
+    static int pin_num = sizeof(gpio_pin_list) / sizeof(int);
+    static const int gpio_val_list[] = {1, 0, 1, 0, 0, 0};
+    static const int gpio_dir_list[] = {MRAA_GPIO_OUT, MRAA_GPIO_OUT,
+                                        MRAA_GPIO_OUT, MRAA_GPIO_OUT,
+                                        MRAA_GPIO_OUT, MRAA_GPIO_OUT};
+    int i;
+    mraa_result_t ret;
 
-    mraa_gpio_context io10_p1 = mraa_gpio_init_raw(263);
-    mraa_gpio_context io10_p2 = mraa_gpio_init_raw(240);
-    mraa_gpio_context io11_p1 = mraa_gpio_init_raw(262);
-    mraa_gpio_context io11_p2 = mraa_gpio_init_raw(241);
-    mraa_gpio_context io12_p1 = mraa_gpio_init_raw(242);
-    mraa_gpio_context io13_p1 = mraa_gpio_init_raw(243);
-    mraa_gpio_dir(io10_p1, MRAA_GPIO_OUT);
-    mraa_gpio_dir(io10_p2, MRAA_GPIO_OUT);
-    mraa_gpio_dir(io11_p1, MRAA_GPIO_OUT);
-    mraa_gpio_dir(io11_p2, MRAA_GPIO_OUT);
-    mraa_gpio_dir(io12_p1, MRAA_GPIO_OUT);
-    mraa_gpio_dir(io13_p1, MRAA_GPIO_OUT);
-
-    mraa_gpio_write(io10_p1, 1);
-    mraa_gpio_write(io10_p2, 0);
-    mraa_gpio_write(io11_p1, 1);
-    mraa_gpio_write(io11_p2, 0);
-    mraa_gpio_write(io12_p1, 0);
-    mraa_gpio_write(io13_p1, 0);
-
-    mraa_gpio_close(io10_p1);
-    mraa_gpio_close(io10_p2);
-    mraa_gpio_close(io11_p1);
-    mraa_gpio_close(io11_p2);
-    mraa_gpio_close(io12_p1);
-    mraa_gpio_close(io13_p1);
-
-    mraa_intel_edison_pinmode_change(115, 1);
-    mraa_intel_edison_pinmode_change(114, 1);
-    mraa_intel_edison_pinmode_change(109, 1);
-    mraa_gpio_write(tristate, 1);
+    MRAA_RETURN_FOR_ERROR(mraa_gpio_write(tristate, 0));
+
+    for (i = 0; i < pin_num; i++) {
+        mraa_gpio_context io = mraa_gpio_init_raw(gpio_pin_list[i]);
+        if (io != NULL) {
+            ret = mraa_gpio_dir(io, gpio_dir_list[i]);
+            if (ret == MRAA_SUCCESS) {
+                ret = mraa_gpio_write(io, gpio_val_list[i]);
+            }
+
+            //Don't care return value of close()
+            mraa_gpio_close(io);
+            MRAA_RETURN_FOR_ERROR(ret);
+        } else {
+          syslog(LOG_ERR, "edison: Failed to init raw gpio %d!",gpio_pin_list[i]);
+          return MRAA_ERROR_NO_RESOURCES;
+        }
+    }
+
+    MRAA_RETURN_FOR_ERROR(mraa_intel_edison_pinmode_change(115, 1));
+    MRAA_RETURN_FOR_ERROR(mraa_intel_edison_pinmode_change(114, 1));
+    MRAA_RETURN_FOR_ERROR(mraa_intel_edison_pinmode_change(109, 1));
+    MRAA_RETURN_FOR_ERROR(mraa_gpio_write(tristate, 1));
 
     return MRAA_SUCCESS;
 }
@@ -429,7 +470,7 @@ mraa_intel_edison_spi_init_post(mraa_spi_context spi)
 }
 
 mraa_result_t
-mraa_intel_edison_gpio_mode_replace(mraa_gpio_context dev, gpio_mode_t mode)
+mraa_intel_edison_gpio_mode_replace(mraa_gpio_context dev, mraa_gpio_mode_t mode)
 {
     if (dev->value_fp != -1) {
         if (close(dev->value_fp) != 0) {
@@ -482,7 +523,7 @@ mraa_intel_edison_gpio_mode_replace(mraa_gpio_context dev, gpio_mode_t mode)
 }
 
 mraa_result_t
-mraa_intel_edsion_mb_gpio_mode(mraa_gpio_context dev, gpio_mode_t mode)
+mraa_intel_edsion_mb_gpio_mode(mraa_gpio_context dev, mraa_gpio_mode_t mode)
 {
     if (dev->value_fp != -1) {
         if (close(dev->value_fp) != 0) {
@@ -492,11 +533,24 @@ mraa_intel_edsion_mb_gpio_mode(mraa_gpio_context dev, gpio_mode_t mode)
     }
 
     char filepath[MAX_SIZE];
-    snprintf(filepath, MAX_SIZE, SYSFS_PINMODE_PATH "%d/current_pullmode", dev->pin);
 
+    mraa_gpio_context mode_gpio = mraa_gpio_init_raw(dev->pin);
+    if (mode_gpio == NULL) {
+        return MRAA_ERROR_NO_RESOURCES;
+    }
+
+    // first try SYSFS_CLASS_GPIO path
+    snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/pullmode", dev->pin);
     int drive = open(filepath, O_WRONLY);
+
+    if (drive == -1) {
+        snprintf(filepath, MAX_SIZE, DEBUGFS_PINMODE_PATH "%d/current_pullmode", dev->pin);
+        drive = open(filepath, O_WRONLY);
+    }
+
     if (drive == -1) {
         syslog(LOG_ERR, "edison: Failed to open drive for writing");
+        mraa_gpio_close(mode_gpio);
         return MRAA_ERROR_INVALID_RESOURCE;
     }
 
@@ -504,6 +558,7 @@ mraa_intel_edsion_mb_gpio_mode(mraa_gpio_context dev, gpio_mode_t mode)
     int length;
     switch (mode) {
         case MRAA_GPIO_STRONG:
+            mraa_gpio_close(mode_gpio);
             close(drive);
             return MRAA_SUCCESS;
         case MRAA_GPIO_PULLUP:
@@ -516,15 +571,18 @@ mraa_intel_edsion_mb_gpio_mode(mraa_gpio_context dev, gpio_mode_t mode)
             length = snprintf(bu, sizeof(bu), "nopull");
             break;
         default:
+            mraa_gpio_close(mode_gpio);
             close(drive);
             return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
     }
     if (write(drive, bu, length * sizeof(char)) == -1) {
         syslog(LOG_ERR, "edison: Failed to write to drive mode");
+        mraa_gpio_close(mode_gpio);
         close(drive);
         return MRAA_ERROR_INVALID_RESOURCE;
     }
 
+    mraa_gpio_close(mode_gpio);
     if (close(drive) != 0) {
         return MRAA_ERROR_INVALID_RESOURCE;
     }
@@ -534,6 +592,10 @@ mraa_intel_edsion_mb_gpio_mode(mraa_gpio_context dev, gpio_mode_t mode)
 mraa_result_t
 mraa_intel_edison_uart_init_pre(int index)
 {
+    if (index != 0) {
+        syslog(LOG_ERR, "edison: Failed to write to drive mode");
+        return MRAA_ERROR_INVALID_RESOURCE;
+    }
     if (miniboard == 0) {
         mraa_gpio_write(tristate, 0);
         mraa_gpio_context io0_output = mraa_gpio_init_raw(248);
@@ -648,7 +710,10 @@ mraa_intel_edison_mmap_setup(mraa_gpio_context dev, mraa_boolean_t en)
         }
 
         struct stat fd_stat;
-        fstat(mmap_fd, &fd_stat);
+        if (fstat(mmap_fd, &fd_stat) != 0) {
+            syslog(LOG_ERR, "edison map: unable to access resource0 file");
+            return MRAA_ERROR_INVALID_HANDLE;
+        }
         mmap_size = fd_stat.st_size;
 
         mmap_reg =
@@ -728,15 +793,19 @@ mraa_intel_edison_miniboard(mraa_board_t* b)
         return MRAA_ERROR_UNSPECIFIED;
     }
 
-    advance_func->gpio_init_post = &mraa_intel_edison_gpio_init_post;
-
-    advance_func->pwm_init_pre = &mraa_intel_edison_pwm_init_pre;
-    advance_func->i2c_init_pre = &mraa_intel_edison_i2c_init_pre;
-    advance_func->i2c_set_frequency_replace = &mraa_intel_edison_i2c_freq;
-    advance_func->spi_init_pre = &mraa_intel_edison_spi_init_pre;
-    advance_func->gpio_mode_replace = &mraa_intel_edsion_mb_gpio_mode;
-    advance_func->uart_init_pre = &mraa_intel_edison_uart_init_pre;
-    advance_func->gpio_mmap_setup = &mraa_intel_edison_mmap_setup;
+    b->adv_func = (mraa_adv_func_t*) calloc(1, sizeof(mraa_adv_func_t));
+    if (b->adv_func == NULL) {
+        free(b->pins);
+        return MRAA_ERROR_UNSPECIFIED;
+    }
+    b->adv_func->gpio_init_post = &mraa_intel_edison_gpio_init_post;
+    b->adv_func->pwm_init_pre = &mraa_intel_edison_pwm_init_pre;
+    b->adv_func->i2c_init_pre = &mraa_intel_edison_i2c_init_pre;
+    b->adv_func->i2c_set_frequency_replace = &mraa_intel_edison_i2c_freq;
+    b->adv_func->spi_init_pre = &mraa_intel_edison_spi_init_pre;
+    b->adv_func->gpio_mode_replace = &mraa_intel_edsion_mb_gpio_mode;
+    b->adv_func->uart_init_pre = &mraa_intel_edison_uart_init_pre;
+    b->adv_func->gpio_mmap_setup = &mraa_intel_edison_mmap_setup;
 
     int pos = 0;
     strncpy(b->pins[pos].name, "J17-1", 8);
@@ -1084,7 +1153,7 @@ mraa_intel_edison_miniboard(mraa_board_t* b)
 mraa_board_t*
 mraa_intel_edison_fab_c()
 {
-    mraa_board_t* b = (mraa_board_t*) malloc(sizeof(mraa_board_t));
+    mraa_board_t* b = (mraa_board_t*) calloc(1, sizeof(mraa_board_t));
     if (b == NULL) {
         return NULL;
     }
@@ -1105,26 +1174,32 @@ mraa_intel_edison_fab_c()
     b->gpio_count = 14;
     b->aio_count = 6;
 
-    advance_func->gpio_dir_pre = &mraa_intel_edison_gpio_dir_pre;
-    advance_func->gpio_init_post = &mraa_intel_edison_gpio_init_post;
-    advance_func->gpio_close_pre = &mraa_intel_edison_gpio_close_pre;
-    advance_func->gpio_dir_post = &mraa_intel_edison_gpio_dir_post;
-    advance_func->i2c_init_pre = &mraa_intel_edison_i2c_init_pre;
-    advance_func->i2c_set_frequency_replace = &mraa_intel_edison_i2c_freq;
-    advance_func->aio_get_valid_fp = &mraa_intel_edison_aio_get_fp;
-    advance_func->aio_init_pre = &mraa_intel_edison_aio_init_pre;
-    advance_func->aio_init_post = &mraa_intel_edison_aio_init_post;
-    advance_func->pwm_init_pre = &mraa_intel_edison_pwm_init_pre;
-    advance_func->pwm_init_post = &mraa_intel_edison_pwm_init_post;
-    advance_func->spi_init_pre = &mraa_intel_edison_spi_init_pre;
-    advance_func->spi_init_post = &mraa_intel_edison_spi_init_post;
-    advance_func->gpio_mode_replace = &mraa_intel_edison_gpio_mode_replace;
-    advance_func->uart_init_pre = &mraa_intel_edison_uart_init_pre;
-    advance_func->uart_init_post = &mraa_intel_edison_uart_init_post;
-    advance_func->gpio_mmap_setup = &mraa_intel_edison_mmap_setup;
+    b->adv_func = (mraa_adv_func_t*) calloc(1, sizeof(mraa_adv_func_t));
+    if (b->adv_func == NULL) {
+        goto error;
+    }
+    b->adv_func->gpio_dir_pre = &mraa_intel_edison_gpio_dir_pre;
+    b->adv_func->gpio_init_post = &mraa_intel_edison_gpio_init_post;
+    b->adv_func->gpio_close_pre = &mraa_intel_edison_gpio_close_pre;
+    b->adv_func->gpio_dir_post = &mraa_intel_edison_gpio_dir_post;
+    b->adv_func->i2c_init_pre = &mraa_intel_edison_i2c_init_pre;
+    b->adv_func->i2c_set_frequency_replace = &mraa_intel_edison_i2c_freq;
+    b->adv_func->aio_get_valid_fp = &mraa_intel_edison_aio_get_fp;
+    b->adv_func->aio_init_pre = &mraa_intel_edison_aio_init_pre;
+    b->adv_func->aio_init_post = &mraa_intel_edison_aio_init_post;
+    b->adv_func->pwm_init_pre = &mraa_intel_edison_pwm_init_pre;
+    b->adv_func->pwm_init_post = &mraa_intel_edison_pwm_init_post;
+    b->adv_func->spi_init_pre = &mraa_intel_edison_spi_init_pre;
+    b->adv_func->spi_init_post = &mraa_intel_edison_spi_init_post;
+    b->adv_func->gpio_mode_replace = &mraa_intel_edison_gpio_mode_replace;
+    b->adv_func->uart_init_pre = &mraa_intel_edison_uart_init_pre;
+    b->adv_func->uart_init_post = &mraa_intel_edison_uart_init_post;
+    b->adv_func->gpio_mmap_setup = &mraa_intel_edison_mmap_setup;
+    b->adv_func->spi_lsbmode_replace = &mraa_intel_edison_spi_lsbmode_replace;
 
     b->pins = (mraa_pininfo_t*) malloc(sizeof(mraa_pininfo_t) * MRAA_INTEL_EDISON_PINCOUNT);
     if (b->pins == NULL) {
+        free(b->adv_func);
         goto error;
     }