/* libhw/rp2040_gpioirq.c - Utilities for sharing the GPIO IRQ (IO_IRQ_BANK0) * * Copyright (C) 2025 Luke T. Shumaker * SPDX-License-Identifier: AGPL-3.0-or-later */ #include /* for io_bank0_hw */ #include /* for irq_set_exclusive_handler() */ #include #include "rp2040_gpioirq.h" struct gpioirq_handler_entry { gpioirq_handler_t fn; void *arg; }; struct gpioirq_handler_entry gpioirq_handlers[NUM_BANK0_GPIOS][4] = {0}; int gpioirq_core = -1; static void gpioirq_handler(void) { uint core = get_core_num(); io_bank0_irq_ctrl_hw_t *irq_ctrl_base; switch (core) { case 0: irq_ctrl_base = &io_bank0_hw->proc0_irq_ctrl; break; case 1: irq_ctrl_base = &io_bank0_hw->proc1_irq_ctrl; break; default: assert_notreached("invalid core number"); } for (uint regnum = 0; regnum < LM_ARRAY_LEN(irq_ctrl_base->ints); regnum++) { uint32_t regval = irq_ctrl_base->ints[regnum]; for (uint bit = 0; bit < 32 && (regnum*8)+(bit/4) < NUM_BANK0_GPIOS; bit++) { if (regval & 1u<fn) handler->fn(handler->arg, gpio, 1u<intr[regnum] = regval; } } void gpioirq_set_and_enable_exclusive_handler(uint gpio, enum gpio_irq_level event, gpioirq_handler_t fn, void *arg) { assert(gpio < NUM_BANK0_GPIOS); assert(event == GPIO_IRQ_LEVEL_LOW || event == GPIO_IRQ_LEVEL_HIGH || event == GPIO_IRQ_EDGE_FALL || event == GPIO_IRQ_EDGE_RISE); assert(fn); uint event_idx = LM_FLOORLOG2(event); assert(gpioirq_handlers[gpio][event_idx].fn == NULL); uint core = get_core_num(); assert(gpioirq_core == -1 || gpioirq_core == (int)core); io_bank0_irq_ctrl_hw_t *irq_ctrl_base; switch (core) { case 0: irq_ctrl_base = &io_bank0_hw->proc0_irq_ctrl; break; case 1: irq_ctrl_base = &io_bank0_hw->proc1_irq_ctrl; break; default: assert_notreached("invalid core number"); } gpioirq_handlers[gpio][event_idx].fn = fn; gpioirq_handlers[gpio][event_idx].arg = arg; hw_set_bits(&irq_ctrl_base->inte[gpio/8], 1u<<((4*(gpio%8))+event_idx)); if (gpioirq_core == -1) { irq_set_exclusive_handler(IO_IRQ_BANK0, gpioirq_handler); irq_set_enabled(IO_IRQ_BANK0, true); gpioirq_core = core; } }