[PATCH v2 4/6] gpio: pca953x: Generalize interrupt mask register handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This change is necessary for a following patch, which introduces an
interrupt mask register different from what is already in the driver.

The driver already handles an interrupt mask register for pcal
chips, PCAL953x_INT_MASK. Extend this implementation to support
interrupt mask registers at other addresses.

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.

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.

Signed-off-by: Levente Révész <levente.revesz@xxxxxxxxxx>
---
Changes in v2

    1. New function pca953x_has_int_mask_reg().
    2. In pca953x_probe() replaced if-else with a switch.
	3. Fix recalc_addr inconsistency pointed out by Martyn Welch

Question:

    This patch uses the PCA_HAS_INT_MASK bit to encode if the chip has
	interrupt register mask. An alternatice approach would be to create
	a new chip type for PCA953X_TYPE chips with the mask register.
	What do you think?

 drivers/gpio/gpio-pca953x.c | 84 ++++++++++++++++++++++++-------------
 1 file changed, 56 insertions(+), 28 deletions(-)

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 1725c1000445..2cf9541057a8 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -62,6 +62,8 @@
 #define PCAL_PINCTRL_MASK	GENMASK(6, 5)
 
 #define PCA_INT			BIT(8)
+#define PCA_HAS_INT_MASK	BIT(9)
+#define PCA_MASKED_INT		(PCA_INT | PCA_HAS_INT_MASK)
 #define PCA953X_TYPE		(0x00 << 12)
 #define PCAL953X_TYPE		(0x01 << 12)
 #define PCAL653X_TYPE		(0x02 << 12)
@@ -89,13 +91,13 @@ static const struct i2c_device_id pca953x_id[] = {
 	{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
 	{ "pca9698", 40 | PCA953X_TYPE, },
 
-	{ "pcal6408", 8 | PCAL953X_TYPE | PCA_INT, },
-	{ "pcal6416", 16 | PCAL953X_TYPE | PCA_INT, },
-	{ "pcal6524", 24 | PCAL953X_TYPE | PCA_INT, },
-	{ "pcal6534", 34 | PCAL653X_TYPE | PCA_INT, },
-	{ "pcal9535", 16 | PCAL953X_TYPE | PCA_INT, },
-	{ "pcal9554b", 8  | PCAL953X_TYPE | PCA_INT, },
-	{ "pcal9555a", 16 | PCAL953X_TYPE | PCA_INT, },
+	{ "pcal6408", 8 | PCAL953X_TYPE | PCA_MASKED_INT, },
+	{ "pcal6416", 16 | PCAL953X_TYPE | PCA_MASKED_INT, },
+	{ "pcal6524", 24 | PCAL953X_TYPE | PCA_MASKED_INT, },
+	{ "pcal6534", 34 | PCAL653X_TYPE | PCA_MASKED_INT, },
+	{ "pcal9535", 16 | PCAL953X_TYPE | PCA_MASKED_INT, },
+	{ "pcal9554b", 8  | PCAL953X_TYPE | PCA_MASKED_INT, },
+	{ "pcal9555a", 16 | PCAL953X_TYPE | PCA_MASKED_INT, },
 
 	{ "max7310", 8  | PCA953X_TYPE, },
 	{ "max7312", 16 | PCA953X_TYPE | PCA_INT, },
@@ -176,6 +178,7 @@ struct pca953x_reg_config {
 	int output;
 	int input;
 	int invert;
+	int int_mask;
 };
 
 static const struct pca953x_reg_config pca953x_regs = {
@@ -185,6 +188,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,
@@ -235,6 +246,11 @@ static inline bool pca953x_has_interrupt(const struct pca953x_chip *chip)
 	return chip->driver_data & PCA_INT;
 }
 
+static inline bool pca953x_has_int_mask_reg(const struct pca953x_chip *chip)
+{
+	return chip->driver_data & PCA_HAS_INT_MASK;
+}
+
 #define PCA953x_BANK_INPUT	BIT(0)
 #define PCA953x_BANK_OUTPUT	BIT(1)
 #define PCA953x_BANK_POLARITY	BIT(2)
@@ -790,14 +806,16 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
 	DECLARE_BITMAP(reg_direction, MAX_LINE);
 	int level;
 
-	if (pca953x_is_pcal_type(chip)) {
-		/* Enable latch on interrupt-enabled inputs */
-		pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask);
-
+	if (pca953x_has_int_mask_reg(chip)) {
 		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 (pca953x_is_pcal_type(chip)) {
+		/* Enable latch on interrupt-enabled inputs */
+		pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask);
 	}
 
 	/* Switch direction to input if needed */
@@ -1193,12 +1211,20 @@ static int pca953x_probe(struct i2c_client *client,
 	/* initialize cached registers from their original values.
 	 * we can't share this chip with another i2c master.
 	 */
-	if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) {
-		chip->regs = &pca957x_regs;
-		ret = device_pca957x_init(chip, invert);
-	} else {
+	switch (PCA_CHIP_TYPE(chip->driver_data)) {
+	case PCA953X_TYPE:
 		chip->regs = &pca953x_regs;
 		ret = device_pca95xx_init(chip, invert);
+		break;
+	case PCAL953X_TYPE:
+	case PCAL653X_TYPE:
+		chip->regs = &pcal953x_regs;
+		ret = device_pca95xx_init(chip, invert);
+		break;
+	case PCA957X_TYPE:
+		chip->regs = &pca957x_regs;
+		ret = device_pca957x_init(chip, invert);
+		break;
 	}
 	if (ret)
 		goto err_exit;
@@ -1264,21 +1290,23 @@ static int pca953x_regcache_sync(struct device *dev)
 	}
 
 #ifdef CONFIG_GPIO_PCA953X_IRQ
-	if (pca953x_is_pcal_type(chip)) {
-		regaddr = chip->recalc_addr(chip, PCAL953X_IN_LATCH, 0);
+	if (pca953x_has_int_mask_reg(chip)) {
+		regaddr = chip->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 (pca953x_is_pcal_type(chip)) {
+		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;
 		}
@@ -1362,13 +1390,13 @@ static const struct of_device_id pca953x_dt_ids[] = {
 	{ .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
 	{ .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
 
-	{ .compatible = "nxp,pcal6408", .data = OF_L953X( 8, PCA_INT), },
-	{ .compatible = "nxp,pcal6416", .data = OF_L953X(16, PCA_INT), },
-	{ .compatible = "nxp,pcal6524", .data = OF_L953X(24, PCA_INT), },
-	{ .compatible = "nxp,pcal6534", .data = OF_L653X(34, PCA_INT), },
-	{ .compatible = "nxp,pcal9535", .data = OF_L953X(16, PCA_INT), },
-	{ .compatible = "nxp,pcal9554b", .data = OF_L953X( 8, PCA_INT), },
-	{ .compatible = "nxp,pcal9555a", .data = OF_L953X(16, PCA_INT), },
+	{ .compatible = "nxp,pcal6408", .data = OF_L953X( 8, PCA_MASKED_INT), },
+	{ .compatible = "nxp,pcal6416", .data = OF_L953X(16, PCA_MASKED_INT), },
+	{ .compatible = "nxp,pcal6524", .data = OF_L953X(24, PCA_MASKED_INT), },
+	{ .compatible = "nxp,pcal6534", .data = OF_L653X(34, PCA_MASKED_INT), },
+	{ .compatible = "nxp,pcal9535", .data = OF_L953X(16, PCA_MASKED_INT), },
+	{ .compatible = "nxp,pcal9554b", .data = OF_L953X( 8, PCA_MASKED_INT), },
+	{ .compatible = "nxp,pcal9555a", .data = OF_L953X(16, PCA_MASKED_INT), },
 
 	{ .compatible = "maxim,max7310", .data = OF_953X( 8, 0), },
 	{ .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), },
-- 
2.37.3





[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux