@@ -63,7 +63,9 @@
#define PCA_INT BIT(8)
#define PCA_PCAL BIT(9)
-#define PCA_LATCH_INT (PCA_PCAL | PCA_INT)
+#define PCA_HAS_INT_MASK BIT(10)
+#define PCA_MASKED_INT (PCA_HAS_INT_MASK | PCA_INT)
+#define PCA_LATCH_INT (PCA_PCAL | PCA_MASKED_INT)
#define PCA953X_TYPE BIT(12)
#define PCA957X_TYPE BIT(13)
#define PCAL653X_TYPE BIT(14)
@@ -177,6 +179,7 @@ struct pca953x_reg_config {
int output;
int input;
int invert;
+ int int_mask;
};
static const struct pca953x_reg_config pca953x_regs = {
@@ -186,6 +189,14 @@ static const struct pca953x_reg_config pca953x_regs = {
.invert = PCA953X_INVERT,
};
+static const struct pca953x_reg_config pcal953x_regs = {
+ .direction = PCA953X_DIRECTION,
+ .output = PCA953X_OUTPUT,
+ .input = PCA953X_INPUT,
+ .invert = PCA953X_INVERT,
+ .int_mask = PCAL953X_INT_MASK,
+};
+
static const struct pca953x_reg_config pca957x_regs = {
.direction = PCA957X_CFG,
.output = PCA957X_OUT,
@@ -356,12 +367,13 @@ static bool pca953x_readable_register(struct device *dev, unsigned int reg)
} else {
bank = PCA953x_BANK_INPUT | PCA953x_BANK_OUTPUT |
PCA953x_BANK_POLARITY | PCA953x_BANK_CONFIG;
- }
- if (chip->driver_data & PCA_PCAL) {
- bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_PULL_EN |
- PCAL9xxx_BANK_PULL_SEL | PCAL9xxx_BANK_IRQ_MASK |
- PCAL9xxx_BANK_IRQ_STAT;
+ if (chip->driver_data & PCA_PCAL)
+ bank |= PCAL9xxx_BANK_IN_LATCH |
+ PCAL9xxx_BANK_PULL_EN |
+ PCAL9xxx_BANK_PULL_SEL |
+ PCAL9xxx_BANK_IRQ_MASK |
+ PCAL9xxx_BANK_IRQ_STAT;
}
return chip->check_reg(chip, reg, bank);
@@ -378,11 +390,13 @@ static bool pca953x_writeable_register(struct device *dev, unsigned int reg)
} else {
bank = PCA953x_BANK_OUTPUT | PCA953x_BANK_POLARITY |
PCA953x_BANK_CONFIG;
- }
- if (chip->driver_data & PCA_PCAL)
- bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_PULL_EN |
- PCAL9xxx_BANK_PULL_SEL | PCAL9xxx_BANK_IRQ_MASK;
+ if (chip->driver_data & PCA_PCAL)
+ bank |= PCAL9xxx_BANK_IN_LATCH |
+ PCAL9xxx_BANK_PULL_EN |
+ PCAL9xxx_BANK_PULL_SEL |
+ PCAL9xxx_BANK_IRQ_MASK;
+ }
return chip->check_reg(chip, reg, bank);
}
@@ -764,14 +778,16 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
DECLARE_BITMAP(reg_direction, MAX_LINE);
int level;
- if (chip->driver_data & PCA_PCAL) {
- /* Enable latch on interrupt-enabled inputs */
- pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask);
-
+ if (chip->driver_data & PCA_HAS_INT_MASK) {
bitmap_complement(irq_mask, chip->irq_mask, gc->ngpio);
/* Unmask enabled interrupts */
- pca953x_write_regs(chip, PCAL953X_INT_MASK, irq_mask);
+ pca953x_write_regs(chip, chip->regs->int_mask, irq_mask);
+ }
+
+ if (chip->driver_data & PCA_PCAL) {
+ /* Enable latch on interrupt-enabled inputs */
+ pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask);
}
/* Switch direction to input if needed */
@@ -1171,7 +1187,11 @@ static int pca953x_probe(struct i2c_client *client,
chip->regs = &pca957x_regs;
ret = device_pca957x_init(chip, invert);
} else {
- chip->regs = &pca953x_regs;
+ if (chip->driver_data & PCA_PCAL)
+ chip->regs = &pcal953x_regs;
+ else
+ chip->regs = &pca953x_regs;
+
ret = device_pca95xx_init(chip, invert);
}
if (ret)
@@ -1245,21 +1265,23 @@ static int pca953x_regcache_sync(struct device *dev)
}
#ifdef CONFIG_GPIO_PCA953X_IRQ
- if (chip->driver_data & PCA_PCAL) {
- regaddr = chip->recalc_addr(chip, PCAL953X_IN_LATCH, 0);
+ if (chip->driver_data & PCA_HAS_INT_MASK) {
+ regaddr = pca953x_recalc_addr(chip, chip->regs->int_mask, 0);
ret = regcache_sync_region(chip->regmap, regaddr,
regaddr + NBANK(chip) - 1);
if (ret) {
- dev_err(dev, "Failed to sync INT latch registers: %d\n",
+ dev_err(dev, "Failed to sync INT mask registers: %d\n",
ret);
return ret;
}
+ }
- regaddr = chip->recalc_addr(chip, PCAL953X_INT_MASK, 0);
+ if (chip->driver_data & PCA_PCAL) {
+ regaddr = chip->recalc_addr(chip, PCAL953X_IN_LATCH, 0);
ret = regcache_sync_region(chip->regmap, regaddr,
regaddr + NBANK(chip) - 1);
if (ret) {
- dev_err(dev, "Failed to sync INT mask registers: %d\n",
+ dev_err(dev, "Failed to sync INT latch registers: %d\n",
ret);
return ret;
}
This change is necessary for a following patch, which introduces an interrupt mask register different from what is already in the driver. Currenty the only interrupt mask register the driver handles is PCAL953x_INT_MASK present in the pcal chips. The functions handling this register can easily be made generic enough to handle the interrupt mask register of other chips that do not use the pcal register set, and have their interrupt mask register at a different address. Add bit flag PCA_HAS_INT_MASK, which is set for each chip with an interrupt mask register (including pcal chips). Define a convenience bitmask PCA_MASKED_INT similar to PCA_LATCH_INT. Add an int_mask member to struct pca953x_reg_config. This way interrupt mask handling code can work with registers at different addresses. Add separate pca953x_reg_config for pcal953x chips. This differs from the pca953x_regs in the new int_mask field. In pca953x_readable_register and pca953x_writeable_register only check for PCA_PCAL if the chip is not PCA957X_TYPE. No chip is both pca957x and pcal. This makes logic for adding a different interrupt mask register cleaner. Signed-off-by: Levente Révész <levente.revesz@eilabs.com> --- drivers/gpio/gpio-pca953x.c | 64 +++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 21 deletions(-)