/**************************************************************************** * arch/arm/src/rp2040/rp2040_gpio.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you 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. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include "arm_arch.h" #include "chip.h" #include "rp2040_gpio.h" /**************************************************************************** * Private Data ****************************************************************************/ /* GPIO interrupt initialize flag */ static bool g_gpio_irq_init = false; /* GPIO interrupt handlers information */ static xcpt_t g_gpio_irq_handlers[RP2040_GPIO_NUM]; static FAR void *g_gpio_irq_args[RP2040_GPIO_NUM]; static int g_gpio_irq_modes[RP2040_GPIO_NUM]; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: rp2040_gpio_interrupt * * Description: * GPIO interrupt handler * ****************************************************************************/ static int rp2040_gpio_interrupt(int irq, void *context, FAR void *arg) { int i; int j; uint32_t stat; uint32_t gpio; xcpt_t handler; /* Scan all GPIO interrupt status registers */ for (i = 0; i < 4; i++) { /* Get and clear pending GPIO interrupt status */ stat = getreg32(RP2040_IO_BANK0_PROC_INTS(i * 8, 0)); if (i == 3) { stat &= 0x00ffffff; /* Clear reserved bits */ } putreg32(stat, RP2040_IO_BANK0_INTR(i * 8)); while (stat != 0) { /* Scan all GPIO pins in one register */ for (j = 0; j < 8; j++) { if (stat & (0xf << (j * 4))) { stat &= ~(0xf << (j * 4)); gpio = i * 8 + j; handler = g_gpio_irq_handlers[gpio]; /* Call GPIO interrupt handler */ if (handler) { handler(gpio, context, g_gpio_irq_args[gpio]); } } } } } return OK; } /**************************************************************************** * Public Functions ****************************************************************************/ void rp2040_gpio_set_function(uint32_t gpio, uint32_t func) { DEBUGASSERT(gpio < RP2040_GPIO_NUM); modbits_reg32(RP2040_PADS_BANK0_GPIO_IE, RP2040_PADS_BANK0_GPIO_IE | RP2040_PADS_BANK0_GPIO_OD, RP2040_PADS_BANK0_GPIO(gpio)); putreg32(func & RP2040_IO_BANK0_GPIO_CTRL_FUNCSEL_MASK, RP2040_IO_BANK0_GPIO_CTRL(gpio)); } void rp2040_gpio_set_pulls(uint32_t gpio, int up, int down) { DEBUGASSERT(gpio < RP2040_GPIO_NUM); modbits_reg32((up ? RP2040_PADS_BANK0_GPIO_PUE : 0) | (down ? RP2040_PADS_BANK0_GPIO_PDE : 0), RP2040_PADS_BANK0_GPIO_PUE | RP2040_PADS_BANK0_GPIO_PDE, RP2040_PADS_BANK0_GPIO(gpio)); } void rp2040_gpio_init(uint32_t gpio) { DEBUGASSERT(gpio < RP2040_GPIO_NUM); rp2040_gpio_setdir(gpio, false); rp2040_gpio_put(gpio, false); rp2040_gpio_set_function(gpio, RP2040_GPIO_FUNC_SIO); } /**************************************************************************** * Name: r2040_gpio_irq_attach * * Description: * Configure the interrupt generated by the specified GPIO pin. * ****************************************************************************/ int rp2040_gpio_irq_attach(uint32_t gpio, uint32_t intrmode, xcpt_t isr, FAR void *arg) { if (!g_gpio_irq_init) { /* Initialize - register GPIO interrupt handler */ g_gpio_irq_init = true; irq_attach(RP2040_IO_IRQ_BANK0, rp2040_gpio_interrupt, NULL); up_enable_irq(RP2040_IO_IRQ_BANK0); } DEBUGASSERT(gpio < RP2040_GPIO_NUM); DEBUGASSERT(intrmode <= RP2040_GPIO_INTR_EDGE_HIGH); /* Save handler information */ g_gpio_irq_handlers[gpio] = isr; g_gpio_irq_args[gpio] = arg; g_gpio_irq_modes[gpio] = intrmode; /* Clear pending interrupts */ setbits_reg32(0xf << ((gpio % 8) * 4), RP2040_IO_BANK0_INTR(gpio)); return OK; } /**************************************************************************** * Name: rp2040_gpio_enable_irq * * Description: * Enable the GPIO IRQ specified by 'gpio' * ****************************************************************************/ void rp2040_gpio_enable_irq(uint32_t gpio) { uint32_t reg; DEBUGASSERT(gpio < RP2040_GPIO_NUM); if (g_gpio_irq_handlers[gpio] != NULL) { /* Set interrupt enable bit */ reg = RP2040_IO_BANK0_PROC_INTE(gpio, 0); clrbits_reg32(0xf << ((gpio % 8) * 4), reg); setbits_reg32(0x1 << ((gpio % 8) * 4 + g_gpio_irq_modes[gpio]), reg); } } /**************************************************************************** * Name: rp2040_gpio_disable_irq * * Description: * Disable the GPIO IRQ specified by 'gpio' * ****************************************************************************/ void rp2040_gpio_disable_irq(uint32_t gpio) { uint32_t reg; DEBUGASSERT(gpio < RP2040_GPIO_NUM); if (g_gpio_irq_handlers[gpio] != NULL) { /* Clear interrupt enable bit */ reg = RP2040_IO_BANK0_PROC_INTE(gpio, 0); clrbits_reg32(0xf << ((gpio % 8) * 4), reg); } }