arm/nrf52,nrf53,nrf91: fix GPIOTE driver bugs

- set_port_event checked the wrong port when deciding whether the
  PORT interrupt can be disabled
- set_event could pick a free channel instead of the one already
  assigned to the pin
- LATCH registers were cleared by writing zeros
- header declared nrfxx_gpio_set_task for a function defined as
  nrfxx_gpiote_set_task

Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
This commit is contained in:
raiden00pl 2026-09-24 15:32:29 +02:00 • committed by Xiang Xiao
parent f86b05351f
commit c8f699a4e3
6 changed files with 106 additions and 58 deletions

View file

@ -315,7 +315,7 @@ void nrf52_gpiote_set_port_event(uint32_t pinset, xcpt_t func, void *arg)
for (i = 0; i < NRF52_GPIO_NPORTS; i++)
{
if (g_gpiote_port_callback[port].callback)
if (g_gpiote_port_callback[i].callback)
{
break;
}
@ -465,36 +465,52 @@ int nrf52_gpiote_set_event(uint32_t pinset,
flags = enter_critical_section();
/* Get free channel or channel already used by pinset */
/* Get channel already used by pinset */
for (i = 0; i < GPIOTE_CHANNELS; i++)
{
if (g_gpiote_ch_callbacks[i].callback == NULL ||
if (g_gpiote_ch_callbacks[i].callback != NULL &&
g_gpiote_ch_callbacks[i].pinset == pinset)
{
g_gpiote_ch_callbacks[i].pinset = pinset;
/* Configure channel */
nrf52_gpiote_set_ch_event(pinset, i,
risingedge, fallingedge,
func, arg);
/* Return the channel index */
ret = i;
break;
}
}
/* Otherwise get a free channel */
if (i == GPIOTE_CHANNELS && func != NULL)
{
for (i = 0; i < GPIOTE_CHANNELS; i++)
{
if (g_gpiote_ch_callbacks[i].callback == NULL)
{
break;
}
}
}
if (i < GPIOTE_CHANNELS)
{
g_gpiote_ch_callbacks[i].pinset = pinset;
/* Configure channel */
nrf52_gpiote_set_ch_event(pinset, i,
risingedge, fallingedge,
func, arg);
/* Return the channel index */
ret = i;
}
leave_critical_section(flags);
return ret;
}
/****************************************************************************
* Name: nrf52_gpio_set_task
* Name: nrf52_gpiote_set_task
*
* Description:
* Configure GPIO in TASK mode (to be controlled via tasks).
@ -579,10 +595,10 @@ int nrf52_gpiote_init(void)
{
/* Clear LATCH register(s) */
putreg32(0, NRF52_GPIO_P0_BASE + NRF52_GPIO_LATCH_OFFSET);
putreg32(0xffffffff, NRF52_GPIO_P0_BASE + NRF52_GPIO_LATCH_OFFSET);
#ifdef CONFIG_NRF52_HAVE_PORT1
putreg32(0, NRF52_GPIO_P1_BASE + NRF52_GPIO_LATCH_OFFSET);
putreg32(0xffffffff, NRF52_GPIO_P1_BASE + NRF52_GPIO_LATCH_OFFSET);
#endif
/* Reset GPIOTE data */

View file

@ -144,7 +144,7 @@ void nrf52_gpiote_set_port_event(uint32_t pinset, xcpt_t func, void *arg);
#endif
/****************************************************************************
* Name: nrf52_gpio_set_task
* Name: nrf52_gpiote_set_task
*
* Description:
* Configure GPIO in TASK mode (to be controlled via tasks).
@ -162,7 +162,7 @@ void nrf52_gpiote_set_port_event(uint32_t pinset, xcpt_t func, void *arg);
*
****************************************************************************/
void nrf52_gpio_set_task(uint32_t pinset, int channel,
void nrf52_gpiote_set_task(uint32_t pinset, int channel,
bool output_high, enum nrf52_gpiote_outcfg_e outcfg);
/****************************************************************************

View file

@ -352,7 +352,7 @@ void nrf53_gpiote_set_port_event(uint32_t pinset, xcpt_t func, void *arg)
for (i = 0; i < NRF53_GPIO_NPORTS; i++)
{
if (g_gpiote_port_callback[port].callback)
if (g_gpiote_port_callback[i].callback)
{
break;
}
@ -506,34 +506,50 @@ int nrf53_gpiote_set_event(uint32_t pinset,
flags = enter_critical_section();
/* Get free channel or channel already used by pinset */
/* Get channel already used by pinset */
for (i = 0; i < GPIOTE_CHANNELS; i++)
{
if (g_gpiote_ch_callbacks[i].callback == NULL ||
if (g_gpiote_ch_callbacks[i].callback != NULL &&
g_gpiote_ch_callbacks[i].pinset == pinset)
{
g_gpiote_ch_callbacks[i].pinset = pinset;
nrf53_gpiote_set_ch_event(pinset, i,
risingedge, fallingedge,
func, arg);
/* Return the channel index */
ret = i;
break;
}
}
/* Otherwise get a free channel */
if (i == GPIOTE_CHANNELS && func != NULL)
{
for (i = 0; i < GPIOTE_CHANNELS; i++)
{
if (g_gpiote_ch_callbacks[i].callback == NULL)
{
break;
}
}
}
if (i < GPIOTE_CHANNELS)
{
g_gpiote_ch_callbacks[i].pinset = pinset;
nrf53_gpiote_set_ch_event(pinset, i,
risingedge, fallingedge,
func, arg);
/* Return the channel index */
ret = i;
}
leave_critical_section(flags);
return ret;
}
/****************************************************************************
* Name: nrf53_gpio_set_task
* Name: nrf53_gpiote_set_task
*
* Description:
* Configure GPIO in TASK mode (to be controlled via tasks).
@ -626,8 +642,8 @@ int nrf53_gpiote_init(void)
{
/* Clear LATCH register(s) */
putreg32(0, NRF53_GPIO_P0_BASE + NRF53_GPIO_LATCH_OFFSET);
putreg32(0, NRF53_GPIO_P1_BASE + NRF53_GPIO_LATCH_OFFSET);
putreg32(0xffffffff, NRF53_GPIO_P0_BASE + NRF53_GPIO_LATCH_OFFSET);
putreg32(0xffffffff, NRF53_GPIO_P1_BASE + NRF53_GPIO_LATCH_OFFSET);
/* Reset GPIOTE data */

View file

@ -140,7 +140,7 @@ void nrf53_gpiote_set_port_event(uint32_t pinset, xcpt_t func, void *arg);
#endif
/****************************************************************************
* Name: nrf53_gpio_set_task
* Name: nrf53_gpiote_set_task
*
* Description:
* Configure GPIO in TASK mode (to be controlled via tasks).
@ -158,7 +158,7 @@ void nrf53_gpiote_set_port_event(uint32_t pinset, xcpt_t func, void *arg);
*
****************************************************************************/
void nrf53_gpio_set_task(uint32_t pinset, int channel,
void nrf53_gpiote_set_task(uint32_t pinset, int channel,
bool output_high, enum nrf53_gpiote_outcfg_e outcfg);
/****************************************************************************

View file

@ -326,7 +326,7 @@ void nrf91_gpiote_set_port_event(uint32_t pinset, xcpt_t func, void *arg)
for (i = 0; i < NRF91_GPIO_NPORTS; i++)
{
if (g_gpiote_port_callback[port].callback)
if (g_gpiote_port_callback[i].callback)
{
break;
}
@ -476,36 +476,52 @@ int nrf91_gpiote_set_event(uint32_t pinset,
flags = enter_critical_section();
/* Get free channel or channel already used by pinset */
/* Get channel already used by pinset */
for (i = 0; i < GPIOTE_CHANNELS; i++)
{
if (g_gpiote_ch_callbacks[i].callback == NULL ||
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;
}
}
/* Otherwise get a free channel */
if (i == GPIOTE_CHANNELS && func != NULL)
{
for (i = 0; i < GPIOTE_CHANNELS; i++)
{
if (g_gpiote_ch_callbacks[i].callback == NULL)
{
break;
}
}
}
if (i < GPIOTE_CHANNELS)
{
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;
}
leave_critical_section(flags);
return ret;
}
/****************************************************************************
* Name: nrf91_gpio_set_task
* Name: nrf91_gpiote_set_task
*
* Description:
* Configure GPIO in TASK mode (to be controlled via tasks).
@ -590,10 +606,10 @@ int nrf91_gpiote_init(void)
{
/* Clear LATCH register(s) */
putreg32(0, NRF91_GPIO_P0_BASE + NRF91_GPIO_LATCH_OFFSET);
putreg32(0xffffffff, NRF91_GPIO_P0_BASE + NRF91_GPIO_LATCH_OFFSET);
#ifdef CONFIG_NRF91_HAVE_PORT1
putreg32(0, NRF91_GPIO_P1_BASE + NRF91_GPIO_LATCH_OFFSET);
putreg32(0xffffffff, NRF91_GPIO_P1_BASE + NRF91_GPIO_LATCH_OFFSET);
#endif
/* Reset GPIOTE data */

View file

@ -144,7 +144,7 @@ void nrf91_gpiote_set_port_event(uint32_t pinset, xcpt_t func, void *arg);
#endif
/****************************************************************************
* Name: nrf91_gpio_set_task
* Name: nrf91_gpiote_set_task
*
* Description:
* Configure GPIO in TASK mode (to be controlled via tasks).
@ -162,7 +162,7 @@ void nrf91_gpiote_set_port_event(uint32_t pinset, xcpt_t func, void *arg);
*
****************************************************************************/
void nrf91_gpio_set_task(uint32_t pinset, int channel,
void nrf91_gpiote_set_task(uint32_t pinset, int channel,
bool output_high, enum nrf91_gpiote_outcfg_e outcfg);
/****************************************************************************