diff mbox series

[RFC,2/3] gpio: pca953x: Describe register maps with enums

Message ID 73a0ab72-1189-0b87-6b26-5525645a591d@eilabs.com
State New
Headers show
Series gpio: pca953x: Redesign handling of chip types | expand

Commit Message

Levente Révész Jan. 30, 2023, 8:59 p.m. UTC
The driver supports 8 chip types, 6 of which have extended registers
with various functions, e.g. pull-up and pull-down bias for the gpio
lines or interrupt masking. To allow supporting these functions, the
driver has to be able to calculate the addresses of these registers.

Replace the register maps with an enum for each chip type. These do not
contain the same numeric values as the old defines, but the new address
calculating functions (in the next patch) use them appropriately.

Add currently used registers to struct pca953x_reg_config.

Create a reg_config struct for each chip type.

Signed-off-by: Levente Révész <levente.revesz@eilabs.com>
---
 drivers/gpio/gpio-pca953x.c | 422 ++++++++++++++++++++++++++++--------
 1 file changed, 333 insertions(+), 89 deletions(-)

Comments

Andy Shevchenko Feb. 2, 2023, 3:04 p.m. UTC | #1
On Mon, Jan 30, 2023 at 09:59:48PM +0100, Levente Révész wrote:
> The driver supports 8 chip types, 6 of which have extended registers
> with various functions, e.g. pull-up and pull-down bias for the gpio
> lines or interrupt masking. To allow supporting these functions, the
> driver has to be able to calculate the addresses of these registers.
> 
> Replace the register maps with an enum for each chip type. These do not
> contain the same numeric values as the old defines, but the new address
> calculating functions (in the next patch) use them appropriately.
> 
> Add currently used registers to struct pca953x_reg_config.
> 
> Create a reg_config struct for each chip type.

...

> +enum xra120x_reg {
> +};

>  static const struct pca953x_reg_config pca953x_regs = {
> +};

Make those enums and reg_config definitions to be sorted by their
respective names.

...

> +	case TYPE_PCA950X:
> +		registers = BIT(PCA950X_REG_INPUT) |
> +			    BIT(PCA950X_REG_OUTPUT) |
> +			    BIT(PCA950X_REG_INVERT) |
> +			    BIT(PCA950X_REG_DIRECTION) |
> +			    BIT(PCA950X_REG_INT_MASK);
> +		break;

Can't it be simplified if you define something like REG_MAX in each of
the enums and use here simply GENMASK(MAX, 0); ?

...

> +	case TYPE_PCA950X:
> +		registers = BIT(PCA950X_REG_OUTPUT) |
> +			    BIT(PCA950X_REG_INVERT) |
> +			    BIT(PCA950X_REG_DIRECTION) |
> +			    BIT(PCA950X_REG_INT_MASK);

Something similar, maybe with a definition of the volatile registers?

> +		break;

...

>  	if (chip->type == TYPE_PCA957X) {
> -		chip->regs = &pca957x_regs;
>  		ret = device_pca957x_init(chip, invert);
>  	} else {
> -		chip->regs = &pca953x_regs;
>  		ret = device_pca95xx_init(chip, invert);
>  	}

After this the {} may be dropped as well.
diff mbox series

Patch

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index d6099fc18b01..3d4c3efeaf35 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -25,24 +25,10 @@ 
 
 #include <asm/unaligned.h>
 
-#define PCA953X_INPUT		0x00
-#define PCA953X_OUTPUT		0x01
-#define PCA953X_INVERT		0x02
-#define PCA953X_DIRECTION	0x03
-
 #define REG_ADDR_MASK		GENMASK(5, 0)
 #define REG_ADDR_EXT		BIT(6)
 #define REG_ADDR_AI		BIT(7)
 
-#define PCA957X_IN		0x00
-#define PCA957X_INVRT		0x01
-#define PCA957X_BKEN		0x02
-#define PCA957X_PUPD		0x03
-#define PCA957X_CFG		0x04
-#define PCA957X_OUT		0x05
-#define PCA957X_MSK		0x06
-#define PCA957X_INTS		0x07
-
 #define PCAL953X_OUT_STRENGTH	0x20
 #define PCAL953X_IN_LATCH	0x22
 #define PCAL953X_PULL_EN	0x23
@@ -191,25 +177,152 @@  MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);
 
 #define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ)
 
+enum pca953x_reg {
+	PCA953X_REG_INPUT,
+	PCA953X_REG_OUTPUT,
+	PCA953X_REG_INVERT,
+	PCA953X_REG_DIRECTION,
+};
+
+enum pca950x_reg {
+	PCA950X_REG_INPUT,
+	PCA950X_REG_OUTPUT,
+	PCA950X_REG_INVERT,
+	PCA950X_REG_DIRECTION,
+	PCA950X_REG_INT_MASK,
+};
+
+enum pcal953x_reg {
+	PCAL953X_REG_INPUT,
+	PCAL953X_REG_OUTPUT,
+	PCAL953X_REG_INVERT,
+	PCAL953X_REG_DIRECTION,
+	PCAL953X_REG_DRIVE_STRENGTH,
+	PCAL953X_REG_INPUT_LATCH,
+	PCAL953X_REG_PULL_EN,
+	PCAL953X_REG_PULL_SEL,
+	PCAL953X_REG_INT_MASK,
+	PCAL953X_REG_INT_STATUS,
+	PCAL953X_REG_DRIVE_MODE,
+};
+
+enum pcal65xx_reg {
+	PCAL65XX_REG_INPUT,
+	PCAL65XX_REG_OUTPUT,
+	PCAL65XX_REG_INVERT,
+	PCAL65XX_REG_DIRECTION,
+	PCAL65XX_REG_DRIVE_STRENGTH,
+	PCAL65XX_REG_INPUT_LATCH,
+	PCAL65XX_REG_PULL_EN,
+	PCAL65XX_REG_PULL_SEL,
+	PCAL65XX_REG_INT_MASK,
+	PCAL65XX_REG_INT_STATUS,
+	PCAL65XX_REG_DRIVE_MODE,
+	PCAL65XX_REG_INT_EDGE,
+	PCAL65XX_REG_INT_CLEAR,
+	PCAL65XX_REG_INPUT_STATUS,
+	PCAL65XX_REG_INDIV_DRIVE_MODE,
+	PCAL65XX_REG_DEBOUNCE_EN,
+	PCAL65XX_REG_DEBOUNCE_COUNT,
+};
+
+#define PCAL65XX_MAX_NUM_DEBOUNCE_PORTS	2
+
+enum pca957x_reg {
+	PCA957X_REG_INPUT,
+	PCA957X_REG_INVERT,
+	PCA957X_REG_PULL_EN,
+	PCA957X_REG_PULL_SEL,
+	PCA957X_REG_DIRECTION,
+	PCA957X_REG_OUTPUT,
+	PCA957X_REG_INT_MASK,
+	PCA957X_REG_INT_STATUS,
+};
+
+enum xra120x_reg {
+	XRA120X_REG_INPUT,
+	XRA120X_REG_OUTPUT,
+	XRA120X_REG_INVERT,
+	XRA120X_REG_DIRECTION,
+	XRA120X_REG_PULL_EN,
+	XRA120X_REG_INT_MASK,
+	XRA120X_REG_TRISTATE,
+	XRA120X_REG_INT_STATUS,
+	XRA120X_REG_RISING_MASK,
+	XRA120X_REG_FALLING_MASK,
+	XRA120X_REG_DEBOUNCE_EN,
+};
+
 struct pca953x_reg_config {
 	int direction;
 	int output;
 	int input;
 	int invert;
+	int input_latch;
+	int int_mask;
+	int int_status;
+	int pull_en;
+	int pull_sel;
 };
 
 static const struct pca953x_reg_config pca953x_regs = {
-	.direction = PCA953X_DIRECTION,
-	.output = PCA953X_OUTPUT,
-	.input = PCA953X_INPUT,
-	.invert = PCA953X_INVERT,
+	.direction = PCA953X_REG_DIRECTION,
+	.output = PCA953X_REG_OUTPUT,
+	.input = PCA953X_REG_INPUT,
+	.invert = PCA953X_REG_INVERT,
+};
+
+static const struct pca953x_reg_config pca950x_regs = {
+	.direction = PCA950X_REG_DIRECTION,
+	.output = PCA950X_REG_OUTPUT,
+	.input = PCA950X_REG_INPUT,
+	.invert = PCA950X_REG_INVERT,
+	.int_mask = PCA950X_REG_INT_MASK,
 };
 
 static const struct pca953x_reg_config pca957x_regs = {
-	.direction = PCA957X_CFG,
-	.output = PCA957X_OUT,
-	.input = PCA957X_IN,
-	.invert = PCA957X_INVRT,
+	.direction = PCA957X_REG_DIRECTION,
+	.output = PCA957X_REG_OUTPUT,
+	.input = PCA957X_REG_INPUT,
+	.invert = PCA957X_REG_INVERT,
+	.int_mask = PCA957X_REG_INT_MASK,
+	.int_status = PCA957X_REG_INT_STATUS,
+	.pull_en = PCA957X_REG_PULL_EN,
+	.pull_sel = PCA957X_REG_PULL_SEL,
+};
+
+static const struct pca953x_reg_config xra120x_regs = {
+	.direction = XRA120X_REG_DIRECTION,
+	.output = XRA120X_REG_OUTPUT,
+	.input = XRA120X_REG_INPUT,
+	.invert = XRA120X_REG_INVERT,
+	.int_mask = XRA120X_REG_INT_MASK,
+	.int_status = XRA120X_REG_INT_STATUS,
+	.pull_en = XRA120X_REG_PULL_EN,
+};
+
+static const struct pca953x_reg_config pcal953x_regs = {
+	.direction = PCAL953X_REG_DIRECTION,
+	.output = PCAL953X_REG_OUTPUT,
+	.input = PCAL953X_REG_INPUT,
+	.invert = PCAL953X_REG_INVERT,
+	.input_latch = PCAL953X_REG_INPUT_LATCH,
+	.int_mask = PCAL953X_REG_INT_MASK,
+	.int_status = PCAL953X_REG_INT_STATUS,
+	.pull_en = PCAL953X_REG_PULL_EN,
+	.pull_sel = PCAL953X_REG_PULL_SEL,
+};
+
+static const struct pca953x_reg_config pcal65xx_regs = {
+	.direction = PCAL65XX_REG_DIRECTION,
+	.output = PCAL65XX_REG_OUTPUT,
+	.input = PCAL65XX_REG_INPUT,
+	.invert = PCAL65XX_REG_INVERT,
+	.input_latch = PCAL65XX_REG_INPUT_LATCH,
+	.int_mask = PCAL65XX_REG_INT_MASK,
+	.int_status = PCAL65XX_REG_INT_STATUS,
+	.pull_en = PCAL65XX_REG_PULL_EN,
+	.pull_sel = PCAL65XX_REG_PULL_SEL,
 };
 
 struct pca953x_chip {
@@ -257,23 +370,6 @@  static int pca953x_bank_shift(struct pca953x_chip *chip)
 	return fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
 }
 
-#define PCA953x_BANK_INPUT	BIT(0)
-#define PCA953x_BANK_OUTPUT	BIT(1)
-#define PCA953x_BANK_POLARITY	BIT(2)
-#define PCA953x_BANK_CONFIG	BIT(3)
-
-#define PCA957x_BANK_INPUT	BIT(0)
-#define PCA957x_BANK_POLARITY	BIT(1)
-#define PCA957x_BANK_BUSHOLD	BIT(2)
-#define PCA957x_BANK_CONFIG	BIT(4)
-#define PCA957x_BANK_OUTPUT	BIT(5)
-
-#define PCAL9xxx_BANK_IN_LATCH	BIT(8 + 2)
-#define PCAL9xxx_BANK_PULL_EN	BIT(8 + 3)
-#define PCAL9xxx_BANK_PULL_SEL	BIT(8 + 4)
-#define PCAL9xxx_BANK_IRQ_MASK	BIT(8 + 5)
-#define PCAL9xxx_BANK_IRQ_STAT	BIT(8 + 6)
-
 /*
  * We care about the following registers:
  * - Standard set, below 0x40, each port can be replicated up to 8 times
@@ -373,63 +469,189 @@  static bool pcal6534_check_register(struct pca953x_chip *chip, unsigned int reg,
 	return true;
 }
 
-static bool pca953x_readable_register(struct device *dev, unsigned int reg)
+static bool pca953x_readable_register(struct device *dev, unsigned int reg_addr)
 {
 	struct pca953x_chip *chip = dev_get_drvdata(dev);
-	u32 bank;
-
-	if (chip->type == TYPE_PCA957X) {
-		bank = PCA957x_BANK_INPUT | PCA957x_BANK_OUTPUT |
-		       PCA957x_BANK_POLARITY | PCA957x_BANK_CONFIG |
-		       PCA957x_BANK_BUSHOLD;
-	} else {
-		bank = PCA953x_BANK_INPUT | PCA953x_BANK_OUTPUT |
-		       PCA953x_BANK_POLARITY | PCA953x_BANK_CONFIG;
-	}
-
-	if (pca953x_is_pcal_type(chip)) {
-		bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_PULL_EN |
-			PCAL9xxx_BANK_PULL_SEL | PCAL9xxx_BANK_IRQ_MASK |
-			PCAL9xxx_BANK_IRQ_STAT;
+	u32 registers;
+
+	switch (chip->type) {
+	case TYPE_PCA950X:
+		registers = BIT(PCA950X_REG_INPUT) |
+			    BIT(PCA950X_REG_OUTPUT) |
+			    BIT(PCA950X_REG_INVERT) |
+			    BIT(PCA950X_REG_DIRECTION) |
+			    BIT(PCA950X_REG_INT_MASK);
+		break;
+	case TYPE_PCAL953X:
+		registers = BIT(PCAL953X_REG_INPUT) |
+			    BIT(PCAL953X_REG_OUTPUT) |
+			    BIT(PCAL953X_REG_INVERT) |
+			    BIT(PCAL953X_REG_DIRECTION) |
+			    BIT(PCAL953X_REG_DRIVE_STRENGTH) |
+			    BIT(PCAL953X_REG_INPUT_LATCH) |
+			    BIT(PCAL953X_REG_PULL_EN) |
+			    BIT(PCAL953X_REG_PULL_SEL) |
+			    BIT(PCAL953X_REG_INT_MASK) |
+			    BIT(PCAL953X_REG_INT_STATUS) |
+			    BIT(PCAL953X_REG_DRIVE_MODE);
+		break;
+	case TYPE_PCAL652X:
+	case TYPE_PCAL653X:
+		registers = BIT(PCAL65XX_REG_INPUT) |
+			    BIT(PCAL65XX_REG_OUTPUT) |
+			    BIT(PCAL65XX_REG_INVERT) |
+			    BIT(PCAL65XX_REG_DIRECTION) |
+			    BIT(PCAL65XX_REG_DRIVE_STRENGTH) |
+			    BIT(PCAL65XX_REG_INPUT_LATCH) |
+			    BIT(PCAL65XX_REG_PULL_EN) |
+			    BIT(PCAL65XX_REG_PULL_SEL) |
+			    BIT(PCAL65XX_REG_INT_MASK) |
+			    BIT(PCAL65XX_REG_INT_STATUS) |
+			    BIT(PCAL65XX_REG_DRIVE_MODE) |
+			    BIT(PCAL65XX_REG_INT_EDGE) |
+			    BIT(PCAL65XX_REG_INPUT_STATUS) |
+			    BIT(PCAL65XX_REG_INDIV_DRIVE_MODE) |
+			    BIT(PCAL65XX_REG_DEBOUNCE_EN) |
+			    BIT(PCAL65XX_REG_DEBOUNCE_COUNT);
+		break;
+	case TYPE_PCA957X:
+		registers = BIT(PCA957X_REG_INPUT) |
+			    BIT(PCA957X_REG_INVERT) |
+			    BIT(PCA957X_REG_PULL_EN) |
+			    BIT(PCA957X_REG_PULL_SEL) |
+			    BIT(PCA957X_REG_DIRECTION) |
+			    BIT(PCA957X_REG_OUTPUT) |
+			    BIT(PCA957X_REG_INT_MASK) |
+			    BIT(PCA957X_REG_INT_STATUS);
+		break;
+	case TYPE_XRA120X:
+		registers = BIT(XRA120X_REG_INPUT) |
+			    BIT(XRA120X_REG_OUTPUT) |
+			    BIT(XRA120X_REG_INVERT) |
+			    BIT(XRA120X_REG_DIRECTION) |
+			    BIT(XRA120X_REG_OUTPUT) |
+			    BIT(XRA120X_REG_PULL_EN) |
+			    BIT(XRA120X_REG_INT_MASK) |
+			    BIT(XRA120X_REG_TRISTATE) |
+			    BIT(XRA120X_REG_INT_STATUS) |
+			    BIT(XRA120X_REG_RISING_MASK) |
+			    BIT(XRA120X_REG_FALLING_MASK) |
+			    BIT(XRA120X_REG_DEBOUNCE_EN);
+		break;
+	default:
+		registers = BIT(PCA953X_REG_INPUT) |
+			    BIT(PCA953X_REG_OUTPUT) |
+			    BIT(PCA953X_REG_INVERT) |
+			    BIT(PCAL953X_REG_DIRECTION);
+		break;
 	}
 
-	return chip->check_reg(chip, reg, bank);
+	return chip->check_reg(chip, reg_addr, registers);
 }
 
-static bool pca953x_writeable_register(struct device *dev, unsigned int reg)
+static bool pca953x_writeable_register(struct device *dev, unsigned int reg_addr)
 {
 	struct pca953x_chip *chip = dev_get_drvdata(dev);
-	u32 bank;
-
-	if (chip->type == TYPE_PCA957X) {
-		bank = PCA957x_BANK_OUTPUT | PCA957x_BANK_POLARITY |
-			PCA957x_BANK_CONFIG | PCA957x_BANK_BUSHOLD;
-	} else {
-		bank = PCA953x_BANK_OUTPUT | PCA953x_BANK_POLARITY |
-			PCA953x_BANK_CONFIG;
+	u32 registers;
+
+	switch (chip->type) {
+	case TYPE_PCA950X:
+		registers = BIT(PCA950X_REG_OUTPUT) |
+			    BIT(PCA950X_REG_INVERT) |
+			    BIT(PCA950X_REG_DIRECTION) |
+			    BIT(PCA950X_REG_INT_MASK);
+		break;
+	case TYPE_PCAL953X:
+		registers = BIT(PCAL953X_REG_OUTPUT) |
+			    BIT(PCAL953X_REG_INVERT) |
+			    BIT(PCAL953X_REG_DIRECTION) |
+			    BIT(PCAL953X_REG_DRIVE_STRENGTH) |
+			    BIT(PCAL953X_REG_INPUT_LATCH) |
+			    BIT(PCAL953X_REG_PULL_EN) |
+			    BIT(PCAL953X_REG_PULL_SEL) |
+			    BIT(PCAL953X_REG_INT_MASK) |
+			    BIT(PCAL953X_REG_DRIVE_MODE);
+		break;
+	case TYPE_PCAL652X:
+	case TYPE_PCAL653X:
+		registers = BIT(PCAL65XX_REG_OUTPUT) |
+			    BIT(PCAL65XX_REG_INVERT) |
+			    BIT(PCAL65XX_REG_DIRECTION) |
+			    BIT(PCAL65XX_REG_DRIVE_STRENGTH) |
+			    BIT(PCAL65XX_REG_INPUT_LATCH) |
+			    BIT(PCAL65XX_REG_PULL_EN) |
+			    BIT(PCAL65XX_REG_PULL_SEL) |
+			    BIT(PCAL65XX_REG_INT_MASK) |
+			    BIT(PCAL65XX_REG_DRIVE_MODE) |
+			    BIT(PCAL65XX_REG_INT_EDGE) |
+			    BIT(PCAL65XX_REG_INT_CLEAR) |
+			    BIT(PCAL65XX_REG_INDIV_DRIVE_MODE) |
+			    BIT(PCAL65XX_REG_DEBOUNCE_EN) |
+			    BIT(PCAL65XX_REG_DEBOUNCE_COUNT);
+		break;
+	case TYPE_PCA957X:
+		registers = BIT(PCA957X_REG_INVERT) |
+			    BIT(PCA957X_REG_PULL_EN) |
+			    BIT(PCA957X_REG_PULL_SEL) |
+			    BIT(PCA957X_REG_DIRECTION) |
+			    BIT(PCA957X_REG_OUTPUT) |
+			    BIT(PCA957X_REG_INT_MASK);
+		break;
+	case TYPE_XRA120X:
+		registers = BIT(XRA120X_REG_OUTPUT) |
+			    BIT(XRA120X_REG_INVERT) |
+			    BIT(XRA120X_REG_DIRECTION) |
+			    BIT(XRA120X_REG_OUTPUT) |
+			    BIT(XRA120X_REG_PULL_EN) |
+			    BIT(XRA120X_REG_INT_MASK) |
+			    BIT(XRA120X_REG_TRISTATE) |
+			    BIT(XRA120X_REG_RISING_MASK) |
+			    BIT(XRA120X_REG_FALLING_MASK) |
+			    BIT(XRA120X_REG_DEBOUNCE_EN);
+		break;
+	default:
+		registers = BIT(PCA953X_REG_OUTPUT) |
+			    BIT(PCA953X_REG_INVERT) |
+			    BIT(PCAL953X_REG_DIRECTION);
+		break;
 	}
 
-	if (pca953x_is_pcal_type(chip))
-		bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_PULL_EN |
-			PCAL9xxx_BANK_PULL_SEL | PCAL9xxx_BANK_IRQ_MASK;
-
-	return chip->check_reg(chip, reg, bank);
+	return chip->check_reg(chip, reg_addr, registers);
 }
 
 static bool pca953x_volatile_register(struct device *dev, unsigned int reg)
 {
 	struct pca953x_chip *chip = dev_get_drvdata(dev);
-	u32 bank;
-
-	if (chip->type == TYPE_PCA957X)
-		bank = PCA957x_BANK_INPUT;
-	else
-		bank = PCA953x_BANK_INPUT;
+	u32 registers;
 
-	if (pca953x_is_pcal_type(chip))
-		bank |= PCAL9xxx_BANK_IRQ_STAT;
+	switch (chip->type) {
+	case TYPE_PCA950X:
+		registers = BIT(PCA950X_REG_INPUT);
+		break;
+	case TYPE_PCAL953X:
+		registers = BIT(PCAL953X_REG_INPUT) |
+			    BIT(PCAL953X_REG_INT_STATUS);
+		break;
+	case TYPE_PCAL652X:
+	case TYPE_PCAL653X:
+		registers = BIT(PCAL65XX_REG_INPUT) |
+			    BIT(PCAL65XX_REG_INT_STATUS) |
+			    BIT(PCAL65XX_REG_INPUT_STATUS);
+		break;
+	case TYPE_PCA957X:
+		registers = BIT(PCA957X_REG_INPUT) |
+			    BIT(PCA957X_REG_INT_STATUS);
+		break;
+	case TYPE_XRA120X:
+		registers = BIT(XRA120X_REG_INPUT) |
+			    BIT(XRA120X_REG_INT_STATUS);
+		break;
+	default:
+		registers = BIT(PCA953X_REG_INPUT);
+		break;
+	}
 
-	return chip->check_reg(chip, reg, bank);
+	return chip->check_reg(chip, reg, registers);
 }
 
 static const struct regmap_config pca953x_i2c_regmap = {
@@ -667,8 +889,8 @@  static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
 {
 	enum pin_config_param param = pinconf_to_config_param(config);
 
-	u8 pull_en_reg = chip->recalc_addr(chip, PCAL953X_PULL_EN, offset);
-	u8 pull_sel_reg = chip->recalc_addr(chip, PCAL953X_PULL_SEL, offset);
+	u8 pull_en_reg = chip->recalc_addr(chip, chip->regs->pull_en, offset);
+	u8 pull_sel_reg = chip->recalc_addr(chip, chip->regs->pull_sel, offset);
 	u8 bit = BIT(offset % BANK_SZ);
 	int ret;
 
@@ -794,12 +1016,12 @@  static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
 
 	if (pca953x_is_pcal_type(chip)) {
 		/* Enable latch on interrupt-enabled inputs */
-		pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask);
+		pca953x_write_regs(chip, chip->regs->input_latch, chip->irq_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);
 	}
 
 	/* Switch direction to input if needed */
@@ -876,7 +1098,7 @@  static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pendin
 
 	if (pca953x_is_pcal_type(chip)) {
 		/* Read the current interrupt status from the device */
-		ret = pca953x_read_regs(chip, PCAL953X_INT_STAT, trigger);
+		ret = pca953x_read_regs(chip, chip->regs->int_status, trigger);
 		if (ret)
 			return false;
 
@@ -1068,7 +1290,7 @@  static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
 	for (i = 0; i < NBANK(chip); i++)
 		bitmap_set_value8(val, 0x02, i * BANK_SZ);
 
-	ret = pca953x_write_regs(chip, PCA957X_BKEN, val);
+	ret = pca953x_write_regs(chip, chip->regs->pull_en, val);
 	if (ret)
 		goto out;
 
@@ -1158,6 +1380,30 @@  static int pca953x_probe(struct i2c_client *client)
 		regmap_config = &pca953x_i2c_regmap;
 	}
 
+	switch (chip->type) {
+	case TYPE_PCA950X:
+		chip->regs = &pca950x_regs;
+		break;
+	case TYPE_PCAL953X:
+		chip->regs = &pcal953x_regs;
+		break;
+	case TYPE_PCAL652X:
+		chip->regs = &pcal65xx_regs;
+		break;
+	case TYPE_PCAL653X:
+		chip->regs = &pcal65xx_regs;
+		break;
+	case TYPE_PCA957X:
+		chip->regs = &pca957x_regs;
+		break;
+	case TYPE_XRA120X:
+		chip->regs = &xra120x_regs;
+		break;
+	default:
+		chip->regs = &pca953x_regs;
+		break;
+	}
+
 	if (chip->type == TYPE_PCAL653X) {
 		chip->recalc_addr = pcal6534_recalc_addr;
 		chip->check_reg = pcal6534_check_register;
@@ -1198,10 +1444,8 @@  static int pca953x_probe(struct i2c_client *client)
 	 * we can't share this chip with another i2c master.
 	 */
 	if (chip->type == TYPE_PCA957X) {
-		chip->regs = &pca957x_regs;
 		ret = device_pca957x_init(chip, invert);
 	} else {
-		chip->regs = &pca953x_regs;
 		ret = device_pca95xx_init(chip, invert);
 	}
 	if (ret)
@@ -1269,7 +1513,7 @@  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);
+		regaddr = chip->recalc_addr(chip, chip->regs->input_latch, 0);
 		ret = regcache_sync_region(chip->regmap, regaddr,
 					   regaddr + NBANK(chip) - 1);
 		if (ret) {
@@ -1278,7 +1522,7 @@  static int pca953x_regcache_sync(struct device *dev)
 			return ret;
 		}
 
-		regaddr = chip->recalc_addr(chip, PCAL953X_INT_MASK, 0);
+		regaddr = chip->recalc_addr(chip, chip->regs->int_mask, 0);
 		ret = regcache_sync_region(chip->regmap, regaddr,
 					   regaddr + NBANK(chip) - 1);
 		if (ret) {