drivers: gpio: Smartbond: add support for both edge triggers
Hardware supports only one edge for GPIO interrupt. This adds software implementation that hides hardware restriction. With this change user code can use GPIO_INT_TRIG_BOTH and does not have to do it in application code. Signed-off-by: Jerzy Kasenberg <jerzy.kasenberg@codecoup.pl>
This commit is contained in:
parent
766af4cc0c
commit
a9b44e08df
1 changed files with 37 additions and 7 deletions
|
@ -56,6 +56,8 @@ struct gpio_smartbond_wkup_regs {
|
||||||
struct gpio_smartbond_data {
|
struct gpio_smartbond_data {
|
||||||
/* gpio_driver_data needs to be first */
|
/* gpio_driver_data needs to be first */
|
||||||
struct gpio_driver_data common;
|
struct gpio_driver_data common;
|
||||||
|
/* Pins that are configured for both edges (handled by software) */
|
||||||
|
gpio_port_pins_t both_edges_pins;
|
||||||
sys_slist_t callbacks;
|
sys_slist_t callbacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -184,12 +186,30 @@ static int gpio_smartbond_port_toggle_bits(const struct device *dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gpio_smartbond_arm_next_edge_interrupt(const struct device *dev,
|
||||||
|
uint32_t pin_mask)
|
||||||
|
{
|
||||||
|
const struct gpio_smartbond_config *config = dev->config;
|
||||||
|
uint32_t pin_value;
|
||||||
|
|
||||||
|
do {
|
||||||
|
pin_value = config->data_regs->data & pin_mask;
|
||||||
|
if (pin_value) {
|
||||||
|
config->wkup_regs->pol |= pin_mask;
|
||||||
|
} else {
|
||||||
|
config->wkup_regs->pol &= ~pin_mask;
|
||||||
|
}
|
||||||
|
} while (pin_value != (config->data_regs->data & pin_mask));
|
||||||
|
}
|
||||||
|
|
||||||
static int gpio_smartbond_pin_interrupt_configure(const struct device *dev,
|
static int gpio_smartbond_pin_interrupt_configure(const struct device *dev,
|
||||||
gpio_pin_t pin,
|
gpio_pin_t pin,
|
||||||
enum gpio_int_mode mode,
|
enum gpio_int_mode mode,
|
||||||
enum gpio_int_trig trig)
|
enum gpio_int_trig trig)
|
||||||
{
|
{
|
||||||
const struct gpio_smartbond_config *config = dev->config;
|
const struct gpio_smartbond_config *config = dev->config;
|
||||||
|
struct gpio_smartbond_data *data = dev->data;
|
||||||
|
uint32_t pin_mask = BIT(pin);
|
||||||
|
|
||||||
/* Not supported by hardware */
|
/* Not supported by hardware */
|
||||||
if (mode == GPIO_INT_MODE_LEVEL) {
|
if (mode == GPIO_INT_MODE_LEVEL) {
|
||||||
|
@ -202,16 +222,15 @@ static int gpio_smartbond_pin_interrupt_configure(const struct device *dev,
|
||||||
} else {
|
} else {
|
||||||
if (trig == GPIO_INT_TRIG_BOTH) {
|
if (trig == GPIO_INT_TRIG_BOTH) {
|
||||||
/* Not supported by hardware */
|
/* Not supported by hardware */
|
||||||
return -ENOTSUP;
|
data->both_edges_pins |= pin_mask;
|
||||||
}
|
gpio_smartbond_arm_next_edge_interrupt(dev, pin_mask);
|
||||||
|
} else if (trig == GPIO_INT_TRIG_HIGH) {
|
||||||
if (trig == GPIO_INT_TRIG_HIGH) {
|
config->wkup_regs->pol &= ~pin_mask;
|
||||||
config->wkup_regs->pol &= ~BIT(pin);
|
|
||||||
} else {
|
} else {
|
||||||
config->wkup_regs->pol |= BIT(pin);
|
config->wkup_regs->pol |= pin_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
config->wkup_regs->sel |= BIT(pin);
|
config->wkup_regs->sel |= pin_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -230,10 +249,21 @@ static void gpio_smartbond_isr(const struct device *dev)
|
||||||
const struct gpio_smartbond_config *config = dev->config;
|
const struct gpio_smartbond_config *config = dev->config;
|
||||||
struct gpio_smartbond_data *data = dev->data;
|
struct gpio_smartbond_data *data = dev->data;
|
||||||
uint32_t stat;
|
uint32_t stat;
|
||||||
|
uint32_t two_edge_triggered;
|
||||||
|
|
||||||
WAKEUP->WKUP_RESET_IRQ_REG = WAKEUP_WKUP_RESET_IRQ_REG_WKUP_IRQ_RST_Msk;
|
WAKEUP->WKUP_RESET_IRQ_REG = WAKEUP_WKUP_RESET_IRQ_REG_WKUP_IRQ_RST_Msk;
|
||||||
|
|
||||||
stat = config->wkup_regs->status;
|
stat = config->wkup_regs->status;
|
||||||
|
|
||||||
|
two_edge_triggered = stat & data->both_edges_pins;
|
||||||
|
while (two_edge_triggered) {
|
||||||
|
int pos = find_lsb_set(two_edge_triggered) - 1;
|
||||||
|
|
||||||
|
two_edge_triggered &= ~BIT(pos);
|
||||||
|
/* Re-arm for other edge */
|
||||||
|
gpio_smartbond_arm_next_edge_interrupt(dev, BIT(pos));
|
||||||
|
}
|
||||||
|
|
||||||
config->wkup_regs->clear = stat;
|
config->wkup_regs->clear = stat;
|
||||||
|
|
||||||
gpio_fire_callbacks(&data->callbacks, dev, stat);
|
gpio_fire_callbacks(&data->callbacks, dev, stat);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue