232 lines
6.4 KiB
C
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);
|
|
}
|
|
}
|