diff --git a/arch/arm/src/nrf91/Kconfig b/arch/arm/src/nrf91/Kconfig index 120688899fd44..1d3a9f8d3c12f 100644 --- a/arch/arm/src/nrf91/Kconfig +++ b/arch/arm/src/nrf91/Kconfig @@ -258,6 +258,13 @@ config NRF91_GPIO0_NS bool "GPIO0 non-secure" default n +config NRF91_GPIOTE1_NS + bool "GPIOTE1 non-secure" + default n + ---help--- + Grant the non-secure GPIOTE instance (GPIOTE1) to the non-secure + domain, so a non-secure application can use GPIO interrupts. + config NRF91_NVMC_NS bool "NVMC non-secure" default n diff --git a/arch/arm/src/nrf91/hardware/nrf91_gpiote.h b/arch/arm/src/nrf91/hardware/nrf91_gpiote.h new file mode 100644 index 0000000000000..4c19a09132e69 --- /dev/null +++ b/arch/arm/src/nrf91/hardware/nrf91_gpiote.h @@ -0,0 +1,105 @@ +/**************************************************************************** + * arch/arm/src/nrf91/hardware/nrf91_gpiote.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF91_HARDWARE_NRF91_GPIOTE_H +#define __ARCH_ARM_SRC_NRF91_HARDWARE_NRF91_GPIOTE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "hardware/nrf91_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* The nRF9160 has two GPIOTE instances: GPIOTE0 (secure) and GPIOTE1 + * (non-secure). Select the one belonging to the build's security domain. + */ + +#ifdef CONFIG_ARCH_TRUSTZONE_NONSECURE +# define NRF91_GPIOTE_BASE NRF91_GPIOTE1_BASE +#else +# define NRF91_GPIOTE_BASE NRF91_GPIOTE0_BASE +#endif + +/* Register offsets for GPIOTE **********************************************/ + +#define NRF91_GPIOTE_TASKS_OUT_OFFSET(x) (0x0000 + (0x04 * x)) /* TASKS_OUT[x] */ +#define NRF91_GPIOTE_TASKS_SET_OFFSET(x) (0x0030 + (0x04 * x)) /* TASKS_SET[x] */ +#define NRF91_GPIOTE_TASKS_CLR_OFFSET(x) (0x0060 + (0x04 * x)) /* TASKS_CLR[x] */ +#define NRF91_GPIOTE_EVENTS_IN_OFFSET(x) (0x0100 + (0x04 * x)) /* EVENTS_IN[x] */ +#define NRF91_GPIOTE_EVENTS_PORT_OFFSET 0x017c /* EVENTS_PORT */ +#define NRF91_GPIOTE_INTENSET_OFFSET 0x0304 /* INTENSET */ +#define NRF91_GPIOTE_INTENCLR_OFFSET 0x0308 /* INTENCLR */ +#define NRF91_GPIOTE_CONFIG_OFFSET(x) (0x0510 + (0x04 * x)) /* CONFIG[x] */ + +/* Register addresses for GPIOTE ********************************************/ + +#define NRF91_GPIOTE_TASKS_OUT(x) (NRF91_GPIOTE_BASE + NRF91_GPIOTE_TASKS_OUT_OFFSET(x)) +#define NRF91_GPIOTE_TASKS_SET(x) (NRF91_GPIOTE_BASE + NRF91_GPIOTE_TASKS_SET_OFFSET(x)) +#define NRF91_GPIOTE_TASKS_CLR(x) (NRF91_GPIOTE_BASE + NRF91_GPIOTE_TASKS_CLR_OFFSET(x)) +#define NRF91_GPIOTE_EVENTS_IN(x) (NRF91_GPIOTE_BASE + NRF91_GPIOTE_EVENTS_IN_OFFSET(x)) +#define NRF91_GPIOTE_EVENTS_PORT (NRF91_GPIOTE_BASE + NRF91_GPIOTE_EVENTS_PORT_OFFSET) +#define NRF91_GPIOTE_INTENSET (NRF91_GPIOTE_BASE + NRF91_GPIOTE_INTENSET_OFFSET) +#define NRF91_GPIOTE_INTENCLR (NRF91_GPIOTE_BASE + NRF91_GPIOTE_INTENCLR_OFFSET) +#define NRF91_GPIOTE_CONFIG(x) (NRF91_GPIOTE_BASE + NRF91_GPIOTE_CONFIG_OFFSET(x)) + +/* Register offsets for GPIOTE **********************************************/ + +/* EVENT_IN Register */ + +#define GPIOTE_EVENT_IN_EVENT (1 << 0) /* Bit 0: Event generated from pin */ + +/* INTENSET/INTENCLR Register */ + +#define GPIOTE_INT_IN_SHIFT 0 /* Bits 0-7: Enable interrupt for event IN[i] */ + +#define GPIOTE_INT_IN_MASK (0xff << GPIOTE_INT_IN_SHIFT) +# define GPIOTE_INT_IN(i) ((1 << (i + GPIOTE_INT_IN_SHIFT)) & GPIOTE_INT_IN_MASK) + +#define GPIOTE_INT_PORT_SHIFT 31 /* Bit 31: Enable interrupt for event PORT */ +#define GPIOTE_INT_PORT (1 << GPIOTE_INT_PORT_SHIFT) + +/* CONFIG Register */ + +#define GPIOTE_CONFIG_MODE_SHIFT 0 /* Bits 0-1: Mode */ +#define GPIOTE_CONFIG_MODE_MASK (0x3 << GPIOTE_CONFIG_MODE_SHIFT) +# define GPIOTE_CONFIG_MODE_DIS (0x0 << GPIOTE_CONFIG_MODE_SHIFT) /* 0: Disabled */ +# define GPIOTE_CONFIG_MODE_EV (0x1 << GPIOTE_CONFIG_MODE_SHIFT) /* 1: Event */ +# define GPIOTE_CONFIG_MODE_TS (0x3 << GPIOTE_CONFIG_MODE_SHIFT) /* 2: Task */ + +#define GPIOTE_CONFIG_PSEL_SHIFT (8) /* Bits 8-12: GPIO number */ +#define GPIOTE_CONFIG_PSEL_MASK (0x1f << GPIOTE_CONFIG_PSEL_SHIFT) +#define GPIOTE_CONFIG_PORT_SHIFT (13) /* Bit 13: GPIO port */ +#define GPIOTE_CONFIG_POL_SHIFT (16) /* Bits 16-17: Polarity */ +#define GPIOTE_CONFIG_POL_MASK (0x3 << GPIOTE_CONFIG_POL_SHIFT) +# define GPIOTE_CONFIG_POL_NONE (0x0 << GPIOTE_CONFIG_POL_SHIFT) /* 0: None */ +# define GPIOTE_CONFIG_POL_LTH (0x1 << GPIOTE_CONFIG_POL_SHIFT) /* 1: LoToHi */ +# define GPIOTE_CONFIG_POL_HTL (0x2 << GPIOTE_CONFIG_POL_SHIFT) /* 2: HiToLo */ +# define GPIOTE_CONFIG_POL_TG (0x3 << GPIOTE_CONFIG_POL_SHIFT) /* 3: Toggle */ + +#define GPIOTE_CONFIG_OUTINIT_SHIFT (20) /* Bit 20: Initial value */ + +#endif /* __ARCH_ARM_SRC_NRF91_HARDWARE_NRF91_GPIOTE_H */ diff --git a/arch/arm/src/nrf91/nrf91_gpiote.c b/arch/arm/src/nrf91/nrf91_gpiote.c new file mode 100644 index 0000000000000..36fb06b5e3ced --- /dev/null +++ b/arch/arm/src/nrf91/nrf91_gpiote.c @@ -0,0 +1,619 @@ +/**************************************************************************** + * arch/arm/src/nrf91/nrf91_gpiote.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 +#include + +#include +#include + +#include "arm_internal.h" +#include "nrf91_gpio.h" +#include "nrf91_gpiote.h" + +#include "hardware/nrf91_gpiote.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define GPIOTE_CHANNELS 8 + +/* Use the GPIOTE instance (and its interrupt) for the build's security + * domain: GPIOTE1 when non-secure, GPIOTE0 when secure. The register base + * is selected in hardware/nrf91_gpiote.h. + */ + +#ifdef CONFIG_ARCH_TRUSTZONE_NONSECURE +# define NRF91_IRQ_GPIOTE NRF91_IRQ_GPIOTE1 +#else +# define NRF91_IRQ_GPIOTE NRF91_IRQ_GPIOTE0 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct nrf91_gpiote_callback_s +{ + xcpt_t callback; + void *arg; + uint32_t pinset; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Callbacks attached to each GPIOTE channel */ + +static struct nrf91_gpiote_callback_s g_gpiote_ch_callbacks[GPIOTE_CHANNELS]; + +#ifdef CONFIG_NRF91_PER_PIN_INTERRUPTS +/* Callbacks attached to each GPIO pin */ + +static struct nrf91_gpiote_callback_s + g_gpiote_pin_callbacks[NRF91_GPIO_NPORTS][NRF91_GPIO_NPINS]; +#else +/* Callback for the PORT event */ + +static struct nrf91_gpiote_callback_s + g_gpiote_port_callback[NRF91_GPIO_NPORTS]; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf91_gpiote_putreg + * + * Description: + * Put a 32-bit register value by offset + * + ****************************************************************************/ + +static inline void nrf91_gpiote_putreg(uint32_t offset, uint32_t value) +{ + putreg32(value, NRF91_GPIOTE_BASE + offset); +} + +/**************************************************************************** + * Name: nrf91_gpiote_getreg + * + * Description: + * Get a 32-bit register value by offset + * + ****************************************************************************/ + +static inline uint32_t nrf91_gpiote_getreg(uint32_t offset) +{ + return getreg32(NRF91_GPIOTE_BASE + offset); +} + +/**************************************************************************** + * Name: nrf91_gpiote_isr + * + * Description: + * Common GPIOTE interrupt handler + * + ****************************************************************************/ + +static int nrf91_gpiote_isr(int irq, void *context, void *arg) +{ + uint32_t regval = 0; + int ret = OK; + int i = 0; +#ifdef CONFIG_NRF91_PER_PIN_INTERRUPTS + int j = 0; +#endif + + /* Scan all GPIOTE channels */ + + for (i = 0; i < GPIOTE_CHANNELS; i += 1) + { + /* Only if callback is registered */ + + if (g_gpiote_ch_callbacks[i].callback != NULL) + { + /* Get input event register */ + + regval = nrf91_gpiote_getreg(NRF91_GPIOTE_EVENTS_IN_OFFSET(i)); + if (regval == GPIOTE_EVENT_IN_EVENT) + { + /* Execute callback */ + + xcpt_t callback = g_gpiote_ch_callbacks[i].callback; + void *cbarg = g_gpiote_ch_callbacks[i].arg; + ret = callback(irq, context, cbarg); + + /* Clear event */ + + nrf91_gpiote_putreg(NRF91_GPIOTE_EVENTS_IN_OFFSET(i), 0); + } + } + } + + /* Check for PORT event */ + + regval = nrf91_gpiote_getreg(NRF91_GPIOTE_EVENTS_PORT_OFFSET); + if (regval) + { + uint32_t addr = 0; + + /* Ack PORT event */ + + nrf91_gpiote_putreg(NRF91_GPIOTE_EVENTS_PORT_OFFSET, 0); + + /* For each GPIO port, get LATCH register */ + + for (i = 0; i < NRF91_GPIO_NPORTS; i++) + { + switch (i) + { + case 0: + addr = NRF91_GPIO_P0_BASE + NRF91_GPIO_LATCH_OFFSET; + break; +#ifdef CONFIG_NRF91_HAVE_PORT1 + case 1: + addr = NRF91_GPIO_P1_BASE + NRF91_GPIO_LATCH_OFFSET; + break; +#endif + } + + /* Retrieve LATCH register */ + + regval = getreg32(addr); + + /* Clear LATCH register (this may set PORT again) */ + + putreg32(0xffffffff, addr); + +#ifdef CONFIG_NRF91_PER_PIN_INTERRUPTS + /* Check for pins with DETECT bit high in LATCH register + * and dispatch callback if set + */ + + for (j = 0; j < NRF91_GPIO_NPINS && regval; j++) + { + if (regval & (1 << j) && g_gpiote_pin_callbacks[i][j].callback) + { + /* Run callback */ + + xcpt_t callback = g_gpiote_pin_callbacks[i][j].callback; + void *cbarg = g_gpiote_pin_callbacks[i][j].arg; + + ret = callback(irq, context, cbarg); + + /* Mark bit is as "visited", we can stop looping sooner + * this way + */ + + regval &= ~(1 << j); + } + } +#else + if (g_gpiote_port_callback[i].callback) + { + xcpt_t callback = g_gpiote_port_callback[i].callback; + void *cbarg = g_gpiote_port_callback[i].arg; + + ret = callback(irq, context, cbarg); + } +#endif + } + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef CONFIG_NRF91_PER_PIN_INTERRUPTS +/**************************************************************************** + * Name: nrf91_gpiote_set_pin_event + * + * Description: + * Sets/clears a handler for a given pin for the GPIO PORT event. This + * will mean edge-sensitive or level-sensitive according to GPIO detect + * mode configuration for the port (see nrf91_gpio_detectmode()). Pin + * will be sensitive to high/low according to GPIO_SENSE_LOW/HIGH + * (set via nrf91_gpio_config()). + * + * The passed handler will be invoked from the main ISR for the PORT + * event and will take care of clearing the LATCH register. + * + * Input Parameters: + * - pinset: GPIO pin configuration + * - func: When non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + ****************************************************************************/ + +void nrf91_gpiote_set_pin_event(uint32_t pinset, xcpt_t func, void *arg) +{ + int pin = 0; + int port = 0; + irqstate_t flags; + + pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; +#ifdef CONFIG_NRF91_HAVE_PORT1 + port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; +#endif + + flags = enter_critical_section(); + + g_gpiote_pin_callbacks[port][pin].callback = func; + g_gpiote_pin_callbacks[port][pin].arg = arg; + + leave_critical_section(flags); +} +#else +/**************************************************************************** + * Name: nrf91_gpiote_set_port_event + * + * Description: + * Sets/clears the handler for the GPIO PORT event. + * + * The passed handler will be invoked from the main ISR for the PORT + * event and will take care of clearing the LATCH register. + * + * Input Parameters: + * - pinset: GPIO port will be extracted from this parameter + * - func: When non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + ****************************************************************************/ + +void nrf91_gpiote_set_port_event(uint32_t pinset, xcpt_t func, void *arg) +{ + int port = 0; + irqstate_t flags; + +#ifdef CONFIG_NRF91_HAVE_PORT1 + port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; +#endif + + flags = enter_critical_section(); + + g_gpiote_port_callback[port].callback = func; + g_gpiote_port_callback[port].arg = arg; + + if (func) + { + /* Enable the ISR */ + + nrf91_gpiote_putreg(NRF91_GPIOTE_INTENSET_OFFSET, GPIOTE_INT_PORT); + } + else + { +#if NRF91_GPIO_NPORTS > 1 + /* Check if we can disable the ISR */ + + int i; + + for (i = 0; i < NRF91_GPIO_NPORTS; i++) + { + if (g_gpiote_port_callback[port].callback) + { + break; + } + } + + if (i == NRF91_GPIO_NPORTS) + { + nrf91_gpiote_putreg(NRF91_GPIOTE_INTENCLR_OFFSET, GPIOTE_INT_PORT); + } +#else + /* Disable the ISR */ + + nrf91_gpiote_putreg(NRF91_GPIOTE_INTENCLR_OFFSET, GPIOTE_INT_PORT); +#endif + } + + leave_critical_section(flags); +} +#endif + +/**************************************************************************** + * Name: nrf91_gpiote_set_ch_event + * + * Description: + * Configures a GPIOTE channel in EVENT mode, assigns it to a given pin + * and sets a handler for the corresponding channel events. + * + * Input Parameters: + * - pinset: GPIO pin configuration + * - channel: GPIOTE channel used to capture events + * - risingedge: Enables interrupt on rising edges + * - fallingedge: Enables interrupt on falling edges + * - func: When non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + ****************************************************************************/ + +void nrf91_gpiote_set_ch_event(uint32_t pinset, int channel, + bool risingedge, bool fallingedge, + xcpt_t func, void *arg) +{ + int pin = 0; +#ifdef CONFIG_NRF91_HAVE_PORT1 + int port = 0; +#endif + uint32_t regval = 0; + irqstate_t flags; + + DEBUGASSERT(channel < GPIOTE_CHANNELS); + + /* NOTE: GPIOTE module has priority over GPIO module + * so GPIO configuration will be ignored + */ + + flags = enter_critical_section(); + + if (func) + { + /* Select EVENT mode */ + + regval |= GPIOTE_CONFIG_MODE_EV; + + /* Select GPIOTE pin */ + + pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + regval |= (pin << GPIOTE_CONFIG_PSEL_SHIFT); + +#ifdef CONFIG_NRF91_HAVE_PORT1 + port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + regval |= (port << GPIOTE_CONFIG_PORT_SHIFT); +#endif + + /* Select polarity */ + + if (risingedge == true && fallingedge == true) + { + regval |= GPIOTE_CONFIG_POL_TG; + } + else if (risingedge == true) + { + regval |= GPIOTE_CONFIG_POL_LTH; + } + else if (fallingedge == true) + { + regval |= GPIOTE_CONFIG_POL_HTL; + } + + /* Enable callback for channel */ + + g_gpiote_ch_callbacks[channel].callback = func; + g_gpiote_ch_callbacks[channel].arg = arg; + + /* Enable interrupt for given event */ + + nrf91_gpiote_putreg(NRF91_GPIOTE_INTENSET_OFFSET, + GPIOTE_INT_IN(channel)); + } + else + { + /* Leave register as zero (disabled mode) */ + + /* Disable interrupt for given event */ + + nrf91_gpiote_putreg(NRF91_GPIOTE_INTENCLR_OFFSET, + GPIOTE_INT_IN(channel)); + + /* Remove callback configuration */ + + g_gpiote_ch_callbacks[channel].callback = NULL; + g_gpiote_ch_callbacks[channel].arg = NULL; + } + + /* Write CONFIG register */ + + nrf91_gpiote_putreg(NRF91_GPIOTE_CONFIG_OFFSET(channel), regval); + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: nrf91_gpiote_set_event + * + * Description: + * Configures a GPIOTE channel in EVENT mode, assigns it to a given pin + * and sets a handler for the first available GPIOTE channel. + * + * Input Parameters: + * - pinset: GPIO pin configuration + * - risingedge: Enables interrupt on rising edges + * - fallingedge: Enables interrupt on falling edges + * - func: When non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure indicating the + * nature of the failure. + * + ****************************************************************************/ + +int nrf91_gpiote_set_event(uint32_t pinset, + bool risingedge, bool fallingedge, + xcpt_t func, void *arg) +{ + irqstate_t flags; + int ret = -ENOMEM; + int i = 0; + + flags = enter_critical_section(); + + /* Get free channel or channel already used by pinset */ + + for (i = 0; i < GPIOTE_CHANNELS; i++) + { + if (g_gpiote_ch_callbacks[i].callback == NULL || + g_gpiote_ch_callbacks[i].pinset == pinset) + { + g_gpiote_ch_callbacks[i].pinset = pinset; + + /* Configure channel */ + + nrf91_gpiote_set_ch_event(pinset, i, + risingedge, fallingedge, + func, arg); + + /* Return the channel index */ + + ret = i; + + break; + } + } + + leave_critical_section(flags); + + return ret; +} + +/**************************************************************************** + * Name: nrf91_gpio_set_task + * + * Description: + * Configure GPIO in TASK mode (to be controlled via tasks). + * Note that a pin can only be either in TASK or EVENT mode (set by + * nrf91_gpiosetevent with event set to true). Also, once set to TASK mode, + * pin control is only possible via tasks on the via nrf91_gpio_write and + * will automatically set the output mode. + * Finally, a given pin should only be assigned to a given channel. + * + * Input Parameters: + * - pinset: gpio pin configuration (only port + pin is important here) + * - channel: the GPIOTE channel used to control the given pin + * - output_high: set pin initially to output HIGH or LOW. + * - outcfg: configure pin behavior one OUT task is triggered + * + ****************************************************************************/ + +void nrf91_gpiote_set_task(uint32_t pinset, int channel, + bool output_high, + enum nrf91_gpiote_outcfg_e outcfg) +{ + uint32_t regval; + int pin; +#ifdef CONFIG_NRF91_HAVE_PORT1 + int port; +#endif + + /* Select GPIOTE pin */ + + pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + regval = (pin << GPIOTE_CONFIG_PSEL_SHIFT); + +#ifdef CONFIG_NRF91_HAVE_PORT1 + port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + regval |= (port << GPIOTE_CONFIG_PORT_SHIFT); +#endif + + /* Select TASK mode */ + + regval |= GPIOTE_CONFIG_MODE_TS; + + /* Select pin number */ + + regval |= (pin << GPIOTE_CONFIG_PSEL_SHIFT); + + /* Select initial output */ + + if (output_high) + { + regval |= (1 << GPIOTE_CONFIG_OUTINIT_SHIFT); + } + + /* Set polarity mode */ + + switch (outcfg) + { + case NRF91_GPIOTE_SET: + regval |= GPIOTE_CONFIG_POL_LTH; + break; + case NRF91_GPIOTE_CLEAR: + regval |= GPIOTE_CONFIG_POL_HTL; + break; + case NRF91_GPIOTE_TOGGLE: + regval |= GPIOTE_CONFIG_POL_TG; + break; + } + + /* Write register */ + + nrf91_gpiote_putreg(NRF91_GPIOTE_CONFIG_OFFSET(channel), regval); +} + +/**************************************************************************** + * Name: nrf91_gpiote_init + * + * Description: + * Initialize GPIOTE + * + ****************************************************************************/ + +int nrf91_gpiote_init(void) +{ + /* Clear LATCH register(s) */ + + putreg32(0, NRF91_GPIO_P0_BASE + NRF91_GPIO_LATCH_OFFSET); + +#ifdef CONFIG_NRF91_HAVE_PORT1 + putreg32(0, NRF91_GPIO_P1_BASE + NRF91_GPIO_LATCH_OFFSET); +#endif + + /* Reset GPIOTE data */ + + memset(&g_gpiote_ch_callbacks, 0, sizeof(g_gpiote_ch_callbacks)); + +#ifdef CONFIG_NRF91_PER_PIN_INTERRUPTS + memset(&g_gpiote_pin_callbacks, 0, sizeof(g_gpiote_pin_callbacks)); + + /* Enable PORT event interrupt */ + + nrf91_gpiote_putreg(NRF91_GPIOTE_INTENSET_OFFSET, GPIOTE_INT_PORT); +#else + memset(&g_gpiote_port_callback, 0, sizeof(g_gpiote_port_callback)); +#endif + + /* Attach GPIOTE interrupt handler */ + + irq_attach(NRF91_IRQ_GPIOTE, nrf91_gpiote_isr, NULL); + up_enable_irq(NRF91_IRQ_GPIOTE); + + return OK; +} diff --git a/arch/arm/src/nrf91/nrf91_gpiote.h b/arch/arm/src/nrf91/nrf91_gpiote.h new file mode 100644 index 0000000000000..ed82dd3759c51 --- /dev/null +++ b/arch/arm/src/nrf91/nrf91_gpiote.h @@ -0,0 +1,178 @@ +/**************************************************************************** + * arch/arm/src/nrf91/nrf91_gpiote.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF91_NRF91_GPIOTE_H +#define __ARCH_ARM_SRC_NRF91_NRF91_GPIOTE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "chip.h" + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* GPIOTE OUT task configuration */ + +enum nrf91_gpiote_outcfg_e +{ + NRF91_GPIOTE_SET = 0, + NRF91_GPIOTE_CLEAR = 1, + NRF91_GPIOTE_TOGGLE = 2, +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf91_gpiote_set_ch_event + * + * Description: + * Configures a GPIOTE channel in EVENT mode, assigns it to a given pin + * and sets a handler for the corresponding channel events. + * + * Input Parameters: + * - pinset: GPIO pin configuration + * - channel: GPIOTE channel used to capture events + * - risingedge: Enables interrupt on rising edges + * - fallingedge: Enables interrupt on falling edges + * - func: When non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + ****************************************************************************/ + +void nrf91_gpiote_set_ch_event(uint32_t pinset, int channel, + bool risingedge, bool fallingedge, + xcpt_t func, void *arg); + +/**************************************************************************** + * Name: nrf91_gpiote_set_event + * + * Description: + * Configures a GPIOTE channel in EVENT mode, assigns it to a given pin + * and sets a handler for the first available GPIOTE channel. + * + * Input Parameters: + * - pinset: GPIO pin configuration + * - risingedge: Enables interrupt on rising edges + * - fallingedge: Enables interrupt on falling edges + * - func: When non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure indicating the + * nature of the failure. + * + ****************************************************************************/ + +int nrf91_gpiote_set_event(uint32_t pinset, + bool risingedge, bool fallingedge, + xcpt_t func, void *arg); + +#ifdef CONFIG_NRF91_PER_PIN_INTERRUPTS +/**************************************************************************** + * Name: nrf91_gpiote_set_pin_event + * + * Description: + * Sets/clears a handler for a given pin for the GPIO PORT event. This + * will mean edge-sensitive or level-sensitive according to GPIO detect + * mode configuration for the port (see nrf91_gpio_detectmode()). Pin + * will be sensitive to high/low according to GPIO_SENSE_LOW/HIGH + * (set via nrf91_gpio_config()). + * + * The passed handler will be invoked from the main ISR for the PORT + * event and will take care of clearing the LATCH register. + * + * Input Parameters: + * - pinset: GPIO pin configuration + * - func: When non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure indicating the + * nature of the failure. + * + ****************************************************************************/ + +void nrf91_gpiote_set_pin_event(uint32_t pinset, xcpt_t func, void *arg); +#else + +/**************************************************************************** + * Name: nrf91_gpiote_set_port_event + * + * Description: + * Sets/clears the handler for the GPIO PORT event. + * + * The passed handler will be invoked from the main ISR for the PORT + * event and will take care of clearing the LATCH register. + * + * Input Parameters: + * - pinset: GPIO port will be extracted from this parameter + * - func: When non-NULL, generate interrupt + * - arg: Argument passed to the interrupt callback + * + ****************************************************************************/ + +void nrf91_gpiote_set_port_event(uint32_t pinset, xcpt_t func, void *arg); + +#endif + +/**************************************************************************** + * Name: nrf91_gpio_set_task + * + * Description: + * Configure GPIO in TASK mode (to be controlled via tasks). + * Note that a pin can only be either in TASK or EVENT mode (set by + * nrf91_gpiosetevent with event set to true). Also, once set to TASK mode, + * pin control is only possible via tasks on the via nrf91_gpio_write and + * will automatically set the output mode. + * Finally, a given pin should only be assigned to a given channel. + * + * Input Parameters: + * - pinset: gpio pin configuration (only port + pin is important here) + * - channel: the GPIOTE channel used to control the given pin + * - output_high: set pin initially to output HIGH or LOW. + * - outcfg: configure pin behavior one OUT task is triggered + * + ****************************************************************************/ + +void nrf91_gpio_set_task(uint32_t pinset, int channel, + bool output_high, enum nrf91_gpiote_outcfg_e outcfg); + +/**************************************************************************** + * Name: nrf91_gpiote_init + * + * Description: + * Initialize GPIOTE + * + ****************************************************************************/ + +int nrf91_gpiote_init(void); + +#endif /* __ARCH_ARM_SRC_NRF91_NRF91_GPIOTE_H */ diff --git a/arch/arm/src/nrf91/nrf91_spu.c b/arch/arm/src/nrf91/nrf91_spu.c index 373fe8eedd87b..33317de780efd 100644 --- a/arch/arm/src/nrf91/nrf91_spu.c +++ b/arch/arm/src/nrf91/nrf91_spu.c @@ -87,6 +87,11 @@ static void nrf91_spu_periph(void) SPU_PERIPHID_PERM_SECATTR, 0); #endif +#ifdef CONFIG_NRF91_GPIOTE1_NS + modifyreg32(NRF91_SPU_PERIPHIDPERM(NRF91_GPIOTE1_ID), + SPU_PERIPHID_PERM_SECATTR, 0); +#endif + #ifdef CONFIG_NRF91_NVMC_NS modifyreg32(NRF91_SPU_PERIPHIDPERM(NRF91_NVMC_ID), SPU_PERIPHID_PERM_SECATTR, 0); diff --git a/boards/Kconfig b/boards/Kconfig index 2a6a401dd15a0..5196f18cbc205 100644 --- a/boards/Kconfig +++ b/boards/Kconfig @@ -1455,6 +1455,7 @@ config ARCH_BOARD_THINGY91 bool "Nordic Thingy:91 cellular IoT prototyping platform - nRF9160" depends on ARCH_CHIP_NRF91 select ARCH_HAVE_BUTTONS + select ARCH_HAVE_IRQBUTTONS ---help--- This option selects the Thingy:91 cellular IoT prototyping platform - nRF9160 chip