Linux GPIO subsystem development
 help / color / mirror / Atom feed
* [PATCH v6 0/8]  gpio: realtek: Add support for Realtek DHC RTD1625
@ 2026-07-21  6:57 Yu-Chun Lin
  2026-07-21  6:57 ` [PATCH v6 1/8] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC" Yu-Chun Lin
                   ` (7 more replies)
  0 siblings, 8 replies; 25+ messages in thread
From: Yu-Chun Lin @ 2026-07-21  6:57 UTC (permalink / raw)
  To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
	mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
	u.kleine-koenig, dakr, bhelgaas, o-takashi
  Cc: eleanor.lin, dlechner, linux-kernel, linux-gpio, linux, linux-iio,
	cy.huang, james.tai

For better review flow, this series includes Andy Shevchenko's
gpio-regmap fix patches [1] as a prerequisite. The first patch
reverts the previously applied patch from Bartosz Golaszewski.

This series then adds GPIO support for the Realtek DHC RTD1625 SoC.

Unlike the existing driver (gpio-rtd.c) which uses shared bank
registers, the RTD1625 features a per-pin register architecture where
each GPIO line is managed by its own dedicated 32-bit control register.
This distinct hardware design requires a new, separate driver.

Link: https://lore.kernel.org/lkml/20260702130903.1790633-1-andriy.shevchenko@linux.intel.com/ [1]
---
Changes in v6:
- The dt-binding patch has already been applied by Bartosz and remains
unchanged. The DTS patch has been applied separately.

Patch 2 & 3:
- Move gpio_regmap_irq_reqres() and gpio_regmap_irq_relres() implementation
  from patch 2 to patch 3 for better split.

Patch 3:
- Add '_maybe_unused' to prevent build fail when CONFIG_REGMAP_IRQ is not
enabled.

Patch 5:
- Remove removed the hardcoded write-enable workarounds.
- Retain the necessary prototype updates in every driver using custom
reg_mask_xlate
- Add value_xlate to dynamically adjust the register mask and value right
before the actual register write operation.

Patch 8:
- Add 'select REGMAP_MMIO' into Kconfig.
- Replace GPIOCHIP_IRQ_RESOURCE_HELPERS with explicit irq_request_resources
and irq_release_resources callbacks using gpio_regmap_reqres_irq() and
gpio_regmap_relres_irq() introduced by Andy's patches.
- Replace the '*mask = 0' hack with 'return -ENOTSUPP'.
- Move variable operations out of scoped_guard().
- Add 'struct lock_class_key' to irq_domain map for proper lockdep annotation.
- Remove redundant 'ret' variable.
- Make regmap disable_locking depend on CONFIG_DEBUG_GPIO to avoid
dropping debugfs support unconditionally.
- Replace irq_domain_add_linear() with irq_domain_create_linear() using
dev_fwnode(dev), and manage lifetime with devm_add_action_or_reset().

v5: https://lore.kernel.org/lkml/20260702090115.2564318-1-eleanor.lin@realtek.com/
v4: https://lore.kernel.org/lkml/20260622092335.1166876-1-eleanor.lin@realtek.com/
v3: https://lore.kernel.org/lkml/20260512033317.1602537-1-eleanor.lin@realtek.com/
v2: https://lore.kernel.org/lkml/20260408025243.1155482-1-eleanor.lin@realtek.com/
v1: https://lore.kernel.org/lkml/20260331113835.3510341-1-eleanor.lin@realtek.com/

Andy Shevchenko (3):
  gpio: regmap: Provide default IRQ resource request and release
    callbacks
  gpio: regmap: Apply default resource callbacks for regmap IRQ chip
  gpio: regmap: Order kernel-doc descriptions with the actual appearance

Tzuyi Chang (1):
  gpio: realtek: Add driver for Realtek DHC RTD1625 SoC

Yu-Chun Lin (4):
  Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC"
  gpio: regmap: Add gpio_regmap_operation and value_xlate support
  gpio: regmap: Add set_config callback
  gpio: regmap: Add IRQ enable/disable helpers

 drivers/gpio/Kconfig                  |   2 +
 drivers/gpio/gpio-104-idi-48.c        |   7 +-
 drivers/gpio/gpio-i8255.c             |   4 +-
 drivers/gpio/gpio-idio-16.c           |   6 +-
 drivers/gpio/gpio-max7360.c           |   8 +-
 drivers/gpio/gpio-pcie-idio-24.c      |   6 +-
 drivers/gpio/gpio-regmap.c            | 101 ++++++-
 drivers/gpio/gpio-rtd1625.c           | 382 +++++++++++++++-----------
 drivers/iio/adc/ad7173.c              |   8 +-
 drivers/iio/addac/stx104.c            |   6 +-
 drivers/pinctrl/bcm/pinctrl-bcm63xx.c |   1 +
 drivers/pinctrl/pinctrl-tps6594.c     |   1 +
 include/linux/gpio/regmap.h           |  75 ++++-
 13 files changed, 401 insertions(+), 206 deletions(-)

-- 
2.43.0


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

* [PATCH v6 1/8] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC"
  2026-07-21  6:57 [PATCH v6 0/8] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
@ 2026-07-21  6:57 ` Yu-Chun Lin
  2026-07-21 10:39   ` Andy Shevchenko
  2026-07-21  6:57 ` [PATCH v6 2/8] gpio: regmap: Provide default IRQ resource request and release callbacks Yu-Chun Lin
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Yu-Chun Lin @ 2026-07-21  6:57 UTC (permalink / raw)
  To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
	mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
	u.kleine-koenig, dakr, bhelgaas, o-takashi
  Cc: eleanor.lin, dlechner, linux-kernel, linux-gpio, linux, linux-iio,
	cy.huang, james.tai

This reverts commit a57e27c43b0315ee86c6896510d69be5257e093e.

The driver will be rewritten to use the gpio-regmap infrastructure
once Andy Shevchenko's patches for gpio-regmap are applied.

Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
 drivers/gpio/Kconfig        |  12 -
 drivers/gpio/Makefile       |   1 -
 drivers/gpio/gpio-rtd1625.c | 611 ------------------------------------
 3 files changed, 624 deletions(-)
 delete mode 100644 drivers/gpio/gpio-rtd1625.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f03c05288376..ed2bc3113374 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -656,18 +656,6 @@ config GPIO_RTD
 	  Say yes here to support GPIO functionality and GPIO interrupt on
 	  Realtek DHC SoCs.
 
-config GPIO_RTD1625
-	tristate "Realtek DHC RTD1625 GPIO support"
-	depends on ARCH_REALTEK || COMPILE_TEST
-	default ARCH_REALTEK
-	select GPIOLIB_IRQCHIP
-	help
-	  This option enables support for the GPIO controller on Realtek
-	  DHC (Digital Home Center) RTD1625 SoC.
-
-	  Say yes here to support both basic GPIO line functionality
-	  and GPIO interrupt handling capabilities for this platform.
-
 config GPIO_SAMA5D2_PIOBU
 	tristate "SAMA5D2 PIOBU GPIO support"
 	depends on OF
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index fa14581e3995..4d0e900402fc 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -160,7 +160,6 @@ obj-$(CONFIG_GPIO_REALTEK_OTTO)		+= gpio-realtek-otto.o
 obj-$(CONFIG_GPIO_REG)			+= gpio-reg.o
 obj-$(CONFIG_GPIO_ROCKCHIP)	+= gpio-rockchip.o
 obj-$(CONFIG_GPIO_RTD)			+= gpio-rtd.o
-obj-$(CONFIG_GPIO_RTD1625)		+= gpio-rtd1625.o
 obj-$(CONFIG_ARCH_SA1100)		+= gpio-sa1100.o
 obj-$(CONFIG_GPIO_SAMA5D2_PIOBU)	+= gpio-sama5d2-piobu.o
 obj-$(CONFIG_GPIO_SCH311X)		+= gpio-sch311x.o
diff --git a/drivers/gpio/gpio-rtd1625.c b/drivers/gpio/gpio-rtd1625.c
deleted file mode 100644
index 409e540bf40b..000000000000
--- a/drivers/gpio/gpio-rtd1625.c
+++ /dev/null
@@ -1,611 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Realtek DHC RTD1625 gpio driver
- *
- * Copyright (c) 2023-2026 Realtek Semiconductor Corp.
- */
-
-#include <linux/bitfield.h>
-#include <linux/bitops.h>
-#include <linux/cleanup.h>
-#include <linux/gpio/driver.h>
-#include <linux/interrupt.h>
-#include <linux/irqchip.h>
-#include <linux/irqchip/chained_irq.h>
-#include <linux/irqdomain.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/property.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-#define RTD1625_GPIO_DIR BIT(0)
-#define RTD1625_GPIO_OUT BIT(2)
-#define RTD1625_GPIO_IN BIT(4)
-#define RTD1625_GPIO_EDGE_INT_DP BIT(6)
-#define RTD1625_GPIO_EDGE_INT_EN BIT(8)
-#define RTD1625_GPIO_LEVEL_INT_EN BIT(16)
-#define RTD1625_GPIO_LEVEL_INT_DP BIT(18)
-#define RTD1625_GPIO_DEBOUNCE GENMASK(30, 28)
-#define RTD1625_GPIO_DEBOUNCE_WREN BIT(31)
-
-#define RTD1625_GPIO_WREN(x) ((x) << 1)
-
-/* Write-enable masks for all GPIO configs and reserved hardware bits */
-#define RTD1625_ISO_GPIO_WREN_ALL 0x8000aa8a
-#define RTD1625_ISOM_GPIO_WREN_ALL 0x800aaa8a
-
-#define RTD1625_GPIO_DEBOUNCE_1US 0
-#define RTD1625_GPIO_DEBOUNCE_10US 1
-#define RTD1625_GPIO_DEBOUNCE_100US 2
-#define RTD1625_GPIO_DEBOUNCE_1MS 3
-#define RTD1625_GPIO_DEBOUNCE_10MS 4
-#define RTD1625_GPIO_DEBOUNCE_20MS 5
-#define RTD1625_GPIO_DEBOUNCE_30MS 6
-#define RTD1625_GPIO_DEBOUNCE_50MS 7
-
-#define GPIO_CONTROL(gpio) ((gpio) * 4)
-
-enum rtd1625_irq_index {
-	RTD1625_IRQ_ASSERT,
-	RTD1625_IRQ_DEASSERT,
-	RTD1625_IRQ_LEVEL,
-	RTD1625_MAX_IRQS
-};
-
-/**
- * struct rtd1625_gpio_info - Specific GPIO register information
- * @num_gpios: The number of GPIOs
- * @irq_type_support: Supported IRQ types
- * @gpa_offset: Offset for GPIO assert interrupt status registers
- * @gpda_offset: Offset for GPIO deassert interrupt status registers
- * @level_offset: Offset of level interrupt status register
- * @write_en_all: Write-enable mask for all configurable bits
- */
-struct rtd1625_gpio_info {
-	unsigned int	num_gpios;
-	unsigned int	irq_type_support;
-	unsigned int	base_offset;
-	unsigned int	gpa_offset;
-	unsigned int	gpda_offset;
-	unsigned int	level_offset;
-	unsigned int	write_en_all;
-};
-
-struct rtd1625_gpio {
-	struct gpio_chip		gpio_chip;
-	const struct rtd1625_gpio_info	*info;
-	void __iomem			*base;
-	void __iomem			*irq_base;
-	unsigned int			irqs[RTD1625_MAX_IRQS];
-	raw_spinlock_t			lock;
-	unsigned int			*save_regs;
-};
-
-static unsigned int rtd1625_gpio_gpa_offset(struct rtd1625_gpio *data, unsigned int offset)
-{
-	return data->info->gpa_offset + ((offset / 32) * 4);
-}
-
-static unsigned int rtd1625_gpio_gpda_offset(struct rtd1625_gpio *data, unsigned int offset)
-{
-	return data->info->gpda_offset + ((offset / 32) * 4);
-}
-
-static unsigned int rtd1625_gpio_level_offset(struct rtd1625_gpio *data, unsigned int offset)
-{
-	return data->info->level_offset + ((offset / 32) * 4);
-}
-
-static int rtd1625_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
-				     unsigned int debounce)
-{
-	struct rtd1625_gpio *data = gpiochip_get_data(chip);
-	u8 deb_val;
-	u32 val;
-
-	switch (debounce) {
-	case 1:
-		deb_val = RTD1625_GPIO_DEBOUNCE_1US;
-		break;
-	case 10:
-		deb_val = RTD1625_GPIO_DEBOUNCE_10US;
-		break;
-	case 100:
-		deb_val = RTD1625_GPIO_DEBOUNCE_100US;
-		break;
-	case 1000:
-		deb_val = RTD1625_GPIO_DEBOUNCE_1MS;
-		break;
-	case 10000:
-		deb_val = RTD1625_GPIO_DEBOUNCE_10MS;
-		break;
-	case 20000:
-		deb_val = RTD1625_GPIO_DEBOUNCE_20MS;
-		break;
-	case 30000:
-		deb_val = RTD1625_GPIO_DEBOUNCE_30MS;
-		break;
-	case 50000:
-		deb_val = RTD1625_GPIO_DEBOUNCE_50MS;
-		break;
-	default:
-		return -ENOTSUPP;
-	}
-
-	val = FIELD_PREP(RTD1625_GPIO_DEBOUNCE, deb_val) | RTD1625_GPIO_DEBOUNCE_WREN;
-
-	guard(raw_spinlock_irqsave)(&data->lock);
-
-	writel_relaxed(val, data->base + GPIO_CONTROL(offset));
-
-	return 0;
-}
-
-static int rtd1625_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
-				   unsigned long config)
-{
-	u32 debounce;
-
-	if (pinconf_to_config_param(config) == PIN_CONFIG_INPUT_DEBOUNCE) {
-		debounce = pinconf_to_config_argument(config);
-		return rtd1625_gpio_set_debounce(chip, offset, debounce);
-	}
-
-	return gpiochip_generic_config(chip, offset, config);
-}
-
-static int rtd1625_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
-{
-	struct rtd1625_gpio *data = gpiochip_get_data(chip);
-	u32 val = RTD1625_GPIO_WREN(RTD1625_GPIO_OUT);
-
-	if (value)
-		val |= RTD1625_GPIO_OUT;
-
-	guard(raw_spinlock_irqsave)(&data->lock);
-
-	writel_relaxed(val, data->base + GPIO_CONTROL(offset));
-
-	return 0;
-}
-
-static int rtd1625_gpio_get(struct gpio_chip *chip, unsigned int offset)
-{
-	struct rtd1625_gpio *data = gpiochip_get_data(chip);
-	u32 val;
-
-	guard(raw_spinlock_irqsave)(&data->lock);
-
-	val = readl_relaxed(data->base + GPIO_CONTROL(offset));
-
-	if (val & RTD1625_GPIO_DIR)
-		return !!(val & RTD1625_GPIO_OUT);
-	else
-		return !!(val & RTD1625_GPIO_IN);
-}
-
-static int rtd1625_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
-{
-	struct rtd1625_gpio *data = gpiochip_get_data(chip);
-	u32 val;
-
-	guard(raw_spinlock_irqsave)(&data->lock);
-
-	val = readl_relaxed(data->base + GPIO_CONTROL(offset));
-
-	if (val & RTD1625_GPIO_DIR)
-		return GPIO_LINE_DIRECTION_OUT;
-
-	return GPIO_LINE_DIRECTION_IN;
-}
-
-static int rtd1625_gpio_set_direction(struct gpio_chip *chip, unsigned int offset, bool out)
-{
-	struct rtd1625_gpio *data = gpiochip_get_data(chip);
-	u32 val = RTD1625_GPIO_WREN(RTD1625_GPIO_DIR);
-
-	if (out)
-		val |= RTD1625_GPIO_DIR;
-
-	guard(raw_spinlock_irqsave)(&data->lock);
-
-	writel_relaxed(val, data->base + GPIO_CONTROL(offset));
-
-	return 0;
-}
-
-static int rtd1625_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
-{
-	return rtd1625_gpio_set_direction(chip, offset, false);
-}
-
-static int rtd1625_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value)
-{
-	rtd1625_gpio_set(chip, offset, value);
-
-	return rtd1625_gpio_set_direction(chip, offset, true);
-}
-
-static void rtd1625_gpio_irq_handle(struct irq_desc *desc)
-{
-	unsigned int (*get_reg_offset)(struct rtd1625_gpio *gpio, unsigned int offset);
-	struct rtd1625_gpio *data = irq_desc_get_handler_data(desc);
-	struct irq_domain *domain = data->gpio_chip.irq.domain;
-	struct irq_chip *chip = irq_desc_get_chip(desc);
-	unsigned int irq = irq_desc_get_irq(desc);
-	unsigned long status;
-	unsigned int reg_offset, i, j;
-	unsigned int girq;
-	irq_hw_number_t hwirq;
-	u32 irq_type;
-
-	if (irq == data->irqs[RTD1625_IRQ_ASSERT])
-		get_reg_offset = &rtd1625_gpio_gpa_offset;
-	else if (irq == data->irqs[RTD1625_IRQ_DEASSERT])
-		get_reg_offset = &rtd1625_gpio_gpda_offset;
-	else if (irq == data->irqs[2])
-		get_reg_offset = &rtd1625_gpio_level_offset;
-	else
-		return;
-
-	chained_irq_enter(chip, desc);
-
-	for (i = 0; i < data->info->num_gpios; i += 32) {
-		reg_offset = get_reg_offset(data, i);
-		status = readl_relaxed(data->irq_base + reg_offset);
-
-		/*
-		 * Hardware quirk: The controller fires both "assert" and "de-assert"
-		 * interrupts simultaneously on any edge toggle.
-		 * We must pre-clear edge interrupts here. If we drop an unwanted
-		 * de-assert interrupt below, it will never reach the IRQ core
-		 * (generic_handle_domain_irq), meaning ->irq_ack() won't be called.
-		 * Failing to clear it here leads to an interrupt storm.
-		 */
-		if (irq != data->irqs[RTD1625_IRQ_LEVEL])
-			writel_relaxed(status, data->irq_base + reg_offset);
-
-		for_each_set_bit(j, &status, 32) {
-			hwirq = i + j;
-			girq = irq_find_mapping(domain, hwirq);
-			irq_type = irq_get_trigger_type(girq);
-
-			/*
-			 * Filter out the hardware-forced de-assert interrupt unless
-			 * the user explicitly requested IRQ_TYPE_EDGE_BOTH.
-			 */
-			if (irq == data->irqs[RTD1625_IRQ_DEASSERT] &&
-			    irq_type != IRQ_TYPE_EDGE_BOTH)
-				continue;
-
-			generic_handle_domain_irq(domain, hwirq);
-		}
-	}
-
-	chained_irq_exit(chip, desc);
-}
-
-static void rtd1625_gpio_ack_irq(struct irq_data *d)
-{
-	struct rtd1625_gpio *data = irq_data_get_irq_chip_data(d);
-	irq_hw_number_t hwirq = irqd_to_hwirq(d);
-	u32 irq_type = irqd_get_trigger_type(d);
-	u32 bit_mask = BIT(hwirq % 32);
-	int reg_offset;
-
-	if (irq_type & IRQ_TYPE_LEVEL_MASK) {
-		reg_offset = rtd1625_gpio_level_offset(data, hwirq);
-		writel_relaxed(bit_mask, data->irq_base + reg_offset);
-	}
-}
-
-static void rtd1625_gpio_enable_edge_irq(struct rtd1625_gpio *data, irq_hw_number_t hwirq)
-{
-	int gpda_reg_offset = rtd1625_gpio_gpda_offset(data, hwirq);
-	int gpa_reg_offset = rtd1625_gpio_gpa_offset(data, hwirq);
-	u32 clr_mask = BIT(hwirq % 32);
-	u32 val;
-
-	guard(raw_spinlock_irqsave)(&data->lock);
-
-	writel_relaxed(clr_mask, data->irq_base + gpa_reg_offset);
-	writel_relaxed(clr_mask, data->irq_base + gpda_reg_offset);
-	val = RTD1625_GPIO_EDGE_INT_EN | RTD1625_GPIO_WREN(RTD1625_GPIO_EDGE_INT_EN);
-	writel_relaxed(val, data->base + GPIO_CONTROL(hwirq));
-}
-
-static void rtd1625_gpio_disable_edge_irq(struct rtd1625_gpio *data, irq_hw_number_t hwirq)
-{
-	u32 val;
-
-	guard(raw_spinlock_irqsave)(&data->lock);
-
-	val = RTD1625_GPIO_WREN(RTD1625_GPIO_EDGE_INT_EN);
-	writel_relaxed(val, data->base + GPIO_CONTROL(hwirq));
-}
-
-static void rtd1625_gpio_enable_level_irq(struct rtd1625_gpio *data, irq_hw_number_t hwirq)
-{
-	int level_reg_offset = rtd1625_gpio_level_offset(data, hwirq);
-	u32 clr_mask = BIT(hwirq % 32);
-	u32 val;
-
-	guard(raw_spinlock_irqsave)(&data->lock);
-
-	writel_relaxed(clr_mask, data->irq_base + level_reg_offset);
-	val = RTD1625_GPIO_LEVEL_INT_EN | RTD1625_GPIO_WREN(RTD1625_GPIO_LEVEL_INT_EN);
-	writel_relaxed(val, data->base + GPIO_CONTROL(hwirq));
-}
-
-static void rtd1625_gpio_disable_level_irq(struct rtd1625_gpio *data, irq_hw_number_t hwirq)
-{
-	u32 val;
-
-	guard(raw_spinlock_irqsave)(&data->lock);
-
-	val = RTD1625_GPIO_WREN(RTD1625_GPIO_LEVEL_INT_EN);
-	writel_relaxed(val, data->base + GPIO_CONTROL(hwirq));
-}
-
-static void rtd1625_gpio_enable_irq(struct irq_data *d)
-{
-	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct rtd1625_gpio *data = gpiochip_get_data(gc);
-	irq_hw_number_t hwirq = irqd_to_hwirq(d);
-	u32 irq_type = irqd_get_trigger_type(d);
-
-	gpiochip_enable_irq(gc, hwirq);
-
-	if (irq_type & IRQ_TYPE_EDGE_BOTH)
-		rtd1625_gpio_enable_edge_irq(data, hwirq);
-	else if (irq_type & IRQ_TYPE_LEVEL_MASK)
-		rtd1625_gpio_enable_level_irq(data, hwirq);
-}
-
-static void rtd1625_gpio_disable_irq(struct irq_data *d)
-{
-	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct rtd1625_gpio *data = gpiochip_get_data(gc);
-	irq_hw_number_t hwirq = irqd_to_hwirq(d);
-	u32 irq_type = irqd_get_trigger_type(d);
-
-	if (irq_type & IRQ_TYPE_EDGE_BOTH)
-		rtd1625_gpio_disable_edge_irq(data, hwirq);
-	else if (irq_type & IRQ_TYPE_LEVEL_MASK)
-		rtd1625_gpio_disable_level_irq(data, hwirq);
-
-	gpiochip_disable_irq(gc, hwirq);
-}
-
-static int rtd1625_gpio_irq_set_level_type(struct irq_data *d, bool level)
-{
-	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct rtd1625_gpio *data = gpiochip_get_data(gc);
-	irq_hw_number_t hwirq = irqd_to_hwirq(d);
-	u32 val = RTD1625_GPIO_WREN(RTD1625_GPIO_LEVEL_INT_DP);
-
-	if (!(data->info->irq_type_support & IRQ_TYPE_LEVEL_MASK))
-		return -EINVAL;
-
-	if (level)
-		val |= RTD1625_GPIO_LEVEL_INT_DP;
-
-	scoped_guard(raw_spinlock_irqsave, &data->lock)
-		writel_relaxed(val, data->base + GPIO_CONTROL(hwirq));
-
-	irq_set_handler_locked(d, handle_level_irq);
-
-	return 0;
-}
-
-static int rtd1625_gpio_irq_set_edge_type(struct irq_data *d, bool polarity)
-{
-	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
-	struct rtd1625_gpio *data = gpiochip_get_data(gc);
-	irq_hw_number_t hwirq = irqd_to_hwirq(d);
-	u32 val = RTD1625_GPIO_WREN(RTD1625_GPIO_EDGE_INT_DP);
-
-	if (!(data->info->irq_type_support & IRQ_TYPE_EDGE_BOTH))
-		return -EINVAL;
-
-	if (polarity)
-		val |= RTD1625_GPIO_EDGE_INT_DP;
-
-	scoped_guard(raw_spinlock_irqsave, &data->lock)
-		writel_relaxed(val, data->base + GPIO_CONTROL(hwirq));
-
-	irq_set_handler_locked(d, handle_edge_irq);
-
-	return 0;
-}
-
-static int rtd1625_gpio_irq_set_type(struct irq_data *d, unsigned int type)
-{
-	switch (type & IRQ_TYPE_SENSE_MASK) {
-	case IRQ_TYPE_EDGE_RISING:
-		return rtd1625_gpio_irq_set_edge_type(d, 1);
-
-	case IRQ_TYPE_EDGE_FALLING:
-		return rtd1625_gpio_irq_set_edge_type(d, 0);
-
-	case IRQ_TYPE_EDGE_BOTH:
-		return rtd1625_gpio_irq_set_edge_type(d, 1);
-
-	case IRQ_TYPE_LEVEL_HIGH:
-		return rtd1625_gpio_irq_set_level_type(d, 0);
-
-	case IRQ_TYPE_LEVEL_LOW:
-		return rtd1625_gpio_irq_set_level_type(d, 1);
-
-	default:
-		return -EINVAL;
-	}
-}
-
-static struct irq_chip rtd1625_iso_gpio_irq_chip = {
-	.name = "rtd1625-gpio",
-	.irq_ack = rtd1625_gpio_ack_irq,
-	.irq_mask = rtd1625_gpio_disable_irq,
-	.irq_unmask = rtd1625_gpio_enable_irq,
-	.irq_set_type = rtd1625_gpio_irq_set_type,
-	.flags = IRQCHIP_IMMUTABLE | IRQCHIP_SKIP_SET_WAKE,
-	GPIOCHIP_IRQ_RESOURCE_HELPERS,
-};
-
-static int rtd1625_gpio_setup_irq(struct platform_device *pdev, struct rtd1625_gpio *data)
-{
-	struct gpio_irq_chip *irq_chip;
-	unsigned int num_irqs;
-	int irq;
-
-	/*
-	 * Interrupt support is optional. All IRQs must be provided together.
-	 * If index 0 is missing, we assume no interrupts are configured in DT
-	 * and fall back to basic GPIO operation.
-	 */
-	irq = platform_get_irq_optional(pdev, 0);
-	if (irq == -ENXIO)
-		return 0;
-	if (irq < 0)
-		return irq;
-
-	num_irqs = (data->info->irq_type_support & IRQ_TYPE_LEVEL_MASK) ? 3 : 2;
-	data->irqs[RTD1625_IRQ_ASSERT] = irq;
-
-	for (unsigned int i = 1; i < num_irqs; i++) {
-		irq = platform_get_irq(pdev, i);
-		if (irq < 0)
-			return irq;
-		data->irqs[i] = irq;
-	}
-
-	irq_chip = &data->gpio_chip.irq;
-	irq_chip->handler = handle_bad_irq;
-	irq_chip->default_type = IRQ_TYPE_NONE;
-	irq_chip->parent_handler = rtd1625_gpio_irq_handle;
-	irq_chip->parent_handler_data = data;
-	irq_chip->num_parents = num_irqs;
-	irq_chip->parents = data->irqs;
-
-	gpio_irq_chip_set_chip(irq_chip, &rtd1625_iso_gpio_irq_chip);
-
-	return 0;
-}
-
-static int rtd1625_gpio_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct rtd1625_gpio *data;
-	void __iomem *irq_base;
-	int ret;
-
-	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	data->info = device_get_match_data(dev);
-	if (!data->info)
-		return -EINVAL;
-
-	raw_spin_lock_init(&data->lock);
-
-	irq_base = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(irq_base))
-		return PTR_ERR(irq_base);
-
-	data->irq_base = irq_base;
-	data->base = irq_base + data->info->base_offset;
-
-	data->save_regs = devm_kcalloc(dev, data->info->num_gpios, sizeof(*data->save_regs),
-				       GFP_KERNEL);
-	if (!data->save_regs)
-		return -ENOMEM;
-
-	data->gpio_chip.label = dev_name(dev);
-	data->gpio_chip.base = -1;
-	data->gpio_chip.ngpio = data->info->num_gpios;
-	data->gpio_chip.request = gpiochip_generic_request;
-	data->gpio_chip.free = gpiochip_generic_free;
-	data->gpio_chip.get_direction = rtd1625_gpio_get_direction;
-	data->gpio_chip.direction_input = rtd1625_gpio_direction_input;
-	data->gpio_chip.direction_output = rtd1625_gpio_direction_output;
-	data->gpio_chip.set = rtd1625_gpio_set;
-	data->gpio_chip.get = rtd1625_gpio_get;
-	data->gpio_chip.set_config = rtd1625_gpio_set_config;
-	data->gpio_chip.parent = dev;
-
-	ret = rtd1625_gpio_setup_irq(pdev, data);
-	if (ret)
-		return ret;
-
-	platform_set_drvdata(pdev, data);
-
-	return devm_gpiochip_add_data(dev, &data->gpio_chip, data);
-}
-
-static const struct rtd1625_gpio_info rtd1625_iso_gpio_info = {
-	.num_gpios        = 166,
-	.irq_type_support = IRQ_TYPE_EDGE_BOTH,
-	.base_offset      = 0x100,
-	.gpa_offset       = 0x000,
-	.gpda_offset      = 0x020,
-	.write_en_all     = RTD1625_ISO_GPIO_WREN_ALL,
-};
-
-static const struct rtd1625_gpio_info rtd1625_isom_gpio_info = {
-	.num_gpios        = 4,
-	.irq_type_support = IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_LEVEL_LOW |
-			    IRQ_TYPE_LEVEL_HIGH,
-	.base_offset      = 0x20,
-	.gpa_offset       = 0x00,
-	.gpda_offset      = 0x04,
-	.level_offset     = 0x18,
-	.write_en_all     = RTD1625_ISOM_GPIO_WREN_ALL,
-};
-
-static int rtd1625_gpio_suspend(struct device *dev)
-{
-	struct rtd1625_gpio *data = dev_get_drvdata(dev);
-	const struct rtd1625_gpio_info *info = data->info;
-
-	for (unsigned int i = 0; i < info->num_gpios; i++)
-		data->save_regs[i] = readl_relaxed(data->base + GPIO_CONTROL(i));
-
-	return 0;
-}
-
-static int rtd1625_gpio_resume(struct device *dev)
-{
-	struct rtd1625_gpio *data = dev_get_drvdata(dev);
-	const struct rtd1625_gpio_info *info = data->info;
-
-	for (unsigned int i = 0; i < info->num_gpios; i++)
-		writel_relaxed(data->save_regs[i] | info->write_en_all,
-			       data->base + GPIO_CONTROL(i));
-
-	return 0;
-}
-
-static DEFINE_NOIRQ_DEV_PM_OPS(rtd1625_gpio_pm_ops, rtd1625_gpio_suspend, rtd1625_gpio_resume);
-
-static const struct of_device_id rtd1625_gpio_of_matches[] = {
-	{ .compatible = "realtek,rtd1625-iso-gpio", .data = &rtd1625_iso_gpio_info },
-	{ .compatible = "realtek,rtd1625-isom-gpio", .data = &rtd1625_isom_gpio_info },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, rtd1625_gpio_of_matches);
-
-static struct platform_driver rtd1625_gpio_platform_driver = {
-	.driver = {
-		.name = "gpio-rtd1625",
-		.of_match_table = rtd1625_gpio_of_matches,
-		.pm = pm_sleep_ptr(&rtd1625_gpio_pm_ops),
-	},
-	.probe = rtd1625_gpio_probe,
-};
-module_platform_driver(rtd1625_gpio_platform_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Realtek Semiconductor Corporation");
-MODULE_DESCRIPTION("Realtek DHC SoC RTD1625 gpio driver");
-- 
2.43.0


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

* [PATCH v6 2/8] gpio: regmap: Provide default IRQ resource request and release callbacks
  2026-07-21  6:57 [PATCH v6 0/8] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
  2026-07-21  6:57 ` [PATCH v6 1/8] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC" Yu-Chun Lin
@ 2026-07-21  6:57 ` Yu-Chun Lin
  2026-07-21  7:05   ` Michael Walle
  2026-07-21  6:57 ` [PATCH v6 3/8] gpio: regmap: Apply default resource callbacks for regmap IRQ chip Yu-Chun Lin
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Yu-Chun Lin @ 2026-07-21  6:57 UTC (permalink / raw)
  To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
	mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
	u.kleine-koenig, dakr, bhelgaas, o-takashi
  Cc: eleanor.lin, dlechner, linux-kernel, linux-gpio, linux, linux-iio,
	cy.huang, james.tai, Andy Shevchenko

From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

When GPIO regmap based driver supplies its own IRQ domain, it might
still want to keep track of the IRQ requests and releases, in particular
to prevent a GPIO, which is used and locked as IRQ, to be requested
via standard ways. Provide default callbacks for such cases and keep
struct gpio_chip private to GPIO regmap implementation.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
 drivers/gpio/gpio-regmap.c  | 12 ++++++++++++
 include/linux/gpio/regmap.h |  3 +++
 2 files changed, 15 insertions(+)

diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index 51b4d69b8740..535bd9deaa71 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -276,6 +276,18 @@ static int gpio_regmap_direction_output(struct gpio_chip *chip,
 	return gpio_regmap_set_direction(chip, offset, true);
 }
 
+int gpio_regmap_reqres_irq(struct gpio_regmap *gpio, unsigned int offset)
+{
+	return gpiochip_reqres_irq(&gpio->gpio_chip, offset);
+}
+EXPORT_SYMBOL_GPL(gpio_regmap_reqres_irq);
+
+void gpio_regmap_relres_irq(struct gpio_regmap *gpio, unsigned int offset)
+{
+	gpiochip_relres_irq(&gpio->gpio_chip, offset);
+}
+EXPORT_SYMBOL_GPL(gpio_regmap_relres_irq);
+
 void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio)
 {
 	return gpio->driver_data;
diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h
index 06255756710d..e939709fde8d 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -121,4 +121,7 @@ struct gpio_regmap *devm_gpio_regmap_register(struct device *dev,
 					      const struct gpio_regmap_config *config);
 void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio);
 
+int gpio_regmap_reqres_irq(struct gpio_regmap *gpio, unsigned int offset);
+void gpio_regmap_relres_irq(struct gpio_regmap *gpio, unsigned int offset);
+
 #endif /* _LINUX_GPIO_REGMAP_H */
-- 
2.43.0


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

* [PATCH v6 3/8] gpio: regmap: Apply default resource callbacks for regmap IRQ chip
  2026-07-21  6:57 [PATCH v6 0/8] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
  2026-07-21  6:57 ` [PATCH v6 1/8] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC" Yu-Chun Lin
  2026-07-21  6:57 ` [PATCH v6 2/8] gpio: regmap: Provide default IRQ resource request and release callbacks Yu-Chun Lin
@ 2026-07-21  6:57 ` Yu-Chun Lin
  2026-07-21  7:07   ` Michael Walle
  2026-07-21  6:57 ` [PATCH v6 4/8] gpio: regmap: Order kernel-doc descriptions with the actual appearance Yu-Chun Lin
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Yu-Chun Lin @ 2026-07-21  6:57 UTC (permalink / raw)
  To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
	mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
	u.kleine-koenig, dakr, bhelgaas, o-takashi
  Cc: eleanor.lin, dlechner, linux-kernel, linux-gpio, linux, linux-iio,
	cy.huang, james.tai, Andy Shevchenko

From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

When GPIO regmap creates an IRQ chip on behalf of the user, it also
takes an ownership of the respective callbacks and driver data.
With that being done, apply default resource callbacks that keep
tracking the IRQ requests and releases.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in this version:
- Move gpio_regmap_irq_reqres() and gpio_regmap_irq_relres() implementation
  from patch 2 to this patch.
- Add '_maybe_unused' to prevent build fail when CONFIG_REGMAP_IRQ is not
enabled.

 drivers/gpio/gpio-max7360.c |  7 ++++---
 drivers/gpio/gpio-regmap.c  | 14 ++++++++++++++
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/gpio/gpio-max7360.c b/drivers/gpio/gpio-max7360.c
index d12cf1dc8d57..07eda49f375b 100644
--- a/drivers/gpio/gpio-max7360.c
+++ b/drivers/gpio/gpio-max7360.c
@@ -127,7 +127,7 @@ static int max7360_handle_mask_sync(const int index,
 				    const unsigned int mask_buf,
 				    void *const irq_drv_data)
 {
-	struct regmap *regmap = irq_drv_data;
+	struct regmap *regmap = gpio_regmap_get_drvdata(irq_drv_data);
 	int ret;
 
 	for (unsigned int i = 0; i < MAX7360_MAX_GPIO; i++) {
@@ -170,7 +170,6 @@ static int max7360_gpio_probe(struct platform_device *pdev)
 
 			/* Create custom IRQ configuration. */
 			irq_chip = devm_kzalloc(dev, sizeof(*irq_chip), GFP_KERNEL);
-			gpio_config.regmap_irq_chip = irq_chip;
 			if (!irq_chip)
 				return -ENOMEM;
 
@@ -181,7 +180,9 @@ static int max7360_gpio_probe(struct platform_device *pdev)
 			irq_chip->num_irqs = MAX7360_MAX_GPIO;
 			irq_chip->irqs = max7360_regmap_irqs;
 			irq_chip->handle_mask_sync = max7360_handle_mask_sync;
-			irq_chip->irq_drv_data = regmap;
+
+			gpio_config.regmap_irq_chip = irq_chip;
+			gpio_config.drvdata = regmap;
 
 			for (unsigned int i = 0; i < MAX7360_MAX_GPIO; i++) {
 				ret = regmap_write_bits(regmap, MAX7360_REG_PWMCFG(i),
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index 535bd9deaa71..658b892b624c 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -6,6 +6,7 @@
  */
 
 #include <linux/bits.h>
+#include <linux/compiler_attributes.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/io.h>
@@ -288,6 +289,16 @@ void gpio_regmap_relres_irq(struct gpio_regmap *gpio, unsigned int offset)
 }
 EXPORT_SYMBOL_GPL(gpio_regmap_relres_irq);
 
+static int __maybe_unused gpio_regmap_irq_reqres(void *irq_drv_data, irq_hw_number_t hwirq)
+{
+	return gpio_regmap_reqres_irq(irq_drv_data, hwirq);
+}
+
+static void __maybe_unused gpio_regmap_irq_relres(void *irq_drv_data, irq_hw_number_t hwirq)
+{
+	gpio_regmap_relres_irq(irq_drv_data, hwirq);
+}
+
 void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio)
 {
 	return gpio->driver_data;
@@ -409,6 +420,9 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
 #ifdef CONFIG_REGMAP_IRQ
 	if (config->regmap_irq_chip) {
 		gpio->regmap_irq_line = config->regmap_irq_line;
+		config->regmap_irq_chip->irq_reqres = gpio_regmap_irq_reqres;
+		config->regmap_irq_chip->irq_relres = gpio_regmap_irq_relres;
+		config->regmap_irq_chip->irq_drv_data = gpio;
 		ret = regmap_add_irq_chip_fwnode(dev_fwnode(config->parent), config->regmap,
 						 config->regmap_irq_line, config->regmap_irq_flags,
 						 0, config->regmap_irq_chip, &gpio->irq_chip_data);
-- 
2.43.0


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

* [PATCH v6 4/8] gpio: regmap: Order kernel-doc descriptions with the actual appearance
  2026-07-21  6:57 [PATCH v6 0/8] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
                   ` (2 preceding siblings ...)
  2026-07-21  6:57 ` [PATCH v6 3/8] gpio: regmap: Apply default resource callbacks for regmap IRQ chip Yu-Chun Lin
@ 2026-07-21  6:57 ` Yu-Chun Lin
  2026-07-21  7:07   ` Michael Walle
  2026-07-21 10:43   ` Andy Shevchenko
  2026-07-21  6:57 ` [PATCH v6 5/8] gpio: regmap: Add gpio_regmap_operation and value_xlate support Yu-Chun Lin
                   ` (3 subsequent siblings)
  7 siblings, 2 replies; 25+ messages in thread
From: Yu-Chun Lin @ 2026-07-21  6:57 UTC (permalink / raw)
  To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
	mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
	u.kleine-koenig, dakr, bhelgaas, o-takashi
  Cc: eleanor.lin, dlechner, linux-kernel, linux-gpio, linux, linux-iio,
	cy.huang, james.tai, Andy Shevchenko

From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

Order kernel-doc descriptions with the actual appearance.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
 include/linux/gpio/regmap.h | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h
index e939709fde8d..a3ba8242c353 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -34,10 +34,6 @@ struct regmap;
  * @ngpio_per_reg:	(Optional) Number of GPIOs per register
  * @irq_domain:		(Optional) IRQ domain if the controller is
  *			interrupt-capable
- * @reg_mask_xlate:     (Optional) Translates base address and GPIO
- *			offset to a register/bitmask pair. If not
- *			given the default gpio_regmap_simple_xlate()
- *			is used.
  * @fixed_direction_mask:
  *			(Optional) Bitmap representing the GPIO lines that
  *			make use of the @fixed_direction_output list to
@@ -48,16 +44,20 @@ struct regmap;
  *			(Optional) Bitmap representing the fixed direction of
  *			the GPIO lines. Useful when there are GPIO lines with a
  *			fixed direction mixed together in the same register.
- * @drvdata:		(Optional) Pointer to driver specific data which is
- *			not used by gpio-remap but is provided "as is" to the
- *			driver callback(s).
- * @init_valid_mask:	(Optional) Routine to initialize @valid_mask, to be used
- *			if not all GPIOs are valid.
  * @regmap_irq_chip:	(Optional) Pointer on an regmap_irq_chip structure. If
  *			set, a regmap-irq device will be created and the IRQ
  *			domain will be set accordingly.
  * @regmap_irq_line:	(Optional) The IRQ the device uses to signal interrupts.
  * @regmap_irq_flags:	(Optional) The IRQF_ flags to use for the interrupt.
+ * @reg_mask_xlate:     (Optional) Translates base address and GPIO
+ *			offset to a register/bitmask pair. If not
+ *			given the default gpio_regmap_simple_xlate()
+ *			is used.
+ * @init_valid_mask:	(Optional) Routine to initialize @valid_mask, to be used
+ *			if not all GPIOs are valid.
+ * @drvdata:		(Optional) Pointer to driver specific data which is
+ *			not used by gpio-remap but is provided "as is" to the
+ *			driver callback(s).
  *
  * The ->reg_mask_xlate translates a given base address and GPIO offset to
  * register and mask pair. The base address is one of the given register
-- 
2.43.0


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

* [PATCH v6 5/8] gpio: regmap: Add gpio_regmap_operation and value_xlate support
  2026-07-21  6:57 [PATCH v6 0/8] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
                   ` (3 preceding siblings ...)
  2026-07-21  6:57 ` [PATCH v6 4/8] gpio: regmap: Order kernel-doc descriptions with the actual appearance Yu-Chun Lin
@ 2026-07-21  6:57 ` Yu-Chun Lin
  2026-07-21  7:15   ` Michael Walle
  2026-07-21 10:46   ` Andy Shevchenko
  2026-07-21  6:58 ` [PATCH v6 6/8] gpio: regmap: Add set_config callback Yu-Chun Lin
                   ` (2 subsequent siblings)
  7 siblings, 2 replies; 25+ messages in thread
From: Yu-Chun Lin @ 2026-07-21  6:57 UTC (permalink / raw)
  To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
	mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
	u.kleine-koenig, dakr, bhelgaas, o-takashi
  Cc: eleanor.lin, dlechner, linux-kernel, linux-gpio, linux, linux-iio,
	cy.huang, james.tai

Extend the reg_mask_xlate callback with an operation type parameter
(enum gpio_regmap_operation) to allow drivers to return different
register/mask combinations depending on the specific GPIO operation.

In addition, introduce a new optional 'value_xlate' callback. This routine
allows drivers to translate or modify the register value and mask
immediately before a write operation. It is particularly useful for
hardware that requires additional control bits, such as a write-enable bit,
to be appended to the data dynamically.

Consequently, update all existing drivers utilizing the gpio-regmap
framework (across drivers/gpio, drivers/iio, and drivers/pinctrl)
to accommodate the new reg_mask_xlate function signature.

Suggested-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v6:
- Remove removed the hardcoded write-enable workarounds.
- Retain the necessary prototype updates in every driver using custom
reg_mask_xlate
- Add value_xlate to dynamically adjust the register mask and value right
before the actual register write operation.
---
 drivers/gpio/gpio-104-idi-48.c        |  7 +--
 drivers/gpio/gpio-i8255.c             |  4 +-
 drivers/gpio/gpio-idio-16.c           |  6 +--
 drivers/gpio/gpio-max7360.c           |  1 +
 drivers/gpio/gpio-pcie-idio-24.c      |  6 +--
 drivers/gpio/gpio-regmap.c            | 62 ++++++++++++++++++++++-----
 drivers/iio/adc/ad7173.c              |  8 ++--
 drivers/iio/addac/stx104.c            |  6 +--
 drivers/pinctrl/bcm/pinctrl-bcm63xx.c |  1 +
 drivers/pinctrl/pinctrl-tps6594.c     |  1 +
 include/linux/gpio/regmap.h           | 44 +++++++++++++++++--
 11 files changed, 115 insertions(+), 31 deletions(-)

diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c
index ba73ee9c0c29..fb017569cfa8 100644
--- a/drivers/gpio/gpio-104-idi-48.c
+++ b/drivers/gpio/gpio-104-idi-48.c
@@ -36,9 +36,10 @@ MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
 #define IDI48_IRQ_STATUS 0x7
 #define IDI48_IRQ_ENABLE IDI48_IRQ_STATUS
 
-static int idi_48_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
-				 unsigned int offset, unsigned int *reg,
-				 unsigned int *mask)
+static int idi_48_reg_mask_xlate(struct gpio_regmap *gpio,
+				 enum gpio_regmap_operation op,
+				 unsigned int base, unsigned int offset,
+				 unsigned int *reg, unsigned int *mask)
 {
 	const unsigned int line = offset % 8;
 	const unsigned int stride = offset / 8;
diff --git a/drivers/gpio/gpio-i8255.c b/drivers/gpio/gpio-i8255.c
index 953018bfa2b1..541a348447cd 100644
--- a/drivers/gpio/gpio-i8255.c
+++ b/drivers/gpio/gpio-i8255.c
@@ -67,8 +67,8 @@ static int i8255_ppi_init(struct regmap *const map, const unsigned int base)
 	return regmap_write(map, base + I8255_PORTC, 0x00);
 }
 
-static int i8255_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
-				unsigned int offset, unsigned int *reg,
+static int i8255_reg_mask_xlate(struct gpio_regmap *gpio, enum gpio_regmap_operation op,
+				unsigned int base, unsigned int offset, unsigned int *reg,
 				unsigned int *mask)
 {
 	const unsigned int ppi = offset / I8255_NGPIO;
diff --git a/drivers/gpio/gpio-idio-16.c b/drivers/gpio/gpio-idio-16.c
index 4fbae6f6a497..9ac967c6b430 100644
--- a/drivers/gpio/gpio-idio-16.c
+++ b/drivers/gpio/gpio-idio-16.c
@@ -66,9 +66,9 @@ static int idio_16_handle_mask_sync(const int index, const unsigned int mask_buf
 	return 0;
 }
 
-static int idio_16_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base,
-				  const unsigned int offset, unsigned int *const reg,
-				  unsigned int *const mask)
+static int idio_16_reg_mask_xlate(struct gpio_regmap *const gpio, enum gpio_regmap_operation op,
+				  const unsigned int base, const unsigned int offset,
+				  unsigned int *const reg, unsigned int *const mask)
 {
 	unsigned int stride;
 
diff --git a/drivers/gpio/gpio-max7360.c b/drivers/gpio/gpio-max7360.c
index 07eda49f375b..6755d58c4534 100644
--- a/drivers/gpio/gpio-max7360.c
+++ b/drivers/gpio/gpio-max7360.c
@@ -93,6 +93,7 @@ static int max7360_set_gpos_count(struct device *dev, struct regmap *regmap)
 }
 
 static int max7360_gpio_reg_mask_xlate(struct gpio_regmap *gpio,
+				       enum gpio_regmap_operation op,
 				       unsigned int base, unsigned int offset,
 				       unsigned int *reg, unsigned int *mask)
 {
diff --git a/drivers/gpio/gpio-pcie-idio-24.c b/drivers/gpio/gpio-pcie-idio-24.c
index 80c0ba0afa67..b99f4863443d 100644
--- a/drivers/gpio/gpio-pcie-idio-24.c
+++ b/drivers/gpio/gpio-pcie-idio-24.c
@@ -225,9 +225,9 @@ static int idio_24_set_type_config(unsigned int **const buf, const unsigned int
 	return ret;
 }
 
-static int idio_24_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base,
-				  const unsigned int offset, unsigned int *const reg,
-				  unsigned int *const mask)
+static int idio_24_reg_mask_xlate(struct gpio_regmap *const gpio, enum gpio_regmap_operation op,
+				  const unsigned int base, const unsigned int offset,
+				  unsigned int *const reg, unsigned int *const mask)
 {
 	const unsigned int out_stride = offset / IDIO_24_NGPIO_PER_REG;
 	const unsigned int in_stride = (offset - 24) / IDIO_24_NGPIO_PER_REG;
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index 658b892b624c..aecc35f610dd 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -40,9 +40,16 @@ struct gpio_regmap {
 	struct regmap_irq_chip_data *irq_chip_data;
 #endif
 
-	int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int base,
-			      unsigned int offset, unsigned int *reg,
-			      unsigned int *mask);
+	int (*reg_mask_xlate)(struct gpio_regmap *gpio,
+			      enum gpio_regmap_operation op,
+			      unsigned int base, unsigned int offset,
+			      unsigned int *reg, unsigned int *mask);
+
+	int (*value_xlate)(struct gpio_regmap *gpio,
+			   enum gpio_regmap_operation op,
+			   unsigned int base, unsigned int offset,
+			   unsigned int reg, unsigned int *mask,
+			   unsigned int *val);
 
 	void *driver_data;
 };
@@ -56,6 +63,7 @@ static unsigned int gpio_regmap_addr(unsigned int addr)
 }
 
 static int gpio_regmap_simple_xlate(struct gpio_regmap *gpio,
+				    enum gpio_regmap_operation op,
 				    unsigned int base, unsigned int offset,
 				    unsigned int *reg, unsigned int *mask)
 {
@@ -71,7 +79,7 @@ static int gpio_regmap_simple_xlate(struct gpio_regmap *gpio,
 static int gpio_regmap_get(struct gpio_chip *chip, unsigned int offset)
 {
 	struct gpio_regmap *gpio = gpiochip_get_data(chip);
-	unsigned int base, val, reg, mask;
+	unsigned int base, val, reg, mask, dir_mask;
 	int ret;
 
 	/* we might not have an output register if we are input only */
@@ -80,7 +88,18 @@ static int gpio_regmap_get(struct gpio_chip *chip, unsigned int offset)
 	else
 		base = gpio_regmap_addr(gpio->reg_set_base);
 
-	ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
+	ret = gpio->reg_mask_xlate(gpio, GPIO_REGMAP_GET_OP, base, offset, &reg, &dir_mask);
+	if (ret)
+		return ret;
+
+	ret = regmap_read(gpio->regmap, reg, &val);
+	if (ret)
+		return ret;
+
+	if (val & dir_mask)
+		ret = gpio->reg_mask_xlate(gpio, GPIO_REGMAP_OUT, base, offset, &reg, &mask);
+	else
+		ret = gpio->reg_mask_xlate(gpio, GPIO_REGMAP_IN, base, offset, &reg, &mask);
 	if (ret)
 		return ret;
 
@@ -103,7 +122,7 @@ static int gpio_regmap_set(struct gpio_chip *chip, unsigned int offset,
 	unsigned int reg, mask, mask_val;
 	int ret;
 
-	ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
+	ret = gpio->reg_mask_xlate(gpio, GPIO_REGMAP_SET_OP, base, offset, &reg, &mask);
 	if (ret)
 		return ret;
 
@@ -112,6 +131,13 @@ static int gpio_regmap_set(struct gpio_chip *chip, unsigned int offset,
 	else
 		mask_val = 0;
 
+	if (gpio->value_xlate) {
+		ret = gpio->value_xlate(gpio, GPIO_REGMAP_SET_OP, base, offset,
+					reg, &mask, &mask_val);
+		if (ret)
+			return ret;
+	}
+
 	/* ignore input values which shadow the old output value */
 	if (gpio->reg_dat_base == gpio->reg_set_base)
 		ret = regmap_write_bits(gpio->regmap, reg, mask, mask_val);
@@ -125,7 +151,7 @@ static int gpio_regmap_set_with_clear(struct gpio_chip *chip,
 				      unsigned int offset, int val)
 {
 	struct gpio_regmap *gpio = gpiochip_get_data(chip);
-	unsigned int base, reg, mask;
+	unsigned int base, reg, mask, value = 0;
 	int ret;
 
 	if (val)
@@ -133,10 +159,17 @@ static int gpio_regmap_set_with_clear(struct gpio_chip *chip,
 	else
 		base = gpio_regmap_addr(gpio->reg_clr_base);
 
-	ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
+	ret = gpio->reg_mask_xlate(gpio, GPIO_REGMAP_SET_OP, base, offset, &reg, &mask);
 	if (ret)
 		return ret;
 
+	if (gpio->value_xlate) {
+		ret = gpio->value_xlate(gpio, GPIO_REGMAP_SET_OP, base, offset,
+					reg, &mask, &value);
+		if (ret)
+			return ret;
+	}
+
 	return regmap_write(gpio->regmap, reg, mask);
 }
 
@@ -183,7 +216,7 @@ static int gpio_regmap_get_direction(struct gpio_chip *chip,
 		return -ENOTSUPP;
 	}
 
-	ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
+	ret = gpio->reg_mask_xlate(gpio, GPIO_REGMAP_GET_DIR_OP, base, offset, &reg, &mask);
 	if (ret)
 		return ret;
 
@@ -237,7 +270,7 @@ static int gpio_regmap_set_direction(struct gpio_chip *chip,
 		return -ENOTSUPP;
 	}
 
-	ret = gpio->reg_mask_xlate(gpio, base, offset, &reg, &mask);
+	ret = gpio->reg_mask_xlate(gpio, GPIO_REGMAP_SET_DIR_OP, base, offset, &reg, &mask);
 	if (ret)
 		return ret;
 
@@ -246,6 +279,13 @@ static int gpio_regmap_set_direction(struct gpio_chip *chip,
 	else
 		val = output ? mask : 0;
 
+	if (gpio->value_xlate) {
+		ret = gpio->value_xlate(gpio, GPIO_REGMAP_SET_DIR_OP, base, offset,
+					reg, &mask, &val);
+		if (ret)
+			return ret;
+	}
+
 	return regmap_update_bits(gpio->regmap, reg, mask, val);
 }
 
@@ -413,6 +453,8 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
 	if (!gpio->reg_mask_xlate)
 		gpio->reg_mask_xlate = gpio_regmap_simple_xlate;
 
+	gpio->value_xlate = config->value_xlate;
+
 	ret = gpiochip_add_data(chip, gpio);
 	if (ret < 0)
 		goto err_free_bitmap_output;
diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c
index 9ee65d63c525..f78e758706ed 100644
--- a/drivers/iio/adc/ad7173.c
+++ b/drivers/iio/adc/ad7173.c
@@ -560,8 +560,8 @@ static int ad4111_openwire_event(struct iio_dev *indio_dev,
 	return ret;
 }
 
-static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
-			     unsigned int offset, unsigned int *reg,
+static int ad7173_mask_xlate(struct gpio_regmap *gpio, enum gpio_regmap_operation op,
+			     unsigned int base, unsigned int offset, unsigned int *reg,
 			     unsigned int *mask)
 {
 	*mask = AD7173_GPO_DATA(offset);
@@ -569,8 +569,8 @@ static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
 	return 0;
 }
 
-static int ad4111_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
-			     unsigned int offset, unsigned int *reg,
+static int ad4111_mask_xlate(struct gpio_regmap *gpio, enum gpio_regmap_operation op,
+			     unsigned int base, unsigned int offset, unsigned int *reg,
 			     unsigned int *mask)
 {
 	*mask = AD4111_GPO01_DATA(offset);
diff --git a/drivers/iio/addac/stx104.c b/drivers/iio/addac/stx104.c
index 7bdf2cb94176..6207eb2fac74 100644
--- a/drivers/iio/addac/stx104.c
+++ b/drivers/iio/addac/stx104.c
@@ -349,9 +349,9 @@ static const struct iio_chan_spec stx104_channels_diff[] = {
 	STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1)
 };
 
-static int stx104_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base,
-				 unsigned int offset, unsigned int *const reg,
-				 unsigned int *const mask)
+static int stx104_reg_mask_xlate(struct gpio_regmap *const gpio, enum gpio_regmap_operation op,
+				 const unsigned int base, unsigned int offset,
+				 unsigned int *const reg, unsigned int *const mask)
 {
 	/* Output lines are located at same register bit offsets as input lines */
 	if (offset >= 4)
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm63xx.c b/drivers/pinctrl/bcm/pinctrl-bcm63xx.c
index a4aa4146b530..b41a3d16aabe 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm63xx.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm63xx.c
@@ -19,6 +19,7 @@
 #define BCM63XX_DATA_REG	0x0c
 
 static int bcm63xx_reg_mask_xlate(struct gpio_regmap *gpio,
+				  enum gpio_regmap_operation op,
 				  unsigned int base, unsigned int offset,
 				  unsigned int *reg, unsigned int *mask)
 {
diff --git a/drivers/pinctrl/pinctrl-tps6594.c b/drivers/pinctrl/pinctrl-tps6594.c
index 456a3cfc8de9..937fc9cb54b7 100644
--- a/drivers/pinctrl/pinctrl-tps6594.c
+++ b/drivers/pinctrl/pinctrl-tps6594.c
@@ -346,6 +346,7 @@ static struct tps6594_pinctrl tps6594_template_pinctrl = {
 };
 
 static int tps6594_gpio_regmap_xlate(struct gpio_regmap *gpio,
+				     enum gpio_regmap_operation op,
 				     unsigned int base, unsigned int offset,
 				     unsigned int *reg, unsigned int *mask)
 {
diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h
index a3ba8242c353..45a30f50043f 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -13,6 +13,36 @@ struct regmap;
 #define GPIO_REGMAP_ADDR_ZERO ((unsigned int)(-1))
 #define GPIO_REGMAP_ADDR(addr) ((addr) ? : GPIO_REGMAP_ADDR_ZERO)
 
+/**
+ * enum gpio_regmap_operation - Operation type for reg_mask_xlate callback
+ *
+ * This enum is used to distinguish between different types of GPIO operations
+ * so that the reg_mask_xlate callback can return the appropriate mask for each
+ * operation type.
+ *
+ * Value operations:
+ * @GPIO_REGMAP_GET_OP: Mask for reading direction to detect if GPIO is input or output.
+ *                      Used in gpio_regmap_get() to determine the GPIO direction.
+ * @GPIO_REGMAP_IN: Mask for reading input value. Used when GPIO is configured as input.
+ * @GPIO_REGMAP_OUT: Mask for reading output value. Used when GPIO is configured as output.
+ *
+ * Output operations:
+ * @GPIO_REGMAP_SET_OP: Mask for setting GPIO output value.
+ *
+ * Direction operations:
+ * @GPIO_REGMAP_GET_DIR_OP: Mask for reading GPIO direction (input/output).
+ * @GPIO_REGMAP_SET_DIR_OP: Mask for setting GPIO direction (input/output).
+ *
+ */
+enum gpio_regmap_operation {
+	GPIO_REGMAP_GET_OP,
+	GPIO_REGMAP_SET_OP,
+	GPIO_REGMAP_GET_DIR_OP,
+	GPIO_REGMAP_SET_DIR_OP,
+	GPIO_REGMAP_IN,
+	GPIO_REGMAP_OUT,
+};
+
 /**
  * struct gpio_regmap_config - Description of a generic regmap gpio_chip.
  * @parent:		The parent device
@@ -55,6 +85,10 @@ struct regmap;
  *			is used.
  * @init_valid_mask:	(Optional) Routine to initialize @valid_mask, to be used
  *			if not all GPIOs are valid.
+ * @value_xlate:	(Optional) Routine to translate the register value and
+ *			mask before writing. This allows driver-specific logic
+ *			to append additional bits (like write-enable masks)
+ *			dynamically based on the current operation.
  * @drvdata:		(Optional) Pointer to driver specific data which is
  *			not used by gpio-remap but is provided "as is" to the
  *			driver callback(s).
@@ -104,14 +138,18 @@ struct gpio_regmap_config {
 	unsigned long regmap_irq_flags;
 #endif
 
-	int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int base,
-			      unsigned int offset, unsigned int *reg,
-			      unsigned int *mask);
+	int (*reg_mask_xlate)(struct gpio_regmap *gpio, enum gpio_regmap_operation,
+			      unsigned int base, unsigned int offset,
+			      unsigned int *reg, unsigned int *mask);
 
 	int (*init_valid_mask)(struct gpio_chip *gc,
 			       unsigned long *valid_mask,
 			       unsigned int ngpios);
 
+	int (*value_xlate)(struct gpio_regmap *gpio, enum gpio_regmap_operation,
+			   unsigned int base, unsigned int offset, unsigned int reg,
+			   unsigned int *mask, unsigned int *val);
+
 	void *drvdata;
 };
 
-- 
2.43.0


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

* [PATCH v6 6/8] gpio: regmap: Add set_config callback
  2026-07-21  6:57 [PATCH v6 0/8] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
                   ` (4 preceding siblings ...)
  2026-07-21  6:57 ` [PATCH v6 5/8] gpio: regmap: Add gpio_regmap_operation and value_xlate support Yu-Chun Lin
@ 2026-07-21  6:58 ` Yu-Chun Lin
  2026-07-21  7:23   ` Michael Walle
  2026-07-21  6:58 ` [PATCH v6 7/8] gpio: regmap: Add IRQ enable/disable helpers Yu-Chun Lin
  2026-07-21  6:58 ` [PATCH v6 8/8] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC Yu-Chun Lin
  7 siblings, 1 reply; 25+ messages in thread
From: Yu-Chun Lin @ 2026-07-21  6:58 UTC (permalink / raw)
  To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
	mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
	u.kleine-koenig, dakr, bhelgaas, o-takashi
  Cc: eleanor.lin, dlechner, linux-kernel, linux-gpio, linux, linux-iio,
	cy.huang, james.tai

Add a new set_config callback to struct gpio_regmap_config to allow drivers
to implement hardware-specific configuration such as debounce settings,
or other platform-specific GPIO properties.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v6:
- None.
---
 drivers/gpio/gpio-regmap.c  | 1 +
 include/linux/gpio/regmap.h | 5 +++++
 2 files changed, 6 insertions(+)

diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index aecc35f610dd..b856326ff01c 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -454,6 +454,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
 		gpio->reg_mask_xlate = gpio_regmap_simple_xlate;
 
 	gpio->value_xlate = config->value_xlate;
+	chip->set_config = config->set_config;
 
 	ret = gpiochip_add_data(chip, gpio);
 	if (ret < 0)
diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h
index 45a30f50043f..23460995c1d1 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -89,6 +89,9 @@ enum gpio_regmap_operation {
  *			mask before writing. This allows driver-specific logic
  *			to append additional bits (like write-enable masks)
  *			dynamically based on the current operation.
+ * @set_config:		(Optional) Callback for setting GPIO configuration such
+ *			as debounce, drive strength, or other hardware specific
+ *			settings.
  * @drvdata:		(Optional) Pointer to driver specific data which is
  *			not used by gpio-remap but is provided "as is" to the
  *			driver callback(s).
@@ -150,6 +153,8 @@ struct gpio_regmap_config {
 			   unsigned int base, unsigned int offset, unsigned int reg,
 			   unsigned int *mask, unsigned int *val);
 
+	int (*set_config)(struct gpio_chip *gc, unsigned int offset, unsigned long config);
+
 	void *drvdata;
 };
 
-- 
2.43.0


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

* [PATCH v6 7/8] gpio: regmap: Add IRQ enable/disable helpers
  2026-07-21  6:57 [PATCH v6 0/8] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
                   ` (5 preceding siblings ...)
  2026-07-21  6:58 ` [PATCH v6 6/8] gpio: regmap: Add set_config callback Yu-Chun Lin
@ 2026-07-21  6:58 ` Yu-Chun Lin
  2026-07-21  7:24   ` Michael Walle
  2026-07-21 10:54   ` Andy Shevchenko
  2026-07-21  6:58 ` [PATCH v6 8/8] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC Yu-Chun Lin
  7 siblings, 2 replies; 25+ messages in thread
From: Yu-Chun Lin @ 2026-07-21  6:58 UTC (permalink / raw)
  To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
	mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
	u.kleine-koenig, dakr, bhelgaas, o-takashi
  Cc: eleanor.lin, dlechner, linux-kernel, linux-gpio, linux, linux-iio,
	cy.huang, james.tai, Andy Shevchenko

Add gpio_regmap_enable_irq() and gpio_regmap_disable_irq(). Since struct
gpio_regmap is opaque, drivers cannot access the embedded gpio_chip directly.

Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v6:
- A new patch.
---
 drivers/gpio/gpio-regmap.c  | 12 ++++++++++++
 include/linux/gpio/regmap.h |  5 +++++
 2 files changed, 17 insertions(+)

diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index b856326ff01c..5c6fdff20cf8 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -345,6 +345,18 @@ void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio)
 }
 EXPORT_SYMBOL_GPL(gpio_regmap_get_drvdata);
 
+void gpio_regmap_enable_irq(struct gpio_regmap *gpio, irq_hw_number_t hwirq)
+{
+	gpiochip_enable_irq(&gpio->gpio_chip, hwirq);
+}
+EXPORT_SYMBOL_GPL(gpio_regmap_enable_irq);
+
+void gpio_regmap_disable_irq(struct gpio_regmap *gpio, irq_hw_number_t hwirq)
+{
+	gpiochip_disable_irq(&gpio->gpio_chip, hwirq);
+}
+EXPORT_SYMBOL_GPL(gpio_regmap_disable_irq);
+
 /**
  * gpio_regmap_register() - Register a generic regmap GPIO controller
  * @config: configuration for gpio_regmap
diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h
index 23460995c1d1..8042e620621d 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -3,6 +3,8 @@
 #ifndef _LINUX_GPIO_REGMAP_H
 #define _LINUX_GPIO_REGMAP_H
 
+#include <linux/types.h>
+
 struct device;
 struct fwnode_handle;
 struct gpio_regmap;
@@ -167,4 +169,7 @@ void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio);
 int gpio_regmap_reqres_irq(struct gpio_regmap *gpio, unsigned int offset);
 void gpio_regmap_relres_irq(struct gpio_regmap *gpio, unsigned int offset);
 
+void gpio_regmap_enable_irq(struct gpio_regmap *gpio, irq_hw_number_t hwirq);
+void gpio_regmap_disable_irq(struct gpio_regmap *gpio, irq_hw_number_t hwirq);
+
 #endif /* _LINUX_GPIO_REGMAP_H */
-- 
2.43.0


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

* [PATCH v6 8/8] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC
  2026-07-21  6:57 [PATCH v6 0/8] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
                   ` (6 preceding siblings ...)
  2026-07-21  6:58 ` [PATCH v6 7/8] gpio: regmap: Add IRQ enable/disable helpers Yu-Chun Lin
@ 2026-07-21  6:58 ` Yu-Chun Lin
  2026-07-21 11:12   ` Andy Shevchenko
  7 siblings, 1 reply; 25+ messages in thread
From: Yu-Chun Lin @ 2026-07-21  6:58 UTC (permalink / raw)
  To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
	mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
	u.kleine-koenig, dakr, bhelgaas, o-takashi
  Cc: eleanor.lin, dlechner, linux-kernel, linux-gpio, linux, linux-iio,
	cy.huang, james.tai

From: Tzuyi Chang <tychang@realtek.com>

Add support for the GPIO controller found on Realtek DHC RTD1625 SoCs.

Unlike the existing Realtek GPIO driver (drivers/gpio/gpio-rtd.c),
which manages pins via shared bank registers, the RTD1625 introduces
a per-pin register architecture. Each GPIO line now has its own
dedicated 32-bit control register to manage configuration independently,
including direction, output value, input value, interrupt enable, and
debounce. Therefore, this distinct hardware design requires a separate
driver.

The RTD1625 GPIO controller has a hardware quirk where both 'assert'
and 'de-assert' interrupts are fired simultaneously on any edge toggle.
The driver works around this quirk to correctly handle edge interrupts.

Interrupt support is optional for this device, matching the dt-bindings.
If the interrupts property is not provided, the driver simply skips IRQ
initialization and operates purely as a basic GPIO controller.

Signed-off-by: Tzuyi Chang <tychang@realtek.com>
Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v6:
- Add 'select REGMAP_MMIO' into Kconfig.
- Replace GPIOCHIP_IRQ_RESOURCE_HELPERS with explicit irq_request_resources
and irq_release_resources callbacks using gpio_regmap_reqres_irq() and
gpio_regmap_relres_irq() introduced by Andy's patches.
- Replace the '*mask = 0' hack with 'return -ENOTSUPP'.
- Move variable operations out of scoped_guard().
- Add 'struct lock_class_key' to irq_domain map for proper lockdep annotation.
- Remove redundant 'ret' variable.
- Make regmap disable_locking depend on CONFIG_DEBUG_GPIO to avoid
dropping debugfs support unconditionally.
- Replace irq_domain_add_linear() with irq_domain_create_linear() using
dev_fwnode(dev), and manage lifetime with devm_add_action_or_reset().
---
 drivers/gpio/Kconfig        |  14 +
 drivers/gpio/Makefile       |   1 +
 drivers/gpio/gpio-rtd1625.c | 667 ++++++++++++++++++++++++++++++++++++
 3 files changed, 682 insertions(+)
 create mode 100644 drivers/gpio/gpio-rtd1625.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index ed2bc3113374..3b402ac505f1 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -656,6 +656,20 @@ config GPIO_RTD
 	  Say yes here to support GPIO functionality and GPIO interrupt on
 	  Realtek DHC SoCs.
 
+config GPIO_RTD1625
+	tristate "Realtek DHC RTD1625 GPIO support"
+	depends on ARCH_REALTEK || COMPILE_TEST
+	default ARCH_REALTEK
+	select GPIOLIB_IRQCHIP
+	select GPIO_REGMAP
+	select REGMAP_MMIO
+	help
+	  This option enables support for the GPIO controller on Realtek
+	  DHC (Digital Home Center) RTD1625 SoC.
+
+	  Say yes here to support both basic GPIO line functionality
+	  and GPIO interrupt handling capabilities for this platform.
+
 config GPIO_SAMA5D2_PIOBU
 	tristate "SAMA5D2 PIOBU GPIO support"
 	depends on OF
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 4d0e900402fc..fa14581e3995 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -160,6 +160,7 @@ obj-$(CONFIG_GPIO_REALTEK_OTTO)		+= gpio-realtek-otto.o
 obj-$(CONFIG_GPIO_REG)			+= gpio-reg.o
 obj-$(CONFIG_GPIO_ROCKCHIP)	+= gpio-rockchip.o
 obj-$(CONFIG_GPIO_RTD)			+= gpio-rtd.o
+obj-$(CONFIG_GPIO_RTD1625)		+= gpio-rtd1625.o
 obj-$(CONFIG_ARCH_SA1100)		+= gpio-sa1100.o
 obj-$(CONFIG_GPIO_SAMA5D2_PIOBU)	+= gpio-sama5d2-piobu.o
 obj-$(CONFIG_GPIO_SCH311X)		+= gpio-sch311x.o
diff --git a/drivers/gpio/gpio-rtd1625.c b/drivers/gpio/gpio-rtd1625.c
new file mode 100644
index 000000000000..0aa9816b4669
--- /dev/null
+++ b/drivers/gpio/gpio-rtd1625.c
@@ -0,0 +1,667 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Realtek DHC RTD1625 gpio driver
+ *
+ * Copyright (c) 2023-2026 Realtek Semiconductor Corp.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio/regmap.h>
+#include <linux/interrupt.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#define RTD1625_GPIO_DIR BIT(0)
+#define RTD1625_GPIO_OUT BIT(2)
+#define RTD1625_GPIO_IN BIT(4)
+#define RTD1625_GPIO_EDGE_INT_DP BIT(6)
+#define RTD1625_GPIO_EDGE_INT_EN BIT(8)
+#define RTD1625_GPIO_LEVEL_INT_EN BIT(16)
+#define RTD1625_GPIO_LEVEL_INT_DP BIT(18)
+#define RTD1625_GPIO_DEBOUNCE GENMASK(30, 28)
+#define RTD1625_GPIO_DEBOUNCE_WREN BIT(31)
+
+#define RTD1625_GPIO_WREN(x) ((x) << 1)
+
+/* Write-enable masks for all GPIO configs and reserved hardware bits */
+#define RTD1625_ISO_GPIO_WREN_ALL 0x8000aa8a
+#define RTD1625_ISOM_GPIO_WREN_ALL 0x800aaa8a
+
+#define RTD1625_GPIO_DEBOUNCE_1US 0
+#define RTD1625_GPIO_DEBOUNCE_10US 1
+#define RTD1625_GPIO_DEBOUNCE_100US 2
+#define RTD1625_GPIO_DEBOUNCE_1MS 3
+#define RTD1625_GPIO_DEBOUNCE_10MS 4
+#define RTD1625_GPIO_DEBOUNCE_20MS 5
+#define RTD1625_GPIO_DEBOUNCE_30MS 6
+#define RTD1625_GPIO_DEBOUNCE_50MS 7
+
+#define GPIO_CONTROL(gpio) ((gpio) * 4)
+
+static struct lock_class_key rtd1625_gpio_irq_lock_class;
+static struct lock_class_key rtd1625_gpio_irq_request_class;
+
+enum rtd1625_irq_index {
+	RTD1625_IRQ_ASSERT,
+	RTD1625_IRQ_DEASSERT,
+	RTD1625_IRQ_LEVEL,
+	RTD1625_MAX_IRQS
+};
+
+/**
+ * struct rtd1625_gpio_info - Specific GPIO register information
+ * @num_gpios: The number of GPIOs
+ * @irq_type_support: Supported IRQ types
+ * @base_offset: Offset for GPIO controller register
+ * @gpa_offset: Offset for GPIO assert interrupt status register
+ * @gpda_offset: Offset for GPIO deassert interrupt status register
+ * @level_offset: Offset of level interrupt status register
+ * @write_en_all: Write-enable mask for all configurable bits
+ */
+struct rtd1625_gpio_info {
+	unsigned int num_gpios;
+	unsigned int irq_type_support;
+	unsigned int base_offset;
+	unsigned int gpa_offset;
+	unsigned int gpda_offset;
+	unsigned int level_offset;
+	unsigned int write_en_all;
+};
+
+struct rtd1625_gpio {
+	struct gpio_regmap *gpio_reg;
+	const struct rtd1625_gpio_info *info;
+	struct regmap *regmap;
+	unsigned int irqs[RTD1625_MAX_IRQS];
+	raw_spinlock_t lock;
+	struct irq_domain *domain;
+	unsigned int *save_regs;
+};
+
+static unsigned int rtd1625_gpio_gpa_offset(struct rtd1625_gpio *data, unsigned int offset)
+{
+	return data->info->gpa_offset + ((offset / 32) * 4);
+}
+
+static unsigned int rtd1625_gpio_gpda_offset(struct rtd1625_gpio *data, unsigned int offset)
+{
+	return data->info->gpda_offset + ((offset / 32) * 4);
+}
+
+static unsigned int rtd1625_gpio_level_offset(struct rtd1625_gpio *data, unsigned int offset)
+{
+	return data->info->level_offset + ((offset / 32) * 4);
+}
+
+static int rtd1625_reg_mask_xlate(struct gpio_regmap *gpio, enum gpio_regmap_operation op,
+				  unsigned int base, unsigned int offset, unsigned int *reg,
+				  unsigned int *mask)
+{
+	/* Each GPIO has its own dedicated 32-bit register */
+	*reg = base + offset * 4;
+
+	switch (op) {
+	case GPIO_REGMAP_IN:
+		*mask = RTD1625_GPIO_IN;
+		break;
+
+	case GPIO_REGMAP_OUT:
+		*mask = RTD1625_GPIO_OUT;
+		break;
+
+	case GPIO_REGMAP_SET_OP:
+		*mask = RTD1625_GPIO_OUT;
+		break;
+
+	case GPIO_REGMAP_GET_OP:
+	case GPIO_REGMAP_GET_DIR_OP:
+	case GPIO_REGMAP_SET_DIR_OP:
+		*mask = RTD1625_GPIO_DIR;
+		break;
+
+	default:
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static int rtd1625_value_xlate(struct gpio_regmap *gpio,
+			       enum gpio_regmap_operation op,
+			       unsigned int base, unsigned int offset,
+			       unsigned int reg, unsigned int *mask,
+			       unsigned int *val)
+{
+	switch (op) {
+	case GPIO_REGMAP_SET_OP:
+		*val |= RTD1625_GPIO_WREN(RTD1625_GPIO_OUT);
+		*mask |= RTD1625_GPIO_WREN(RTD1625_GPIO_OUT);
+		break;
+
+	case GPIO_REGMAP_SET_DIR_OP:
+		*val |= RTD1625_GPIO_WREN(RTD1625_GPIO_DIR);
+		*mask |= RTD1625_GPIO_WREN(RTD1625_GPIO_DIR);
+		break;
+
+	default:
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static int rtd1625_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
+				     unsigned int debounce)
+{
+	struct rtd1625_gpio *data = gpiochip_get_data(chip);
+	u8 deb_val;
+	u32 val;
+	int ret;
+
+	switch (debounce) {
+	case 1:
+		deb_val = RTD1625_GPIO_DEBOUNCE_1US;
+		break;
+	case 10:
+		deb_val = RTD1625_GPIO_DEBOUNCE_10US;
+		break;
+	case 100:
+		deb_val = RTD1625_GPIO_DEBOUNCE_100US;
+		break;
+	case 1000:
+		deb_val = RTD1625_GPIO_DEBOUNCE_1MS;
+		break;
+	case 10000:
+		deb_val = RTD1625_GPIO_DEBOUNCE_10MS;
+		break;
+	case 20000:
+		deb_val = RTD1625_GPIO_DEBOUNCE_20MS;
+		break;
+	case 30000:
+		deb_val = RTD1625_GPIO_DEBOUNCE_30MS;
+		break;
+	case 50000:
+		deb_val = RTD1625_GPIO_DEBOUNCE_50MS;
+		break;
+	default:
+		return -ENOTSUPP;
+	}
+
+	val = FIELD_PREP(RTD1625_GPIO_DEBOUNCE, deb_val) | RTD1625_GPIO_DEBOUNCE_WREN;
+
+	scoped_guard(raw_spinlock_irqsave, &data->lock)
+		ret = regmap_write(data->regmap, data->info->base_offset + GPIO_CONTROL(offset),
+				   val);
+
+	return ret;
+}
+
+static int rtd1625_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+				   unsigned long config)
+{
+	u32 debounce;
+
+	if (pinconf_to_config_param(config) == PIN_CONFIG_INPUT_DEBOUNCE) {
+		debounce = pinconf_to_config_argument(config);
+		return rtd1625_gpio_set_debounce(chip, offset, debounce);
+	}
+
+	return gpiochip_generic_config(chip, offset, config);
+}
+
+static void rtd1625_gpio_irq_handle(struct irq_desc *desc)
+{
+	unsigned int (*get_reg_offset)(struct rtd1625_gpio *gpio, unsigned int offset);
+	struct rtd1625_gpio *data = irq_desc_get_handler_data(desc);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	unsigned int irq = irq_desc_get_irq(desc);
+	struct irq_domain *domain = data->domain;
+	unsigned int reg_offset, i, j, val;
+	irq_hw_number_t hwirq;
+	unsigned long status;
+	u32 irq_type;
+
+	if (irq == data->irqs[RTD1625_IRQ_ASSERT])
+		get_reg_offset = &rtd1625_gpio_gpa_offset;
+	else if (irq == data->irqs[RTD1625_IRQ_DEASSERT])
+		get_reg_offset = &rtd1625_gpio_gpda_offset;
+	else if (irq == data->irqs[RTD1625_IRQ_LEVEL])
+		get_reg_offset = &rtd1625_gpio_level_offset;
+	else
+		return;
+
+	chained_irq_enter(chip, desc);
+
+	for (i = 0; i < data->info->num_gpios; i += 32) {
+		reg_offset = get_reg_offset(data, i);
+		regmap_read(data->regmap, reg_offset, &val);
+
+		status = val;
+		/*
+		 * Hardware quirk: The controller fires both "assert" and "de-assert"
+		 * interrupts simultaneously on any edge toggle.
+		 * We must pre-clear edge interrupts here. If we drop an unwanted
+		 * de-assert interrupt below, it will never reach the IRQ core
+		 * (generic_handle_domain_irq), meaning ->irq_ack() won't be called.
+		 * Failing to clear it here leads to an interrupt storm.
+		 */
+		if (irq != data->irqs[RTD1625_IRQ_LEVEL])
+			regmap_write(data->regmap, reg_offset, status);
+
+		for_each_set_bit(j, &status, 32) {
+			hwirq = i + j;
+			irq_type = irq_get_trigger_type(irq_find_mapping(domain, hwirq));
+
+			/*
+			 * Filter out the hardware-forced de-assert interrupt unless
+			 * the user explicitly requested IRQ_TYPE_EDGE_BOTH.
+			 */
+			if (irq == data->irqs[RTD1625_IRQ_DEASSERT] &&
+			    irq_type != IRQ_TYPE_EDGE_BOTH)
+				continue;
+
+			generic_handle_domain_irq(domain, hwirq);
+		}
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+static void rtd1625_gpio_ack_irq(struct irq_data *d)
+{
+	struct rtd1625_gpio *data = irq_data_get_irq_chip_data(d);
+	irq_hw_number_t hwirq = irqd_to_hwirq(d);
+	u32 irq_type = irqd_get_trigger_type(d);
+	u32 bit_mask = BIT(hwirq % 32);
+	int reg_offset;
+
+	if (irq_type & IRQ_TYPE_LEVEL_MASK) {
+		reg_offset = rtd1625_gpio_level_offset(data, hwirq);
+		regmap_write(data->regmap, reg_offset, bit_mask);
+	}
+}
+
+static void rtd1625_gpio_enable_edge_irq(struct rtd1625_gpio *data, irq_hw_number_t hwirq)
+{
+	int gpda_reg_offset = rtd1625_gpio_gpda_offset(data, hwirq);
+	int gpa_reg_offset = rtd1625_gpio_gpa_offset(data, hwirq);
+	u32 clr_mask = BIT(hwirq % 32);
+	u32 val;
+
+	guard(raw_spinlock_irqsave)(&data->lock);
+
+	regmap_write(data->regmap, gpa_reg_offset, clr_mask);
+	regmap_write(data->regmap, gpda_reg_offset, clr_mask);
+	val = RTD1625_GPIO_EDGE_INT_EN | RTD1625_GPIO_WREN(RTD1625_GPIO_EDGE_INT_EN);
+	regmap_write(data->regmap, data->info->base_offset + GPIO_CONTROL(hwirq), val);
+}
+
+static void rtd1625_gpio_disable_edge_irq(struct rtd1625_gpio *data, irq_hw_number_t hwirq)
+{
+	u32 val;
+
+	guard(raw_spinlock_irqsave)(&data->lock);
+
+	val = RTD1625_GPIO_WREN(RTD1625_GPIO_EDGE_INT_EN);
+	regmap_write(data->regmap, data->info->base_offset + GPIO_CONTROL(hwirq), val);
+}
+
+static void rtd1625_gpio_enable_level_irq(struct rtd1625_gpio *data, irq_hw_number_t hwirq)
+{
+	int level_reg_offset = rtd1625_gpio_level_offset(data, hwirq);
+	u32 clr_mask = BIT(hwirq % 32);
+	u32 val;
+
+	guard(raw_spinlock_irqsave)(&data->lock);
+
+	regmap_write(data->regmap, level_reg_offset, clr_mask);
+	val = RTD1625_GPIO_LEVEL_INT_EN | RTD1625_GPIO_WREN(RTD1625_GPIO_LEVEL_INT_EN);
+	regmap_write(data->regmap, data->info->base_offset + GPIO_CONTROL(hwirq), val);
+}
+
+static void rtd1625_gpio_disable_level_irq(struct rtd1625_gpio *data, irq_hw_number_t hwirq)
+{
+	u32 val;
+
+	guard(raw_spinlock_irqsave)(&data->lock);
+
+	val = RTD1625_GPIO_WREN(RTD1625_GPIO_LEVEL_INT_EN);
+	regmap_write(data->regmap, data->info->base_offset + GPIO_CONTROL(hwirq), val);
+}
+
+static void rtd1625_gpio_enable_irq(struct irq_data *d)
+{
+	struct rtd1625_gpio *data = irq_data_get_irq_chip_data(d);
+	irq_hw_number_t hwirq = irqd_to_hwirq(d);
+	u32 irq_type = irqd_get_trigger_type(d);
+
+	gpio_regmap_enable_irq(data->gpio_reg, hwirq);
+
+	if (irq_type & IRQ_TYPE_EDGE_BOTH)
+		rtd1625_gpio_enable_edge_irq(data, hwirq);
+	else if (irq_type & IRQ_TYPE_LEVEL_MASK)
+		rtd1625_gpio_enable_level_irq(data, hwirq);
+}
+
+static void rtd1625_gpio_disable_irq(struct irq_data *d)
+{
+	struct rtd1625_gpio *data = irq_data_get_irq_chip_data(d);
+	irq_hw_number_t hwirq = irqd_to_hwirq(d);
+	u32 irq_type = irqd_get_trigger_type(d);
+
+	if (irq_type & IRQ_TYPE_EDGE_BOTH)
+		rtd1625_gpio_disable_edge_irq(data, hwirq);
+	else if (irq_type & IRQ_TYPE_LEVEL_MASK)
+		rtd1625_gpio_disable_level_irq(data, hwirq);
+
+	gpio_regmap_disable_irq(data->gpio_reg, hwirq);
+}
+
+static int rtd1625_gpio_irq_set_level_type(struct irq_data *d, bool level)
+{
+	u32 val = RTD1625_GPIO_WREN(RTD1625_GPIO_LEVEL_INT_DP);
+	irq_hw_number_t hwirq = irqd_to_hwirq(d);
+	struct rtd1625_gpio *data;
+	int ret;
+
+	data = irq_data_get_irq_chip_data(d);
+	if (!(data->info->irq_type_support & IRQ_TYPE_LEVEL_MASK))
+		return -EINVAL;
+
+	if (level)
+		val |= RTD1625_GPIO_LEVEL_INT_DP;
+
+	scoped_guard(raw_spinlock_irqsave, &data->lock)
+		ret = regmap_write(data->regmap, data->info->base_offset + GPIO_CONTROL(hwirq), val);
+
+	if (ret)
+		return ret;
+
+	irq_set_handler_locked(d, handle_level_irq);
+
+	return 0;
+}
+
+static int rtd1625_gpio_irq_set_edge_type(struct irq_data *d, bool polarity)
+{
+	struct rtd1625_gpio *data = irq_data_get_irq_chip_data(d);
+	u32 val = RTD1625_GPIO_WREN(RTD1625_GPIO_EDGE_INT_DP);
+	irq_hw_number_t hwirq = irqd_to_hwirq(d);
+	int ret;
+
+	if (!(data->info->irq_type_support & IRQ_TYPE_EDGE_BOTH))
+		return -EINVAL;
+
+	if (polarity)
+		val |= RTD1625_GPIO_EDGE_INT_DP;
+
+	scoped_guard(raw_spinlock_irqsave, &data->lock)
+		ret = regmap_write(data->regmap, data->info->base_offset + GPIO_CONTROL(hwirq), val);
+
+	if (ret)
+		return ret;
+
+	irq_set_handler_locked(d, handle_edge_irq);
+
+	return 0;
+}
+
+static int rtd1625_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+	switch (type & IRQ_TYPE_SENSE_MASK) {
+	case IRQ_TYPE_EDGE_RISING:
+		return rtd1625_gpio_irq_set_edge_type(d, 1);
+
+	case IRQ_TYPE_EDGE_FALLING:
+		return rtd1625_gpio_irq_set_edge_type(d, 0);
+
+	case IRQ_TYPE_EDGE_BOTH:
+		return rtd1625_gpio_irq_set_edge_type(d, 1);
+
+	case IRQ_TYPE_LEVEL_HIGH:
+		return rtd1625_gpio_irq_set_level_type(d, 0);
+
+	case IRQ_TYPE_LEVEL_LOW:
+		return rtd1625_gpio_irq_set_level_type(d, 1);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int rtd1625_gpio_irq_request_resources(struct irq_data *d)
+{
+	struct rtd1625_gpio *data = irq_data_get_irq_chip_data(d);
+
+	return gpio_regmap_reqres_irq(data->gpio_reg, d->hwirq);
+}
+
+static void rtd1625_gpio_irq_release_resources(struct irq_data *d)
+{
+	struct rtd1625_gpio *data = irq_data_get_irq_chip_data(d);
+
+	gpio_regmap_relres_irq(data->gpio_reg, d->hwirq);
+}
+
+static struct irq_chip rtd1625_iso_gpio_irq_chip = {
+	.name = "rtd1625-gpio",
+	.irq_ack = rtd1625_gpio_ack_irq,
+	.irq_mask = rtd1625_gpio_disable_irq,
+	.irq_unmask = rtd1625_gpio_enable_irq,
+	.irq_set_type = rtd1625_gpio_irq_set_type,
+	.flags = IRQCHIP_IMMUTABLE | IRQCHIP_SKIP_SET_WAKE,
+	.irq_request_resources = rtd1625_gpio_irq_request_resources,
+	.irq_release_resources = rtd1625_gpio_irq_release_resources,
+};
+
+static int rtd1625_gpio_setup_irq(struct platform_device *pdev, struct rtd1625_gpio *data)
+{
+	unsigned int num_irqs;
+	int irq;
+
+	irq = platform_get_irq_optional(pdev, 0);
+	if (irq == -ENXIO)
+		return 0;
+	if (irq < 0)
+		return irq;
+
+	num_irqs = (data->info->irq_type_support & IRQ_TYPE_LEVEL_MASK) ? 3 : 2;
+
+	for (unsigned int i = 0; i < num_irqs; i++) {
+		irq = platform_get_irq(pdev, i);
+		if (irq < 0)
+			return irq;
+
+		data->irqs[i] = irq;
+		irq_set_chained_handler_and_data(data->irqs[i], rtd1625_gpio_irq_handle, data);
+	}
+
+	return 0;
+}
+
+static int rtd1625_gpio_irq_map(struct irq_domain *domain, unsigned int irq,
+				irq_hw_number_t hwirq)
+{
+	struct rtd1625_gpio *data = domain->host_data;
+
+	irq_set_chip_data(irq, data);
+
+	irq_set_chip_and_handler(irq, &rtd1625_iso_gpio_irq_chip, handle_bad_irq);
+
+	irq_set_noprobe(irq);
+
+	irq_set_lockdep_class(irq, &rtd1625_gpio_irq_lock_class,
+			      &rtd1625_gpio_irq_request_class);
+
+	return 0;
+}
+
+static const struct irq_domain_ops rtd1625_gpio_irq_domain_ops = {
+	.map = rtd1625_gpio_irq_map,
+	.xlate = irq_domain_xlate_twocell,
+};
+
+static const struct regmap_config rtd1625_gpio_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+#ifndef CONFIG_DEBUG_GPIO
+	.disable_locking = true,
+#endif
+};
+
+static int rtd1625_gpio_probe(struct platform_device *pdev)
+{
+	struct gpio_regmap_config config = {};
+	struct device *dev = &pdev->dev;
+	struct gpio_regmap *gpio_reg;
+	struct rtd1625_gpio *data;
+	void __iomem *irq_base;
+	int ret;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->info = device_get_match_data(dev);
+	if (!data->info)
+		return -EINVAL;
+
+	irq_base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(irq_base))
+		return PTR_ERR(irq_base);
+
+	data->regmap = devm_regmap_init_mmio(dev, irq_base, &rtd1625_gpio_regmap_config);
+	if (IS_ERR(data->regmap))
+		return PTR_ERR(data->regmap);
+
+	raw_spin_lock_init(&data->lock);
+	platform_set_drvdata(pdev, data);
+
+	data->save_regs = devm_kcalloc(dev, data->info->num_gpios, sizeof(*data->save_regs),
+				       GFP_KERNEL);
+	if (!data->save_regs)
+		return -ENOMEM;
+
+	config.parent = dev;
+	config.regmap = data->regmap;
+	config.ngpio = data->info->num_gpios;
+	config.reg_dat_base = data->info->base_offset;
+	config.reg_set_base = data->info->base_offset;
+	config.reg_dir_out_base = data->info->base_offset;
+
+	config.reg_mask_xlate = rtd1625_reg_mask_xlate;
+	config.set_config = rtd1625_gpio_set_config;
+	config.value_xlate = rtd1625_value_xlate;
+
+	data->domain = irq_domain_create_linear(dev_fwnode(dev),
+						data->info->num_gpios,
+						&rtd1625_gpio_irq_domain_ops,
+						data);
+	if (!data->domain)
+		return -ENOMEM;
+
+	ret = devm_add_action_or_reset(dev, (void (*)(void *))irq_domain_remove, data->domain);
+	if (ret)
+		return ret;
+
+	ret = rtd1625_gpio_setup_irq(pdev, data);
+	if (ret)
+		return ret;
+
+	config.irq_domain = data->domain;
+	config.drvdata = data;
+
+	gpio_reg = devm_gpio_regmap_register(dev, &config);
+	if (IS_ERR(gpio_reg))
+		return PTR_ERR(gpio_reg);
+
+	data->gpio_reg = gpio_reg;
+
+	return 0;
+}
+
+static const struct rtd1625_gpio_info rtd1625_iso_gpio_info = {
+	.num_gpios        = 166,
+	.irq_type_support = IRQ_TYPE_EDGE_BOTH,
+	.base_offset      = 0x100,
+	.gpa_offset       = 0x000,
+	.gpda_offset      = 0x020,
+	.write_en_all     = RTD1625_ISO_GPIO_WREN_ALL,
+};
+
+static const struct rtd1625_gpio_info rtd1625_isom_gpio_info = {
+	.num_gpios        = 4,
+	.irq_type_support = IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_LEVEL_LOW |
+			    IRQ_TYPE_LEVEL_HIGH,
+	.base_offset      = 0x20,
+	.gpa_offset       = 0x00,
+	.gpda_offset      = 0x04,
+	.level_offset     = 0x18,
+	.write_en_all     = RTD1625_ISOM_GPIO_WREN_ALL,
+};
+
+static int rtd1625_gpio_suspend(struct device *dev)
+{
+	struct rtd1625_gpio *data = dev_get_drvdata(dev);
+	const struct rtd1625_gpio_info *info = data->info;
+	int ret;
+
+	for (unsigned int i = 0; i < info->num_gpios; i++) {
+		ret = regmap_read(data->regmap, data->info->base_offset + GPIO_CONTROL(i),
+				  &data->save_regs[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int rtd1625_gpio_resume(struct device *dev)
+{
+	struct rtd1625_gpio *data = dev_get_drvdata(dev);
+	const struct rtd1625_gpio_info *info = data->info;
+	int ret;
+
+	for (unsigned int i = 0; i < info->num_gpios; i++) {
+		ret = regmap_write(data->regmap, data->info->base_offset + GPIO_CONTROL(i),
+				   data->save_regs[i] | info->write_en_all);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static DEFINE_NOIRQ_DEV_PM_OPS(rtd1625_gpio_pm_ops, rtd1625_gpio_suspend, rtd1625_gpio_resume);
+
+static const struct of_device_id rtd1625_gpio_of_matches[] = {
+	{ .compatible = "realtek,rtd1625-iso-gpio", .data = &rtd1625_iso_gpio_info },
+	{ .compatible = "realtek,rtd1625-isom-gpio", .data = &rtd1625_isom_gpio_info },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, rtd1625_gpio_of_matches);
+
+static struct platform_driver rtd1625_gpio_platform_driver = {
+	.driver = {
+		.name = "gpio-rtd1625",
+		.of_match_table = rtd1625_gpio_of_matches,
+		.pm = pm_sleep_ptr(&rtd1625_gpio_pm_ops),
+	},
+	.probe = rtd1625_gpio_probe,
+};
+module_platform_driver(rtd1625_gpio_platform_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Realtek Semiconductor Corporation");
+MODULE_DESCRIPTION("Realtek DHC SoC RTD1625 gpio driver");
-- 
2.43.0


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

* Re: [PATCH v6 2/8] gpio: regmap: Provide default IRQ resource request and release callbacks
  2026-07-21  6:57 ` [PATCH v6 2/8] gpio: regmap: Provide default IRQ resource request and release callbacks Yu-Chun Lin
@ 2026-07-21  7:05   ` Michael Walle
  0 siblings, 0 replies; 25+ messages in thread
From: Michael Walle @ 2026-07-21  7:05 UTC (permalink / raw)
  To: Yu-Chun Lin, linusw, andriy.shevchenko, brgl, tychang, wbg,
	mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
	u.kleine-koenig, dakr, bhelgaas, o-takashi
  Cc: dlechner, linux-kernel, linux-gpio, linux, linux-iio, cy.huang,
	james.tai, Andy Shevchenko

[-- Attachment #1: Type: text/plain, Size: 649 bytes --]

On Tue Jul 21, 2026 at 8:57 AM CEST, Yu-Chun Lin wrote:
> From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>
> When GPIO regmap based driver supplies its own IRQ domain, it might
> still want to keep track of the IRQ requests and releases, in particular
> to prevent a GPIO, which is used and locked as IRQ, to be requested
> via standard ways. Provide default callbacks for such cases and keep
> struct gpio_chip private to GPIO regmap implementation.
>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>

Reviewed-by: Michael Walle <mwalle@kernel.org>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 297 bytes --]

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

* Re: [PATCH v6 3/8] gpio: regmap: Apply default resource callbacks for regmap IRQ chip
  2026-07-21  6:57 ` [PATCH v6 3/8] gpio: regmap: Apply default resource callbacks for regmap IRQ chip Yu-Chun Lin
@ 2026-07-21  7:07   ` Michael Walle
  0 siblings, 0 replies; 25+ messages in thread
From: Michael Walle @ 2026-07-21  7:07 UTC (permalink / raw)
  To: Yu-Chun Lin, linusw, andriy.shevchenko, brgl, tychang, wbg,
	mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
	u.kleine-koenig, dakr, bhelgaas, o-takashi
  Cc: dlechner, linux-kernel, linux-gpio, linux, linux-iio, cy.huang,
	james.tai, Andy Shevchenko

[-- Attachment #1: Type: text/plain, Size: 549 bytes --]

On Tue Jul 21, 2026 at 8:57 AM CEST, Yu-Chun Lin wrote:
> From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>
> When GPIO regmap creates an IRQ chip on behalf of the user, it also
> takes an ownership of the respective callbacks and driver data.
> With that being done, apply default resource callbacks that keep
> tracking the IRQ requests and releases.
>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>

Reviewed-by: Michael Walle <mwalle@kernel.org>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 297 bytes --]

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

* Re: [PATCH v6 4/8] gpio: regmap: Order kernel-doc descriptions with the actual appearance
  2026-07-21  6:57 ` [PATCH v6 4/8] gpio: regmap: Order kernel-doc descriptions with the actual appearance Yu-Chun Lin
@ 2026-07-21  7:07   ` Michael Walle
  2026-07-21 10:43   ` Andy Shevchenko
  1 sibling, 0 replies; 25+ messages in thread
From: Michael Walle @ 2026-07-21  7:07 UTC (permalink / raw)
  To: Yu-Chun Lin, linusw, andriy.shevchenko, brgl, tychang, wbg,
	mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
	u.kleine-koenig, dakr, bhelgaas, o-takashi
  Cc: dlechner, linux-kernel, linux-gpio, linux, linux-iio, cy.huang,
	james.tai, Andy Shevchenko

[-- Attachment #1: Type: text/plain, Size: 361 bytes --]

On Tue Jul 21, 2026 at 8:57 AM CEST, Yu-Chun Lin wrote:
> From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>
> Order kernel-doc descriptions with the actual appearance.
>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>

Reviewed-by: Michael Walle <mwalle@kernel.org>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 297 bytes --]

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

* Re: [PATCH v6 5/8] gpio: regmap: Add gpio_regmap_operation and value_xlate support
  2026-07-21  6:57 ` [PATCH v6 5/8] gpio: regmap: Add gpio_regmap_operation and value_xlate support Yu-Chun Lin
@ 2026-07-21  7:15   ` Michael Walle
  2026-07-21 10:34     ` Yu-Chun Lin [林祐君]
  2026-07-21 10:46   ` Andy Shevchenko
  1 sibling, 1 reply; 25+ messages in thread
From: Michael Walle @ 2026-07-21  7:15 UTC (permalink / raw)
  To: Yu-Chun Lin, linusw, andriy.shevchenko, brgl, tychang, wbg,
	mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
	u.kleine-koenig, dakr, bhelgaas, o-takashi
  Cc: dlechner, linux-kernel, linux-gpio, linux, linux-iio, cy.huang,
	james.tai

[-- Attachment #1: Type: text/plain, Size: 5298 bytes --]

Hi

Thanks! Looks very good, a few comments below.

On Tue Jul 21, 2026 at 8:57 AM CEST, Yu-Chun Lin wrote:
> Extend the reg_mask_xlate callback with an operation type parameter
> (enum gpio_regmap_operation) to allow drivers to return different
> register/mask combinations depending on the specific GPIO operation.
>
> In addition, introduce a new optional 'value_xlate' callback. This routine
> allows drivers to translate or modify the register value and mask
> immediately before a write operation. It is particularly useful for
> hardware that requires additional control bits, such as a write-enable bit,
> to be appended to the data dynamically.

Please split that into two patches.

> Consequently, update all existing drivers utilizing the gpio-regmap
> framework (across drivers/gpio, drivers/iio, and drivers/pinctrl)
> to accommodate the new reg_mask_xlate function signature.
>
> Suggested-by: Linus Walleij <linusw@kernel.org>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Remove removed the hardcoded write-enable workarounds.
> - Retain the necessary prototype updates in every driver using custom
> reg_mask_xlate
> - Add value_xlate to dynamically adjust the register mask and value right
> before the actual register write operation.
> ---
>  drivers/gpio/gpio-104-idi-48.c        |  7 +--
>  drivers/gpio/gpio-i8255.c             |  4 +-
>  drivers/gpio/gpio-idio-16.c           |  6 +--
>  drivers/gpio/gpio-max7360.c           |  1 +
>  drivers/gpio/gpio-pcie-idio-24.c      |  6 +--
>  drivers/gpio/gpio-regmap.c            | 62 ++++++++++++++++++++++-----
>  drivers/iio/adc/ad7173.c              |  8 ++--
>  drivers/iio/addac/stx104.c            |  6 +--
>  drivers/pinctrl/bcm/pinctrl-bcm63xx.c |  1 +
>  drivers/pinctrl/pinctrl-tps6594.c     |  1 +
>  include/linux/gpio/regmap.h           | 44 +++++++++++++++++--
>  11 files changed, 115 insertions(+), 31 deletions(-)
>

..

> diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h
> index a3ba8242c353..45a30f50043f 100644
> --- a/include/linux/gpio/regmap.h
> +++ b/include/linux/gpio/regmap.h
> @@ -13,6 +13,36 @@ struct regmap;
>  #define GPIO_REGMAP_ADDR_ZERO ((unsigned int)(-1))
>  #define GPIO_REGMAP_ADDR(addr) ((addr) ? : GPIO_REGMAP_ADDR_ZERO)
>  
> +/**
> + * enum gpio_regmap_operation - Operation type for reg_mask_xlate callback
> + *
> + * This enum is used to distinguish between different types of GPIO operations
> + * so that the reg_mask_xlate callback can return the appropriate mask for each
> + * operation type.

"Traditionally it was inferred from the base regsister. But that
might not always work, for example if all the control bits of one
GPIO lives in the same register. The user is free to choose which
method they'll use."

> + *
> + * Value operations:
> + * @GPIO_REGMAP_GET_OP: Mask for reading direction to detect if GPIO is input or output.
> + *                      Used in gpio_regmap_get() to determine the GPIO direction.
> + * @GPIO_REGMAP_IN: Mask for reading input value. Used when GPIO is configured as input.
> + * @GPIO_REGMAP_OUT: Mask for reading output value. Used when GPIO is configured as output.
> + *
> + * Output operations:
> + * @GPIO_REGMAP_SET_OP: Mask for setting GPIO output value.
> + *
> + * Direction operations:
> + * @GPIO_REGMAP_GET_DIR_OP: Mask for reading GPIO direction (input/output).
> + * @GPIO_REGMAP_SET_DIR_OP: Mask for setting GPIO direction (input/output).
> + *
> + */
> +enum gpio_regmap_operation {
> +	GPIO_REGMAP_GET_OP,
> +	GPIO_REGMAP_SET_OP,
> +	GPIO_REGMAP_GET_DIR_OP,
> +	GPIO_REGMAP_SET_DIR_OP,
> +	GPIO_REGMAP_IN,
> +	GPIO_REGMAP_OUT,
> +};
> +
>  /**
>   * struct gpio_regmap_config - Description of a generic regmap gpio_chip.
>   * @parent:		The parent device
> @@ -55,6 +85,10 @@ struct regmap;
>   *			is used.
>   * @init_valid_mask:	(Optional) Routine to initialize @valid_mask, to be used
>   *			if not all GPIOs are valid.
> + * @value_xlate:	(Optional) Routine to translate the register value and
> + *			mask before writing. This allows driver-specific logic
> + *			to append additional bits (like write-enable masks)
> + *			dynamically based on the current operation.
>   * @drvdata:		(Optional) Pointer to driver specific data which is
>   *			not used by gpio-remap but is provided "as is" to the
>   *			driver callback(s).
> @@ -104,14 +138,18 @@ struct gpio_regmap_config {
>  	unsigned long regmap_irq_flags;
>  #endif
>  
> -	int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int base,
> -			      unsigned int offset, unsigned int *reg,
> -			      unsigned int *mask);
> +	int (*reg_mask_xlate)(struct gpio_regmap *gpio, enum gpio_regmap_operation,
> +			      unsigned int base, unsigned int offset,
> +			      unsigned int *reg, unsigned int *mask);
>  
>  	int (*init_valid_mask)(struct gpio_chip *gc,
>  			       unsigned long *valid_mask,
>  			       unsigned int ngpios);
>  
> +	int (*value_xlate)(struct gpio_regmap *gpio, enum gpio_regmap_operation,
> +			   unsigned int base, unsigned int offset, unsigned int reg,
> +			   unsigned int *mask, unsigned int *val);
> +
>  	void *drvdata;
>  };
>  


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 297 bytes --]

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

* Re: [PATCH v6 6/8] gpio: regmap: Add set_config callback
  2026-07-21  6:58 ` [PATCH v6 6/8] gpio: regmap: Add set_config callback Yu-Chun Lin
@ 2026-07-21  7:23   ` Michael Walle
  2026-07-21 10:46     ` Yu-Chun Lin [林祐君]
  0 siblings, 1 reply; 25+ messages in thread
From: Michael Walle @ 2026-07-21  7:23 UTC (permalink / raw)
  To: Yu-Chun Lin, linusw, andriy.shevchenko, brgl, tychang, wbg,
	mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
	u.kleine-koenig, dakr, bhelgaas, o-takashi
  Cc: dlechner, linux-kernel, linux-gpio, linux, linux-iio, cy.huang,
	james.tai

[-- Attachment #1: Type: text/plain, Size: 2425 bytes --]

On Tue Jul 21, 2026 at 8:58 AM CEST, Yu-Chun Lin wrote:
> Add a new set_config callback to struct gpio_regmap_config to allow drivers
> to implement hardware-specific configuration such as debounce settings,
> or other platform-specific GPIO properties.
>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - None.
> ---
>  drivers/gpio/gpio-regmap.c  | 1 +
>  include/linux/gpio/regmap.h | 5 +++++
>  2 files changed, 6 insertions(+)
>
> diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
> index aecc35f610dd..b856326ff01c 100644
> --- a/drivers/gpio/gpio-regmap.c
> +++ b/drivers/gpio/gpio-regmap.c
> @@ -454,6 +454,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
>  		gpio->reg_mask_xlate = gpio_regmap_simple_xlate;
>  
>  	gpio->value_xlate = config->value_xlate;
> +	chip->set_config = config->set_config;
>  
>  	ret = gpiochip_add_data(chip, gpio);
>  	if (ret < 0)
> diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h
> index 45a30f50043f..23460995c1d1 100644
> --- a/include/linux/gpio/regmap.h
> +++ b/include/linux/gpio/regmap.h
> @@ -89,6 +89,9 @@ enum gpio_regmap_operation {
>   *			mask before writing. This allows driver-specific logic
>   *			to append additional bits (like write-enable masks)
>   *			dynamically based on the current operation.
> + * @set_config:		(Optional) Callback for setting GPIO configuration such
> + *			as debounce, drive strength, or other hardware specific
> + *			settings.
>   * @drvdata:		(Optional) Pointer to driver specific data which is
>   *			not used by gpio-remap but is provided "as is" to the
>   *			driver callback(s).
> @@ -150,6 +153,8 @@ struct gpio_regmap_config {
>  			   unsigned int base, unsigned int offset, unsigned int reg,
>  			   unsigned int *mask, unsigned int *val);
>  
> +	int (*set_config)(struct gpio_chip *gc, unsigned int offset, unsigned long config);
> +

Do we need an additional struct gpio_regmap pointer as a first
argument? How does the driver fetch the attached opaque data
pointer? I see that your driver is doing

 struct rtd1625_gpio *data = gpiochip_get_data(chip)

But it is the gpio-regmap core which will attach it's own data
pointer to gpio_chip, no?

-michael

>  	void *drvdata;
>  };
>  


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 297 bytes --]

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

* Re: [PATCH v6 7/8] gpio: regmap: Add IRQ enable/disable helpers
  2026-07-21  6:58 ` [PATCH v6 7/8] gpio: regmap: Add IRQ enable/disable helpers Yu-Chun Lin
@ 2026-07-21  7:24   ` Michael Walle
  2026-07-21 10:54   ` Andy Shevchenko
  1 sibling, 0 replies; 25+ messages in thread
From: Michael Walle @ 2026-07-21  7:24 UTC (permalink / raw)
  To: Yu-Chun Lin, linusw, andriy.shevchenko, brgl, tychang, wbg,
	mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
	u.kleine-koenig, dakr, bhelgaas, o-takashi
  Cc: dlechner, linux-kernel, linux-gpio, linux, linux-iio, cy.huang,
	james.tai, Andy Shevchenko

[-- Attachment #1: Type: text/plain, Size: 392 bytes --]

On Tue Jul 21, 2026 at 8:58 AM CEST, Yu-Chun Lin wrote:
> Add gpio_regmap_enable_irq() and gpio_regmap_disable_irq(). Since struct
> gpio_regmap is opaque, drivers cannot access the embedded gpio_chip directly.
>
> Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>

Reviewed-by: Michael Walle <mwalle@kernel.org>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 297 bytes --]

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

* RE: [PATCH v6 5/8] gpio: regmap: Add gpio_regmap_operation and value_xlate support
  2026-07-21  7:15   ` Michael Walle
@ 2026-07-21 10:34     ` Yu-Chun Lin [林祐君]
  0 siblings, 0 replies; 25+ messages in thread
From: Yu-Chun Lin [林祐君] @ 2026-07-21 10:34 UTC (permalink / raw)
  To: Michael Walle, linusw@kernel.org, andriy.shevchenko@intel.com,
	brgl@kernel.org, TY_Chang[張子逸],
	wbg@kernel.org, mathieu.dubois-briand@bootlin.com,
	nuno.sa@analog.com, Michael.Hennerich@analog.com,
	jic23@kernel.org, andy@kernel.org, u.kleine-koenig@baylibre.com,
	dakr@kernel.org, bhelgaas@google.com, o-takashi@sakamocchi.jp
  Cc: dlechner@baylibre.com, linux-kernel@vger.kernel.org,
	linux-gpio@vger.kernel.org, linux@analog.com,
	linux-iio@vger.kernel.org, CY_Huang[黃鉦晏],
	James Tai [戴志峰]

Hi Michael,

> Hi
>
> Thanks! Looks very good, a few comments below.
>
> On Tue Jul 21, 2026 at 8:57 AM CEST, Yu-Chun Lin wrote:
>> Extend the reg_mask_xlate callback with an operation type parameter 
>> (enum gpio_regmap_operation) to allow drivers to return different 
>> register/mask combinations depending on the specific GPIO operation.
>>
>> In addition, introduce a new optional 'value_xlate' callback. This 
>> routine allows drivers to translate or modify the register value and 
>> mask immediately before a write operation. It is particularly useful 
>> for hardware that requires additional control bits, such as a 
>> write-enable bit, to be appended to the data dynamically.
>
> Please split that into two patches.
>

I will split the value_xlate and reg_mask_xlate changes into separate
patches.

>> Consequently, update all existing drivers utilizing the gpio-regmap 
>> framework (across drivers/gpio, drivers/iio, and drivers/pinctrl) to 
>> accommodate the new reg_mask_xlate function signature.
>>
>> Suggested-by: Linus Walleij <linusw@kernel.org>
>> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
>> ---
>> Changes in v6:
>> - Remove removed the hardcoded write-enable workarounds.
>> - Retain the necessary prototype updates in every driver using custom 
>> reg_mask_xlate
>> - Add value_xlate to dynamically adjust the register mask and value 
>> right before the actual register write operation.
>> ---
>>  drivers/gpio/gpio-104-idi-48.c        |  7 +--
>>  drivers/gpio/gpio-i8255.c             |  4 +-
>>  drivers/gpio/gpio-idio-16.c           |  6 +--
>>  drivers/gpio/gpio-max7360.c           |  1 +
>>  drivers/gpio/gpio-pcie-idio-24.c      |  6 +--
>>  drivers/gpio/gpio-regmap.c            | 62 ++++++++++++++++++++++-----
>>  drivers/iio/adc/ad7173.c              |  8 ++--
>>  drivers/iio/addac/stx104.c            |  6 +--
>>  drivers/pinctrl/bcm/pinctrl-bcm63xx.c |  1 +
>>  drivers/pinctrl/pinctrl-tps6594.c     |  1 +
>>  include/linux/gpio/regmap.h           | 44 +++++++++++++++++--
>>  11 files changed, 115 insertions(+), 31 deletions(-)
>>
>
>..
>
>> diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h 
>> index a3ba8242c353..45a30f50043f 100644
>> --- a/include/linux/gpio/regmap.h
>> +++ b/include/linux/gpio/regmap.h
>> @@ -13,6 +13,36 @@ struct regmap;
>>  #define GPIO_REGMAP_ADDR_ZERO ((unsigned int)(-1))  #define 
>> GPIO_REGMAP_ADDR(addr) ((addr) ? : GPIO_REGMAP_ADDR_ZERO)
>>  
>> +/**
>> + * enum gpio_regmap_operation - Operation type for reg_mask_xlate 
>> +callback
>> + *
>> + * This enum is used to distinguish between different types of GPIO 
>> +operations
>> + * so that the reg_mask_xlate callback can return the appropriate 
>> +mask for each
>> + * operation type.
>
> "Traditionally it was inferred from the base regsister. But that might not
> always work, for example if all the control bits of one GPIO lives in the
> same register. The user is free to choose which method they'll use."
>

Understood. I will add this background context to the comment.

Best Regards,
Yu-Chun

>> + *
>> + * Value operations:
>> + * @GPIO_REGMAP_GET_OP: Mask for reading direction to detect if GPIO is input or output.
>> + *                      Used in gpio_regmap_get() to determine the GPIO direction.
>> + * @GPIO_REGMAP_IN: Mask for reading input value. Used when GPIO is configured as input.
>> + * @GPIO_REGMAP_OUT: Mask for reading output value. Used when GPIO is configured as output.
>> + *
>> + * Output operations:
>> + * @GPIO_REGMAP_SET_OP: Mask for setting GPIO output value.
>> + *
>> + * Direction operations:
>> + * @GPIO_REGMAP_GET_DIR_OP: Mask for reading GPIO direction (input/output).
>> + * @GPIO_REGMAP_SET_DIR_OP: Mask for setting GPIO direction (input/output).
>> + *
>> + */

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

* Re: [PATCH v6 1/8] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC"
  2026-07-21  6:57 ` [PATCH v6 1/8] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC" Yu-Chun Lin
@ 2026-07-21 10:39   ` Andy Shevchenko
  0 siblings, 0 replies; 25+ messages in thread
From: Andy Shevchenko @ 2026-07-21 10:39 UTC (permalink / raw)
  To: Yu-Chun Lin
  Cc: linusw, mwalle, brgl, tychang, wbg, mathieu.dubois-briand,
	nuno.sa, Michael.Hennerich, jic23, andy, u.kleine-koenig, dakr,
	bhelgaas, o-takashi, dlechner, linux-kernel, linux-gpio, linux,
	linux-iio, cy.huang, james.tai

On Tue, Jul 21, 2026 at 02:57:55PM +0800, Yu-Chun Lin wrote:
> This reverts commit a57e27c43b0315ee86c6896510d69be5257e093e.
> 
> The driver will be rewritten to use the gpio-regmap infrastructure
> once Andy Shevchenko's patches for gpio-regmap are applied.

Acked-by: Andy Shevchenko <andriy.shevchenko@intel.com>

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v6 4/8] gpio: regmap: Order kernel-doc descriptions with the actual appearance
  2026-07-21  6:57 ` [PATCH v6 4/8] gpio: regmap: Order kernel-doc descriptions with the actual appearance Yu-Chun Lin
  2026-07-21  7:07   ` Michael Walle
@ 2026-07-21 10:43   ` Andy Shevchenko
  1 sibling, 0 replies; 25+ messages in thread
From: Andy Shevchenko @ 2026-07-21 10:43 UTC (permalink / raw)
  To: Yu-Chun Lin
  Cc: linusw, mwalle, brgl, tychang, wbg, mathieu.dubois-briand,
	nuno.sa, Michael.Hennerich, jic23, andy, u.kleine-koenig, dakr,
	bhelgaas, o-takashi, dlechner, linux-kernel, linux-gpio, linux,
	linux-iio, cy.huang, james.tai

On Tue, Jul 21, 2026 at 02:57:58PM +0800, Yu-Chun Lin wrote:

> Order kernel-doc descriptions with the actual appearance.

...

> + * @reg_mask_xlate:     (Optional) Translates base address and GPIO

This thous be tab (no need to resend just for this, perhaps Bart can tweak it).

> + *			offset to a register/bitmask pair. If not
> + *			given the default gpio_regmap_simple_xlate()
> + *			is used.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v6 5/8] gpio: regmap: Add gpio_regmap_operation and value_xlate support
  2026-07-21  6:57 ` [PATCH v6 5/8] gpio: regmap: Add gpio_regmap_operation and value_xlate support Yu-Chun Lin
  2026-07-21  7:15   ` Michael Walle
@ 2026-07-21 10:46   ` Andy Shevchenko
  1 sibling, 0 replies; 25+ messages in thread
From: Andy Shevchenko @ 2026-07-21 10:46 UTC (permalink / raw)
  To: Yu-Chun Lin
  Cc: linusw, mwalle, brgl, tychang, wbg, mathieu.dubois-briand,
	nuno.sa, Michael.Hennerich, jic23, andy, u.kleine-koenig, dakr,
	bhelgaas, o-takashi, dlechner, linux-kernel, linux-gpio, linux,
	linux-iio, cy.huang, james.tai

On Tue, Jul 21, 2026 at 02:57:59PM +0800, Yu-Chun Lin wrote:
> Extend the reg_mask_xlate callback with an operation type parameter
> (enum gpio_regmap_operation) to allow drivers to return different
> register/mask combinations depending on the specific GPIO operation.
> 
> In addition, introduce a new optional 'value_xlate' callback. This routine
> allows drivers to translate or modify the register value and mask
> immediately before a write operation. It is particularly useful for
> hardware that requires additional control bits, such as a write-enable bit,
> to be appended to the data dynamically.
> 
> Consequently, update all existing drivers utilizing the gpio-regmap
> framework (across drivers/gpio, drivers/iio, and drivers/pinctrl)
> to accommodate the new reg_mask_xlate function signature.

...

> +/**
> + * enum gpio_regmap_operation - Operation type for reg_mask_xlate callback
> + *
> + * This enum is used to distinguish between different types of GPIO operations
> + * so that the reg_mask_xlate callback can return the appropriate mask for each
> + * operation type.
> + *
> + * Value operations:
> + * @GPIO_REGMAP_GET_OP: Mask for reading direction to detect if GPIO is input or output.
> + *                      Used in gpio_regmap_get() to determine the GPIO direction.
> + * @GPIO_REGMAP_IN: Mask for reading input value. Used when GPIO is configured as input.
> + * @GPIO_REGMAP_OUT: Mask for reading output value. Used when GPIO is configured as output.
> + *
> + * Output operations:
> + * @GPIO_REGMAP_SET_OP: Mask for setting GPIO output value.
> + *
> + * Direction operations:
> + * @GPIO_REGMAP_GET_DIR_OP: Mask for reading GPIO direction (input/output).
> + * @GPIO_REGMAP_SET_DIR_OP: Mask for setting GPIO direction (input/output).

> + *

Unneeded blank line. Also not the big deal. Update only if new version is needed.

> + */
> +enum gpio_regmap_operation {
> +	GPIO_REGMAP_GET_OP,
> +	GPIO_REGMAP_SET_OP,
> +	GPIO_REGMAP_GET_DIR_OP,
> +	GPIO_REGMAP_SET_DIR_OP,
> +	GPIO_REGMAP_IN,
> +	GPIO_REGMAP_OUT,
> +};

-- 
With Best Regards,
Andy Shevchenko



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

* RE: [PATCH v6 6/8] gpio: regmap: Add set_config callback
  2026-07-21  7:23   ` Michael Walle
@ 2026-07-21 10:46     ` Yu-Chun Lin [林祐君]
  2026-07-21 11:18       ` Michael Walle
  0 siblings, 1 reply; 25+ messages in thread
From: Yu-Chun Lin [林祐君] @ 2026-07-21 10:46 UTC (permalink / raw)
  To: Michael Walle, linusw@kernel.org, andriy.shevchenko@intel.com,
	brgl@kernel.org, TY_Chang[張子逸],
	wbg@kernel.org, mathieu.dubois-briand@bootlin.com,
	nuno.sa@analog.com, Michael.Hennerich@analog.com,
	jic23@kernel.org, andy@kernel.org, u.kleine-koenig@baylibre.com,
	dakr@kernel.org, bhelgaas@google.com, o-takashi@sakamocchi.jp
  Cc: dlechner@baylibre.com, linux-kernel@vger.kernel.org,
	linux-gpio@vger.kernel.org, linux@analog.com,
	linux-iio@vger.kernel.org, CY_Huang[黃鉦晏],
	James Tai [戴志峰]

Hi Michael,

>On Tue Jul 21, 2026 at 8:58 AM CEST, Yu-Chun Lin wrote:

(...)

>> diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h 
>> index 45a30f50043f..23460995c1d1 100644
>> --- a/include/linux/gpio/regmap.h
>> +++ b/include/linux/gpio/regmap.h
>> @@ -89,6 +89,9 @@ enum gpio_regmap_operation {
>>   *			mask before writing. This allows driver-specific logic
>>   *			to append additional bits (like write-enable masks)
>>   *			dynamically based on the current operation.
>> + * @set_config:		(Optional) Callback for setting GPIO configuration such
>> + *			as debounce, drive strength, or other hardware specific
>> + *			settings.
>>   * @drvdata:		(Optional) Pointer to driver specific data which is
>>   *			not used by gpio-remap but is provided "as is" to the
>>   *			driver callback(s).
>> @@ -150,6 +153,8 @@ struct gpio_regmap_config {
>>  			   unsigned int base, unsigned int offset, unsigned int reg,
>>  			   unsigned int *mask, unsigned int *val);
>>  
>> +	int (*set_config)(struct gpio_chip *gc, unsigned int offset, 
>> +unsigned long config);
>> +
>
> Do we need an additional struct gpio_regmap pointer as a first argument? How
> does the driver fetch the attached opaque data pointer? I see that your driver is doing
>
> struct rtd1625_gpio *data = gpiochip_get_data(chip)
>
> But it is the gpio-regmap core which will attach it's own data pointer to gpio_chip, no?
>
> -michael

You are right. I mistakenly used gpiochip_get_data() here.

My current plan to fix this is:
The set_config callback in 'struct gpio_regmap_config' and 'struct gpio_regmap'
should take 'struct gpio_regmap *' as the first argument (replacing
'struct gpio_chip *'), and the driver should use 'gpio_regmap_get_drvdata()'
to retrieve its own data pointer.

I'll add a wrapper in gpio-regmap.c that bridges gpio_chip to gpio_regmap and
handles the fallback to gpiochip_generic_config().

Best Regards,
Yu-Chun

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

* Re: [PATCH v6 7/8] gpio: regmap: Add IRQ enable/disable helpers
  2026-07-21  6:58 ` [PATCH v6 7/8] gpio: regmap: Add IRQ enable/disable helpers Yu-Chun Lin
  2026-07-21  7:24   ` Michael Walle
@ 2026-07-21 10:54   ` Andy Shevchenko
  1 sibling, 0 replies; 25+ messages in thread
From: Andy Shevchenko @ 2026-07-21 10:54 UTC (permalink / raw)
  To: Yu-Chun Lin
  Cc: linusw, mwalle, brgl, tychang, wbg, mathieu.dubois-briand,
	nuno.sa, Michael.Hennerich, jic23, andy, u.kleine-koenig, dakr,
	bhelgaas, o-takashi, dlechner, linux-kernel, linux-gpio, linux,
	linux-iio, cy.huang, james.tai

On Tue, Jul 21, 2026 at 02:58:01PM +0800, Yu-Chun Lin wrote:
> Add gpio_regmap_enable_irq() and gpio_regmap_disable_irq(). Since struct
> gpio_regmap is opaque, drivers cannot access the embedded gpio_chip directly.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v6 8/8] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC
  2026-07-21  6:58 ` [PATCH v6 8/8] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC Yu-Chun Lin
@ 2026-07-21 11:12   ` Andy Shevchenko
  2026-07-21 12:09     ` Yu-Chun Lin [林祐君]
  0 siblings, 1 reply; 25+ messages in thread
From: Andy Shevchenko @ 2026-07-21 11:12 UTC (permalink / raw)
  To: Yu-Chun Lin
  Cc: linusw, mwalle, brgl, tychang, wbg, mathieu.dubois-briand,
	nuno.sa, Michael.Hennerich, jic23, andy, u.kleine-koenig, dakr,
	bhelgaas, o-takashi, dlechner, linux-kernel, linux-gpio, linux,
	linux-iio, cy.huang, james.tai

On Tue, Jul 21, 2026 at 02:58:02PM +0800, Yu-Chun Lin wrote:

> Add support for the GPIO controller found on Realtek DHC RTD1625 SoCs.
> 
> Unlike the existing Realtek GPIO driver (drivers/gpio/gpio-rtd.c),
> which manages pins via shared bank registers, the RTD1625 introduces
> a per-pin register architecture. Each GPIO line now has its own
> dedicated 32-bit control register to manage configuration independently,
> including direction, output value, input value, interrupt enable, and
> debounce. Therefore, this distinct hardware design requires a separate
> driver.
> 
> The RTD1625 GPIO controller has a hardware quirk where both 'assert'
> and 'de-assert' interrupts are fired simultaneously on any edge toggle.
> The driver works around this quirk to correctly handle edge interrupts.
> 
> Interrupt support is optional for this device, matching the dt-bindings.
> If the interrupts property is not provided, the driver simply skips IRQ
> initialization and operates purely as a basic GPIO controller.

...

> +struct rtd1625_gpio_info {
> +	unsigned int num_gpios;

Do you need this? Isn't it available via struct gpio_chip?

> +	unsigned int irq_type_support;
> +	unsigned int base_offset;
> +	unsigned int gpa_offset;
> +	unsigned int gpda_offset;
> +	unsigned int level_offset;
> +	unsigned int write_en_all;
> +};

...

> +static int rtd1625_reg_mask_xlate(struct gpio_regmap *gpio, enum gpio_regmap_operation op,
> +				  unsigned int base, unsigned int offset, unsigned int *reg,
> +				  unsigned int *mask)
> +{
> +	/* Each GPIO has its own dedicated 32-bit register */
> +	*reg = base + offset * 4;
> +
> +	switch (op) {
> +	case GPIO_REGMAP_IN:
> +		*mask = RTD1625_GPIO_IN;
> +		break;
> +
> +	case GPIO_REGMAP_OUT:
> +		*mask = RTD1625_GPIO_OUT;
> +		break;
> +
> +	case GPIO_REGMAP_SET_OP:
> +		*mask = RTD1625_GPIO_OUT;
> +		break;
> +
> +	case GPIO_REGMAP_GET_OP:
> +	case GPIO_REGMAP_GET_DIR_OP:
> +	case GPIO_REGMAP_SET_DIR_OP:
> +		*mask = RTD1625_GPIO_DIR;
> +		break;
> +
> +	default:
> +		return -ENOTSUPP;
> +	}

> +
> +	return 0;

Just spread this to each case by replacing break:s.

> +}
> +
> +static int rtd1625_value_xlate(struct gpio_regmap *gpio,
> +			       enum gpio_regmap_operation op,
> +			       unsigned int base, unsigned int offset,
> +			       unsigned int reg, unsigned int *mask,
> +			       unsigned int *val)
> +{
> +	switch (op) {
> +	case GPIO_REGMAP_SET_OP:
> +		*val |= RTD1625_GPIO_WREN(RTD1625_GPIO_OUT);
> +		*mask |= RTD1625_GPIO_WREN(RTD1625_GPIO_OUT);
> +		break;
> +
> +	case GPIO_REGMAP_SET_DIR_OP:
> +		*val |= RTD1625_GPIO_WREN(RTD1625_GPIO_DIR);
> +		*mask |= RTD1625_GPIO_WREN(RTD1625_GPIO_DIR);
> +		break;
> +
> +	default:
> +		return -ENOTSUPP;
> +	}
> +
> +	return 0;

Ditto.

> +}

...

> +static int rtd1625_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
> +				     unsigned int debounce)
> +{
> +	struct rtd1625_gpio *data = gpiochip_get_data(chip);
> +	u8 deb_val;
> +	u32 val;
> +	int ret;
> +
> +	switch (debounce) {
> +	case 1:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_1US;
> +		break;
> +	case 10:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_10US;
> +		break;
> +	case 100:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_100US;
> +		break;
> +	case 1000:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_1MS;
> +		break;
> +	case 10000:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_10MS;
> +		break;
> +	case 20000:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_20MS;
> +		break;
> +	case 30000:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_30MS;
> +		break;
> +	case 50000:
> +		deb_val = RTD1625_GPIO_DEBOUNCE_50MS;
> +		break;
> +	default:
> +		return -ENOTSUPP;
> +	}

> +	val = FIELD_PREP(RTD1625_GPIO_DEBOUNCE, deb_val) | RTD1625_GPIO_DEBOUNCE_WREN;
> +
> +	scoped_guard(raw_spinlock_irqsave, &data->lock)
> +		ret = regmap_write(data->regmap, data->info->base_offset + GPIO_CONTROL(offset),
> +				   val);
> +
> +	return ret;

guard()() is fine here.

	val = FIELD_PREP(RTD1625_GPIO_DEBOUNCE, deb_val) | RTD1625_GPIO_DEBOUNCE_WREN;

	guard(raw_spinlock_irqsave)(&data->lock);

	return regmap_write(data->regmap, data->info->base_offset + GPIO_CONTROL(offset), val);

> +}

...

> +static int rtd1625_gpio_irq_set_level_type(struct irq_data *d, bool level)
> +{
> +	u32 val = RTD1625_GPIO_WREN(RTD1625_GPIO_LEVEL_INT_DP);
> +	irq_hw_number_t hwirq = irqd_to_hwirq(d);
> +	struct rtd1625_gpio *data;
> +	int ret;
> +
> +	data = irq_data_get_irq_chip_data(d);
> +	if (!(data->info->irq_type_support & IRQ_TYPE_LEVEL_MASK))
> +		return -EINVAL;
> +
> +	if (level)
> +		val |= RTD1625_GPIO_LEVEL_INT_DP;

> +	scoped_guard(raw_spinlock_irqsave, &data->lock)
> +		ret = regmap_write(data->regmap, data->info->base_offset + GPIO_CONTROL(hwirq), val);
> +
> +	if (ret)
> +		return ret;

Better to move it inside the scoped_guard() loop.

> +	irq_set_handler_locked(d, handle_level_irq);
> +
> +	return 0;
> +}

...

> +static int rtd1625_gpio_setup_irq(struct platform_device *pdev, struct rtd1625_gpio *data)
> +{
> +	unsigned int num_irqs;
> +	int irq;
> +
> +	irq = platform_get_irq_optional(pdev, 0);

Perhaps a comment to explain that IRQ is (fully) optional?

> +	if (irq == -ENXIO)
> +		return 0;
> +	if (irq < 0)
> +		return irq;
> +
> +	num_irqs = (data->info->irq_type_support & IRQ_TYPE_LEVEL_MASK) ? 3 : 2;
> +
> +	for (unsigned int i = 0; i < num_irqs; i++) {
> +		irq = platform_get_irq(pdev, i);
> +		if (irq < 0)
> +			return irq;
> +
> +		data->irqs[i] = irq;
> +		irq_set_chained_handler_and_data(data->irqs[i], rtd1625_gpio_irq_handle, data);
> +	}
> +
> +	return 0;
> +}

...

> +static int rtd1625_gpio_probe(struct platform_device *pdev)
> +{
> +	struct gpio_regmap_config config = {};
> +	struct device *dev = &pdev->dev;
> +	struct gpio_regmap *gpio_reg;
> +	struct rtd1625_gpio *data;
> +	void __iomem *irq_base;
> +	int ret;
> +
> +	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	data->info = device_get_match_data(dev);
> +	if (!data->info)
> +		return -EINVAL;

-ENODATA

> +	irq_base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(irq_base))
> +		return PTR_ERR(irq_base);
> +
> +	data->regmap = devm_regmap_init_mmio(dev, irq_base, &rtd1625_gpio_regmap_config);
> +	if (IS_ERR(data->regmap))
> +		return PTR_ERR(data->regmap);
> +
> +	raw_spin_lock_init(&data->lock);
> +	platform_set_drvdata(pdev, data);
> +
> +	data->save_regs = devm_kcalloc(dev, data->info->num_gpios, sizeof(*data->save_regs),
> +				       GFP_KERNEL);
> +	if (!data->save_regs)
> +		return -ENOMEM;
> +
> +	config.parent = dev;
> +	config.regmap = data->regmap;
> +	config.ngpio = data->info->num_gpios;
> +	config.reg_dat_base = data->info->base_offset;
> +	config.reg_set_base = data->info->base_offset;
> +	config.reg_dir_out_base = data->info->base_offset;
> +
> +	config.reg_mask_xlate = rtd1625_reg_mask_xlate;
> +	config.set_config = rtd1625_gpio_set_config;
> +	config.value_xlate = rtd1625_value_xlate;
> +
> +	data->domain = irq_domain_create_linear(dev_fwnode(dev),
> +						data->info->num_gpios,
> +						&rtd1625_gpio_irq_domain_ops,
> +						data);
> +	if (!data->domain)
> +		return -ENOMEM;


devm_irq_domain_instantiate()

> +	ret = devm_add_action_or_reset(dev, (void (*)(void *))irq_domain_remove, data->domain);
> +	if (ret)
> +		return ret;
> +
> +	ret = rtd1625_gpio_setup_irq(pdev, data);
> +	if (ret)
> +		return ret;
> +
> +	config.irq_domain = data->domain;
> +	config.drvdata = data;
> +
> +	gpio_reg = devm_gpio_regmap_register(dev, &config);
> +	if (IS_ERR(gpio_reg))
> +		return PTR_ERR(gpio_reg);
> +
> +	data->gpio_reg = gpio_reg;
> +
> +	return 0;
> +}

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v6 6/8] gpio: regmap: Add set_config callback
  2026-07-21 10:46     ` Yu-Chun Lin [林祐君]
@ 2026-07-21 11:18       ` Michael Walle
  2026-07-21 12:10         ` Yu-Chun Lin [林祐君]
  0 siblings, 1 reply; 25+ messages in thread
From: Michael Walle @ 2026-07-21 11:18 UTC (permalink / raw)
  To: Yu-Chun Lin [林祐君], linusw@kernel.org,
	andriy.shevchenko@intel.com, brgl@kernel.org,
	TY_Chang[張子逸], wbg@kernel.org,
	mathieu.dubois-briand@bootlin.com, nuno.sa@analog.com,
	Michael.Hennerich@analog.com, jic23@kernel.org, andy@kernel.org,
	u.kleine-koenig@baylibre.com, dakr@kernel.org,
	bhelgaas@google.com, o-takashi@sakamocchi.jp
  Cc: dlechner@baylibre.com, linux-kernel@vger.kernel.org,
	linux-gpio@vger.kernel.org, linux@analog.com,
	linux-iio@vger.kernel.org, CY_Huang[黃鉦晏],
	James Tai [戴志峰]

[-- Attachment #1: Type: text/plain, Size: 2341 bytes --]

On Tue Jul 21, 2026 at 12:46 PM CEST, Yu-Chun Lin [林祐君] wrote:
> Hi Michael,
>
>>On Tue Jul 21, 2026 at 8:58 AM CEST, Yu-Chun Lin wrote:
>
> (...)
>
>>> diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h 
>>> index 45a30f50043f..23460995c1d1 100644
>>> --- a/include/linux/gpio/regmap.h
>>> +++ b/include/linux/gpio/regmap.h
>>> @@ -89,6 +89,9 @@ enum gpio_regmap_operation {
>>>   *			mask before writing. This allows driver-specific logic
>>>   *			to append additional bits (like write-enable masks)
>>>   *			dynamically based on the current operation.
>>> + * @set_config:		(Optional) Callback for setting GPIO configuration such
>>> + *			as debounce, drive strength, or other hardware specific
>>> + *			settings.
>>>   * @drvdata:		(Optional) Pointer to driver specific data which is
>>>   *			not used by gpio-remap but is provided "as is" to the
>>>   *			driver callback(s).
>>> @@ -150,6 +153,8 @@ struct gpio_regmap_config {
>>>  			   unsigned int base, unsigned int offset, unsigned int reg,
>>>  			   unsigned int *mask, unsigned int *val);
>>>  
>>> +	int (*set_config)(struct gpio_chip *gc, unsigned int offset, 
>>> +unsigned long config);
>>> +
>>
>> Do we need an additional struct gpio_regmap pointer as a first argument? How
>> does the driver fetch the attached opaque data pointer? I see that your driver is doing
>>
>> struct rtd1625_gpio *data = gpiochip_get_data(chip)
>>
>> But it is the gpio-regmap core which will attach it's own data pointer to gpio_chip, no?
>>
>> -michael
>
> You are right. I mistakenly used gpiochip_get_data() here.
>
> My current plan to fix this is:
> The set_config callback in 'struct gpio_regmap_config' and 'struct gpio_regmap'
> should take 'struct gpio_regmap *' as the first argument (replacing
> 'struct gpio_chip *'), and the driver should use 'gpio_regmap_get_drvdata()'
> to retrieve its own data pointer.

You also probably need the struct gpio_chip, to maybe call into the
gpio core, no?

If so, what about

int (*set_config)(struct gpio_regmap *gpio, struct gpio_chip *gc,
                  unsigned int offset, unsigned long config)

> I'll add a wrapper in gpio-regmap.c that bridges gpio_chip to gpio_regmap and
> handles the fallback to gpiochip_generic_config().

Yes.

-michael

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 297 bytes --]

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

* RE: [PATCH v6 8/8] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC
  2026-07-21 11:12   ` Andy Shevchenko
@ 2026-07-21 12:09     ` Yu-Chun Lin [林祐君]
  0 siblings, 0 replies; 25+ messages in thread
From: Yu-Chun Lin [林祐君] @ 2026-07-21 12:09 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: linusw@kernel.org, mwalle@kernel.org, brgl@kernel.org,
	TY_Chang[張子逸], wbg@kernel.org,
	mathieu.dubois-briand@bootlin.com, nuno.sa@analog.com,
	Michael.Hennerich@analog.com, jic23@kernel.org, andy@kernel.org,
	u.kleine-koenig@baylibre.com, dakr@kernel.org,
	bhelgaas@google.com, o-takashi@sakamocchi.jp,
	dlechner@baylibre.com, linux-kernel@vger.kernel.org,
	linux-gpio@vger.kernel.org, linux@analog.com,
	linux-iio@vger.kernel.org, CY_Huang[黃鉦晏],
	James Tai [戴志峰]

Hi Andy,
Thanks for your feedback.

> On Tue, Jul 21, 2026 at 02:58:02PM +0800, Yu-Chun Lin wrote:
> 
> > Add support for the GPIO controller found on Realtek DHC RTD1625 SoCs.
> >
> > Unlike the existing Realtek GPIO driver (drivers/gpio/gpio-rtd.c),
> > which manages pins via shared bank registers, the RTD1625 introduces a
> > per-pin register architecture. Each GPIO line now has its own
> > dedicated 32-bit control register to manage configuration
> > independently, including direction, output value, input value,
> > interrupt enable, and debounce. Therefore, this distinct hardware
> > design requires a separate driver.
> >
> > The RTD1625 GPIO controller has a hardware quirk where both 'assert'
> > and 'de-assert' interrupts are fired simultaneously on any edge toggle.
> > The driver works around this quirk to correctly handle edge interrupts.
> >
> > Interrupt support is optional for this device, matching the dt-bindings.
> > If the interrupts property is not provided, the driver simply skips
> > IRQ initialization and operates purely as a basic GPIO controller.
> 
> ...
> 
> > +struct rtd1625_gpio_info {
> > +     unsigned int num_gpios;
> 
> Do you need this? Isn't it available via struct gpio_chip?
> 

I need num_gpios here because I need to know the number of GPIOs before the
gpio_chip is registered.

> > +     unsigned int irq_type_support;
> > +     unsigned int base_offset;
> > +     unsigned int gpa_offset;
> > +     unsigned int gpda_offset;
> > +     unsigned int level_offset;
> > +     unsigned int write_en_all;
> > +};
> 
> ...
> 
> > +static int rtd1625_reg_mask_xlate(struct gpio_regmap *gpio, enum
> gpio_regmap_operation op,
> > +                               unsigned int base, unsigned int offset,
> unsigned int *reg,
> > +                               unsigned int *mask) {
> > +     /* Each GPIO has its own dedicated 32-bit register */
> > +     *reg = base + offset * 4;
> > +
> > +     switch (op) {
> > +     case GPIO_REGMAP_IN:
> > +             *mask = RTD1625_GPIO_IN;
> > +             break;
> > +
> > +     case GPIO_REGMAP_OUT:
> > +             *mask = RTD1625_GPIO_OUT;
> > +             break;
> > +
> > +     case GPIO_REGMAP_SET_OP:
> > +             *mask = RTD1625_GPIO_OUT;
> > +             break;
> > +
> > +     case GPIO_REGMAP_GET_OP:
> > +     case GPIO_REGMAP_GET_DIR_OP:
> > +     case GPIO_REGMAP_SET_DIR_OP:
> > +             *mask = RTD1625_GPIO_DIR;
> > +             break;
> > +
> > +     default:
> > +             return -ENOTSUPP;
> > +     }
> 
> > +
> > +     return 0;
> 
> Just spread this to each case by replacing break:s.
> 

Ack.

> > +}
> > +
> > +static int rtd1625_value_xlate(struct gpio_regmap *gpio,
> > +                            enum gpio_regmap_operation op,
> > +                            unsigned int base, unsigned int offset,
> > +                            unsigned int reg, unsigned int *mask,
> > +                            unsigned int *val) {
> > +     switch (op) {
> > +     case GPIO_REGMAP_SET_OP:
> > +             *val |= RTD1625_GPIO_WREN(RTD1625_GPIO_OUT);
> > +             *mask |= RTD1625_GPIO_WREN(RTD1625_GPIO_OUT);
> > +             break;
> > +
> > +     case GPIO_REGMAP_SET_DIR_OP:
> > +             *val |= RTD1625_GPIO_WREN(RTD1625_GPIO_DIR);
> > +             *mask |= RTD1625_GPIO_WREN(RTD1625_GPIO_DIR);
> > +             break;
> > +
> > +     default:
> > +             return -ENOTSUPP;
> > +     }
> > +
> > +     return 0;
> 
> Ditto.
> 

Ack.

> > +}
> 
> ...
> 
> > +static int rtd1625_gpio_set_debounce(struct gpio_chip *chip, unsigned int
> offset,
> > +                                  unsigned int debounce) {
> > +     struct rtd1625_gpio *data = gpiochip_get_data(chip);
> > +     u8 deb_val;
> > +     u32 val;
> > +     int ret;
> > +
> > +     switch (debounce) {
> > +     case 1:
> > +             deb_val = RTD1625_GPIO_DEBOUNCE_1US;
> > +             break;
> > +     case 10:
> > +             deb_val = RTD1625_GPIO_DEBOUNCE_10US;
> > +             break;
> > +     case 100:
> > +             deb_val = RTD1625_GPIO_DEBOUNCE_100US;
> > +             break;
> > +     case 1000:
> > +             deb_val = RTD1625_GPIO_DEBOUNCE_1MS;
> > +             break;
> > +     case 10000:
> > +             deb_val = RTD1625_GPIO_DEBOUNCE_10MS;
> > +             break;
> > +     case 20000:
> > +             deb_val = RTD1625_GPIO_DEBOUNCE_20MS;
> > +             break;
> > +     case 30000:
> > +             deb_val = RTD1625_GPIO_DEBOUNCE_30MS;
> > +             break;
> > +     case 50000:
> > +             deb_val = RTD1625_GPIO_DEBOUNCE_50MS;
> > +             break;
> > +     default:
> > +             return -ENOTSUPP;
> > +     }
> 
> > +     val = FIELD_PREP(RTD1625_GPIO_DEBOUNCE, deb_val) |
> > + RTD1625_GPIO_DEBOUNCE_WREN;
> > +
> > +     scoped_guard(raw_spinlock_irqsave, &data->lock)
> > +             ret = regmap_write(data->regmap, data->info->base_offset
> + GPIO_CONTROL(offset),
> > +                                val);
> > +
> > +     return ret;
> 
> guard()() is fine here.
> 
>         val = FIELD_PREP(RTD1625_GPIO_DEBOUNCE, deb_val) |
> RTD1625_GPIO_DEBOUNCE_WREN;
> 
>         guard(raw_spinlock_irqsave)(&data->lock);
> 
>         return regmap_write(data->regmap, data->info->base_offset +
> GPIO_CONTROL(offset), val);
> 

Ack.

> > +}
> 
> ...
> 
> > +static int rtd1625_gpio_irq_set_level_type(struct irq_data *d, bool
> > +level) {
> > +     u32 val = RTD1625_GPIO_WREN(RTD1625_GPIO_LEVEL_INT_DP);
> > +     irq_hw_number_t hwirq = irqd_to_hwirq(d);
> > +     struct rtd1625_gpio *data;
> > +     int ret;
> > +
> > +     data = irq_data_get_irq_chip_data(d);
> > +     if (!(data->info->irq_type_support & IRQ_TYPE_LEVEL_MASK))
> > +             return -EINVAL;
> > +
> > +     if (level)
> > +             val |= RTD1625_GPIO_LEVEL_INT_DP;
> 
> > +     scoped_guard(raw_spinlock_irqsave, &data->lock)
> > +             ret = regmap_write(data->regmap, data->info->base_offset
> > + + GPIO_CONTROL(hwirq), val);
> > +
> > +     if (ret)
> > +             return ret;
> 
> Better to move it inside the scoped_guard() loop.
> 

Ack.

> > +     irq_set_handler_locked(d, handle_level_irq);
> > +
> > +     return 0;
> > +}
> 
> ...
> 
> > +static int rtd1625_gpio_setup_irq(struct platform_device *pdev,
> > +struct rtd1625_gpio *data) {
> > +     unsigned int num_irqs;
> > +     int irq;
> > +
> > +     irq = platform_get_irq_optional(pdev, 0);
> 
> Perhaps a comment to explain that IRQ is (fully) optional?
> 

Ack.

> > +     if (irq == -ENXIO)
> > +             return 0;
> > +     if (irq < 0)
> > +             return irq;
> > +
> > +     num_irqs = (data->info->irq_type_support &
> IRQ_TYPE_LEVEL_MASK)
> > + ? 3 : 2;
> > +
> > +     for (unsigned int i = 0; i < num_irqs; i++) {
> > +             irq = platform_get_irq(pdev, i);
> > +             if (irq < 0)
> > +                     return irq;
> > +
> > +             data->irqs[i] = irq;
> > +             irq_set_chained_handler_and_data(data->irqs[i],
> rtd1625_gpio_irq_handle, data);
> > +     }
> > +
> > +     return 0;
> > +}
> 
> ...
> 
> > +static int rtd1625_gpio_probe(struct platform_device *pdev) {
> > +     struct gpio_regmap_config config = {};
> > +     struct device *dev = &pdev->dev;
> > +     struct gpio_regmap *gpio_reg;
> > +     struct rtd1625_gpio *data;
> > +     void __iomem *irq_base;
> > +     int ret;
> > +
> > +     data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> > +     if (!data)
> > +             return -ENOMEM;
> > +
> > +     data->info = device_get_match_data(dev);
> > +     if (!data->info)
> > +             return -EINVAL;
> 
> -ENODATA
> 

Ack.

> > +     irq_base = devm_platform_ioremap_resource(pdev, 0);
> > +     if (IS_ERR(irq_base))
> > +             return PTR_ERR(irq_base);
> > +
> > +     data->regmap = devm_regmap_init_mmio(dev, irq_base,
> &rtd1625_gpio_regmap_config);
> > +     if (IS_ERR(data->regmap))
> > +             return PTR_ERR(data->regmap);
> > +
> > +     raw_spin_lock_init(&data->lock);
> > +     platform_set_drvdata(pdev, data);
> > +
> > +     data->save_regs = devm_kcalloc(dev, data->info->num_gpios,
> sizeof(*data->save_regs),
> > +                                    GFP_KERNEL);
> > +     if (!data->save_regs)
> > +             return -ENOMEM;
> > +
> > +     config.parent = dev;
> > +     config.regmap = data->regmap;
> > +     config.ngpio = data->info->num_gpios;
> > +     config.reg_dat_base = data->info->base_offset;
> > +     config.reg_set_base = data->info->base_offset;
> > +     config.reg_dir_out_base = data->info->base_offset;
> > +
> > +     config.reg_mask_xlate = rtd1625_reg_mask_xlate;
> > +     config.set_config = rtd1625_gpio_set_config;
> > +     config.value_xlate = rtd1625_value_xlate;
> > +
> > +     data->domain = irq_domain_create_linear(dev_fwnode(dev),
> > +
> data->info->num_gpios,
> > +
> &rtd1625_gpio_irq_domain_ops,
> > +                                             data);
> > +     if (!data->domain)
> > +             return -ENOMEM;
> 
> 
> devm_irq_domain_instantiate()
> 

Ack.

Best Regards,
Yu-Chun

> > +     ret = devm_add_action_or_reset(dev, (void (*)(void
> *))irq_domain_remove, data->domain);
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = rtd1625_gpio_setup_irq(pdev, data);
> > +     if (ret)
> > +             return ret;
> > +
> > +     config.irq_domain = data->domain;
> > +     config.drvdata = data;
> > +
> > +     gpio_reg = devm_gpio_regmap_register(dev, &config);
> > +     if (IS_ERR(gpio_reg))
> > +             return PTR_ERR(gpio_reg);
> > +
> > +     data->gpio_reg = gpio_reg;
> > +
> > +     return 0;
> > +}
> 
> --
> With Best Regards,
> Andy Shevchenko
>

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

* RE: [PATCH v6 6/8] gpio: regmap: Add set_config callback
  2026-07-21 11:18       ` Michael Walle
@ 2026-07-21 12:10         ` Yu-Chun Lin [林祐君]
  0 siblings, 0 replies; 25+ messages in thread
From: Yu-Chun Lin [林祐君] @ 2026-07-21 12:10 UTC (permalink / raw)
  To: Michael Walle, linusw@kernel.org, andriy.shevchenko@intel.com,
	brgl@kernel.org, TY_Chang[張子逸],
	wbg@kernel.org, mathieu.dubois-briand@bootlin.com,
	nuno.sa@analog.com, Michael.Hennerich@analog.com,
	jic23@kernel.org, andy@kernel.org, u.kleine-koenig@baylibre.com,
	dakr@kernel.org, bhelgaas@google.com, o-takashi@sakamocchi.jp
  Cc: dlechner@baylibre.com, linux-kernel@vger.kernel.org,
	linux-gpio@vger.kernel.org, linux@analog.com,
	linux-iio@vger.kernel.org, CY_Huang[黃鉦晏],
	James Tai [戴志峰]

>> On Tue Jul 21, 2026 at 12:46 PM CEST, Yu-Chun Lin [林祐君] wrote:
>> Hi Michael,
>>
>>>On Tue Jul 21, 2026 at 8:58 AM CEST, Yu-Chun Lin wrote:
>>
>> (...)
>>
>>>> diff --git a/include/linux/gpio/regmap.h 
>>>> b/include/linux/gpio/regmap.h index 45a30f50043f..23460995c1d1 
>>>> 100644
>>>> --- a/include/linux/gpio/regmap.h
>>>> +++ b/include/linux/gpio/regmap.h
>>>> @@ -89,6 +89,9 @@ enum gpio_regmap_operation {
>>>>   *			mask before writing. This allows driver-specific logic
>>>>   *			to append additional bits (like write-enable masks)
>>>>   *			dynamically based on the current operation.
>>>> + * @set_config:		(Optional) Callback for setting GPIO configuration such
>>>> + *			as debounce, drive strength, or other hardware specific
>>>> + *			settings.
>>>>   * @drvdata:		(Optional) Pointer to driver specific data which is
>>>>   *			not used by gpio-remap but is provided "as is" to the
>>>>   *			driver callback(s).
>>>> @@ -150,6 +153,8 @@ struct gpio_regmap_config {
>>>>  			   unsigned int base, unsigned int offset, unsigned int reg,
>>>>  			   unsigned int *mask, unsigned int *val);
>>>>  
>>>> +	int (*set_config)(struct gpio_chip *gc, unsigned int offset, 
>>>> +unsigned long config);
>>>> +
>>>
>>> Do we need an additional struct gpio_regmap pointer as a first 
>>> argument? How does the driver fetch the attached opaque data pointer? 
>>> I see that your driver is doing
>>>
>>> struct rtd1625_gpio *data = gpiochip_get_data(chip)
>>>
>>> But it is the gpio-regmap core which will attach it's own data pointer to gpio_chip, no?
>>>
>>> -michael
>>
>> You are right. I mistakenly used gpiochip_get_data() here.
>>
>> My current plan to fix this is:
>> The set_config callback in 'struct gpio_regmap_config' and 'struct gpio_regmap'
>> should take 'struct gpio_regmap *' as the first argument (replacing 
>> 'struct gpio_chip *'), and the driver should use 'gpio_regmap_get_drvdata()'
>> to retrieve its own data pointer.
> 
> You also probably need the struct gpio_chip, to maybe call into the gpio core, no?
> 
> If so, what about
> 
> int (*set_config)(struct gpio_regmap *gpio, struct gpio_chip *gc,
>                   unsigned int offset, unsigned long config)
>

Agreed. I will take this design.

Best Regards,
Yu-Chun

>> I'll add a wrapper in gpio-regmap.c that bridges gpio_chip to 
>> gpio_regmap and handles the fallback to gpiochip_generic_config().
>
> Yes.
>
> -michael

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

end of thread, other threads:[~2026-07-21 12:11 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-21  6:57 [PATCH v6 0/8] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
2026-07-21  6:57 ` [PATCH v6 1/8] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC" Yu-Chun Lin
2026-07-21 10:39   ` Andy Shevchenko
2026-07-21  6:57 ` [PATCH v6 2/8] gpio: regmap: Provide default IRQ resource request and release callbacks Yu-Chun Lin
2026-07-21  7:05   ` Michael Walle
2026-07-21  6:57 ` [PATCH v6 3/8] gpio: regmap: Apply default resource callbacks for regmap IRQ chip Yu-Chun Lin
2026-07-21  7:07   ` Michael Walle
2026-07-21  6:57 ` [PATCH v6 4/8] gpio: regmap: Order kernel-doc descriptions with the actual appearance Yu-Chun Lin
2026-07-21  7:07   ` Michael Walle
2026-07-21 10:43   ` Andy Shevchenko
2026-07-21  6:57 ` [PATCH v6 5/8] gpio: regmap: Add gpio_regmap_operation and value_xlate support Yu-Chun Lin
2026-07-21  7:15   ` Michael Walle
2026-07-21 10:34     ` Yu-Chun Lin [林祐君]
2026-07-21 10:46   ` Andy Shevchenko
2026-07-21  6:58 ` [PATCH v6 6/8] gpio: regmap: Add set_config callback Yu-Chun Lin
2026-07-21  7:23   ` Michael Walle
2026-07-21 10:46     ` Yu-Chun Lin [林祐君]
2026-07-21 11:18       ` Michael Walle
2026-07-21 12:10         ` Yu-Chun Lin [林祐君]
2026-07-21  6:58 ` [PATCH v6 7/8] gpio: regmap: Add IRQ enable/disable helpers Yu-Chun Lin
2026-07-21  7:24   ` Michael Walle
2026-07-21 10:54   ` Andy Shevchenko
2026-07-21  6:58 ` [PATCH v6 8/8] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC Yu-Chun Lin
2026-07-21 11:12   ` Andy Shevchenko
2026-07-21 12:09     ` Yu-Chun Lin [林祐君]

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox