mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-07 16:11:43 +00:00
nrf51: Add support for the interrupts in GPIOTE to gpio.c
Add structures to keep track of which interrupts are associated with which pin. There are IN[] events, and one PORT event. The IN[] events have an array. The PORT event can be used for multiple pins at once. BUG=chrome-os-partner:34477 BRANCH=none TEST=Configured pins as IN[] events and PORT events, and saw console output. Signed-off-by: Myles Watson <mylesgw@chromium.org> Change-Id: I129a6586dca4d5eb141c86fd92fbfbb70080bc2a Reviewed-on: https://chromium-review.googlesource.com/234392 Reviewed-by: Randall Spangler <rspangler@chromium.org> Tested-by: Myles Watson <mylesgw@chromium.org> Commit-Queue: Myles Watson <mylesgw@chromium.org>
This commit is contained in:
committed by
ChromeOS Commit Bot
parent
741a2d4589
commit
215399af25
@@ -10,6 +10,13 @@
|
||||
#include "task.h"
|
||||
#include "util.h"
|
||||
|
||||
/*
|
||||
* For each interrupt (INT0-INT3, PORT), record which GPIO entry uses it.
|
||||
*/
|
||||
|
||||
static const struct gpio_info *gpio_ints[NRF51_GPIOTE_IN_COUNT];
|
||||
static const struct gpio_info *gpio_int_port;
|
||||
|
||||
volatile uint32_t * const nrf51_alt_funcs[] = {
|
||||
/* UART */
|
||||
&NRF51_UART_PSELRTS,
|
||||
@@ -74,6 +81,20 @@ void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags)
|
||||
NRF51_GPIO0_OUTCLR = mask;
|
||||
}
|
||||
|
||||
/* Interrupt levels */
|
||||
if (flags & GPIO_INT_SHARED) {
|
||||
/*
|
||||
* There are no shared edge-triggered interrupts;
|
||||
* they're either high or low.
|
||||
*/
|
||||
ASSERT((flags & (GPIO_INT_F_RISING | GPIO_INT_F_FALLING)) == 0);
|
||||
ASSERT((flags & GPIO_INT_LEVEL) != GPIO_INT_LEVEL);
|
||||
if (flags & GPIO_INT_F_LOW)
|
||||
val |= NRF51_PIN_CNF_SENSE_LOW;
|
||||
else if (flags & GPIO_INT_F_HIGH)
|
||||
val |= NRF51_PIN_CNF_SENSE_HIGH;
|
||||
}
|
||||
|
||||
NRF51_PIN_CNF(bit) = val;
|
||||
}
|
||||
|
||||
@@ -110,6 +131,11 @@ void gpio_pre_init(void)
|
||||
is_warm = 1;
|
||||
}
|
||||
|
||||
/* Initialize Interrupt configuration */
|
||||
for (i = 0; i < NRF51_GPIOTE_IN_COUNT; i++)
|
||||
gpio_ints[i] = NULL;
|
||||
gpio_int_port = NULL;
|
||||
|
||||
/* Set all GPIOs to defaults */
|
||||
for (i = 0; i < GPIO_COUNT; i++, g++) {
|
||||
int flags = g->flags;
|
||||
@@ -155,13 +181,124 @@ void gpio_set_alternate_function(uint32_t port, uint32_t mask, int func)
|
||||
|
||||
|
||||
/*
|
||||
* TODO: implement GPIO interrupt.
|
||||
* Enable the interrupt associated with the "signal"
|
||||
* The architecture has one general (PORT)
|
||||
* and NRF51_GPIOTE_IN_COUNT single-pin (IN0, IN1, ...) interrupts.
|
||||
*
|
||||
*/
|
||||
int gpio_enable_interrupt(enum gpio_signal signal)
|
||||
{
|
||||
return EC_ERROR_INVAL;
|
||||
int pin;
|
||||
const struct gpio_info *g = gpio_list + signal;
|
||||
|
||||
/* Fail if not implemented or no interrupt handler */
|
||||
if (!g->mask || !g->irq_handler)
|
||||
return EC_ERROR_INVAL;
|
||||
|
||||
/* If it's not shared, use INT0-INT3, otherwise use PORT. */
|
||||
if (!(g->flags & GPIO_INT_SHARED)) {
|
||||
int int_num, free_slot = -1;
|
||||
uint32_t event_config = 0;
|
||||
|
||||
for (int_num = 0; int_num < NRF51_GPIOTE_IN_COUNT; int_num++) {
|
||||
if (gpio_ints[int_num] == g)
|
||||
return EC_SUCCESS; /* This is already set up. */
|
||||
|
||||
if (gpio_ints[int_num] == NULL && free_slot == -1)
|
||||
free_slot = int_num;
|
||||
}
|
||||
|
||||
ASSERT(free_slot != -1);
|
||||
|
||||
gpio_ints[free_slot] = g;
|
||||
pin = 31 - __builtin_clz(g->mask);
|
||||
event_config = (pin << NRF51_GPIOTE_PSEL_POS) |
|
||||
NRF51_GPIOTE_MODE_EVENT;
|
||||
|
||||
ASSERT(g->flags & (GPIO_INT_F_RISING | GPIO_INT_F_FALLING));
|
||||
|
||||
/* RISING | FALLING = TOGGLE */
|
||||
if (g->flags & GPIO_INT_F_RISING)
|
||||
event_config |= NRF51_GPIOTE_POLARITY_LOTOHI;
|
||||
if (g->flags & GPIO_INT_F_FALLING)
|
||||
event_config |= NRF51_GPIOTE_POLARITY_HITOLO;
|
||||
|
||||
NRF51_GPIOTE_CONFIG(free_slot) = event_config;
|
||||
|
||||
/* Enable the IN[] interrupt. */
|
||||
NRF51_GPIOTE_INTENSET = 1 << free_slot;
|
||||
|
||||
} else {
|
||||
/* The first handler for the shared interrupt wins. */
|
||||
if (gpio_int_port == NULL) {
|
||||
gpio_int_port = g;
|
||||
|
||||
/* Enable the PORT interrupt. */
|
||||
NRF51_GPIOTE_INTENSET = 1 << NRF51_GPIOTE_PORT_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable the interrupt associated with the "signal"
|
||||
* The architecture has one general (PORT)
|
||||
* and NRF51_GPIOTE_IN_COUNT single-pin (IN0, IN1, ...) interrupts.
|
||||
*/
|
||||
int gpio_disable_interrupt(enum gpio_signal signal)
|
||||
{
|
||||
const struct gpio_info *g = gpio_list + signal;
|
||||
int i;
|
||||
|
||||
/* Fail if not implemented or no interrupt handler */
|
||||
if (!g->mask || !g->irq_handler)
|
||||
return EC_ERROR_INVAL;
|
||||
|
||||
/* If it's not shared, use INT0-INT3, otherwise use PORT. */
|
||||
if (!(g->flags && GPIO_INT_SHARED)) {
|
||||
for (i = 0; i < NRF51_GPIOTE_IN_COUNT; i++) {
|
||||
/* Remove matching handler. */
|
||||
if (gpio_ints[i] == g) {
|
||||
/* Disable the interrupt */
|
||||
NRF51_GPIOTE_INTENCLR =
|
||||
1 << NRF51_GPIOTE_IN_BIT(i);
|
||||
/* Zero the handler */
|
||||
gpio_ints[i] = NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Disable the interrupt */
|
||||
NRF51_GPIOTE_INTENCLR = 1 << NRF51_GPIOTE_PORT_BIT;
|
||||
/* Zero the shared handler */
|
||||
gpio_int_port = NULL;
|
||||
}
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear interrupt and run handler.
|
||||
*/
|
||||
void gpio_interrupt(void)
|
||||
{
|
||||
const struct gpio_info *g;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NRF51_GPIOTE_IN_COUNT; i++) {
|
||||
if (NRF51_GPIOTE_IN(i)) {
|
||||
NRF51_GPIOTE_IN(i) = 0;
|
||||
g = gpio_ints[i];
|
||||
if (g && g->irq_handler)
|
||||
g->irq_handler(g - gpio_list);
|
||||
}
|
||||
}
|
||||
|
||||
if (NRF51_GPIOTE_PORT) {
|
||||
NRF51_GPIOTE_PORT = 0;
|
||||
g = gpio_int_port;
|
||||
if (g && g->irq_handler)
|
||||
g->irq_handler(g - gpio_list);
|
||||
}
|
||||
}
|
||||
DECLARE_IRQ(NRF51_PERID_GPIOTE, gpio_interrupt, 1);
|
||||
|
||||
Reference in New Issue
Block a user