drivers: gpio: nrf: Add mask to track GPIOTE usage
So far, register state was used to determine if GPIOTE channel is busy. This leads to issues if channel is used in more customized way after allocation. In particular, if it temporarly disabled since disabled channel is treated as available and can be allocated to another user. Added additional mask which tracks allocated channels. After allocation user can reconfigure the channel. Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
parent
77bc550746
commit
1089b91ba2
|
@ -10,6 +10,9 @@
|
|||
|
||||
#include "gpio_utils.h"
|
||||
|
||||
/* Mask holding information about which channels are allocated. */
|
||||
static atomic_t gpiote_alloc_mask;
|
||||
|
||||
struct gpio_nrfx_data {
|
||||
/* gpio_driver_data needs to be first */
|
||||
struct gpio_driver_data common;
|
||||
|
@ -47,10 +50,13 @@ static inline const struct gpio_nrfx_cfg *get_port_cfg(struct device *port)
|
|||
return port->config_info;
|
||||
}
|
||||
|
||||
static int gpiote_channel_alloc(uint32_t abs_pin, nrf_gpiote_polarity_t polarity)
|
||||
static int gpiote_channel_alloc(atomic_t *mask, uint32_t abs_pin,
|
||||
nrf_gpiote_polarity_t polarity)
|
||||
{
|
||||
for (uint8_t channel = 0; channel < GPIOTE_CH_NUM; ++channel) {
|
||||
if (!nrf_gpiote_te_is_enabled(NRF_GPIOTE, channel)) {
|
||||
atomic_val_t prev = atomic_or(mask, BIT(channel));
|
||||
|
||||
if ((prev & BIT(channel)) == 0) {
|
||||
nrf_gpiote_event_t evt =
|
||||
offsetof(NRF_GPIOTE_Type, EVENTS_IN[channel]);
|
||||
|
||||
|
@ -66,7 +72,10 @@ static int gpiote_channel_alloc(uint32_t abs_pin, nrf_gpiote_polarity_t polarity
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void gpiote_channel_free(uint32_t abs_pin)
|
||||
/* Function checks if given pin does not have already enabled GPIOTE event and
|
||||
* disables it.
|
||||
*/
|
||||
static void gpiote_pin_cleanup(atomic_t *mask, uint32_t abs_pin)
|
||||
{
|
||||
uint32_t intenset = nrf_gpiote_int_enable_check(NRF_GPIOTE,
|
||||
NRF_GPIOTE_INT_IN_MASK);
|
||||
|
@ -74,6 +83,7 @@ static void gpiote_channel_free(uint32_t abs_pin)
|
|||
for (size_t i = 0; i < GPIOTE_CH_NUM; i++) {
|
||||
if ((nrf_gpiote_event_pin_get(NRF_GPIOTE, i) == abs_pin)
|
||||
&& (intenset & BIT(i))) {
|
||||
atomic_set_bit_to(mask, i, 0);
|
||||
nrf_gpiote_event_disable(NRF_GPIOTE, i);
|
||||
nrf_gpiote_int_disable(NRF_GPIOTE, BIT(i));
|
||||
return;
|
||||
|
@ -97,7 +107,7 @@ static int gpiote_pin_int_cfg(struct device *port, uint32_t pin)
|
|||
uint32_t abs_pin = NRF_GPIO_PIN_MAP(cfg->port_num, pin);
|
||||
int res = 0;
|
||||
|
||||
gpiote_channel_free(abs_pin);
|
||||
gpiote_pin_cleanup(&gpiote_alloc_mask, abs_pin);
|
||||
nrf_gpio_cfg_sense_set(abs_pin, NRF_GPIO_PIN_NOSENSE);
|
||||
|
||||
/* Pins trigger interrupts only if pin has been configured to do so
|
||||
|
@ -116,7 +126,8 @@ static int gpiote_pin_int_cfg(struct device *port, uint32_t pin)
|
|||
pol = NRF_GPIOTE_POLARITY_HITOLO;
|
||||
}
|
||||
|
||||
res = gpiote_channel_alloc(abs_pin, pol);
|
||||
res = gpiote_channel_alloc(&gpiote_alloc_mask,
|
||||
abs_pin, pol);
|
||||
} else {
|
||||
/* For level triggering we use sense mechanism. */
|
||||
uint32_t sense = sense_for_pin(data, pin);
|
||||
|
|
Loading…
Reference in a new issue