arm/rp2040: Add RP2040 GPIO interrupt functions

This commit is contained in:
Yuichi Nakamura 2021-03-11 23:19:27 +09:00 committed by Alan Carvalho de Assis
parent 9fd0df3931
commit 174a4c1b68
2 changed files with 212 additions and 0 deletions

View File

@ -37,16 +37,89 @@
#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));
@ -57,6 +130,8 @@ void rp2040_gpio_set_function(uint32_t gpio, uint32_t func)
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,
@ -65,7 +140,92 @@ void rp2040_gpio_set_pulls(uint32_t gpio, int up, int down)
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);
}
}

View File

@ -27,6 +27,10 @@
#include <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <debug.h>
#include "hardware/rp2040_sio.h"
#include "hardware/rp2040_io_bank0.h"
#include "hardware/rp2040_pads_bank0.h"
@ -35,6 +39,10 @@
* Pre-processor Definitions
****************************************************************************/
#define RP2040_GPIO_NUM 30 /* Number of GPIO pins */
/* GPIO function types ******************************************************/
#define RP2040_GPIO_FUNC_JTAG RP2040_IO_BANK0_GPIO_CTRL_FUNCSEL_JTAG
#define RP2040_GPIO_FUNC_SPI RP2040_IO_BANK0_GPIO_CTRL_FUNCSEL_SPI
#define RP2040_GPIO_FUNC_UART RP2040_IO_BANK0_GPIO_CTRL_FUNCSEL_UART
@ -47,6 +55,13 @@
#define RP2040_GPIO_FUNC_USB RP2040_IO_BANK0_GPIO_CTRL_FUNCSEL_USB
#define RP2040_GPIO_FUNC_NULL RP2040_IO_BANK0_GPIO_CTRL_FUNCSEL_NULL
/* GPIO interrupt modes *****************************************************/
#define RP2040_GPIO_INTR_LEVEL_LOW 0
#define RP2040_GPIO_INTR_LEVEL_HIGH 1
#define RP2040_GPIO_INTR_EDGE_LOW 2
#define RP2040_GPIO_INTR_EDGE_HIGH 3
/****************************************************************************
* Public Types
****************************************************************************/
@ -74,6 +89,8 @@ static inline void rp2040_gpio_put(uint32_t gpio, int set)
{
uint32_t value = 1 << gpio;
DEBUGASSERT(gpio < RP2040_GPIO_NUM);
if (set)
{
putreg32(value, RP2040_SIO_GPIO_OUT_SET);
@ -88,6 +105,8 @@ static inline bool rp2040_gpio_get(uint32_t gpio)
{
uint32_t value = 1 << gpio;
DEBUGASSERT(gpio < RP2040_GPIO_NUM);
return (getreg32(RP2040_SIO_GPIO_IN) & value) != 0;
}
@ -95,6 +114,8 @@ static inline void rp2040_gpio_setdir(uint32_t gpio, int out)
{
uint32_t value = 1 << gpio;
DEBUGASSERT(gpio < RP2040_GPIO_NUM);
if (out)
{
putreg32(value, RP2040_SIO_GPIO_OE_SET);
@ -113,6 +134,37 @@ void rp2040_gpio_set_function(uint32_t gpio, uint32_t func);
void rp2040_gpio_set_pulls(uint32_t gpio, int up, int down);
void rp2040_gpio_init(uint32_t gpio);
/****************************************************************************
* 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);
/****************************************************************************
* Name: rp2040_gpio_enable_irq
*
* Description:
* Enable the GPIO IRQ specified by 'gpio'
*
****************************************************************************/
void rp2040_gpio_enable_irq(uint32_t gpio);
/****************************************************************************
* Name: rp2040_gpio_disable_irq
*
* Description:
* Disable the GPIO IRQ specified by 'gpio'
*
****************************************************************************/
void rp2040_gpio_disable_irq(uint32_t gpio);
#undef EXTERN
#if defined(__cplusplus)
}