@@ -89,6 +89,7 @@ struct gpio_pca95xx_drv_data {
89
89
uint16_t pud_en ;
90
90
uint16_t pud_sel ;
91
91
uint16_t int_mask ;
92
+ uint16_t input_latch ;
92
93
} reg_cache ;
93
94
94
95
struct k_sem lock ;
@@ -326,6 +327,9 @@ static inline int update_int_mask_reg(const struct device *dev, uint8_t pin,
326
327
struct gpio_pca95xx_drv_data * const drv_data =
327
328
(struct gpio_pca95xx_drv_data * const )dev -> data ;
328
329
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
+
329
333
return write_port_reg (dev , REG_INT_MASK_PORT0 , pin ,
330
334
& drv_data -> reg_cache .int_mask , value );
331
335
}
@@ -574,34 +578,45 @@ static int gpio_pca95xx_port_toggle_bits(const struct device *dev,
574
578
}
575
579
576
580
#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 )
578
583
{
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 ;
584
585
int ret ;
585
586
586
- k_sem_take (& drv_data -> lock , K_FOREVER );
587
-
588
587
input_cache = drv_data -> reg_cache .input ;
589
-
590
588
ret = update_input_regs (drv_data -> instance , & input_new );
591
589
if (ret == 0 ) {
592
- /* Note: PCA Interrupt status is cleared by reading inputs */
593
-
594
590
changed_pins = (input_cache ^ input_new );
595
591
596
- trig_edge = (changed_pins & input_new &
592
+ * trig_edge | = (changed_pins & input_new &
597
593
drv_data -> interrupts .edge_rising );
598
- trig_edge |= (changed_pins & input_cache &
594
+ * trig_edge |= (changed_pins & input_cache &
599
595
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
+ }
602
600
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 );
604
615
}
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 );
605
620
606
621
k_sem_give (& drv_data -> lock );
607
622
@@ -847,6 +862,8 @@ static struct gpio_pca95xx_drv_data gpio_pca95xx_##inst##_drvdata = { \
847
862
.reg_cache.dir = 0xFFFF, \
848
863
.reg_cache.pud_en = 0x0, \
849
864
.reg_cache.pud_sel = 0xFFFF, \
865
+ .reg_cache.int_mask = 0xFFFF, \
866
+ .reg_cache.input_latch = 0x0, \
850
867
IF_ENABLED(CONFIG_GPIO_PCA95XX_INTERRUPT, ( \
851
868
.interrupt_active = false, \
852
869
)) \
0 commit comments