diff --git a/drivers/gpio/gpio_pca95xx.c b/drivers/gpio/gpio_pca95xx.c index 98f73bb10d0..d42b6d6fdc2 100644 --- a/drivers/gpio/gpio_pca95xx.c +++ b/drivers/gpio/gpio_pca95xx.c @@ -8,7 +8,7 @@ #define DT_DRV_COMPAT nxp_pca95xx /** - * @file Driver for PCA95XX I2C-based GPIO driver. + * @file Driver for PCA95XX and PCAL95XX I2C-based GPIO driver. */ #include @@ -55,6 +55,7 @@ LOG_MODULE_REGISTER(gpio_pca95xx); /* Driver flags */ #define PCA_HAS_PUD BIT(0) #define PCA_HAS_INTERRUPT BIT(1) +#define PCA_HAS_INTERRUPT_MASK_REG BIT(2) /** Configuration data */ struct gpio_pca95xx_config { @@ -78,6 +79,7 @@ struct gpio_pca95xx_drv_data { uint16_t dir; uint16_t pud_en; uint16_t pud_sel; + uint16_t int_mask; } reg_cache; struct k_sem lock; @@ -226,6 +228,17 @@ static inline int update_pul_en_regs(const struct device *dev, uint16_t value) &drv_data->reg_cache.pud_en, value); } +#ifdef CONFIG_GPIO_PCA95XX_INTERRUPT +static inline int update_int_mask_regs(const struct device *dev, uint16_t value) +{ + struct gpio_pca95xx_drv_data * const drv_data = + (struct gpio_pca95xx_drv_data * const)dev->data; + + return write_port_regs(dev, REG_INT_MASK_PORT0, + &drv_data->reg_cache.int_mask, value); +} +#endif /* CONFIG_GPIO_PCA95XX_INTERRUPT */ + /** * @brief Setup the pin direction (input or output) * @@ -567,6 +580,21 @@ static int gpio_pca95xx_pin_interrupt_configure(const struct device *dev, k_sem_take(&drv_data->lock, K_FOREVER); + /* Check if GPIO port has an interrupt mask register */ + if (config->capabilities & PCA_HAS_INTERRUPT_MASK_REG) { + uint16_t reg_out; + + reg_out = drv_data->reg_cache.int_mask; + WRITE_BIT(reg_out, pin, (mode == GPIO_INT_MODE_DISABLED)); + + ret = update_int_mask_regs(dev, reg_out); + if (ret != 0) { + LOG_ERR("PCA95XX[0x%X]: failed to update int mask (%d)", + config->bus.addr, ret); + goto err; + } + } + /* Update interrupt masks */ enabled = ((mode & GPIO_INT_MODE_DISABLED) == 0U); edge = (mode == GPIO_INT_MODE_EDGE); @@ -711,11 +739,12 @@ static const struct gpio_pca95xx_config gpio_pca95xx_##inst##_cfg = { \ }, \ .bus = I2C_DT_SPEC_INST_GET(inst), \ .capabilities = \ - (DT_INST_PROP(inst, has_pud) ? \ - PCA_HAS_PUD : 0) | \ + (DT_INST_PROP(inst, has_pud) ? PCA_HAS_PUD : 0) | \ IF_ENABLED(CONFIG_GPIO_PCA95XX_INTERRUPT, ( \ (DT_INST_NODE_HAS_PROP(inst, interrupt_gpios) ? \ PCA_HAS_INTERRUPT : 0) | \ + (DT_INST_PROP(inst, has_interrupt_mask_reg) ? \ + PCA_HAS_INTERRUPT_MASK_REG : 0) | \ )) \ 0, \ IF_ENABLED(CONFIG_GPIO_PCA95XX_INTERRUPT, \ diff --git a/dts/bindings/gpio/nxp,pca95xx.yaml b/dts/bindings/gpio/nxp,pca95xx.yaml index 4039f823161..e422b77dd00 100644 --- a/dts/bindings/gpio/nxp,pca95xx.yaml +++ b/dts/bindings/gpio/nxp,pca95xx.yaml @@ -16,6 +16,11 @@ properties: required: false description: Supports pull-up/pull-down + has-interrupt-mask-reg: + type: boolean + required: false + description: Has Interrupt mask register (PCAL95xx) + interrupt-gpios: type: phandle-array required: false