[PATCH 1/2] 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.

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@xxxxxxxxxx>
---
 drivers/gpio/gpio-pca953x.c | 64 +++++++++++++++++++++++++------------
 1 file changed, 43 insertions(+), 21 deletions(-)

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 61e874c0cde4..71bfc38c3930 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -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;
 		}
-- 
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