diff options
author | Lee Campbell <leecam@google.com> | 2016-05-03 02:45:39 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2016-05-03 02:45:39 +0000 |
commit | 38d47130db72823f90d17b07ccc1e29513e49221 (patch) | |
tree | f941cf2c603e0746727f6b9044439770cc3e58b3 | |
parent | 00129e9bc0561963432626bed82766fb7f36a738 (diff) | |
parent | 17b4001e01d43e7d554d52ff54453128299592eb (diff) | |
download | edison-38d47130db72823f90d17b07ccc1e29513e49221.tar.gz |
PeripheralIO - Edison PIO HAL am: 9b390fdb19
am: 17b4001e01
* commit '17b4001e01d43e7d554d52ff54453128299592eb':
PeripheralIO - Edison PIO HAL
Change-Id: I87f4c5893978601d44ed97b753e33bf4dd09c394
-rw-r--r-- | BoardConfig.mk | 2 | ||||
-rw-r--r-- | pio_hal/Android.mk | 30 | ||||
-rw-r--r-- | pio_hal/pio_hal.cc | 309 |
3 files changed, 341 insertions, 0 deletions
diff --git a/BoardConfig.mk b/BoardConfig.mk index 3d2f8ae..1dfae99 100644 --- a/BoardConfig.mk +++ b/BoardConfig.mk @@ -63,5 +63,7 @@ BRILLO_VENDOR_PARTITIONS := \ $(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, +}; |