Skip to content

Commit 06e4ba8

Browse files
Vincent Genevesnashif
authored andcommitted
drivers: gpio: pca95xx: add latch for interrupt pins
Basically, once a pin is configured for interrupt, we enable the latch on it, in order not to miss short pulses. The bottom half of the interrupt then reads the input port twice, to read the latch and then read the potentially new state of the pins, to compute the posedge, negedge, and level callbacks accordingly. Signed-off-by: Vincent Geneves <[email protected]>
1 parent 6612f1e commit 06e4ba8

File tree

1 file changed

+33
-16
lines changed

1 file changed

+33
-16
lines changed

drivers/gpio/gpio_pca95xx.c

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ struct gpio_pca95xx_drv_data {
8989
uint16_t pud_en;
9090
uint16_t pud_sel;
9191
uint16_t int_mask;
92+
uint16_t input_latch;
9293
} reg_cache;
9394

9495
struct k_sem lock;
@@ -326,6 +327,9 @@ static inline int update_int_mask_reg(const struct device *dev, uint8_t pin,
326327
struct gpio_pca95xx_drv_data * const drv_data =
327328
(struct gpio_pca95xx_drv_data * const)dev->data;
328329

330+
/* If the interrupt mask is present, so is the input latch */
331+
write_port_reg(dev, REG_INPUT_LATCH_PORT0, pin, &drv_data->reg_cache.input_latch, ~value);
332+
329333
return write_port_reg(dev, REG_INT_MASK_PORT0, pin,
330334
&drv_data->reg_cache.int_mask, value);
331335
}
@@ -574,34 +578,45 @@ static int gpio_pca95xx_port_toggle_bits(const struct device *dev,
574578
}
575579

576580
#ifdef CONFIG_GPIO_PCA95XX_INTERRUPT
577-
static void gpio_pca95xx_interrupt_worker(struct k_work *work)
581+
static void get_triggered_it(struct gpio_pca95xx_drv_data *drv_data,
582+
uint16_t *trig_edge, uint16_t *trig_level)
578583
{
579-
struct gpio_pca95xx_drv_data * const drv_data = CONTAINER_OF(
580-
work, struct gpio_pca95xx_drv_data, interrupt_worker);
581-
uint16_t input_new, input_cache, changed_pins, trig_edge;
582-
uint16_t trig_level = 0;
583-
uint32_t triggered_int = 0;
584+
uint16_t input_cache, changed_pins, input_new;
584585
int ret;
585586

586-
k_sem_take(&drv_data->lock, K_FOREVER);
587-
588587
input_cache = drv_data->reg_cache.input;
589-
590588
ret = update_input_regs(drv_data->instance, &input_new);
591589
if (ret == 0) {
592-
/* Note: PCA Interrupt status is cleared by reading inputs */
593-
594590
changed_pins = (input_cache ^ input_new);
595591

596-
trig_edge = (changed_pins & input_new &
592+
*trig_edge |= (changed_pins & input_new &
597593
drv_data->interrupts.edge_rising);
598-
trig_edge |= (changed_pins & input_cache &
594+
*trig_edge |= (changed_pins & input_cache &
599595
drv_data->interrupts.edge_falling);
600-
trig_level = (input_new & drv_data->interrupts.level_high);
601-
trig_level |= (~input_new & drv_data->interrupts.level_low);
596+
*trig_level |= (input_new & drv_data->interrupts.level_high);
597+
*trig_level |= (~input_new & drv_data->interrupts.level_low);
598+
}
599+
}
602600

603-
triggered_int = (trig_edge | trig_level);
601+
static void gpio_pca95xx_interrupt_worker(struct k_work *work)
602+
{
603+
struct gpio_pca95xx_drv_data * const drv_data = CONTAINER_OF(
604+
work, struct gpio_pca95xx_drv_data, interrupt_worker);
605+
const struct gpio_pca95xx_config * const config = drv_data->instance->config;
606+
uint16_t trig_edge = 0, trig_level = 0;
607+
uint32_t triggered_int = 0;
608+
609+
k_sem_take(&drv_data->lock, K_FOREVER);
610+
611+
/* Note: PCA Interrupt status is cleared by reading inputs */
612+
if (config->capabilities & PCA_HAS_INTERRUPT_MASK_REG) {
613+
/* gpio latched read values, to be compared to cached ones */
614+
get_triggered_it(drv_data, &trig_edge, &trig_level);
604615
}
616+
/* gpio unlatched read values, in case signal has flipped again */
617+
get_triggered_it(drv_data, &trig_edge, &trig_level);
618+
619+
triggered_int = (trig_edge | trig_level);
605620

606621
k_sem_give(&drv_data->lock);
607622

@@ -847,6 +862,8 @@ static struct gpio_pca95xx_drv_data gpio_pca95xx_##inst##_drvdata = { \
847862
.reg_cache.dir = 0xFFFF, \
848863
.reg_cache.pud_en = 0x0, \
849864
.reg_cache.pud_sel = 0xFFFF, \
865+
.reg_cache.int_mask = 0xFFFF, \
866+
.reg_cache.input_latch = 0x0, \
850867
IF_ENABLED(CONFIG_GPIO_PCA95XX_INTERRUPT, ( \
851868
.interrupt_active = false, \
852869
)) \

0 commit comments

Comments
 (0)