* [PATCH v8 1/9] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC"
2026-07-26 12:51 [PATCH v8 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
@ 2026-07-26 12:51 ` Yu-Chun Lin
2026-07-26 12:51 ` [PATCH v8 2/9] gpio: regmap: Provide default IRQ resource request and release callbacks Yu-Chun Lin
` (7 subsequent siblings)
8 siblings, 0 replies; 15+ messages in thread
From: Yu-Chun Lin @ 2026-07-26 12:51 UTC (permalink / raw)
To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
o-takashi
Cc: u.kleine-koenig, dakr, bhelgaas, eleanor.lin, dlechner,
linux-kernel, linux-gpio, linux, linux-iio, cy.huang, james.tai,
stanley_chang
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>
Acked-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v8:
- Add Acked-by tag from Linus.
---
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] 15+ messages in thread* [PATCH v8 2/9] gpio: regmap: Provide default IRQ resource request and release callbacks
2026-07-26 12:51 [PATCH v8 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
2026-07-26 12:51 ` [PATCH v8 1/9] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC" Yu-Chun Lin
@ 2026-07-26 12:51 ` Yu-Chun Lin
2026-07-26 12:51 ` [PATCH v8 3/9] gpio: regmap: Apply default resource callbacks for regmap IRQ chip Yu-Chun Lin
` (6 subsequent siblings)
8 siblings, 0 replies; 15+ messages in thread
From: Yu-Chun Lin @ 2026-07-26 12:51 UTC (permalink / raw)
To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
o-takashi
Cc: u.kleine-koenig, dakr, bhelgaas, eleanor.lin, dlechner,
linux-kernel, linux-gpio, linux, linux-iio, cy.huang, james.tai,
stanley_chang, 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>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v8:
- Add Reviewed-by tag from Linus.
---
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] 15+ messages in thread* [PATCH v8 3/9] gpio: regmap: Apply default resource callbacks for regmap IRQ chip
2026-07-26 12:51 [PATCH v8 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
2026-07-26 12:51 ` [PATCH v8 1/9] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC" Yu-Chun Lin
2026-07-26 12:51 ` [PATCH v8 2/9] gpio: regmap: Provide default IRQ resource request and release callbacks Yu-Chun Lin
@ 2026-07-26 12:51 ` Yu-Chun Lin
2026-07-26 12:51 ` [PATCH v8 4/9] gpio: regmap: Order kernel-doc descriptions with the actual appearance Yu-Chun Lin
` (5 subsequent siblings)
8 siblings, 0 replies; 15+ messages in thread
From: Yu-Chun Lin @ 2026-07-26 12:51 UTC (permalink / raw)
To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
o-takashi
Cc: u.kleine-koenig, dakr, bhelgaas, eleanor.lin, dlechner,
linux-kernel, linux-gpio, linux, linux-iio, cy.huang, james.tai,
stanley_chang, 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>
Reviewed-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v8:
- Add Reviewed-by tags from Mathieu and Linus.
---
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] 15+ messages in thread* [PATCH v8 4/9] gpio: regmap: Order kernel-doc descriptions with the actual appearance
2026-07-26 12:51 [PATCH v8 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
` (2 preceding siblings ...)
2026-07-26 12:51 ` [PATCH v8 3/9] gpio: regmap: Apply default resource callbacks for regmap IRQ chip Yu-Chun Lin
@ 2026-07-26 12:51 ` Yu-Chun Lin
2026-07-26 12:51 ` [PATCH v8 5/9] gpio: regmap: Add gpio_regmap_operation to extend reg_mask_xlate callback Yu-Chun Lin
` (4 subsequent siblings)
8 siblings, 0 replies; 15+ messages in thread
From: Yu-Chun Lin @ 2026-07-26 12:51 UTC (permalink / raw)
To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
o-takashi
Cc: u.kleine-koenig, dakr, bhelgaas, eleanor.lin, dlechner,
linux-kernel, linux-gpio, linux, linux-iio, cy.huang, james.tai,
stanley_chang, 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>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v8:
- Add Reviewed-by tag from Linus.
---
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] 15+ messages in thread* [PATCH v8 5/9] gpio: regmap: Add gpio_regmap_operation to extend reg_mask_xlate callback
2026-07-26 12:51 [PATCH v8 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
` (3 preceding siblings ...)
2026-07-26 12:51 ` [PATCH v8 4/9] gpio: regmap: Order kernel-doc descriptions with the actual appearance Yu-Chun Lin
@ 2026-07-26 12:51 ` Yu-Chun Lin
2026-07-26 12:51 ` [PATCH v8 6/9] gpio: regmap: Add value_xlate callback Yu-Chun Lin
` (3 subsequent siblings)
8 siblings, 0 replies; 15+ messages in thread
From: Yu-Chun Lin @ 2026-07-26 12:51 UTC (permalink / raw)
To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
o-takashi
Cc: u.kleine-koenig, dakr, bhelgaas, eleanor.lin, dlechner,
linux-kernel, linux-gpio, linux, linux-iio, cy.huang, james.tai,
stanley_chang, Jonathan Cameron
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.
Acked-by: William Breathitt Gray <wbg@kernel.org>
Acked-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com> #for-iio
Suggested-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v8:
- Remove GPIO_REGMAP_IN and GPIO_REGMAP_OUT from 'enum gpio_regmap_operation'
and one extra regmap_read in gpio_regmap_get().
- Add Acked-by tags from William Breathitt Gray and Jonathan Cameron.
---
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 | 18 ++++++++-------
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 | 32 ++++++++++++++++++++++++---
11 files changed, 61 insertions(+), 29 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..ceab805d053c 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)
{
@@ -80,7 +82,7 @@ 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, ®, &mask);
if (ret)
return ret;
@@ -103,7 +105,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 +135,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 +185,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 +239,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..7eebb6381296 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -13,6 +13,32 @@ 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.
+ *
+ * Read operation:
+ * @GPIO_REGMAP_GET_OP: Indicates a read operation to get the current GPIO value.
+ *
+ * Write operation:
+ * @GPIO_REGMAP_SET_OP: Indicates a write operation to set the GPIO output value.
+ *
+ * Direction operations:
+ * @GPIO_REGMAP_GET_DIR_OP: Indicates a read operation to get the GPIO direction.
+ * @GPIO_REGMAP_SET_DIR_OP: Indicates a write operation to set the GPIO direction.
+ */
+enum gpio_regmap_operation {
+ GPIO_REGMAP_GET_OP,
+ GPIO_REGMAP_SET_OP,
+ GPIO_REGMAP_GET_DIR_OP,
+ GPIO_REGMAP_SET_DIR_OP,
+};
+
/**
* struct gpio_regmap_config - Description of a generic regmap gpio_chip.
* @parent: The parent device
@@ -104,9 +130,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] 15+ messages in thread* [PATCH v8 6/9] gpio: regmap: Add value_xlate callback
2026-07-26 12:51 [PATCH v8 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
` (4 preceding siblings ...)
2026-07-26 12:51 ` [PATCH v8 5/9] gpio: regmap: Add gpio_regmap_operation to extend reg_mask_xlate callback Yu-Chun Lin
@ 2026-07-26 12:51 ` Yu-Chun Lin
2026-07-26 12:51 ` [PATCH v8 7/9] gpio: regmap: Add set_config callback Yu-Chun Lin
` (2 subsequent siblings)
8 siblings, 0 replies; 15+ messages in thread
From: Yu-Chun Lin @ 2026-07-26 12:51 UTC (permalink / raw)
To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
o-takashi
Cc: u.kleine-koenig, dakr, bhelgaas, eleanor.lin, dlechner,
linux-kernel, linux-gpio, linux, linux-iio, cy.huang, james.tai,
stanley_chang
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.
Reviewed-by: Michael Walle <mwalle@kernel.org>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Suggested-by: Michael Walle <mwalle@kernel.org>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v8:
- Add Reviewed-by tags from Michael and Linus.
- Improve kernel-doc comments for 'enum gpio_regmap_operation' and value_xlate.
---
drivers/gpio/gpio-regmap.c | 31 ++++++++++++++++++++++++++++++-
include/linux/gpio/regmap.h | 15 ++++++++++++---
2 files changed, 42 insertions(+), 4 deletions(-)
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index ceab805d053c..cff7db8036f7 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;
};
@@ -114,6 +120,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);
@@ -127,7 +140,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)
@@ -139,6 +152,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);
}
@@ -248,6 +268,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);
}
@@ -415,6 +442,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 7eebb6381296..77dbb353bc1f 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -14,13 +14,13 @@ struct regmap;
#define GPIO_REGMAP_ADDR(addr) ((addr) ? : GPIO_REGMAP_ADDR_ZERO)
/**
- * enum gpio_regmap_operation - Operation type for reg_mask_xlate callback
+ * enum gpio_regmap_operation - Operation type for gpio_regmap callbacks
*
* 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.
+ * callbacks (reg_mask_xlate and value_xlate) to explicitly distinguish between
+ * operation types. The user is free to choose which method to use.
*
* Read operation:
* @GPIO_REGMAP_GET_OP: Indicates a read operation to get the current GPIO value.
@@ -81,6 +81,11 @@ 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
+ * (GPIO_REGMAP_SET_OP and GPIO_REGMAP_SET_DIR_OP).
* @drvdata: (Optional) Pointer to driver specific data which is
* not used by gpio-remap but is provided "as is" to the
* driver callback(s).
@@ -138,6 +143,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] 15+ messages in thread* [PATCH v8 7/9] gpio: regmap: Add set_config callback
2026-07-26 12:51 [PATCH v8 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
` (5 preceding siblings ...)
2026-07-26 12:51 ` [PATCH v8 6/9] gpio: regmap: Add value_xlate callback Yu-Chun Lin
@ 2026-07-26 12:51 ` Yu-Chun Lin
2026-07-26 12:51 ` [PATCH v8 8/9] gpio: regmap: Add IRQ enable/disable helpers Yu-Chun Lin
2026-07-26 12:52 ` [PATCH v8 9/9] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC Yu-Chun Lin
8 siblings, 0 replies; 15+ messages in thread
From: Yu-Chun Lin @ 2026-07-26 12:51 UTC (permalink / raw)
To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
o-takashi
Cc: u.kleine-koenig, dakr, bhelgaas, eleanor.lin, dlechner,
linux-kernel, linux-gpio, linux, linux-iio, cy.huang, james.tai,
stanley_chang
Add a new set_config callback to allow drivers to implement
hardware-specific configuration such as debounce settings, or other
platform-specific GPIO properties.
Reviewed-by: Michael Walle <mwalle@kernel.org>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v8:
- Move the assignment of gpio->set_config into the if (config->set_config)
block.
- Add Reviewed-by tags from Michael and Linus.
---
drivers/gpio/gpio-regmap.c | 17 +++++++++++++++++
include/linux/gpio/regmap.h | 6 ++++++
2 files changed, 23 insertions(+)
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index cff7db8036f7..19e33e361cc4 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;
};
@@ -306,6 +309,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);
@@ -444,6 +456,11 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
gpio->value_xlate = config->value_xlate;
+ if (config->set_config) {
+ gpio->set_config = 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 77dbb353bc1f..dd9de9958409 100644
--- a/include/linux/gpio/regmap.h
+++ b/include/linux/gpio/regmap.h
@@ -86,6 +86,9 @@ enum gpio_regmap_operation {
* to append additional bits (like write-enable masks)
* dynamically based on the current operation
* (GPIO_REGMAP_SET_OP and GPIO_REGMAP_SET_DIR_OP).
+ * @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).
@@ -147,6 +150,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] 15+ messages in thread* [PATCH v8 8/9] gpio: regmap: Add IRQ enable/disable helpers
2026-07-26 12:51 [PATCH v8 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
` (6 preceding siblings ...)
2026-07-26 12:51 ` [PATCH v8 7/9] gpio: regmap: Add set_config callback Yu-Chun Lin
@ 2026-07-26 12:51 ` Yu-Chun Lin
2026-07-26 12:52 ` [PATCH v8 9/9] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC Yu-Chun Lin
8 siblings, 0 replies; 15+ messages in thread
From: Yu-Chun Lin @ 2026-07-26 12:51 UTC (permalink / raw)
To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
o-takashi
Cc: u.kleine-koenig, dakr, bhelgaas, eleanor.lin, dlechner,
linux-kernel, linux-gpio, linux, linux-iio, cy.huang, james.tai,
stanley_chang, 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>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
---
Changes in v8:
- Add Reviewed-by tag from Linus.
---
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 19e33e361cc4..fb21396e1d02 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -346,6 +346,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 dd9de9958409..6f52c140e50d 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;
@@ -165,4 +167,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] 15+ messages in thread* [PATCH v8 9/9] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC
2026-07-26 12:51 [PATCH v8 0/9] gpio: realtek: Add support for Realtek DHC RTD1625 Yu-Chun Lin
` (7 preceding siblings ...)
2026-07-26 12:51 ` [PATCH v8 8/9] gpio: regmap: Add IRQ enable/disable helpers Yu-Chun Lin
@ 2026-07-26 12:52 ` Yu-Chun Lin
2026-07-27 8:20 ` Mathieu Dubois-Briand
8 siblings, 1 reply; 15+ messages in thread
From: Yu-Chun Lin @ 2026-07-26 12:52 UTC (permalink / raw)
To: linusw, andriy.shevchenko, mwalle, brgl, tychang, wbg,
mathieu.dubois-briand, nuno.sa, Michael.Hennerich, jic23, andy,
o-takashi
Cc: u.kleine-koenig, dakr, bhelgaas, eleanor.lin, dlechner,
linux-kernel, linux-gpio, linux, linux-iio, cy.huang, james.tai,
stanley_chang
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.
Reviewed-by: Linus Walleij <linusw@kernel.org>
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 v8:
- Add error handlers in td1625_gpio_irq_handle().
- Move the direction-checking logic from the core to our custom
reg_mask_xlate() callback.
- Add Reviewed-by tag from Linus.
---
drivers/gpio/Kconfig | 14 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-rtd1625.c | 677 ++++++++++++++++++++++++++++++++++++
3 files changed, 692 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..483e44cf5abc
--- /dev/null
+++ b/drivers/gpio/gpio-rtd1625.c
@@ -0,0 +1,677 @@
+// 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 */
+ struct rtd1625_gpio *data = gpio_regmap_get_drvdata(gpio);
+ int val = 0, ret = 0;
+ *reg = base + offset * 4;
+
+ switch (op) {
+ case GPIO_REGMAP_SET_OP:
+ *mask = RTD1625_GPIO_OUT;
+ return 0;
+
+ case GPIO_REGMAP_GET_OP:
+ ret = regmap_read(data->regmap, *reg, &val);
+ if (ret)
+ return ret;
+
+ if (val & RTD1625_GPIO_DIR)
+ *mask = RTD1625_GPIO_OUT;
+ else
+ *mask = RTD1625_GPIO_IN;
+ return 0;
+
+ 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;
+ int ret;
+
+ 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);
+ ret = regmap_read(data->regmap, reg_offset, &val);
+ if (ret) {
+ pr_err_ratelimited("Failed to read IRQ status for GPIO %u: %d\n", i, ret);
+ continue;
+ }
+
+ 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]) {
+ ret = regmap_write(data->regmap, reg_offset, status);
+ if (ret)
+ pr_err_ratelimited("Failed to clear edge IRQ for GPIO %u: %d\n",
+ i, ret);
+ }
+
+ 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] 15+ messages in thread* Re: [PATCH v8 9/9] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC
2026-07-26 12:52 ` [PATCH v8 9/9] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC Yu-Chun Lin
@ 2026-07-27 8:20 ` Mathieu Dubois-Briand
2026-07-27 11:10 ` Bartosz Golaszewski
0 siblings, 1 reply; 15+ messages in thread
From: Mathieu Dubois-Briand @ 2026-07-27 8:20 UTC (permalink / raw)
To: Yu-Chun Lin, linusw, andriy.shevchenko, mwalle, brgl, tychang,
wbg, nuno.sa, Michael.Hennerich, jic23, andy, o-takashi
Cc: u.kleine-koenig, dakr, bhelgaas, dlechner, linux-kernel,
linux-gpio, linux, linux-iio, cy.huang, james.tai, stanley_chang
On Sun Jul 26, 2026 at 2:52 PM CEST, Yu-Chun Lin wrote:
> 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.
>
> Reviewed-by: Linus Walleij <linusw@kernel.org>
> 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 v8:
> - Add error handlers in td1625_gpio_irq_handle().
> - Move the direction-checking logic from the core to our custom
> reg_mask_xlate() callback.
> - Add Reviewed-by tag from Linus.
> ---
Thanks for the fixes.
Reviewed-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
--
Mathieu Dubois-Briand, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 9/9] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC
2026-07-27 8:20 ` Mathieu Dubois-Briand
@ 2026-07-27 11:10 ` Bartosz Golaszewski
2026-07-27 11:23 ` Mathieu Dubois-Briand
0 siblings, 1 reply; 15+ messages in thread
From: Bartosz Golaszewski @ 2026-07-27 11:10 UTC (permalink / raw)
To: Mathieu Dubois-Briand
Cc: u.kleine-koenig, dakr, bhelgaas, dlechner, linux-kernel,
linux-gpio, linux, linux-iio, cy.huang, james.tai, stanley_chang,
Yu-Chun Lin, linusw, andriy.shevchenko, mwalle, brgl, tychang,
wbg, nuno.sa, Michael.Hennerich, jic23, andy, o-takashi
On Mon, 27 Jul 2026 10:20:35 +0200, Mathieu Dubois-Briand
<mathieu.dubois-briand@bootlin.com> said:
> On Sun Jul 26, 2026 at 2:52 PM CEST, Yu-Chun Lin wrote:
>> 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.
>>
>> Reviewed-by: Linus Walleij <linusw@kernel.org>
>> 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 v8:
>> - Add error handlers in td1625_gpio_irq_handle().
>> - Move the direction-checking logic from the core to our custom
>> reg_mask_xlate() callback.
>> - Add Reviewed-by tag from Linus.
>> ---
>
> Thanks for the fixes.
>
> Reviewed-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
>
Hi!
Please leave series-wide tags under the cover letter, otherwise b4 will only
apply it to the specific patch under which you commented.
Bart
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 9/9] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC
2026-07-27 11:10 ` Bartosz Golaszewski
@ 2026-07-27 11:23 ` Mathieu Dubois-Briand
2026-07-27 13:04 ` Bartosz Golaszewski
0 siblings, 1 reply; 15+ messages in thread
From: Mathieu Dubois-Briand @ 2026-07-27 11:23 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: u.kleine-koenig, dakr, bhelgaas, dlechner, linux-kernel,
linux-gpio, linux, linux-iio, cy.huang, james.tai, stanley_chang,
Yu-Chun Lin, linusw, andriy.shevchenko, mwalle, tychang, wbg,
nuno.sa, Michael.Hennerich, jic23, andy, o-takashi
On Mon Jul 27, 2026 at 1:10 PM CEST, Bartosz Golaszewski wrote:
> On Mon, 27 Jul 2026 10:20:35 +0200, Mathieu Dubois-Briand
> <mathieu.dubois-briand@bootlin.com> said:
>> On Sun Jul 26, 2026 at 2:52 PM CEST, Yu-Chun Lin wrote:
>>> 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.
>>>
>>> Reviewed-by: Linus Walleij <linusw@kernel.org>
>>> 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 v8:
>>> - Add error handlers in td1625_gpio_irq_handle().
>>> - Move the direction-checking logic from the core to our custom
>>> reg_mask_xlate() callback.
>>> - Add Reviewed-by tag from Linus.
>>> ---
>>
>> Thanks for the fixes.
>>
>> Reviewed-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
>>
>
> Hi!
>
> Please leave series-wide tags under the cover letter, otherwise b4 will only
> apply it to the specific patch under which you commented.
>
> Bart
Sorry, this was a patch-specific review, but the way I sent it was a bit
misleading.
Thanks,
Mathieu
--
Mathieu Dubois-Briand, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 9/9] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC
2026-07-27 11:23 ` Mathieu Dubois-Briand
@ 2026-07-27 13:04 ` Bartosz Golaszewski
2026-07-27 14:07 ` Mathieu Dubois-Briand
0 siblings, 1 reply; 15+ messages in thread
From: Bartosz Golaszewski @ 2026-07-27 13:04 UTC (permalink / raw)
To: Mathieu Dubois-Briand
Cc: u.kleine-koenig, dakr, bhelgaas, dlechner, linux-kernel,
linux-gpio, linux, linux-iio, cy.huang, james.tai, stanley_chang,
Yu-Chun Lin, linusw, andriy.shevchenko, mwalle, tychang, wbg,
nuno.sa, Michael.Hennerich, jic23, andy, o-takashi,
Bartosz Golaszewski
On Mon, 27 Jul 2026 13:23:24 +0200, Mathieu Dubois-Briand
<mathieu.dubois-briand@bootlin.com> said:
> On Mon Jul 27, 2026 at 1:10 PM CEST, Bartosz Golaszewski wrote:
>> On Mon, 27 Jul 2026 10:20:35 +0200, Mathieu Dubois-Briand
>> <mathieu.dubois-briand@bootlin.com> said:
>>> On Sun Jul 26, 2026 at 2:52 PM CEST, Yu-Chun Lin wrote:
>>>> 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.
>>>>
>>>> Reviewed-by: Linus Walleij <linusw@kernel.org>
>>>> 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 v8:
>>>> - Add error handlers in td1625_gpio_irq_handle().
>>>> - Move the direction-checking logic from the core to our custom
>>>> reg_mask_xlate() callback.
>>>> - Add Reviewed-by tag from Linus.
>>>> ---
>>>
>>> Thanks for the fixes.
>>>
>>> Reviewed-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
>>>
>>
>> Hi!
>>
>> Please leave series-wide tags under the cover letter, otherwise b4 will only
>> apply it to the specific patch under which you commented.
>>
>> Bart
>
> Sorry, this was a patch-specific review, but the way I sent it was a bit
> misleading.
>
Ah, no worries then. Is this series good to go now?
Bart
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 9/9] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC
2026-07-27 13:04 ` Bartosz Golaszewski
@ 2026-07-27 14:07 ` Mathieu Dubois-Briand
0 siblings, 0 replies; 15+ messages in thread
From: Mathieu Dubois-Briand @ 2026-07-27 14:07 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: u.kleine-koenig, dakr, bhelgaas, dlechner, linux-kernel,
linux-gpio, linux, linux-iio, cy.huang, james.tai, stanley_chang,
Yu-Chun Lin, linusw, andriy.shevchenko, mwalle, tychang, wbg,
nuno.sa, Michael.Hennerich, jic23, andy, o-takashi
On Mon Jul 27, 2026 at 3:04 PM CEST, Bartosz Golaszewski wrote:
> On Mon, 27 Jul 2026 13:23:24 +0200, Mathieu Dubois-Briand
> <mathieu.dubois-briand@bootlin.com> said:
>> On Mon Jul 27, 2026 at 1:10 PM CEST, Bartosz Golaszewski wrote:
>>> On Mon, 27 Jul 2026 10:20:35 +0200, Mathieu Dubois-Briand
>>> <mathieu.dubois-briand@bootlin.com> said:
>>>> On Sun Jul 26, 2026 at 2:52 PM CEST, Yu-Chun Lin wrote:
>>>>> 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.
>>>>>
>>>>> Reviewed-by: Linus Walleij <linusw@kernel.org>
>>>>> 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 v8:
>>>>> - Add error handlers in td1625_gpio_irq_handle().
>>>>> - Move the direction-checking logic from the core to our custom
>>>>> reg_mask_xlate() callback.
>>>>> - Add Reviewed-by tag from Linus.
>>>>> ---
>>>>
>>>> Thanks for the fixes.
>>>>
>>>> Reviewed-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
>>>>
>>>
>>> Hi!
>>>
>>> Please leave series-wide tags under the cover letter, otherwise b4 will only
>>> apply it to the specific patch under which you commented.
>>>
>>> Bart
>>
>> Sorry, this was a patch-specific review, but the way I sent it was a bit
>> misleading.
>>
>
> Ah, no worries then. Is this series good to go now?
>
> Bart
It is good to go on my side, I made the comments I had.
--
Mathieu Dubois-Briand, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 15+ messages in thread