* [PATCH v7 0/9] gpio: realtek: Add support for Realtek DHC RTD1625
@ 2026-07-23 3:42 Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 1/9] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC" Yu-Chun Lin
` (8 more replies)
0 siblings, 9 replies; 13+ messages in thread
From: Yu-Chun Lin @ 2026-07-23 3:42 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 v7:
Patch 1:
- Add Acked-by tag from Andy.
Patch 2:
- Add Reviewed-by tag from Michael.
Patch 3:
- Add Reviewed-by tag from Michael.
Patch 4:
- Add Reviewed-by tag from Michael.
- Fix indentation by replacing spaces with a tab.
Patch 5 & 6:
- Create patch 6 and move value_xlate changes into patch 6.
- Add background context to kernel-doc comment for
'enum gpio_regmap_operation'.
Patch 7:
- Drop the reviewed by tag from Andy due to the signature changes.
- Add 'struct gpio_regmap' as the first parameter to the set_config callback.
- Add wrapper to bridge gpio_chip to gpio_regmap.
Patch 8:
- Add Reviewed-by tags from Michael and Andy.
Patch 9:
- Replace break with return 0 in functions that only consist of a switch-case
statement.
- Add a comment for 'platform_get_irq_optional()'.
- Update rtd1625_gpio_set_config() to align with the newly revised set_config
signature.
- Replace 'irq_domain_create_linear()' and 'devm_add_action_or_reset' with
'devm_irq_domain_instantiate()'.
v6: https://lore.kernel.org/lkml/20260721065802.689530-1-eleanor.lin@realtek.com/
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 (5):
Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC"
gpio: regmap: Add gpio_regmap_operation to extend reg_mask_xlate
callback
gpio: regmap: Add value_xlate callback
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 | 116 +++++++-
drivers/gpio/gpio-rtd1625.c | 389 +++++++++++++++-----------
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 | 80 +++++-
13 files changed, 422 insertions(+), 212 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v7 1/9] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC"
2026-07-23 3:42 [PATCH v7 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
@ 2026-07-23 3:42 ` Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 2/9] gpio: regmap: Provide default IRQ resource request and release callbacks Yu-Chun Lin
` (7 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Yu-Chun Lin @ 2026-07-23 3:42 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.
Acked-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v7:
- Add Acked-by tag from Andy.
---
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] 13+ messages in thread
* [PATCH v7 2/9] gpio: regmap: Provide default IRQ resource request and release callbacks
2026-07-23 3:42 [PATCH v7 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 1/9] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC" Yu-Chun Lin
@ 2026-07-23 3:42 ` Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 3/9] gpio: regmap: Apply default resource callbacks for regmap IRQ chip Yu-Chun Lin
` (6 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Yu-Chun Lin @ 2026-07-23 3:42 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.
Reviewed-by: Michael Walle <mwalle@kernel.org>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v7:
- Add Reviewed-by tag from Michael.
---
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] 13+ messages in thread
* [PATCH v7 3/9] gpio: regmap: Apply default resource callbacks for regmap IRQ chip
2026-07-23 3:42 [PATCH v7 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 1/9] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC" Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 2/9] gpio: regmap: Provide default IRQ resource request and release callbacks Yu-Chun Lin
@ 2026-07-23 3:42 ` Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 4/9] gpio: regmap: Order kernel-doc descriptions with the actual appearance Yu-Chun Lin
` (5 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Yu-Chun Lin @ 2026-07-23 3:42 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.
Reviewed-by: Michael Walle <mwalle@kernel.org>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v7:
- Add Reviewed-by tag from Michael.
---
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] 13+ messages in thread
* [PATCH v7 4/9] gpio: regmap: Order kernel-doc descriptions with the actual appearance
2026-07-23 3:42 [PATCH v7 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
` (2 preceding siblings ...)
2026-07-23 3:42 ` [PATCH v7 3/9] gpio: regmap: Apply default resource callbacks for regmap IRQ chip Yu-Chun Lin
@ 2026-07-23 3:42 ` Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 5/9] gpio: regmap: Add gpio_regmap_operation to extend reg_mask_xlate callback Yu-Chun Lin
` (4 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Yu-Chun Lin @ 2026-07-23 3:42 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.
Reviewed-by: Michael Walle <mwalle@kernel.org>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v7:
- Add Reviewed-by tag from Michael.
- Fix indentation by replacing spaces with a tab.
---
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..eb3931fbbad0 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] 13+ messages in thread
* [PATCH v7 5/9] gpio: regmap: Add gpio_regmap_operation to extend reg_mask_xlate callback
2026-07-23 3:42 [PATCH v7 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
` (3 preceding siblings ...)
2026-07-23 3:42 ` [PATCH v7 4/9] gpio: regmap: Order kernel-doc descriptions with the actual appearance Yu-Chun Lin
@ 2026-07-23 3:42 ` Yu-Chun Lin
2026-07-23 6:51 ` Michael Walle
2026-07-23 3:42 ` [PATCH v7 6/9] gpio: regmap: Add value_xlate callback Yu-Chun Lin
` (3 subsequent siblings)
8 siblings, 1 reply; 13+ messages in thread
From: Yu-Chun Lin @ 2026-07-23 3:42 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.
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 v7:
- Move value_xlate changes into patch 6.
- Add background context to kernel-doc comment for
'enum gpio_regmap_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 | 31 +++++++++++++++------
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 | 40 +++++++++++++++++++++++++--
11 files changed, 81 insertions(+), 30 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..1cc9c03ade99 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -40,9 +40,10 @@ 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);
void *driver_data;
};
@@ -56,6 +57,7 @@ static unsigned int gpio_regmap_addr(unsigned int addr)
}
static int gpio_regmap_simple_xlate(struct gpio_regmap *gpio,
+ enum gpio_regmap_operation __maybe_unused op,
unsigned int base, unsigned int offset,
unsigned int *reg, unsigned int *mask)
{
@@ -71,7 +73,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 +82,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, ®, &mask);
+ ret = gpio->reg_mask_xlate(gpio, GPIO_REGMAP_GET_OP, base, offset, ®, &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, ®, &mask);
+ else
+ ret = gpio->reg_mask_xlate(gpio, GPIO_REGMAP_IN, base, offset, ®, &mask);
if (ret)
return ret;
@@ -103,7 +116,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, ®, &mask);
+ ret = gpio->reg_mask_xlate(gpio, GPIO_REGMAP_SET_OP, base, offset, ®, &mask);
if (ret)
return ret;
@@ -133,7 +146,7 @@ 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, ®, &mask);
+ ret = gpio->reg_mask_xlate(gpio, GPIO_REGMAP_SET_OP, base, offset, ®, &mask);
if (ret)
return ret;
@@ -183,7 +196,7 @@ static int gpio_regmap_get_direction(struct gpio_chip *chip,
return -ENOTSUPP;
}
- ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask);
+ ret = gpio->reg_mask_xlate(gpio, GPIO_REGMAP_GET_DIR_OP, base, offset, ®, &mask);
if (ret)
return ret;
@@ -237,7 +250,7 @@ static int gpio_regmap_set_direction(struct gpio_chip *chip,
return -ENOTSUPP;
}
- ret = gpio->reg_mask_xlate(gpio, base, offset, ®, &mask);
+ ret = gpio->reg_mask_xlate(gpio, GPIO_REGMAP_SET_DIR_OP, base, offset, ®, &mask);
if (ret)
return ret;
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 eb3931fbbad0..ececc287d519 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -13,6 +13,40 @@ 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
+ *
+ * Traditionally, the operation type was inferred from the base register.
+ * However, that approach does not always work — for example, when all control
+ * bits of a single GPIO reside in the same register. This enum allows the
+ * reg_mask_xlate callback to explicitly distinguish between operation types.
+ * The user is free to choose which method to 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
@@ -104,9 +138,9 @@ 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,
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v7 6/9] gpio: regmap: Add value_xlate callback
2026-07-23 3:42 [PATCH v7 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
` (4 preceding siblings ...)
2026-07-23 3:42 ` [PATCH v7 5/9] gpio: regmap: Add gpio_regmap_operation to extend reg_mask_xlate callback Yu-Chun Lin
@ 2026-07-23 3:42 ` Yu-Chun Lin
2026-07-23 6:54 ` Michael Walle
2026-07-23 3:42 ` [PATCH v7 7/9] gpio: regmap: Add set_config callback Yu-Chun Lin
` (2 subsequent siblings)
8 siblings, 1 reply; 13+ messages in thread
From: Yu-Chun Lin @ 2026-07-23 3:42 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
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.
Suggested-by: Michael Walle <mwalle@kernel.org>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v7:
- New patch
---
drivers/gpio/gpio-regmap.c | 31 ++++++++++++++++++++++++++++++-
include/linux/gpio/regmap.h | 8 ++++++++
2 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index 1cc9c03ade99..8f58b272b870 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -45,6 +45,12 @@ struct gpio_regmap {
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;
};
@@ -125,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);
@@ -138,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)
@@ -150,6 +163,13 @@ static int gpio_regmap_set_with_clear(struct gpio_chip *chip,
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);
}
@@ -259,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);
}
@@ -426,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/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h
index ececc287d519..b77d6371cd9c 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -89,6 +89,10 @@ enum gpio_regmap_operation {
* 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).
@@ -146,6 +150,10 @@ struct gpio_regmap_config {
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] 13+ messages in thread
* [PATCH v7 7/9] gpio: regmap: Add set_config callback
2026-07-23 3:42 [PATCH v7 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
` (5 preceding siblings ...)
2026-07-23 3:42 ` [PATCH v7 6/9] gpio: regmap: Add value_xlate callback Yu-Chun Lin
@ 2026-07-23 3:42 ` Yu-Chun Lin
2026-07-23 7:01 ` Michael Walle
2026-07-23 3:42 ` [PATCH v7 8/9] gpio: regmap: Add IRQ enable/disable helpers Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 9/9] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC Yu-Chun Lin
8 siblings, 1 reply; 13+ messages in thread
From: Yu-Chun Lin @ 2026-07-23 3:42 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 allow drivers to implement
hardware-specific configuration such as debounce settings, or other
platform-specific GPIO properties.
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v7:
- Drop the reviewed by tag from Andy due to the signature changes.
- Add 'struct gpio_regmap' as the first parameter to the set_config callback.
- Add wrapper to bridge gpio_chip to gpio_regmap.
---
drivers/gpio/gpio-regmap.c | 16 ++++++++++++++++
include/linux/gpio/regmap.h | 6 ++++++
2 files changed, 22 insertions(+)
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index 8f58b272b870..98cfdd890069 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -51,6 +51,9 @@ struct gpio_regmap {
unsigned int reg, unsigned int *mask,
unsigned int *val);
+ int (*set_config)(struct gpio_regmap *gpio, struct gpio_chip *chip,
+ unsigned int offset, unsigned long config);
+
void *driver_data;
};
@@ -317,6 +320,15 @@ static int gpio_regmap_direction_output(struct gpio_chip *chip,
return gpio_regmap_set_direction(chip, offset, true);
}
+static int gpio_regmap_set_config(struct gpio_chip *chip,
+ unsigned int offset,
+ unsigned long cfg)
+{
+ struct gpio_regmap *gpio = gpiochip_get_data(chip);
+
+ return gpio->set_config(gpio, chip, offset, cfg);
+}
+
int gpio_regmap_reqres_irq(struct gpio_regmap *gpio, unsigned int offset)
{
return gpiochip_reqres_irq(&gpio->gpio_chip, offset);
@@ -386,6 +398,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
gpio->reg_clr_base = config->reg_clr_base;
gpio->reg_dir_in_base = config->reg_dir_in_base;
gpio->reg_dir_out_base = config->reg_dir_out_base;
+ gpio->set_config = config->set_config;
chip = &gpio->gpio_chip;
chip->parent = config->parent;
@@ -455,6 +468,9 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
gpio->value_xlate = config->value_xlate;
+ if (config->set_config)
+ chip->set_config = gpio_regmap_set_config;
+
ret = gpiochip_add_data(chip, gpio);
if (ret < 0)
goto err_free_bitmap_output;
diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h
index b77d6371cd9c..4bf4319ec12e 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -93,6 +93,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).
@@ -154,6 +157,9 @@ struct gpio_regmap_config {
unsigned int base, unsigned int offset, unsigned int reg,
unsigned int *mask, unsigned int *val);
+ int (*set_config)(struct gpio_regmap *gpio, struct gpio_chip *chip,
+ unsigned int offset, unsigned long config);
+
void *drvdata;
};
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v7 8/9] gpio: regmap: Add IRQ enable/disable helpers
2026-07-23 3:42 [PATCH v7 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
` (6 preceding siblings ...)
2026-07-23 3:42 ` [PATCH v7 7/9] gpio: regmap: Add set_config callback Yu-Chun Lin
@ 2026-07-23 3:42 ` Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 9/9] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC Yu-Chun Lin
8 siblings, 0 replies; 13+ messages in thread
From: Yu-Chun Lin @ 2026-07-23 3:42 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.
Reviewed-by: Michael Walle <mwalle@kernel.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v7:
- Add Reviewed-by tags from Michael and Andy.
---
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 98cfdd890069..75b70aa1eb5b 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -357,6 +357,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 4bf4319ec12e..483b5deadda9 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;
@@ -172,4 +174,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] 13+ messages in thread
* [PATCH v7 9/9] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC
2026-07-23 3:42 [PATCH v7 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
` (7 preceding siblings ...)
2026-07-23 3:42 ` [PATCH v7 8/9] gpio: regmap: Add IRQ enable/disable helpers Yu-Chun Lin
@ 2026-07-23 3:42 ` Yu-Chun Lin
8 siblings, 0 replies; 13+ messages in thread
From: Yu-Chun Lin @ 2026-07-23 3:42 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 v7:
- Replace break with return 0 in functions that only consist of a switch-case
statement.
- Add a comment for 'platform_get_irq_optional()'.
- Update rtd1625_gpio_set_config() to align with the newly revised set_config
signature.
- Replace 'irq_domain_create_linear()' and 'devm_add_action_or_reset' with
'devm_irq_domain_instantiate()'.
---
drivers/gpio/Kconfig | 14 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-rtd1625.c | 662 ++++++++++++++++++++++++++++++++++++
3 files changed, 677 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..5bb4fc91b24e
--- /dev/null
+++ b/drivers/gpio/gpio-rtd1625.c
@@ -0,0 +1,662 @@
+// 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;
+ return 0;
+
+ case GPIO_REGMAP_OUT:
+ *mask = RTD1625_GPIO_OUT;
+ return 0;
+
+ case GPIO_REGMAP_SET_OP:
+ *mask = RTD1625_GPIO_OUT;
+ return 0;
+
+ case GPIO_REGMAP_GET_OP:
+ case GPIO_REGMAP_GET_DIR_OP:
+ case GPIO_REGMAP_SET_DIR_OP:
+ *mask = RTD1625_GPIO_DIR;
+ return 0;
+
+ default:
+ return -ENOTSUPP;
+ }
+}
+
+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);
+ return 0;
+
+ case GPIO_REGMAP_SET_DIR_OP:
+ *val |= RTD1625_GPIO_WREN(RTD1625_GPIO_DIR);
+ *mask |= RTD1625_GPIO_WREN(RTD1625_GPIO_DIR);
+ return 0;
+
+ default:
+ return -ENOTSUPP;
+ }
+}
+
+static int rtd1625_gpio_set_debounce(struct rtd1625_gpio *data, unsigned int offset,
+ unsigned int debounce)
+{
+ 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);
+
+ return regmap_write(data->regmap, data->info->base_offset + GPIO_CONTROL(offset), val);
+}
+
+static int rtd1625_gpio_set_config(struct gpio_regmap *gpio, struct gpio_chip *chip,
+ unsigned int offset, unsigned long config)
+{
+ struct rtd1625_gpio *data = gpio_regmap_get_drvdata(gpio);
+ u32 debounce;
+
+ if (pinconf_to_config_param(config) == PIN_CONFIG_INPUT_DEBOUNCE) {
+ debounce = pinconf_to_config_argument(config);
+ return rtd1625_gpio_set_debounce(data, 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 is optional; operate as basic GPIO if absent */
+ 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 irq_domain_info d_info = {};
+ 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 -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;
+
+ d_info.fwnode = dev_fwnode(&pdev->dev);
+ d_info.size = data->info->num_gpios;
+ d_info.hwirq_max = data->info->num_gpios;
+ d_info.ops = &rtd1625_gpio_irq_domain_ops;
+ d_info.host_data = data;
+
+ data->domain = devm_irq_domain_instantiate(dev, &d_info);
+ if (IS_ERR(data->domain))
+ return PTR_ERR(data->domain);
+
+ 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] 13+ messages in thread
* Re: [PATCH v7 5/9] gpio: regmap: Add gpio_regmap_operation to extend reg_mask_xlate callback
2026-07-23 3:42 ` [PATCH v7 5/9] gpio: regmap: Add gpio_regmap_operation to extend reg_mask_xlate callback Yu-Chun Lin
@ 2026-07-23 6:51 ` Michael Walle
0 siblings, 0 replies; 13+ messages in thread
From: Michael Walle @ 2026-07-23 6:51 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: 4541 bytes --]
On Thu Jul 23, 2026 at 5:42 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.
>
> 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>
> ---
...
> @@ -71,7 +73,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 +82,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, ®, &mask);
> + ret = gpio->reg_mask_xlate(gpio, GPIO_REGMAP_GET_OP, base, offset, ®, &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, ®, &mask);
> + else
> + ret = gpio->reg_mask_xlate(gpio, GPIO_REGMAP_IN, base, offset, ®, &mask);
What's going on here? Looks like I've missed this in the previous
patches. All the other drivers we are now reading the value twice.
In the regmap_read() above and the one that follows just after this
hunk.
Has the gpio controller two different bits, one for output and one
for input? Are you sure, the input bit doesn't reflect the output
bit if it's configured as an output?
IMHO this shouldn't be part of the core. rtd1625_reg_mask_xlate()
should either return RTD1625_GPIO_IN or RTD1625_GPIO_OUT depending
on the mode, if that's needed at all. I'd guess RTD1625_GPIO_IN
will just work fine and will actually fetch the actual line state.
-michael
> if (ret)
> return ret;
>
...
>
> +/**
> + * enum gpio_regmap_operation - Operation type for reg_mask_xlate callback
> + *
> + * Traditionally, the operation type was inferred from the base register.
> + * However, that approach does not always work — for example, when all control
> + * bits of a single GPIO reside in the same register. This enum allows the
> + * reg_mask_xlate callback to explicitly distinguish between operation types.
> + * The user is free to choose which method to 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.
This is also not very intuitive. I'd expect there is only one
operation for the gpio_regmap_get and that is exactly this one.
> + * @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
> @@ -104,9 +138,9 @@ 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,
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 297 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v7 6/9] gpio: regmap: Add value_xlate callback
2026-07-23 3:42 ` [PATCH v7 6/9] gpio: regmap: Add value_xlate callback Yu-Chun Lin
@ 2026-07-23 6:54 ` Michael Walle
0 siblings, 0 replies; 13+ messages in thread
From: Michael Walle @ 2026-07-23 6:54 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: 544 bytes --]
On Thu Jul 23, 2026 at 5:42 AM CEST, Yu-Chun Lin wrote:
> 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.
>
> Suggested-by: Michael Walle <mwalle@kernel.org>
> 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] 13+ messages in thread
* Re: [PATCH v7 7/9] gpio: regmap: Add set_config callback
2026-07-23 3:42 ` [PATCH v7 7/9] gpio: regmap: Add set_config callback Yu-Chun Lin
@ 2026-07-23 7:01 ` Michael Walle
0 siblings, 0 replies; 13+ messages in thread
From: Michael Walle @ 2026-07-23 7:01 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: 3739 bytes --]
On Thu Jul 23, 2026 at 5:42 AM CEST, Yu-Chun Lin wrote:
> Add a new set_config callback to allow drivers to implement
> hardware-specific configuration such as debounce settings, or other
> platform-specific GPIO properties.
>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v7:
> - Drop the reviewed by tag from Andy due to the signature changes.
> - Add 'struct gpio_regmap' as the first parameter to the set_config callback.
> - Add wrapper to bridge gpio_chip to gpio_regmap.
> ---
> drivers/gpio/gpio-regmap.c | 16 ++++++++++++++++
> include/linux/gpio/regmap.h | 6 ++++++
> 2 files changed, 22 insertions(+)
>
> diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
> index 8f58b272b870..98cfdd890069 100644
> --- a/drivers/gpio/gpio-regmap.c
> +++ b/drivers/gpio/gpio-regmap.c
> @@ -51,6 +51,9 @@ struct gpio_regmap {
> unsigned int reg, unsigned int *mask,
> unsigned int *val);
>
> + int (*set_config)(struct gpio_regmap *gpio, struct gpio_chip *chip,
> + unsigned int offset, unsigned long config);
> +
> void *driver_data;
> };
>
> @@ -317,6 +320,15 @@ static int gpio_regmap_direction_output(struct gpio_chip *chip,
> return gpio_regmap_set_direction(chip, offset, true);
> }
>
> +static int gpio_regmap_set_config(struct gpio_chip *chip,
> + unsigned int offset,
> + unsigned long cfg)
> +{
> + struct gpio_regmap *gpio = gpiochip_get_data(chip);
> +
> + return gpio->set_config(gpio, chip, offset, cfg);
> +}
> +
> int gpio_regmap_reqres_irq(struct gpio_regmap *gpio, unsigned int offset)
> {
> return gpiochip_reqres_irq(&gpio->gpio_chip, offset);
> @@ -386,6 +398,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
> gpio->reg_clr_base = config->reg_clr_base;
> gpio->reg_dir_in_base = config->reg_dir_in_base;
> gpio->reg_dir_out_base = config->reg_dir_out_base;
> + gpio->set_config = config->set_config;
>
> chip = &gpio->gpio_chip;
> chip->parent = config->parent;
> @@ -455,6 +468,9 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
>
> gpio->value_xlate = config->value_xlate;
>
> + if (config->set_config)
> + chip->set_config = gpio_regmap_set_config;
> +
Please keep both settings together. i.e.
if (config->set_config) {
gpio->set_config = config->set_config;
chip->set_config = gpio_regmap_set_config;
}
With that fixed:
Reviewed-by: Michael Walle <mwalle@kernel.org>
-michael
> ret = gpiochip_add_data(chip, gpio);
> if (ret < 0)
> goto err_free_bitmap_output;
> diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h
> index b77d6371cd9c..4bf4319ec12e 100644
> --- a/include/linux/gpio/regmap.h
> +++ b/include/linux/gpio/regmap.h
> @@ -93,6 +93,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).
> @@ -154,6 +157,9 @@ struct gpio_regmap_config {
> unsigned int base, unsigned int offset, unsigned int reg,
> unsigned int *mask, unsigned int *val);
>
> + int (*set_config)(struct gpio_regmap *gpio, struct gpio_chip *chip,
> + unsigned int offset, unsigned long config);
> +
> void *drvdata;
> };
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 297 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-07-23 7:01 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-23 3:42 [PATCH v7 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 1/9] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC" Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 2/9] gpio: regmap: Provide default IRQ resource request and release callbacks Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 3/9] gpio: regmap: Apply default resource callbacks for regmap IRQ chip Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 4/9] gpio: regmap: Order kernel-doc descriptions with the actual appearance Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 5/9] gpio: regmap: Add gpio_regmap_operation to extend reg_mask_xlate callback Yu-Chun Lin
2026-07-23 6:51 ` Michael Walle
2026-07-23 3:42 ` [PATCH v7 6/9] gpio: regmap: Add value_xlate callback Yu-Chun Lin
2026-07-23 6:54 ` Michael Walle
2026-07-23 3:42 ` [PATCH v7 7/9] gpio: regmap: Add set_config callback Yu-Chun Lin
2026-07-23 7:01 ` Michael Walle
2026-07-23 3:42 ` [PATCH v7 8/9] gpio: regmap: Add IRQ enable/disable helpers Yu-Chun Lin
2026-07-23 3:42 ` [PATCH v7 9/9] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC 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