All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] gpio: pca953x: add support for open drain pins on PCAL6524
@ 2021-01-28 15:36 Alban Bedel
  2021-02-02 11:42 ` Bartosz Golaszewski
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Alban Bedel @ 2021-01-28 15:36 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski; +Cc: linux-gpio, linux-kernel, Alban Bedel

From a quick glance at various datasheet the PCAL6524 seems to be the
only chip in this familly that support setting the drive mode of
single pins. Other chips either don't support it at all, or can only
set the drive mode of whole banks, which doesn't map to the GPIO API.

Add a new flag, PCAL6524, to mark chips that have the extra registers
needed for this feature. Then mark the needed register banks as
readable and writable, here we don't set OUT_CONF as writable,
although it is, as we only need to read it. Finally add a function
that configure the OUT_INDCONF register when the GPIO API set the
drive mode of the pins.

Signed-off-by: Alban Bedel <alban.bedel@aerq.com>
---
 drivers/gpio/gpio-pca953x.c | 64 +++++++++++++++++++++++++++++++++++--
 1 file changed, 61 insertions(+), 3 deletions(-)

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 825b362eb4b7..db0b3dab1490 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -64,6 +64,8 @@
 #define PCA_INT			BIT(8)
 #define PCA_PCAL		BIT(9)
 #define PCA_LATCH_INT		(PCA_PCAL | PCA_INT)
+#define PCAL6524		BIT(10)
+
 #define PCA953X_TYPE		BIT(12)
 #define PCA957X_TYPE		BIT(13)
 #define PCA_TYPE_MASK		GENMASK(15, 12)
@@ -88,7 +90,7 @@ static const struct i2c_device_id pca953x_id[] = {
 	{ "pca9698", 40 | PCA953X_TYPE, },
 
 	{ "pcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
-	{ "pcal6524", 24 | PCA953X_TYPE | PCA_LATCH_INT, },
+	{ "pcal6524", 24 | PCA953X_TYPE | PCA_LATCH_INT | PCAL6524, },
 	{ "pcal9535", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
 	{ "pcal9554b", 8  | PCA953X_TYPE | PCA_LATCH_INT, },
 	{ "pcal9555a", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
@@ -265,6 +267,9 @@ static int pca953x_bank_shift(struct pca953x_chip *chip)
 #define PCAL9xxx_BANK_PULL_SEL	BIT(8 + 4)
 #define PCAL9xxx_BANK_IRQ_MASK	BIT(8 + 5)
 #define PCAL9xxx_BANK_IRQ_STAT	BIT(8 + 6)
+#define PCAL9xxx_BANK_OUT_CONF	BIT(8 + 7)
+
+#define PCAL6524_BANK_INDOUT_CONF BIT(8 + 12)
 
 /*
  * We care about the following registers:
@@ -288,6 +293,10 @@ static int pca953x_bank_shift(struct pca953x_chip *chip)
  *     Pull-up/pull-down select reg	0x40 + 4 * bank_size    RW
  *     Interrupt mask register		0x40 + 5 * bank_size	RW
  *     Interrupt status register	0x40 + 6 * bank_size	R
+ *     Output port configuration	0x40 + 7 * bank_size	R
+ *
+ *   - PCAL6524 with individual pin configuration
+ *     Individual pin output config	0x40 + 12 * bank_size	RW
  *
  * - Registers with bit 0x80 set, the AI bit
  *   The bit is cleared and the registers fall into one of the
@@ -336,9 +345,12 @@ static bool pca953x_readable_register(struct device *dev, unsigned int reg)
 	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;
+			PCAL9xxx_BANK_IRQ_STAT | PCAL9xxx_BANK_OUT_CONF;
 	}
 
+	if (chip->driver_data & PCAL6524)
+		bank |= PCAL6524_BANK_INDOUT_CONF;
+
 	return pca953x_check_register(chip, reg, bank);
 }
 
@@ -359,6 +371,9 @@ static bool pca953x_writeable_register(struct device *dev, unsigned int reg)
 		bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_PULL_EN |
 			PCAL9xxx_BANK_PULL_SEL | PCAL9xxx_BANK_IRQ_MASK;
 
+	if (chip->driver_data & PCAL6524)
+		bank |= PCAL6524_BANK_INDOUT_CONF;
+
 	return pca953x_check_register(chip, reg, bank);
 }
 
@@ -618,6 +633,46 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
 	return ret;
 }
 
+static int pcal6524_gpio_set_drive_mode(struct pca953x_chip *chip,
+					unsigned int offset,
+					unsigned long config)
+{
+	u8 out_conf_reg = pca953x_recalc_addr(
+		chip, PCAL953X_OUT_CONF, 0);
+	u8 out_indconf_reg = pca953x_recalc_addr(
+		chip, PCAL6524_OUT_INDCONF, offset);
+	u8 mask = BIT(offset % BANK_SZ), val;
+	unsigned int out_conf;
+	int ret;
+
+	/* configuration requires PCAL6524 extended registers */
+	if (!(chip->driver_data & PCAL6524))
+		return -ENOTSUPP;
+
+	if (config == PIN_CONFIG_DRIVE_OPEN_DRAIN)
+		val = mask;
+	else if (config == PIN_CONFIG_DRIVE_PUSH_PULL)
+		val = 0;
+	else
+		return -EINVAL;
+
+	mutex_lock(&chip->i2c_lock);
+
+	/* Invert the value if ODENn is set */
+	ret = regmap_read(chip->regmap, out_conf_reg, &out_conf);
+	if (ret)
+		goto exit;
+	if (out_conf & BIT(offset / BANK_SZ))
+		val ^= mask;
+
+	/* Configure the drive mode */
+	ret = regmap_write_bits(chip->regmap, out_indconf_reg, mask, val);
+
+exit:
+	mutex_unlock(&chip->i2c_lock);
+	return ret;
+}
+
 static int pca953x_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
 				   unsigned long config)
 {
@@ -627,6 +682,9 @@ static int pca953x_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
 	case PIN_CONFIG_BIAS_PULL_UP:
 	case PIN_CONFIG_BIAS_PULL_DOWN:
 		return pca953x_gpio_set_pull_up_down(chip, offset, config);
+	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+	case PIN_CONFIG_DRIVE_PUSH_PULL:
+		return pcal6524_gpio_set_drive_mode(chip, offset, config);
 	default:
 		return -ENOTSUPP;
 	}
@@ -1251,7 +1309,7 @@ static const struct of_device_id pca953x_dt_ids[] = {
 	{ .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
 
 	{ .compatible = "nxp,pcal6416", .data = OF_953X(16, PCA_LATCH_INT), },
-	{ .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), },
+	{ .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT | PCAL6524), },
 	{ .compatible = "nxp,pcal9535", .data = OF_953X(16, PCA_LATCH_INT), },
 	{ .compatible = "nxp,pcal9554b", .data = OF_953X( 8, PCA_LATCH_INT), },
 	{ .compatible = "nxp,pcal9555a", .data = OF_953X(16, PCA_LATCH_INT), },
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-02-03 10:13 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-28 15:36 [PATCH] gpio: pca953x: add support for open drain pins on PCAL6524 Alban Bedel
2021-02-02 11:42 ` Bartosz Golaszewski
2021-02-02 17:45   ` Bedel, Alban
2021-02-03 10:12   ` Andy Shevchenko
2021-02-02 13:57 ` Linus Walleij
2021-02-02 17:45   ` Bedel, Alban
2021-02-02 19:21     ` Linus Walleij
2021-02-03 10:10 ` Andy Shevchenko

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.