diff options
Diffstat (limited to 'zephyr/shim/src/gpio.c')
-rw-r--r-- | zephyr/shim/src/gpio.c | 441 |
1 files changed, 0 insertions, 441 deletions
diff --git a/zephyr/shim/src/gpio.c b/zephyr/shim/src/gpio.c deleted file mode 100644 index 2bae272361..0000000000 --- a/zephyr/shim/src/gpio.c +++ /dev/null @@ -1,441 +0,0 @@ -/* Copyright 2020 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include <device.h> -#include <init.h> -#include <kernel.h> -#include <logging/log.h> - -#include "gpio.h" -#include "gpio/gpio.h" -#include "sysjump.h" -#include "cros_version.h" - -LOG_MODULE_REGISTER(gpio_shim, LOG_LEVEL_ERR); - -/* - * Static information about each GPIO that is configured in the named_gpios - * device tree node. - */ -struct gpio_config { - /* GPIO net name */ - const char *name; - /* Set at build time for lookup */ - const struct device *dev; - /* Bit number of pin within device */ - gpio_pin_t pin; - /* From DTS, excludes interrupts flags */ - gpio_flags_t init_flags; -}; - -#define GPIO_CONFIG(id) \ - COND_CODE_1( \ - DT_NODE_HAS_PROP(id, enum_name), \ - ( \ - { \ - .name = DT_LABEL(id), \ - .dev = DEVICE_DT_GET(DT_PHANDLE(id, gpios)), \ - .pin = DT_GPIO_PIN(id, gpios), \ - .init_flags = DT_GPIO_FLAGS(id, gpios), \ - }, ), \ - ()) -static const struct gpio_config configs[] = { -#if DT_NODE_EXISTS(DT_PATH(named_gpios)) - DT_FOREACH_CHILD(DT_PATH(named_gpios), GPIO_CONFIG) -#endif -}; - -/* Runtime information for each GPIO that is configured in named_gpios */ -struct gpio_data { - /* Runtime device for gpio port. Set during in init function */ - const struct device *dev; -}; - -#define GPIO_DATA(id) COND_CODE_1(DT_NODE_HAS_PROP(id, enum_name), ({}, ), ()) -static struct gpio_data data[] = { -#if DT_NODE_EXISTS(DT_PATH(named_gpios)) - DT_FOREACH_CHILD(DT_PATH(named_gpios), GPIO_DATA) -#endif -}; - -/* Maps platform/ec gpio callback information */ -struct gpio_signal_callback { - /* The platform/ec gpio_signal */ - const enum gpio_signal signal; - /* IRQ handler from platform/ec code */ - void (*const irq_handler)(enum gpio_signal signal); - /* Interrupt-related gpio flags */ - const gpio_flags_t flags; -}; - -/* - * Each zephyr project should define EC_CROS_GPIO_INTERRUPTS in their gpio_map.h - * file if there are any interrupts that should be registered. The - * corresponding handler will be declared here, which will prevent - * needing to include headers with complex dependencies in gpio_map.h. - * - * EC_CROS_GPIO_INTERRUPTS is a space-separated list of GPIO_INT items. - */ - -/* - * Validate interrupt flags are valid for the Zephyr GPIO driver. - */ -#define IS_GPIO_INTERRUPT_FLAG(flag, mask) ((flag & mask) == mask) -#define VALID_GPIO_INTERRUPT_FLAG(flag) \ - (IS_GPIO_INTERRUPT_FLAG(flag, GPIO_INT_EDGE_RISING) || \ - IS_GPIO_INTERRUPT_FLAG(flag, GPIO_INT_EDGE_FALLING) || \ - IS_GPIO_INTERRUPT_FLAG(flag, GPIO_INT_EDGE_BOTH) || \ - IS_GPIO_INTERRUPT_FLAG(flag, GPIO_INT_LEVEL_LOW) || \ - IS_GPIO_INTERRUPT_FLAG(flag, GPIO_INT_LEVEL_HIGH) || \ - IS_GPIO_INTERRUPT_FLAG(flag, GPIO_INT_EDGE_TO_INACTIVE) || \ - IS_GPIO_INTERRUPT_FLAG(flag, GPIO_INT_EDGE_TO_ACTIVE) || \ - IS_GPIO_INTERRUPT_FLAG(flag, GPIO_INT_LEVEL_INACTIVE) || \ - IS_GPIO_INTERRUPT_FLAG(flag, GPIO_INT_LEVEL_ACTIVE)) - -#define GPIO_INT(sig, f, cb) \ - BUILD_ASSERT(VALID_GPIO_INTERRUPT_FLAG(f), \ - STRINGIFY(sig) " is not using Zephyr interrupt flags"); -#ifdef EC_CROS_GPIO_INTERRUPTS -EC_CROS_GPIO_INTERRUPTS -#endif -#undef GPIO_INT - -/* - * Create unique enum values for each GPIO_INT entry, which also sets - * the ZEPHYR_GPIO_INT_COUNT value. - */ -#define ZEPHYR_GPIO_INT_ID(sig) INT_##sig -#define GPIO_INT(sig, f, cb) ZEPHYR_GPIO_INT_ID(sig), -enum zephyr_gpio_int_id { -#ifdef EC_CROS_GPIO_INTERRUPTS - EC_CROS_GPIO_INTERRUPTS -#endif - ZEPHYR_GPIO_INT_COUNT, -}; -#undef GPIO_INT - -/* Create prototypes for each GPIO IRQ handler */ -#define GPIO_INT(sig, f, cb) void cb(enum gpio_signal signal); -#ifdef EC_CROS_GPIO_INTERRUPTS -EC_CROS_GPIO_INTERRUPTS -#endif -#undef GPIO_INT - -/* - * The Zephyr gpio_callback data needs to be updated at runtime, so allocate - * into uninitialized data (BSS). The constant data pulled from - * EC_CROS_GPIO_INTERRUPTS is stored separately in the gpio_interrupts[] array. - */ -static struct gpio_callback zephyr_gpio_callbacks[ZEPHYR_GPIO_INT_COUNT]; - -#define ZEPHYR_GPIO_CALLBACK_TO_INDEX(cb) \ - (int)(((int)(cb) - (int)&zephyr_gpio_callbacks) / \ - sizeof(struct gpio_callback)) - -#define GPIO_INT(sig, f, cb) \ - { \ - .signal = sig, \ - .flags = f, \ - .irq_handler = cb, \ - }, -const static struct gpio_signal_callback - gpio_interrupts[ZEPHYR_GPIO_INT_COUNT] = { -#ifdef EC_CROS_GPIO_INTERRUPTS - EC_CROS_GPIO_INTERRUPTS -#endif -#undef GPIO_INT - }; - -/* The single zephyr gpio handler that routes to appropriate platform/ec cb */ -static void gpio_handler_shim(const struct device *port, - struct gpio_callback *cb, gpio_port_pins_t pins) -{ - int callback_index = ZEPHYR_GPIO_CALLBACK_TO_INDEX(cb); - const struct gpio_signal_callback *const gpio = - &gpio_interrupts[callback_index]; - - /* Call the platform/ec gpio interrupt handler */ - gpio->irq_handler(gpio->signal); -} - -/** - * get_interrupt_from_signal() - Translate a gpio_signal to the - * corresponding gpio_signal_callback - * - * @signal The signal to convert. - * - * Return: A pointer to the corresponding entry in gpio_interrupts, or - * NULL if one does not exist. - */ -const static struct gpio_signal_callback * -get_interrupt_from_signal(enum gpio_signal signal) -{ - if (!gpio_is_implemented(signal)) - return NULL; - - for (size_t i = 0; i < ARRAY_SIZE(gpio_interrupts); i++) { - if (gpio_interrupts[i].signal == signal) - return &gpio_interrupts[i]; - } - - LOG_ERR("No interrupt defined for GPIO %s", configs[signal].name); - return NULL; -} - -int gpio_is_implemented(enum gpio_signal signal) -{ - return signal >= 0 && signal < ARRAY_SIZE(configs); -} - -int gpio_get_level(enum gpio_signal signal) -{ - if (!gpio_is_implemented(signal)) - return 0; - - const int l = gpio_pin_get_raw(data[signal].dev, configs[signal].pin); - - if (l < 0) { - LOG_ERR("Cannot read %s (%d)", configs[signal].name, l); - return 0; - } - return l; -} - -int gpio_get_ternary(enum gpio_signal signal) -{ - int pd, pu; - int flags = gpio_get_default_flags(signal); - - /* Read GPIO with internal pull-down */ - gpio_set_flags(signal, GPIO_INPUT | GPIO_PULL_DOWN); - pd = gpio_get_level(signal); - udelay(100); - - /* Read GPIO with internal pull-up */ - gpio_set_flags(signal, GPIO_INPUT | GPIO_PULL_UP); - pu = gpio_get_level(signal); - udelay(100); - - /* Reset GPIO flags */ - gpio_set_flags(signal, flags); - - /* Check PU and PD readings to determine tristate */ - return pu && !pd ? 2 : pd; -} - -const char *gpio_get_name(enum gpio_signal signal) -{ - if (!gpio_is_implemented(signal)) - return "UNIMPLEMENTED"; - - return configs[signal].name; -} - -void gpio_set_level(enum gpio_signal signal, int value) -{ - if (!gpio_is_implemented(signal)) - return; - - int rv = gpio_pin_set_raw(data[signal].dev, configs[signal].pin, value); - - if (rv < 0) { - LOG_ERR("Cannot write %s (%d)", configs[signal].name, rv); - } -} - -void gpio_set_level_verbose(enum console_channel channel, - enum gpio_signal signal, int value) -{ - cprints(channel, "Set %s: %d", gpio_get_name(signal), value); - gpio_set_level(signal, value); -} - -/* GPIO flags which are the same in Zephyr and this codebase */ -#define GPIO_CONVERSION_SAME_BITS \ - (GPIO_OPEN_DRAIN | GPIO_PULL_UP | GPIO_PULL_DOWN | GPIO_INPUT | \ - GPIO_OUTPUT) - -static int convert_from_zephyr_flags(const gpio_flags_t zephyr) -{ - /* Start out with the bits that are the same. */ - int ec_flags = zephyr & GPIO_CONVERSION_SAME_BITS; - gpio_flags_t unhandled_flags = zephyr & ~GPIO_CONVERSION_SAME_BITS; - - /* TODO(b/173789980): handle conversion of more bits? */ - if (unhandled_flags) { - LOG_WRN("Unhandled GPIO bits in zephyr->ec conversion: 0x%08X", - unhandled_flags); - } - - return ec_flags; -} - -static gpio_flags_t convert_to_zephyr_flags(int ec_flags) -{ - /* Start out with the bits that are the same. */ - gpio_flags_t zephyr_flags = ec_flags & GPIO_CONVERSION_SAME_BITS; - int unhandled_flags = ec_flags & ~GPIO_CONVERSION_SAME_BITS; - - /* TODO(b/173789980): handle conversion of more bits? */ - if (unhandled_flags) { - LOG_WRN("Unhandled GPIO bits in ec->zephyr conversion: 0x%08X", - unhandled_flags); - } - - return zephyr_flags; -} - -int gpio_get_default_flags(enum gpio_signal signal) -{ - if (!gpio_is_implemented(signal)) - return 0; - - return convert_from_zephyr_flags(configs[signal].init_flags); -} - -static int init_gpios(const struct device *unused) -{ - gpio_flags_t flags; - struct jump_data *jdata; - bool is_sys_jumped; - - ARG_UNUSED(unused); - - jdata = get_jump_data(); - - if (jdata && jdata->magic == JUMP_DATA_MAGIC) - is_sys_jumped = true; - else - is_sys_jumped = false; - - /* Loop through all GPIOs in device tree to set initial configuration */ - for (size_t i = 0; i < ARRAY_SIZE(configs); ++i) { - data[i].dev = configs[i].dev; - int rv; - - if (!device_is_ready(data[i].dev)) - LOG_ERR("Not found (%s)", configs[i].name); - - /* - * The configs[i].init_flags variable is read-only, so the - * following assignment is needed because the flags need - * adjusting on a warm reboot. - */ - flags = configs[i].init_flags; - - if (is_sys_jumped) { - flags &= - ~(GPIO_OUTPUT_INIT_LOW | GPIO_OUTPUT_INIT_HIGH); - } - - rv = gpio_pin_configure(data[i].dev, configs[i].pin, flags); - if (rv < 0) { - LOG_ERR("Config failed %s (%d)", configs[i].name, rv); - } - } - - /* - * Loop through all interrupt pins and set their callback. - */ - for (size_t i = 0; i < ARRAY_SIZE(gpio_interrupts); ++i) { - const enum gpio_signal signal = gpio_interrupts[i].signal; - int rv; - - if (signal == GPIO_UNIMPLEMENTED) - continue; - - gpio_init_callback(&zephyr_gpio_callbacks[i], gpio_handler_shim, - BIT(configs[signal].pin)); - rv = gpio_add_callback(data[signal].dev, - &zephyr_gpio_callbacks[i]); - - if (rv < 0) { - LOG_ERR("Callback reg failed %s (%d)", - configs[signal].name, rv); - continue; - } - } - - /* Configure unused pins in chip driver for better power consumption */ - if (gpio_config_unused_pins) { - int rv; - - rv = gpio_config_unused_pins(); - if (rv < 0) { - return rv; - } - } - - return 0; -} -#if CONFIG_PLATFORM_EC_GPIO_INIT_PRIORITY <= CONFIG_KERNEL_INIT_PRIORITY_DEFAULT -#error "GPIOs must initialize after the kernel default initialization" -#endif -SYS_INIT(init_gpios, POST_KERNEL, CONFIG_PLATFORM_EC_GPIO_INIT_PRIORITY); - -int gpio_enable_interrupt(enum gpio_signal signal) -{ - int rv; - const struct gpio_signal_callback *interrupt; - - interrupt = get_interrupt_from_signal(signal); - - if (!interrupt) - return -1; - - /* - * Config interrupt flags (e.g. INT_EDGE_BOTH) & enable interrupt - * together. - */ - rv = gpio_pin_interrupt_configure(data[signal].dev, configs[signal].pin, - (interrupt->flags | GPIO_INT_ENABLE) & - ~GPIO_INT_DISABLE); - if (rv < 0) { - LOG_ERR("Failed to enable interrupt on %s (%d)", - configs[signal].name, rv); - } - - return rv; -} - -int gpio_disable_interrupt(enum gpio_signal signal) -{ - int rv; - - if (!gpio_is_implemented(signal)) - return -1; - - rv = gpio_pin_interrupt_configure(data[signal].dev, configs[signal].pin, - GPIO_INT_DISABLE); - if (rv < 0) { - LOG_ERR("Failed to disable interrupt on %s (%d)", - configs[signal].name, rv); - } - - return rv; -} - -void gpio_reset(enum gpio_signal signal) -{ - if (!gpio_is_implemented(signal)) - return; - - gpio_pin_configure(data[signal].dev, configs[signal].pin, - configs[signal].init_flags); -} - -void gpio_set_flags(enum gpio_signal signal, int flags) -{ - if (!gpio_is_implemented(signal)) - return; - - gpio_pin_configure(data[signal].dev, configs[signal].pin, - convert_to_zephyr_flags(flags)); -} - -int signal_is_gpio(int signal) -{ - return true; -} |