@@ -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