nuttx/arch/arm/src/rp2040/rp2040_gpio.c
2021-03-11 19:31:17 -03:00

232 lines
6.4 KiB
C

/****************************************************************************
* 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 <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <arch/board/board.h>
#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);
}
}