Linux GPIO subsystem development
 help / color / mirror / Atom feed
From: "Yu-Chun Lin [林祐君]" <eleanor.lin@realtek.com>
To: Andy Shevchenko <andriy.shevchenko@intel.com>
Cc: "linusw@kernel.org" <linusw@kernel.org>,
	"mwalle@kernel.org" <mwalle@kernel.org>,
	"brgl@kernel.org" <brgl@kernel.org>,
	"TY_Chang[張子逸]" <tychang@realtek.com>,
	"wbg@kernel.org" <wbg@kernel.org>,
	"mathieu.dubois-briand@bootlin.com"
	<mathieu.dubois-briand@bootlin.com>,
	"nuno.sa@analog.com" <nuno.sa@analog.com>,
	"Michael.Hennerich@analog.com" <Michael.Hennerich@analog.com>,
	"jic23@kernel.org" <jic23@kernel.org>,
	"andy@kernel.org" <andy@kernel.org>,
	"u.kleine-koenig@baylibre.com" <u.kleine-koenig@baylibre.com>,
	"dakr@kernel.org" <dakr@kernel.org>,
	"bhelgaas@google.com" <bhelgaas@google.com>,
	"o-takashi@sakamocchi.jp" <o-takashi@sakamocchi.jp>,
	"dlechner@baylibre.com" <dlechner@baylibre.com>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"linux-gpio@vger.kernel.org" <linux-gpio@vger.kernel.org>,
	"linux@analog.com" <linux@analog.com>,
	"linux-iio@vger.kernel.org" <linux-iio@vger.kernel.org>,
	"CY_Huang[黃鉦晏]" <cy.huang@realtek.com>,
	"James Tai [戴志峰]" <james.tai@realtek.com>
Subject: RE: [PATCH v6 8/8] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC
Date: Tue, 21 Jul 2026 12:09:25 +0000	[thread overview]
Message-ID: <969142b30fbe4238bbbd46ce6d8ef56c@realtek.com> (raw)
In-Reply-To: <al9ULO_55RlDQxgl@ashevche-desk.local>

Hi Andy,
Thanks for your feedback.

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

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

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

Ack.

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

Ack.

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

Ack.

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

Ack.

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

Ack.

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

Ack.

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

Ack.

Best Regards,
Yu-Chun

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

      reply	other threads:[~2026-07-21 12:09 UTC|newest]

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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=969142b30fbe4238bbbd46ce6d8ef56c@realtek.com \
    --to=eleanor.lin@realtek.com \
    --cc=Michael.Hennerich@analog.com \
    --cc=andriy.shevchenko@intel.com \
    --cc=andy@kernel.org \
    --cc=bhelgaas@google.com \
    --cc=brgl@kernel.org \
    --cc=cy.huang@realtek.com \
    --cc=dakr@kernel.org \
    --cc=dlechner@baylibre.com \
    --cc=james.tai@realtek.com \
    --cc=jic23@kernel.org \
    --cc=linusw@kernel.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@analog.com \
    --cc=mathieu.dubois-briand@bootlin.com \
    --cc=mwalle@kernel.org \
    --cc=nuno.sa@analog.com \
    --cc=o-takashi@sakamocchi.jp \
    --cc=tychang@realtek.com \
    --cc=u.kleine-koenig@baylibre.com \
    --cc=wbg@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox