PeripheralIO - Edison PIO HAL
am: 9b390fdb19

* commit '9b390fdb193796442069d567dfb4499bc1b2c78d':
  PeripheralIO - Edison PIO HAL

Change-Id: I28d448b0e02aa0ec5f28c7092f8adebda2d4c5e2
diff --git a/BoardConfig.mk b/BoardConfig.mk
index 3d2f8ae..1dfae99 100644
--- a/BoardConfig.mk
+++ b/BoardConfig.mk
@@ -63,5 +63,7 @@
     $(vendor_partition_directory)/uboot_firmware:u-boot-edison.bin \
     $(vendor_partition_directory)/uboot_firmware:gpt.bin
 
+DEVICE_PACKAGES += peripheral_io.$(TARGET_DEVICE)
+
 # Must defined at the end of the file
 $(call add_device_packages)
diff --git a/pio_hal/Android.mk b/pio_hal/Android.mk
new file mode 100644
index 0000000..33ea923
--- /dev/null
+++ b/pio_hal/Android.mk
@@ -0,0 +1,30 @@
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+ifeq ($(TARGET_DEVICE), edison)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := pio_hal.cc
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SHARED_LIBRARIES := liblog libchrome
+LOCAL_STATIC_LIBRARIES := peripheral_manager_hal_headers
+LOCAL_MODULE := peripheral_io.$(TARGET_DEVICE)
+LOCAL_CFLAGS := -fexceptions
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
\ No newline at end of file
diff --git a/pio_hal/pio_hal.cc b/pio_hal/pio_hal.cc
new file mode 100644
index 0000000..21784ba
--- /dev/null
+++ b/pio_hal/pio_hal.cc
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <string>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <map>
+#include <string>
+
+#include <base/logging.h>
+#include <hardware/hardware.h>
+#include <hardware/peripheral_io.h>
+
+// Path to sysfd gpio.
+const char kSysfsGpioPathPrefix[] = "/sys/class/gpio/gpio";
+
+// Path to export file.
+const char kSysfsGpioExportPath[] = "/sys/class/gpio/export";
+
+// Direction filename.
+const char kDirection[] = "direction";
+
+// Value filename.
+const char kValue[] = "value";
+
+static bool write_to_file(const std::string& path, const std::string& val) {
+  int fd = open(path.c_str(), O_WRONLY);
+  if (fd < 0)
+    return false;
+  ssize_t bytes = write(fd, val.c_str(), val.size());
+  close(fd);
+  if (bytes < 0)
+    return false;
+  if ((size_t)bytes != val.size())
+    return false;
+  return true;
+}
+
+static bool export_gpio(uint32_t index) {
+  std::string path = kSysfsGpioPathPrefix + std::to_string(index);
+  struct stat stat_buf;
+  if (!stat(path.c_str(), &stat_buf))
+    return true;
+
+  return write_to_file(kSysfsGpioExportPath, std::to_string(index));
+}
+
+static bool set_pin_direction(uint32_t index, const std::string& val) {
+  export_gpio(index);
+  std::string path =
+      kSysfsGpioPathPrefix + std::to_string(index) + "/direction";
+  return write_to_file(path, val);
+}
+
+static bool set_pin_val(uint32_t index, int val) {
+  export_gpio(index);
+  set_pin_direction(index, "out");
+  std::string path = kSysfsGpioPathPrefix + std::to_string(index) + "/value";
+  return write_to_file(path, std::to_string(val));
+}
+
+static bool set_output_buffer(uint32_t index, int val) {
+  export_gpio(index);
+  std::string path = kSysfsGpioPathPrefix + std::to_string(index) + "/value";
+  return write_to_file(path, std::to_string(val));
+}
+
+static bool set_mux_pin(uint32_t index, int val) {
+  set_pin_val(index, val);
+  return true;
+}
+
+static bool set_mode(uint32_t index, int val) {
+  export_gpio(index);
+  std::string path = kSysfsGpioPathPrefix + std::to_string(index) + "/pinmux";
+  return write_to_file(path, std::to_string(val));
+}
+
+struct EdisonPin {
+  uint32_t index;
+  uint32_t output_buffer;
+};
+
+std::map<std::string, EdisonPin> board_pins = {
+    {"IO0", {130, 248}}, {"IO1", {131, 249}},  {"IO2", {128, 250}},
+    {"IO3", {12, 251}},  {"IO4", {129, 252}},  {"IO5", {13, 253}},
+    {"IO6", {182, 254}}, {"IO7", {48, 255}},   {"IO8", {49, 256}},
+    {"IO9", {183, 257}}, {"IO10", {41, 258}},  {"IO11", {43, 259}},
+    {"IO12", {42, 260}}, {"IO13", {40, 261}},  {"IO14", {44, 232}},
+    {"IO15", {45, 233}}, {"IO16", {46, 234}},  {"IO17", {47, 235}},
+    {"IO18", {14, 236}}, {"IO19", {165, 237}},
+};
+
+static int pin_mux(const char* pin, const char* source) {
+  LOG(INFO) << "pin_mux1 " << pin << " ";
+  std::string pin_name(pin);
+
+  // If source is NULL, PIO is requesting GPIO.
+  if (!source) {
+    if (!board_pins.count(pin_name)) {
+      LOG(ERROR) << "PIO HAL: Unknown GPIO pin " << pin_name;
+      return false;
+    }
+
+    // Pin mode is always 0 for gpio.
+    set_mode(board_pins[pin_name].index, 0);
+    // Default to output buffer to input
+    set_output_buffer(board_pins[pin_name].output_buffer, 0);
+
+    // The following pins have an extra mux to set
+    if (pin_name == "IO10") {
+      set_mux_pin(263, 1);
+      set_mux_pin(240, 0);
+      set_mode(111, 0);
+    } else if (pin_name == "IO11") {
+      set_mux_pin(262, 1);
+      set_mux_pin(241, 0);
+      set_mode(115, 0);
+    } else if (pin_name == "IO12") {
+      set_mux_pin(242, 0);
+      set_mode(114, 0);
+    } else if (pin_name == "IO13") {
+      set_mux_pin(243, 0);
+      set_mode(109, 0);
+    } else if (pin_name == "IO14") {
+      set_mux_pin(200, 0);
+    } else if (pin_name == "IO15") {
+      set_mux_pin(201, 0);
+    } else if (pin_name == "IO16") {
+      set_mux_pin(202, 0);
+    } else if (pin_name == "IO17") {
+      set_mux_pin(203, 0);
+    } else if (pin_name == "IO18") {
+      set_mux_pin(204, 0);
+    } else if (pin_name == "IO19") {
+      set_mux_pin(205, 0);
+    }
+    return true;
+  }
+
+  std::string s = source;
+
+  // Configure SPI2
+  if (s == "SPI") {
+    LOG(INFO) << "SPI PIN " << pin_name;
+    if (pin_name == "IO10") {
+      set_pin_direction(226, "in");
+      set_mode(111, 1);
+      set_mux_pin(263, 1);
+      set_mux_pin(240, 1);
+      set_output_buffer(258, 1);
+      return true;
+    }
+    if (pin_name == "IO11") {
+      set_pin_direction(227, "in");
+      set_mode(115, 1);
+      set_mux_pin(262, 1);
+      set_mux_pin(241, 1);
+      set_output_buffer(259, 1);
+      return true;
+    }
+    if (pin_name == "IO12") {
+      set_pin_direction(228, "in");
+      set_output_buffer(260, 0);
+      set_mode(114, 1);
+      set_mux_pin(242, 1);
+      return true;
+    }
+    if (pin_name == "IO13") {
+      set_output_buffer(261, 0);
+      set_pin_direction(229, "in");
+      set_mode(109, 1);
+      set_mode(40, 1);
+      set_mux_pin(243, 1);
+      set_output_buffer(261, 1);
+      return true;
+    }
+    LOG(ERROR) << "PIO HAL: Unknown SPI pin " << pin_name;
+    return false;
+  }
+
+  // Configure I2C
+  if (s == "I2C") {
+    LOG(INFO) << "PIO HAL I2C pin " << pin_name;
+    if (pin_name == "IO18") {
+      set_pin_direction(212, "in");
+      set_pin_direction(14, "in");
+      set_mode(28, 1);
+      set_mode(14, 1);
+      set_mux_pin(204, 0);
+      set_output_buffer(236, 0);
+      return true;
+    }
+    if (pin_name == "IO19") {
+      set_pin_direction(213, "in");
+      set_pin_direction(165, "in");
+      set_mode(165, 1);
+      set_mode(27, 1);
+      set_mux_pin(205, 0);
+      set_output_buffer(237, 0);
+      return true;
+    }
+    LOG(ERROR) << "PIO HAL: Unknown I2C pin " << pin_name;
+  }
+
+  if (s == "UART") {
+    LOG(INFO) << "PIO HAL UART pin" << pin_name;
+
+    if (pin_name == "IO0") {
+      set_pin_direction(248, "out");
+      set_pin_direction(216, "out");
+      set_output_buffer(248, 0);
+      set_output_buffer(216, 0);
+      set_mode(130, 1);
+    } else if(pin_name == "IO1") {
+      set_pin_direction(249, "out");
+      set_pin_direction(217, "in");
+      set_output_buffer(249, 1);
+      set_mode(131, 1);
+    }
+  }
+
+  return false;
+}
+
+static int pin_mux_directon(const char* pin, int dir) {
+  LOG(INFO) << "pin_mux_directon1 " << pin << " " << dir;
+  std::string pin_name(pin);
+
+  if (!board_pins.count(pin_name)) {
+    LOG(ERROR) << "PIO HAL: Unknown GPIO pin " << pin_name;
+    return false;
+  }
+  set_output_buffer(board_pins[pin_name].output_buffer, dir);
+
+  return true;
+}
+
+static int register_device(const peripheral_io_module_t* dev,
+                           const peripheral_registration_cb_t* callbacks) {
+  LOG(INFO) << "register_device";
+  (void)dev;
+  // Set up pin muxing and register GPIO pins.
+  for (auto& pin : board_pins) {
+    callbacks->register_pin(pin.first.c_str(), true,
+                            {pin_mux, pin_mux_directon});
+    callbacks->register_gpio_sysfs(pin.first.c_str(), pin.second.index);
+    callbacks->set_gpio_pin_mux(pin.first.c_str(), pin.first.c_str());
+    set_pin_direction(pin.second.output_buffer, "low");
+  }
+  const char* spi_pins[4] = {"IO10", "IO11", "IO12", "IO13"};
+  callbacks->register_simple_source("SPI", spi_pins, 4);
+
+  // Register the SPI bus
+  callbacks->register_spi_dev_bus("SPI2", 5, 1);
+  callbacks->set_spi_pin_mux("SPI2", "SPI");
+
+  const char* i2c_pins[2] = {"IO18", "IO19"};
+  callbacks->register_simple_source("I2C", i2c_pins, 2);
+
+  // Register the I2C bus
+  callbacks->register_i2c_dev_bus("I2C6", 6);
+  callbacks->set_i2c_pin_mux("I2C6", "I2C");
+
+  const char* uart_pins[2] = {"IO0", "IO1"};
+  callbacks->register_simple_source("UART", uart_pins, 2);
+
+  // TODO(leecam): Add UART back in once UART code lands
+  //callbacks->register_uart_bus("UART1", "/dev/ttyMFD1");
+  //callbacks->set_uart_pin_mux("UART1", "UART");
+
+  // Enable the Tri-State
+  set_pin_direction(214, "out");
+  set_pin_val(214, 1);
+
+  return 0;
+}
+
+static struct hw_module_methods_t hal_module_methods = {};
+
+peripheral_io_module_t HAL_MODULE_INFO_SYM = {
+    .common =
+        {
+            .tag = HARDWARE_MODULE_TAG,
+            .module_api_version = 0,
+            .hal_api_version = HARDWARE_HAL_API_VERSION,
+            .id = PERIPHERAL_IO_HARDWARE_MODULE_ID,
+            .name = "periperal IO HAL",
+            .author = "The Android Open Source Project",
+            .methods = &hal_module_methods,
+        },
+    .register_devices = register_device,
+};