Skip to content

Commit

Permalink
drivers: gpio: nrf5: Fix GPIOTE channel use overlap
Browse files Browse the repository at this point in the history
Fixes issues caused in GPIO driver due to overlapping GPIOTE
channel use in nRF5 software PWM driver and in Bluetooth
controller for implementing PA/LNA feature.

The issue is solved by assigning the base and available
channel count for GPIOTE considering whether PWM and/or
PA/LNA feature is selected in the Kconfig.

Fixes zephyrproject-rtos#8815.

Signed-off-by: Vinayak Kariappa Chettimada <[email protected]>
  • Loading branch information
cvinayak authored and walter-xie committed Jul 13, 2018
1 parent e854dd0 commit 7fbd868
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 42 deletions.
36 changes: 20 additions & 16 deletions drivers/gpio/Kconfig.nrf5
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ menuconfig GPIO_NRF5

if GPIO_NRF5

config GPIO_NRF5_INIT_PRIORITY
int "nRF5 GPIO initialization priority"
default 40
help
Initialization priority for nRF5 GPIO.

config GPIO_NRF5_P0
bool "nRF5x GPIO Port P0"
help
Enable nRF5 GPIO port P0 config options.

config GPIO_NRF5_P1
bool "nRF5x GPIO Port P1"
depends on SOC_NRF52840
help
Enable nRF5 GPIO port P1 config options.

if !HAS_DTS_GPIO

config GPIO_NRF5_P0_DEV_NAME
Expand All @@ -34,16 +34,6 @@ config GPIO_NRF5_P0_DEV_NAME
help
Specify the device name to be used for the GPIO port.

endif # !HAS_DTS_GPIO

config GPIO_NRF5_P1
bool "nRF5x GPIO Port P1"
depends on SOC_NRF52840
help
Enable nRF5 GPIO port P1 config options.

if !HAS_DTS_GPIO

config GPIO_NRF5_P1_DEV_NAME
string "GPIO Port P1 Device Name"
depends on GPIO_NRF5_P1
Expand Down Expand Up @@ -73,4 +63,18 @@ config GPIOTE_NRF5_IRQ

endif # !HAS_DTS_GPIO

config GPIO_NRF5_INIT_PRIORITY
int "nRF5 GPIO initialization priority"
default 40
help
Initialization priority for nRF5 GPIO.

config GPIO_NRF5_GPIOTE_CHAN_BASE
# hidden
int
default 0
default 1 if (BT_CTLR_GPIO_PA || BT_CTLR_GPIO_LNA)
default 3 if PWM_NRF5_SW
default 4 if (BT_CTLR_GPIO_PA || BT_CTLR_GPIO_LNA) && PWM_NRF5_SW

endif # GPIO_NRF5
44 changes: 19 additions & 25 deletions drivers/gpio/gpio_nrf5.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,6 @@
#include "nrf_common.h"
#include "gpio_utils.h"

#if defined(CONFIG_SOC_SERIES_NRF51X)
#define GPIOTE_CHAN_COUNT (4)
#elif defined(CONFIG_SOC_SERIES_NRF52X)
#define GPIOTE_CHAN_COUNT (8)
#else
#error "Platform not defined."
#endif
#define GPIO_PIN_CNF_SENSE_Invalid 0x01

/* GPIO structure for nRF5X. More detailed description of each register can be found in nrf5X.h */
Expand Down Expand Up @@ -66,7 +59,9 @@ struct _gpiote {
};

/*@todo: move GPIOTE channel management to a separate module */
static u32_t gpiote_chan_mask;
/* Reserve channels below the base index */
#define GPIOTE_CH_BASE CONFIG_GPIO_NRF5_GPIOTE_CHAN_BASE
static u32_t gpiote_chan_mask = BIT_MASK(GPIOTE_CH_BASE);

/** Configuration data */
struct gpio_nrf5_config {
Expand Down Expand Up @@ -155,7 +150,7 @@ static int gpiote_find_channel(struct device *dev, u32_t pin, u32_t port)
volatile struct _gpiote *gpiote = (void *)NRF_GPIOTE_BASE;
int i;

for (i = 0; i < GPIOTE_CHAN_COUNT; i++) {
for (i = GPIOTE_CH_BASE; i < GPIOTE_CH_NUM; i++) {
if ((gpiote_chan_mask & BIT(i)) &&
(GPIOTE_CFG_PIN_GET(gpiote->CONFIG[i]) == pin) &&
(GPIOTE_CFG_PORT_GET(gpiote->CONFIG[i]) == port)) {
Expand Down Expand Up @@ -233,6 +228,20 @@ static int gpio_nrf5_config(struct device *dev,
u32_t config = 0;
u32_t port = GPIO_PORT(dev);

/* check if already allocated to replace */
int i = gpiote_find_channel(dev, pin, port);

if (i < 0) {
if (popcount(gpiote_chan_mask) == GPIOTE_CH_NUM) {
return -EIO;
}

/* allocate a GPIOTE channel */
i = find_lsb_set(~gpiote_chan_mask) - 1;
gpiote_chan_mask |= BIT(i);
}

/* configure GPIOTE channel */
if (flags & GPIO_INT_EDGE) {
if (flags & GPIO_INT_DOUBLE_EDGE) {
config |= GPIOTE_CFG_POL_TOGG;
Expand All @@ -245,21 +254,6 @@ static int gpio_nrf5_config(struct device *dev,
/*@todo: use SENSE for this? */
return -ENOTSUP;
}
if (popcount(gpiote_chan_mask) == GPIOTE_CHAN_COUNT) {
return -EIO;
}

/* check if already allocated to replace */
int i = gpiote_find_channel(dev, pin, port);

if (i < 0) {
/* allocate a GPIOTE channel */
i = find_lsb_set(~gpiote_chan_mask) - 1;
}

gpiote_chan_mask |= BIT(i);

/* configure GPIOTE channel */
config |= GPIOTE_CFG_EVT;
config |= GPIOTE_CFG_PIN(pin);
config |= GPIOTE_CFG_PORT(port);
Expand Down Expand Up @@ -389,7 +383,7 @@ static void gpio_nrf5_port_isr(void *arg)
u32_t enabled_int;
int i;

for (i = 0; i < GPIOTE_CHAN_COUNT; i++) {
for (i = GPIOTE_CH_BASE; i < GPIOTE_CH_NUM; i++) {
if (gpiote->EVENTS_IN[i]) {
int port = GPIOTE_CFG_PORT_GET(gpiote->CONFIG[i]);
int pin = GPIOTE_CFG_PIN_GET(gpiote->CONFIG[i]);
Expand Down
3 changes: 2 additions & 1 deletion subsys/bluetooth/controller/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,8 @@ config BT_CTLR_PA_LNA_GPIOTE_CHAN
# Hidden "nRF5 GPIO PA/LNA GPIOTE Channel"
depends on SOC_FAMILY_NRF && (BT_CTLR_GPIO_PA || BT_CTLR_GPIO_LNA)
int
default 3
default 0
default 3 if PWM_NRF5_SW
help
Select the nRF5 GPIOTE channel to use for PA/LNA GPIO feature.

Expand Down

0 comments on commit 7fbd868

Please sign in to comment.