diff options
Diffstat (limited to 'zephyr/shim/src/tcpc.c')
-rw-r--r-- | zephyr/shim/src/tcpc.c | 83 |
1 files changed, 80 insertions, 3 deletions
diff --git a/zephyr/shim/src/tcpc.c b/zephyr/shim/src/tcpc.c index c4682fce85..98a3cd880b 100644 --- a/zephyr/shim/src/tcpc.c +++ b/zephyr/shim/src/tcpc.c @@ -3,6 +3,7 @@ * found in the LICENSE file. */ +#include "hooks.h" #include "usb_pd.h" #include "usb_pd_tcpm.h" #include "usbc/tcpc_anx7447.h" @@ -20,8 +21,11 @@ #include "usbc/utils.h" #include <zephyr/devicetree.h> +#include <zephyr/logging/log.h> #include <zephyr/sys/util.h> +LOG_MODULE_REGISTER(tcpc, CONFIG_GPIO_LOG_LEVEL); + #define HAS_TCPC_PROP(usbc_id) \ COND_CODE_1(DT_NODE_HAS_PROP(usbc_id, tcpc), (|| 1), ()) @@ -77,14 +81,86 @@ MAYBE_CONST struct tcpc_config_t tcpc_config[] = { DT_FOREACH_STATUS_OKAY( named_usbc_port, TCPC_CHIP) }; +#ifdef CONFIG_PLATFORM_EC_TCPC_INTERRUPT + +BUILD_ASSERT(ARRAY_SIZE(tcpc_config) == CONFIG_USB_PD_PORT_MAX_COUNT); + +struct gpio_callback int_gpio_cb[CONFIG_USB_PD_PORT_MAX_COUNT]; + +static void tcpc_int_gpio_callback(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) +{ + /* + * Retrieve the array index from the callback pointer, and + * use that to get the port number. + */ + int port = cb - &int_gpio_cb[0]; + + schedule_deferred_pd_interrupt(port); +} + +/* + * Enable all tcpc interrupts from devicetree bindings. + * Check whether the callback is already installed, and if + * not, init and add the callback before enabling the + * interrupt. + */ +void tcpc_enable_interrupt(void) +{ + gpio_flags_t flags; + + for (int i = 0; i < CONFIG_USB_PD_PORT_MAX_COUNT; i++) { + /* + * Check whether the interrupt pin has been configured + * by the devicetree. + */ + if (!tcpc_config[i].irq_gpio.port) + continue; + /* + * Check whether the gpio pin is ready + */ + if (!gpio_is_ready_dt(&tcpc_config[i].irq_gpio)) { + LOG_ERR("tcpc port #%i interrupt not ready.", i); + return; + } + /* + * TODO(b/267537103): Once named-gpios support is dropped, + * evaluate if this code should call gpio_pin_configure_dt() + * + * Check whether callback has been initialised + */ + if (!int_gpio_cb[i].handler) { + /* + * Initialise and add the callback. + */ + gpio_init_callback(&int_gpio_cb[i], + tcpc_int_gpio_callback, + BIT(tcpc_config[i].irq_gpio.pin)); + gpio_add_callback(tcpc_config[i].irq_gpio.port, + &int_gpio_cb[i]); + } + flags = tcpc_config[i].flags & TCPC_FLAGS_ALERT_ACTIVE_HIGH ? + GPIO_INT_EDGE_RISING : + GPIO_INT_EDGE_FALLING; + flags = (flags | GPIO_INT_ENABLE) & ~GPIO_INT_DISABLE; + gpio_pin_interrupt_configure_dt(&tcpc_config[i].irq_gpio, + flags); + } +} +/* + * priority set to POST_I2C + 1 so projects can make local edits to + * tcpc_config as needed at POST_I2C before the interrupts are enabled. + */ +DECLARE_HOOK(HOOK_INIT, tcpc_enable_interrupt, HOOK_PRIO_POST_I2C + 1); + +#else /* CONFIG_PLATFORM_EC_TCPC_INTERRUPT */ + /* TCPC GPIO Interrupt Handlers */ void tcpc_alert_event(enum gpio_signal signal) { for (int i = 0; i < ARRAY_SIZE(tcpc_config); i++) { - /* No alerts for embedded TCPC */ /* No alerts if the alert pin is not set in the devicetree */ - if (tcpc_config[i].bus_type == EC_BUS_TYPE_EMBEDDED || - tcpc_config[i].alert_signal == GPIO_LIMIT) { + if (tcpc_config[i].alert_signal == GPIO_LIMIT) { continue; } @@ -95,4 +171,5 @@ void tcpc_alert_event(enum gpio_signal signal) } } +#endif /* CONFIG_PLATFORM_EC_TCPC_INTERRUPT */ #endif /* DT_HAS_COMPAT_STATUS_OKAY */ |