From nobody Sat Jul 25 01:35:29 2026 Received: from rtits2.realtek.com.tw (rtits2.realtek.com [211.75.126.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0D23542A162; Tue, 21 Jul 2026 06:58:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.75.126.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617117; cv=none; b=cRaU5ZP/3t8K1wskOW5nhsHMUIU82jdvjQXNTxZppE/F1ztjo6U9LESzQ0iUnAAlDSZo2E4f0FBGk4yZGhtAdpJRDxk3LGuhr6V1jOCtA5VXZiK92PBUL5tB+AWpORvI3Fc8Vfz2xtB9o3bYF5qMELI67X4RksaGCZoBdEq7Sd4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617117; c=relaxed/simple; bh=QKJ9SeSLmsjdNhfiPhWc0XppmIzy/lVdNbHvQ+KHcdE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=WUvOj66Dnmg9aiRgwMGpmfaDppv9cMJG5G4bNVDRUvQ5Hgs2uYWm1JfjP+HBViZoZkI2fAbFQwHd7LgFi1EqIMA2gXjUf0mv10Z2sAm6pfsu/WyOe4Ufrq5B0+BwWGTD+D62G0EGcSGOrRNODa2TSI9c9+DBQjHLGRUYbmACZgs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com; spf=pass smtp.mailfrom=realtek.com; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b=kjNVTfmF; arc=none smtp.client-ip=211.75.126.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=realtek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b="kjNVTfmF" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 66L6w2LO13014032, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realtek.com; s=dkim; t=1784617082; bh=qXuJdaIZSjN90xnJGPa+er0eRReVsNj5mtIZDg+jJ/8=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=kjNVTfmFHoRwmyEgFfkDefJqeXvfOrTRSvUuekUBxhm9+5yIUYA9W92FUbrmBvwyH QDRedklQZV79IGcRasVwccsmeRqHKoUhhfIw+4un03MiLhdirveZL7hoptEZ3ERgS1 k0OgJZYyX+/xYoOQZIQ9EIgcZaHiQei6gtrmf57iX9FVMiX/DN5xXQrWMO2Bxm6nfJ labY2h5gmkXQwFhfYICEXw4Ula5cl2QDEuw49T8R6+SfhTZSwS4Azj8jlu57dEVB4N Jean9zLGzIuHonHFstaHeQOIStGBuwZKpKg2XDPdFSIeJTOHFMaA4AD7nMK+1ZmOeD +LspZO8WKyWRg== Received: from mail.realtek.com (rtkexhmbs02.realtek.com.tw[172.21.6.41]) by rtits2.realtek.com.tw (8.15.2/3.29/5.94) with ESMTPS id 66L6w2LO13014032 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 21 Jul 2026 14:58:02 +0800 Received: from RTKEXHMBS05.realtek.com.tw (10.21.1.55) by RTKEXHMBS02.realtek.com.tw (172.21.6.41) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 21 Jul 2026 14:58:02 +0800 Received: from cn1dhc-k02 (172.21.252.101) by RTKEXHMBS05.realtek.com.tw (10.21.1.55) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Tue, 21 Jul 2026 14:58:02 +0800 From: Yu-Chun Lin To: , , , , , , , , , , , , , , CC: , , , , , , , Subject: [PATCH v6 1/8] Revert "gpio: realtek: Add driver for Realtek DHC RTD1625 SoC" Date: Tue, 21 Jul 2026 14:57:55 +0800 Message-ID: <20260721065802.689530-2-eleanor.lin@realtek.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260721065802.689530-1-eleanor.lin@realtek.com> References: <20260721065802.689530-1-eleanor.lin@realtek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This reverts commit a57e27c43b0315ee86c6896510d69be5257e093e. The driver will be rewritten to use the gpio-regmap infrastructure once Andy Shevchenko's patches for gpio-regmap are applied. Signed-off-by: Yu-Chun Lin Acked-by: Andy Shevchenko Acked-by: Linus Walleij --- 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. =20 -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) +=3D gpio-realtek-otto= .o obj-$(CONFIG_GPIO_REG) +=3D gpio-reg.o obj-$(CONFIG_GPIO_ROCKCHIP) +=3D gpio-rockchip.o obj-$(CONFIG_GPIO_RTD) +=3D gpio-rtd.o -obj-$(CONFIG_GPIO_RTD1625) +=3D gpio-rtd1625.o obj-$(CONFIG_ARCH_SA1100) +=3D gpio-sa1100.o obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) +=3D gpio-sama5d2-piobu.o obj-$(CONFIG_GPIO_SCH311X) +=3D 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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, uns= igned int offset) -{ - return data->info->gpa_offset + ((offset / 32) * 4); -} - -static unsigned int rtd1625_gpio_gpda_offset(struct rtd1625_gpio *data, un= signed int offset) -{ - return data->info->gpda_offset + ((offset / 32) * 4); -} - -static unsigned int rtd1625_gpio_level_offset(struct rtd1625_gpio *data, u= nsigned 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 =3D gpiochip_get_data(chip); - u8 deb_val; - u32 val; - - switch (debounce) { - case 1: - deb_val =3D RTD1625_GPIO_DEBOUNCE_1US; - break; - case 10: - deb_val =3D RTD1625_GPIO_DEBOUNCE_10US; - break; - case 100: - deb_val =3D RTD1625_GPIO_DEBOUNCE_100US; - break; - case 1000: - deb_val =3D RTD1625_GPIO_DEBOUNCE_1MS; - break; - case 10000: - deb_val =3D RTD1625_GPIO_DEBOUNCE_10MS; - break; - case 20000: - deb_val =3D RTD1625_GPIO_DEBOUNCE_20MS; - break; - case 30000: - deb_val =3D RTD1625_GPIO_DEBOUNCE_30MS; - break; - case 50000: - deb_val =3D RTD1625_GPIO_DEBOUNCE_50MS; - break; - default: - return -ENOTSUPP; - } - - val =3D FIELD_PREP(RTD1625_GPIO_DEBOUNCE, deb_val) | RTD1625_GPIO_DEBOUNC= E_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 of= fset, - unsigned long config) -{ - u32 debounce; - - if (pinconf_to_config_param(config) =3D=3D PIN_CONFIG_INPUT_DEBOUNCE) { - debounce =3D 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, i= nt value) -{ - struct rtd1625_gpio *data =3D gpiochip_get_data(chip); - u32 val =3D RTD1625_GPIO_WREN(RTD1625_GPIO_OUT); - - if (value) - val |=3D 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 =3D gpiochip_get_data(chip); - u32 val; - - guard(raw_spinlock_irqsave)(&data->lock); - - val =3D 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 =3D gpiochip_get_data(chip); - u32 val; - - guard(raw_spinlock_irqsave)(&data->lock); - - val =3D 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 =3D gpiochip_get_data(chip); - u32 val =3D RTD1625_GPIO_WREN(RTD1625_GPIO_DIR); - - if (out) - val |=3D 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 i= nt 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 of= fset); - struct rtd1625_gpio *data =3D irq_desc_get_handler_data(desc); - struct irq_domain *domain =3D data->gpio_chip.irq.domain; - struct irq_chip *chip =3D irq_desc_get_chip(desc); - unsigned int irq =3D 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 =3D=3D data->irqs[RTD1625_IRQ_ASSERT]) - get_reg_offset =3D &rtd1625_gpio_gpa_offset; - else if (irq =3D=3D data->irqs[RTD1625_IRQ_DEASSERT]) - get_reg_offset =3D &rtd1625_gpio_gpda_offset; - else if (irq =3D=3D data->irqs[2]) - get_reg_offset =3D &rtd1625_gpio_level_offset; - else - return; - - chained_irq_enter(chip, desc); - - for (i =3D 0; i < data->info->num_gpios; i +=3D 32) { - reg_offset =3D get_reg_offset(data, i); - status =3D 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 !=3D data->irqs[RTD1625_IRQ_LEVEL]) - writel_relaxed(status, data->irq_base + reg_offset); - - for_each_set_bit(j, &status, 32) { - hwirq =3D i + j; - girq =3D irq_find_mapping(domain, hwirq); - irq_type =3D irq_get_trigger_type(girq); - - /* - * Filter out the hardware-forced de-assert interrupt unless - * the user explicitly requested IRQ_TYPE_EDGE_BOTH. - */ - if (irq =3D=3D data->irqs[RTD1625_IRQ_DEASSERT] && - irq_type !=3D 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 =3D irq_data_get_irq_chip_data(d); - irq_hw_number_t hwirq =3D irqd_to_hwirq(d); - u32 irq_type =3D irqd_get_trigger_type(d); - u32 bit_mask =3D BIT(hwirq % 32); - int reg_offset; - - if (irq_type & IRQ_TYPE_LEVEL_MASK) { - reg_offset =3D 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 =3D rtd1625_gpio_gpda_offset(data, hwirq); - int gpa_reg_offset =3D rtd1625_gpio_gpa_offset(data, hwirq); - u32 clr_mask =3D 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 =3D RTD1625_GPIO_EDGE_INT_EN | RTD1625_GPIO_WREN(RTD1625_GPIO_EDGE_IN= T_EN); - writel_relaxed(val, data->base + GPIO_CONTROL(hwirq)); -} - -static void rtd1625_gpio_disable_edge_irq(struct rtd1625_gpio *data, irq_h= w_number_t hwirq) -{ - u32 val; - - guard(raw_spinlock_irqsave)(&data->lock); - - val =3D 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_h= w_number_t hwirq) -{ - int level_reg_offset =3D rtd1625_gpio_level_offset(data, hwirq); - u32 clr_mask =3D BIT(hwirq % 32); - u32 val; - - guard(raw_spinlock_irqsave)(&data->lock); - - writel_relaxed(clr_mask, data->irq_base + level_reg_offset); - val =3D 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 =3D 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 =3D irq_data_get_irq_chip_data(d); - struct rtd1625_gpio *data =3D gpiochip_get_data(gc); - irq_hw_number_t hwirq =3D irqd_to_hwirq(d); - u32 irq_type =3D 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 =3D irq_data_get_irq_chip_data(d); - struct rtd1625_gpio *data =3D gpiochip_get_data(gc); - irq_hw_number_t hwirq =3D irqd_to_hwirq(d); - u32 irq_type =3D 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 =3D irq_data_get_irq_chip_data(d); - struct rtd1625_gpio *data =3D gpiochip_get_data(gc); - irq_hw_number_t hwirq =3D irqd_to_hwirq(d); - u32 val =3D RTD1625_GPIO_WREN(RTD1625_GPIO_LEVEL_INT_DP); - - if (!(data->info->irq_type_support & IRQ_TYPE_LEVEL_MASK)) - return -EINVAL; - - if (level) - val |=3D 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 polarit= y) -{ - struct gpio_chip *gc =3D irq_data_get_irq_chip_data(d); - struct rtd1625_gpio *data =3D gpiochip_get_data(gc); - irq_hw_number_t hwirq =3D irqd_to_hwirq(d); - u32 val =3D RTD1625_GPIO_WREN(RTD1625_GPIO_EDGE_INT_DP); - - if (!(data->info->irq_type_support & IRQ_TYPE_EDGE_BOTH)) - return -EINVAL; - - if (polarity) - val |=3D 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 =3D { - .name =3D "rtd1625-gpio", - .irq_ack =3D rtd1625_gpio_ack_irq, - .irq_mask =3D rtd1625_gpio_disable_irq, - .irq_unmask =3D rtd1625_gpio_enable_irq, - .irq_set_type =3D rtd1625_gpio_irq_set_type, - .flags =3D IRQCHIP_IMMUTABLE | IRQCHIP_SKIP_SET_WAKE, - GPIOCHIP_IRQ_RESOURCE_HELPERS, -}; - -static int rtd1625_gpio_setup_irq(struct platform_device *pdev, struct rtd= 1625_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 =3D platform_get_irq_optional(pdev, 0); - if (irq =3D=3D -ENXIO) - return 0; - if (irq < 0) - return irq; - - num_irqs =3D (data->info->irq_type_support & IRQ_TYPE_LEVEL_MASK) ? 3 : 2; - data->irqs[RTD1625_IRQ_ASSERT] =3D irq; - - for (unsigned int i =3D 1; i < num_irqs; i++) { - irq =3D platform_get_irq(pdev, i); - if (irq < 0) - return irq; - data->irqs[i] =3D irq; - } - - irq_chip =3D &data->gpio_chip.irq; - irq_chip->handler =3D handle_bad_irq; - irq_chip->default_type =3D IRQ_TYPE_NONE; - irq_chip->parent_handler =3D rtd1625_gpio_irq_handle; - irq_chip->parent_handler_data =3D data; - irq_chip->num_parents =3D num_irqs; - irq_chip->parents =3D 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 =3D &pdev->dev; - struct rtd1625_gpio *data; - void __iomem *irq_base; - int ret; - - data =3D devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->info =3D device_get_match_data(dev); - if (!data->info) - return -EINVAL; - - raw_spin_lock_init(&data->lock); - - irq_base =3D devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(irq_base)) - return PTR_ERR(irq_base); - - data->irq_base =3D irq_base; - data->base =3D irq_base + data->info->base_offset; - - data->save_regs =3D devm_kcalloc(dev, data->info->num_gpios, sizeof(*data= ->save_regs), - GFP_KERNEL); - if (!data->save_regs) - return -ENOMEM; - - data->gpio_chip.label =3D dev_name(dev); - data->gpio_chip.base =3D -1; - data->gpio_chip.ngpio =3D data->info->num_gpios; - data->gpio_chip.request =3D gpiochip_generic_request; - data->gpio_chip.free =3D gpiochip_generic_free; - data->gpio_chip.get_direction =3D rtd1625_gpio_get_direction; - data->gpio_chip.direction_input =3D rtd1625_gpio_direction_input; - data->gpio_chip.direction_output =3D rtd1625_gpio_direction_output; - data->gpio_chip.set =3D rtd1625_gpio_set; - data->gpio_chip.get =3D rtd1625_gpio_get; - data->gpio_chip.set_config =3D rtd1625_gpio_set_config; - data->gpio_chip.parent =3D dev; - - ret =3D 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 =3D { - .num_gpios =3D 166, - .irq_type_support =3D IRQ_TYPE_EDGE_BOTH, - .base_offset =3D 0x100, - .gpa_offset =3D 0x000, - .gpda_offset =3D 0x020, - .write_en_all =3D RTD1625_ISO_GPIO_WREN_ALL, -}; - -static const struct rtd1625_gpio_info rtd1625_isom_gpio_info =3D { - .num_gpios =3D 4, - .irq_type_support =3D IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_LEVEL_LOW | - IRQ_TYPE_LEVEL_HIGH, - .base_offset =3D 0x20, - .gpa_offset =3D 0x00, - .gpda_offset =3D 0x04, - .level_offset =3D 0x18, - .write_en_all =3D RTD1625_ISOM_GPIO_WREN_ALL, -}; - -static int rtd1625_gpio_suspend(struct device *dev) -{ - struct rtd1625_gpio *data =3D dev_get_drvdata(dev); - const struct rtd1625_gpio_info *info =3D data->info; - - for (unsigned int i =3D 0; i < info->num_gpios; i++) - data->save_regs[i] =3D readl_relaxed(data->base + GPIO_CONTROL(i)); - - return 0; -} - -static int rtd1625_gpio_resume(struct device *dev) -{ - struct rtd1625_gpio *data =3D dev_get_drvdata(dev); - const struct rtd1625_gpio_info *info =3D data->info; - - for (unsigned int i =3D 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[] =3D { - { .compatible =3D "realtek,rtd1625-iso-gpio", .data =3D &rtd1625_iso_gpio= _info }, - { .compatible =3D "realtek,rtd1625-isom-gpio", .data =3D &rtd1625_isom_gp= io_info }, - { } -}; -MODULE_DEVICE_TABLE(of, rtd1625_gpio_of_matches); - -static struct platform_driver rtd1625_gpio_platform_driver =3D { - .driver =3D { - .name =3D "gpio-rtd1625", - .of_match_table =3D rtd1625_gpio_of_matches, - .pm =3D pm_sleep_ptr(&rtd1625_gpio_pm_ops), - }, - .probe =3D 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"); --=20 2.43.0 From nobody Sat Jul 25 01:35:29 2026 Received: from rtits2.realtek.com.tw (rtits2.realtek.com [211.75.126.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4979F42DA35; Tue, 21 Jul 2026 06:58:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.75.126.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617119; cv=none; b=Yv1iE64S1Zn7pk8lfC+lBrrLM9cf8CIox/CgDgccpkH1TuoX0rr5t92/ZyHNEgQfMCeE1ILZzgKV6BfdZlNFz537Y10b7xv+DC+M8p7PYW9YKxKaS7p9Imk4QuqVPVdOtygpJVJdjK1T0POLuZnDLaQLfayWwuTPyQU/ZDB82R8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617119; c=relaxed/simple; bh=RvwDCpRXnN9dI+Byg7715D5QgV5d4OjI058sswEXLbA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=mB8OgAaVcrHnHhBuSCD21KVhF3WRWh8EMh8jTb6wsm93eE0iRZCsn+pbKYboPjg+GqHDODAKobdcMlnYi+RXMN+4hhXvEvAqosQMykDaU4JQyOszKhR5T9OegEuKicjm9iLni/Y1E0cJ3jjkduMGa/YvmLVCCr99nJ2SoV5JFJk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com; spf=pass smtp.mailfrom=realtek.com; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b=Ve7axBCg; arc=none smtp.client-ip=211.75.126.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=realtek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b="Ve7axBCg" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 66L6w44s93014041, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realtek.com; s=dkim; t=1784617084; bh=d9U7R70n3ivMA5xWfoEJlAr7TNsouCIjO8amTPMYc80=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=Ve7axBCgF4V+pwoLPOAkchqNv9OSuXj8B7m30aaT5hv4vqgoAp5Hl8N9Ih+go5y+V MNbxG4OIGbOItZwDpAXgmsQw2CdOqet4CTR7T5dy/nnut/jjnjQ6rISYMF1tEry0zH PI8FGRGCF0XQuZeKVDwMRA4cOLiPAOEUVM4UbfIinYD1JzbazmybbBWPdz2Mr7zwCm ALL8bm1Jr5IBsQhcBBugv4QFRugOvOgo2LftWRlKM4tQh2a5Kgtrg7uIpaZhlb7H9n 61GJc2xTMazJACBn9de50EN0Bp7i9hAAw2buyAIphvFvC8e0OURP4b8Ksa5cv+0Pw+ +oBExkm6CMpVA== Received: from mail.realtek.com (rtkexhmbs02.realtek.com.tw[172.21.6.41]) by rtits2.realtek.com.tw (8.15.2/3.29/5.94) with ESMTPS id 66L6w44s93014041 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 21 Jul 2026 14:58:04 +0800 Received: from RTKEXHMBS05.realtek.com.tw (10.21.1.55) by RTKEXHMBS02.realtek.com.tw (172.21.6.41) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 21 Jul 2026 14:58:03 +0800 Received: from cn1dhc-k02 (172.21.252.101) by RTKEXHMBS05.realtek.com.tw (10.21.1.55) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Tue, 21 Jul 2026 14:58:03 +0800 From: Yu-Chun Lin To: , , , , , , , , , , , , , , CC: , , , , , , , , Andy Shevchenko Subject: [PATCH v6 2/8] gpio: regmap: Provide default IRQ resource request and release callbacks Date: Tue, 21 Jul 2026 14:57:56 +0800 Message-ID: <20260721065802.689530-3-eleanor.lin@realtek.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260721065802.689530-1-eleanor.lin@realtek.com> References: <20260721065802.689530-1-eleanor.lin@realtek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Andy Shevchenko When GPIO regmap based driver supplies its own IRQ domain, it might still want to keep track of the IRQ requests and releases, in particular to prevent a GPIO, which is used and locked as IRQ, to be requested via standard ways. Provide default callbacks for such cases and keep struct gpio_chip private to GPIO regmap implementation. Signed-off-by: Andy Shevchenko Signed-off-by: Yu-Chun Lin Reviewed-by: Michael Walle --- 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_ch= ip *chip, return gpio_regmap_set_direction(chip, offset, true); } =20 +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 de= vice *dev, const struct gpio_regmap_config *config); void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio); =20 +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 */ --=20 2.43.0 From nobody Sat Jul 25 01:35:29 2026 Received: from rtits2.realtek.com.tw (rtits2.realtek.com [211.75.126.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 88E873AEF46; Tue, 21 Jul 2026 06:58:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.75.126.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617118; cv=none; b=aV0pX1BF/o0DKuNXClxOMiiJzbiZJRuSg3sRade/w3pNTAuKO82ZpMXr5DU2bnDbPFdXudu3wVMokRCn0IpmX/k3yE2H9WeWy48u/1TxXdDc6oHRAq9mJ1LORu7P497ccdt3lh9i20CaILJhc1FJef0TYRUur7yUEVYtUHxj8fU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617118; c=relaxed/simple; bh=mvZ6LfaiMOk8Gtbk0sYAeRWlXPYsQaMZJi1mCmNpF2E=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=FYa/Dh8s8rshWuPbT5BkXZkaWnDtLCVQZYpNn8AwT4N+PMDmSly1vrH9OTyCC8HPlthet/iLkoS08y8Ey9zaMoeFk2CWDXFAAv/mt7iWbITWVjs+XMWXRBWyEkvwrn0sK4KjJmzwP9IEmNDHHkIFA4yNjbfYx4K0mSfnmxIiXhI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com; spf=pass smtp.mailfrom=realtek.com; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b=Qz+lg8YG; arc=none smtp.client-ip=211.75.126.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=realtek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b="Qz+lg8YG" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 66L6w5ZL13014048, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realtek.com; s=dkim; t=1784617086; bh=ufwCg89unn13pq1kHfq4a9TgOvopaDEBjmJvtqc5OBo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=Qz+lg8YGjolG89fxHiGOeFbyt0SMbxEgqBTs7D8FZgUVehGEa9qoOe1Geetx5VNL1 Nu9yJ1gnAzJGQaOpJn/EjuJZEYOyKpwD9cnUyMqcNJBxrPMPSPCnglX/g6NfyoEJG8 KhrS5CCDzIE+fcxlkcgb29GkuiJQGw12y5ih4krBUuB9U1N5qd1938jTDLCUk6TH7r nvvNC3yuPr5y31nsfG59aR0CqPb9AfRqhk+bA+3yAPwRtEh8v4S5MicSwcAY/yJels 1tCZd1EMIyJmiGdZ3suyet7LdeWIXCuFbHZJfRUOlVNDNWT1EZiLrJ9fosKsONzb68 UyXeBVdo1/96Q== Received: from mail.realtek.com (rtkexhmbs02.realtek.com.tw[172.21.6.41]) by rtits2.realtek.com.tw (8.15.2/3.29/5.94) with ESMTPS id 66L6w5ZL13014048 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 21 Jul 2026 14:58:05 +0800 Received: from RTKEXHMBS05.realtek.com.tw (10.21.1.55) by RTKEXHMBS02.realtek.com.tw (172.21.6.41) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 21 Jul 2026 14:58:06 +0800 Received: from RTKEXHMBS05.realtek.com.tw (10.21.1.55) by RTKEXHMBS05.realtek.com.tw (10.21.1.55) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 21 Jul 2026 14:58:05 +0800 Received: from cn1dhc-k02 (172.21.252.101) by RTKEXHMBS05.realtek.com.tw (10.21.1.55) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Tue, 21 Jul 2026 14:58:04 +0800 From: Yu-Chun Lin To: , , , , , , , , , , , , , , CC: , , , , , , , , Andy Shevchenko Subject: [PATCH v6 3/8] gpio: regmap: Apply default resource callbacks for regmap IRQ chip Date: Tue, 21 Jul 2026 14:57:57 +0800 Message-ID: <20260721065802.689530-4-eleanor.lin@realtek.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260721065802.689530-1-eleanor.lin@realtek.com> References: <20260721065802.689530-1-eleanor.lin@realtek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Andy Shevchenko When GPIO regmap creates an IRQ chip on behalf of the user, it also takes an ownership of the respective callbacks and driver data. With that being done, apply default resource callbacks that keep tracking the IRQ requests and releases. Signed-off-by: Andy Shevchenko Signed-off-by: Yu-Chun Lin Reviewed-by: Michael Walle --- Changes in this version: - Move gpio_regmap_irq_reqres() and gpio_regmap_irq_relres() implementation from patch 2 to this patch. - Add '_maybe_unused' to prevent build fail when CONFIG_REGMAP_IRQ is not enabled. drivers/gpio/gpio-max7360.c | 7 ++++--- drivers/gpio/gpio-regmap.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-max7360.c b/drivers/gpio/gpio-max7360.c index d12cf1dc8d57..07eda49f375b 100644 --- a/drivers/gpio/gpio-max7360.c +++ b/drivers/gpio/gpio-max7360.c @@ -127,7 +127,7 @@ static int max7360_handle_mask_sync(const int index, const unsigned int mask_buf, void *const irq_drv_data) { - struct regmap *regmap =3D irq_drv_data; + struct regmap *regmap =3D gpio_regmap_get_drvdata(irq_drv_data); int ret; =20 for (unsigned int i =3D 0; i < MAX7360_MAX_GPIO; i++) { @@ -170,7 +170,6 @@ static int max7360_gpio_probe(struct platform_device *p= dev) =20 /* Create custom IRQ configuration. */ irq_chip =3D devm_kzalloc(dev, sizeof(*irq_chip), GFP_KERNEL); - gpio_config.regmap_irq_chip =3D irq_chip; if (!irq_chip) return -ENOMEM; =20 @@ -181,7 +180,9 @@ static int max7360_gpio_probe(struct platform_device *p= dev) irq_chip->num_irqs =3D MAX7360_MAX_GPIO; irq_chip->irqs =3D max7360_regmap_irqs; irq_chip->handle_mask_sync =3D max7360_handle_mask_sync; - irq_chip->irq_drv_data =3D regmap; + + gpio_config.regmap_irq_chip =3D irq_chip; + gpio_config.drvdata =3D regmap; =20 for (unsigned int i =3D 0; i < MAX7360_MAX_GPIO; i++) { ret =3D 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 @@ */ =20 #include +#include #include #include #include @@ -288,6 +289,16 @@ void gpio_regmap_relres_irq(struct gpio_regmap *gpio, = unsigned int offset) } EXPORT_SYMBOL_GPL(gpio_regmap_relres_irq); =20 +static int __maybe_unused gpio_regmap_irq_reqres(void *irq_drv_data, irq_h= w_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 g= pio_regmap_config *config #ifdef CONFIG_REGMAP_IRQ if (config->regmap_irq_chip) { gpio->regmap_irq_line =3D config->regmap_irq_line; + config->regmap_irq_chip->irq_reqres =3D gpio_regmap_irq_reqres; + config->regmap_irq_chip->irq_relres =3D gpio_regmap_irq_relres; + config->regmap_irq_chip->irq_drv_data =3D gpio; ret =3D regmap_add_irq_chip_fwnode(dev_fwnode(config->parent), config->r= egmap, config->regmap_irq_line, config->regmap_irq_flags, 0, config->regmap_irq_chip, &gpio->irq_chip_data); --=20 2.43.0 From nobody Sat Jul 25 01:35:29 2026 Received: from rtits2.realtek.com.tw (rtits2.realtek.com [211.75.126.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0D019426D0B; Tue, 21 Jul 2026 06:58:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.75.126.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617118; cv=none; b=E1NGByPCRuOIIzZBFB4DAfaiKIWUO0OcQZflqSM7dkt7ZvpvkTVRQnbJe8Uj94W/slPRfqgwHMCNYQotgdf+TCuAYj2h3eR8gA2Wc83SnvrWpZ9fNK2LsSNKFlSVcebaotx2mvwrDr3R/WmvZHzcsn+/licxLVY7OQEQE+FeRRE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617118; c=relaxed/simple; bh=Vqz+nVCANrmG0nBPiQCae3LnVy/TVJREPgG7CMvvBjw=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=QaP6ZC+B/bVwG/WoBUCWkFp6WhiaZ5+w94XYZE+OlpOgelsNKsIraOTn+vfSxEfJKvgdOVuAKL4ZPHEnIfO/y5vjYRZZXmL/6FYRkddokNkIMPh3J8p2o6X3HlIo34YzidmnzkFmGzTSzrnIIUmcuUvlCdy9dB7zW2tIE4LMCFk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com; spf=pass smtp.mailfrom=realtek.com; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b=aaY55ElL; arc=none smtp.client-ip=211.75.126.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=realtek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b="aaY55ElL" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 66L6w5kgD3014050, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realtek.com; s=dkim; t=1784617086; bh=eWlRWLs1pdVm5B63t53C0fv+dfzkTbgn606FaZxMG/M=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=aaY55ElLRQ0v2OYhFNqbDhp/D2/hhPb4kHQYwXPUlOXjXdllOXoNKoconW14u7WRa omPUNkAjWKu3sIs5rSRoIs/XoPsubimD1hc0JNRGl4TOCCA66BtZD6oXuWvIJhhJnx 6dbMowfCZ5LlMpmuMDBW0oF7JJm7r5wIpIY7/ooyJxiUNNtW/brWfSwfBePhdTQjBU w4he0ncBlBUR/jqlgxRA7vZRE++nr9Fr1M+V1ASCQaqeCXW/VsONinHDtp3rTX2LI2 V1MVna7Vq9w2WgJQB4Q0ca1Bv9bDK7UwXBt9wng6bNg3MoW4ngbCrPL4NRKYVsNZMU 8OT5ylmIrUyOw== Received: from mail.realtek.com (rtkexhmbs04.realtek.com.tw[10.21.1.54]) by rtits2.realtek.com.tw (8.15.2/3.29/5.94) with ESMTPS id 66L6w5kgD3014050 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 21 Jul 2026 14:58:05 +0800 Received: from RTKEXHMBS05.realtek.com.tw (10.21.1.55) by RTKEXHMBS04.realtek.com.tw (10.21.1.54) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 21 Jul 2026 14:58:06 +0800 Received: from cn1dhc-k02 (172.21.252.101) by RTKEXHMBS05.realtek.com.tw (10.21.1.55) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Tue, 21 Jul 2026 14:58:06 +0800 From: Yu-Chun Lin To: , , , , , , , , , , , , , , CC: , , , , , , , , Andy Shevchenko Subject: [PATCH v6 4/8] gpio: regmap: Order kernel-doc descriptions with the actual appearance Date: Tue, 21 Jul 2026 14:57:58 +0800 Message-ID: <20260721065802.689530-5-eleanor.lin@realtek.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260721065802.689530-1-eleanor.lin@realtek.com> References: <20260721065802.689530-1-eleanor.lin@realtek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Andy Shevchenko Order kernel-doc descriptions with the actual appearance. Signed-off-by: Andy Shevchenko Signed-off-by: Yu-Chun Lin Reviewed-by: Michael Walle --- include/linux/gpio/regmap.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h index e939709fde8d..a3ba8242c353 100644 --- a/include/linux/gpio/regmap.h +++ b/include/linux/gpio/regmap.h @@ -34,10 +34,6 @@ struct regmap; * @ngpio_per_reg: (Optional) Number of GPIOs per register * @irq_domain: (Optional) IRQ domain if the controller is * interrupt-capable - * @reg_mask_xlate: (Optional) Translates base address and GPIO - * offset to a register/bitmask pair. If not - * given the default gpio_regmap_simple_xlate() - * is used. * @fixed_direction_mask: * (Optional) Bitmap representing the GPIO lines that * make use of the @fixed_direction_output list to @@ -48,16 +44,20 @@ struct regmap; * (Optional) Bitmap representing the fixed direction of * the GPIO lines. Useful when there are GPIO lines with a * fixed direction mixed together in the same register. - * @drvdata: (Optional) Pointer to driver specific data which is - * not used by gpio-remap but is provided "as is" to the - * driver callback(s). - * @init_valid_mask: (Optional) Routine to initialize @valid_mask, to be u= sed - * 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 interrup= ts. * @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 u= sed + * 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 --=20 2.43.0 From nobody Sat Jul 25 01:35:29 2026 Received: from rtits2.realtek.com.tw (rtits2.realtek.com [211.75.126.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0D19542A144; Tue, 21 Jul 2026 06:58:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.75.126.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617117; cv=none; b=juJo3geuoSWurxcgiaZ4WLdFqj3obHs1ZpvLgNSbvSDDCWktVCD1XGyzU+dYE91stFKxacb+tlQ3Phz8luNj+joO68y9+QcLg/tRdDW/oVNzG/OiVnst0yXtsIFXU5b+/KdMX9in0/l5gtMdL07tWPmpBE8Phu/LoyBjxuqFC5E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617117; c=relaxed/simple; bh=+bhXdOTY4yijgnDNcKKLMglqtOkd6GcBoEfWj5v7u/k=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ZBv0F3A2rI6oFRENbpuEOfLb5J7zBsObSZBkXL+AiMkFoALEYKliTmP9cH68VV3zU2uisJ2Dq9YRNUBbI4VvQPo/bt5cGR7wxu+/cjvVvEwx26slcWyg872NlikK1tzNLf/Dk05iyiAQOs5UFpd9P5vCaV4ILfoe4bTWlGBWbvc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com; spf=pass smtp.mailfrom=realtek.com; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b=pN0W1BiO; arc=none smtp.client-ip=211.75.126.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=realtek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b="pN0W1BiO" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 66L6w6MM13014054, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realtek.com; s=dkim; t=1784617086; bh=MwD/01m1eJN+aia/KT/cteuyoxG4f47EF4qMlDzjW78=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=pN0W1BiOtnHU4ZscFrQRslNK8Bu37v6eBEXx8g4FH3T+uSXfpBxVaqDiqZMWTlMx/ LKg1zOuExCyNwyRZCXgXx9gdQXldJOxx2o0To+UduNx7NQsVPa/oCQq8g/gBBFVusX 7+emxj/YXxOhs4z+Mkvr1v/hBhpHscmKRrAeGSsHBNRqdoBLz1ROiolFEGegQ5GzH+ hJ50uzS5LrhsrnTCUOaLFoTi78d/AP+kE1I0GXYWGvijlE8IPcU38zEk6Xhx6NmZLg jlDXozvTTvr/BVBaf2nyn6OVI5hoDHJpOYlQGgD4ttNSljmaDXUZtRjWhjRDq7d9ud EtZ4zmNu86zHg== Received: from mail.realtek.com (rtkexhmbs03.realtek.com.tw[10.21.1.53]) by rtits2.realtek.com.tw (8.15.2/3.29/5.94) with ESMTPS id 66L6w6MM13014054 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 21 Jul 2026 14:58:06 +0800 Received: from RTKEXHMBS05.realtek.com.tw (10.21.1.55) by RTKEXHMBS03.realtek.com.tw (10.21.1.53) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 21 Jul 2026 14:58:06 +0800 Received: from cn1dhc-k02 (172.21.252.101) by RTKEXHMBS05.realtek.com.tw (10.21.1.55) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Tue, 21 Jul 2026 14:58:06 +0800 From: Yu-Chun Lin To: , , , , , , , , , , , , , , CC: , , , , , , , Subject: [PATCH v6 5/8] gpio: regmap: Add gpio_regmap_operation and value_xlate support Date: Tue, 21 Jul 2026 14:57:59 +0800 Message-ID: <20260721065802.689530-6-eleanor.lin@realtek.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260721065802.689530-1-eleanor.lin@realtek.com> References: <20260721065802.689530-1-eleanor.lin@realtek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Extend the reg_mask_xlate callback with an operation type parameter (enum gpio_regmap_operation) to allow drivers to return different register/mask combinations depending on the specific GPIO operation. In addition, introduce a new optional 'value_xlate' callback. This routine allows drivers to translate or modify the register value and mask immediately before a write operation. It is particularly useful for hardware that requires additional control bits, such as a write-enable bit, to be appended to the data dynamically. Consequently, update all existing drivers utilizing the gpio-regmap framework (across drivers/gpio, drivers/iio, and drivers/pinctrl) to accommodate the new reg_mask_xlate function signature. Suggested-by: Linus Walleij Signed-off-by: Yu-Chun Lin Acked-by: Jonathan Cameron #for-iio --- Changes in v6: - Remove removed the hardcoded write-enable workarounds. - Retain the necessary prototype updates in every driver using custom reg_mask_xlate - Add value_xlate to dynamically adjust the register mask and value right before the actual register write operation. --- drivers/gpio/gpio-104-idi-48.c | 7 +-- drivers/gpio/gpio-i8255.c | 4 +- drivers/gpio/gpio-idio-16.c | 6 +-- drivers/gpio/gpio-max7360.c | 1 + drivers/gpio/gpio-pcie-idio-24.c | 6 +-- drivers/gpio/gpio-regmap.c | 62 ++++++++++++++++++++++----- drivers/iio/adc/ad7173.c | 8 ++-- drivers/iio/addac/stx104.c | 6 +-- drivers/pinctrl/bcm/pinctrl-bcm63xx.c | 1 + drivers/pinctrl/pinctrl-tps6594.c | 1 + include/linux/gpio/regmap.h | 44 +++++++++++++++++-- 11 files changed, 115 insertions(+), 31 deletions(-) diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index ba73ee9c0c29..fb017569cfa8 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -36,9 +36,10 @@ MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line n= umbers"); #define IDI48_IRQ_STATUS 0x7 #define IDI48_IRQ_ENABLE IDI48_IRQ_STATUS =20 -static int idi_48_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int ba= se, - 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 =3D offset % 8; const unsigned int stride =3D 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); } =20 -static int i8255_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int bas= e, - 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 =3D 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, cons= t unsigned int mask_buf return 0; } =20 -static int idio_16_reg_mask_xlate(struct gpio_regmap *const gpio, const un= signed 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 gpi= o_regmap_operation op, + const unsigned int base, const unsigned int offset, + unsigned int *const reg, unsigned int *const mask) { unsigned int stride; =20 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, str= uct regmap *regmap) } =20 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; } =20 -static int idio_24_reg_mask_xlate(struct gpio_regmap *const gpio, const un= signed 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 gpi= o_regmap_operation op, + const unsigned int base, const unsigned int offset, + unsigned int *const reg, unsigned int *const mask) { const unsigned int out_stride =3D offset / IDIO_24_NGPIO_PER_REG; const unsigned int in_stride =3D (offset - 24) / IDIO_24_NGPIO_PER_REG; diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index 658b892b624c..aecc35f610dd 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -40,9 +40,16 @@ struct gpio_regmap { struct regmap_irq_chip_data *irq_chip_data; #endif =20 - int (*reg_mask_xlate)(struct gpio_regmap *gpio, unsigned int base, - unsigned int offset, unsigned int *reg, - unsigned int *mask); + int (*reg_mask_xlate)(struct gpio_regmap *gpio, + enum gpio_regmap_operation op, + unsigned int base, unsigned int offset, + unsigned int *reg, unsigned int *mask); + + int (*value_xlate)(struct gpio_regmap *gpio, + enum gpio_regmap_operation op, + unsigned int base, unsigned int offset, + unsigned int reg, unsigned int *mask, + unsigned int *val); =20 void *driver_data; }; @@ -56,6 +63,7 @@ static unsigned int gpio_regmap_addr(unsigned int addr) } =20 static int gpio_regmap_simple_xlate(struct gpio_regmap *gpio, + enum gpio_regmap_operation op, unsigned int base, unsigned int offset, unsigned int *reg, unsigned int *mask) { @@ -71,7 +79,7 @@ static int gpio_regmap_simple_xlate(struct gpio_regmap *g= pio, static int gpio_regmap_get(struct gpio_chip *chip, unsigned int offset) { struct gpio_regmap *gpio =3D gpiochip_get_data(chip); - unsigned int base, val, reg, mask; + unsigned int base, val, reg, mask, dir_mask; int ret; =20 /* we might not have an output register if we are input only */ @@ -80,7 +88,18 @@ static int gpio_regmap_get(struct gpio_chip *chip, unsig= ned int offset) else base =3D gpio_regmap_addr(gpio->reg_set_base); =20 - ret =3D gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + ret =3D gpio->reg_mask_xlate(gpio, GPIO_REGMAP_GET_OP, base, offset, ®= , &dir_mask); + if (ret) + return ret; + + ret =3D regmap_read(gpio->regmap, reg, &val); + if (ret) + return ret; + + if (val & dir_mask) + ret =3D gpio->reg_mask_xlate(gpio, GPIO_REGMAP_OUT, base, offset, ®, = &mask); + else + ret =3D gpio->reg_mask_xlate(gpio, GPIO_REGMAP_IN, base, offset, ®, &= mask); if (ret) return ret; =20 @@ -103,7 +122,7 @@ static int gpio_regmap_set(struct gpio_chip *chip, unsi= gned int offset, unsigned int reg, mask, mask_val; int ret; =20 - ret =3D gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + ret =3D gpio->reg_mask_xlate(gpio, GPIO_REGMAP_SET_OP, base, offset, ®= , &mask); if (ret) return ret; =20 @@ -112,6 +131,13 @@ static int gpio_regmap_set(struct gpio_chip *chip, uns= igned int offset, else mask_val =3D 0; =20 + if (gpio->value_xlate) { + ret =3D 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 =3D=3D gpio->reg_set_base) ret =3D regmap_write_bits(gpio->regmap, reg, mask, mask_val); @@ -125,7 +151,7 @@ static int gpio_regmap_set_with_clear(struct gpio_chip = *chip, unsigned int offset, int val) { struct gpio_regmap *gpio =3D gpiochip_get_data(chip); - unsigned int base, reg, mask; + unsigned int base, reg, mask, value =3D 0; int ret; =20 if (val) @@ -133,10 +159,17 @@ static int gpio_regmap_set_with_clear(struct gpio_chi= p *chip, else base =3D gpio_regmap_addr(gpio->reg_clr_base); =20 - ret =3D gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + ret =3D gpio->reg_mask_xlate(gpio, GPIO_REGMAP_SET_OP, base, offset, ®= , &mask); if (ret) return ret; =20 + if (gpio->value_xlate) { + ret =3D gpio->value_xlate(gpio, GPIO_REGMAP_SET_OP, base, offset, + reg, &mask, &value); + if (ret) + return ret; + } + return regmap_write(gpio->regmap, reg, mask); } =20 @@ -183,7 +216,7 @@ static int gpio_regmap_get_direction(struct gpio_chip *= chip, return -ENOTSUPP; } =20 - ret =3D gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + ret =3D gpio->reg_mask_xlate(gpio, GPIO_REGMAP_GET_DIR_OP, base, offset, = ®, &mask); if (ret) return ret; =20 @@ -237,7 +270,7 @@ static int gpio_regmap_set_direction(struct gpio_chip *= chip, return -ENOTSUPP; } =20 - ret =3D gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + ret =3D gpio->reg_mask_xlate(gpio, GPIO_REGMAP_SET_DIR_OP, base, offset, = ®, &mask); if (ret) return ret; =20 @@ -246,6 +279,13 @@ static int gpio_regmap_set_direction(struct gpio_chip = *chip, else val =3D output ? mask : 0; =20 + if (gpio->value_xlate) { + ret =3D 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); } =20 @@ -413,6 +453,8 @@ struct gpio_regmap *gpio_regmap_register(const struct g= pio_regmap_config *config if (!gpio->reg_mask_xlate) gpio->reg_mask_xlate =3D gpio_regmap_simple_xlate; =20 + gpio->value_xlate =3D config->value_xlate; + ret =3D gpiochip_add_data(chip, gpio); if (ret < 0) goto err_free_bitmap_output; diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 9ee65d63c525..f78e758706ed 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -560,8 +560,8 @@ static int ad4111_openwire_event(struct iio_dev *indio_= dev, return ret; } =20 -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_op= eration op, + unsigned int base, unsigned int offset, unsigned int *reg, unsigned int *mask) { *mask =3D AD7173_GPO_DATA(offset); @@ -569,8 +569,8 @@ static int ad7173_mask_xlate(struct gpio_regmap *gpio, = unsigned int base, return 0; } =20 -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_op= eration op, + unsigned int base, unsigned int offset, unsigned int *reg, unsigned int *mask) { *mask =3D 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[= ] =3D { STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1) }; =20 -static int stx104_reg_mask_xlate(struct gpio_regmap *const gpio, const uns= igned 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 >=3D 4) diff --git a/drivers/pinctrl/bcm/pinctrl-bcm63xx.c b/drivers/pinctrl/bcm/pi= nctrl-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 =20 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-tp= s6594.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 = =3D { }; =20 static int tps6594_gpio_regmap_xlate(struct gpio_regmap *gpio, + enum gpio_regmap_operation op, unsigned int base, unsigned int offset, unsigned int *reg, unsigned int *mask) { diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h index a3ba8242c353..45a30f50043f 100644 --- a/include/linux/gpio/regmap.h +++ b/include/linux/gpio/regmap.h @@ -13,6 +13,36 @@ struct regmap; #define GPIO_REGMAP_ADDR_ZERO ((unsigned int)(-1)) #define GPIO_REGMAP_ADDR(addr) ((addr) ? : GPIO_REGMAP_ADDR_ZERO) =20 +/** + * enum gpio_regmap_operation - Operation type for reg_mask_xlate callback + * + * This enum is used to distinguish between different types of GPIO operat= ions + * so that the reg_mask_xlate callback can return the appropriate mask for= each + * operation type. + * + * Value operations: + * @GPIO_REGMAP_GET_OP: Mask for reading direction to detect if GPIO is in= put or output. + * Used in gpio_regmap_get() to determine the GPIO di= rection. + * @GPIO_REGMAP_IN: Mask for reading input value. Used when GPIO is config= ured as input. + * @GPIO_REGMAP_OUT: Mask for reading output value. Used when GPIO is conf= igured as output. + * + * Output operations: + * @GPIO_REGMAP_SET_OP: Mask for setting GPIO output value. + * + * Direction operations: + * @GPIO_REGMAP_GET_DIR_OP: Mask for reading GPIO direction (input/output). + * @GPIO_REGMAP_SET_DIR_OP: Mask for setting GPIO direction (input/output). + * + */ +enum gpio_regmap_operation { + GPIO_REGMAP_GET_OP, + GPIO_REGMAP_SET_OP, + GPIO_REGMAP_GET_DIR_OP, + GPIO_REGMAP_SET_DIR_OP, + GPIO_REGMAP_IN, + GPIO_REGMAP_OUT, +}; + /** * struct gpio_regmap_config - Description of a generic regmap gpio_chip. * @parent: The parent device @@ -55,6 +85,10 @@ struct regmap; * is used. * @init_valid_mask: (Optional) Routine to initialize @valid_mask, to be u= sed * if not all GPIOs are valid. + * @value_xlate: (Optional) Routine to translate the register value and + * mask before writing. This allows driver-specific logic + * to append additional bits (like write-enable masks) + * dynamically based on the current operation. * @drvdata: (Optional) Pointer to driver specific data which is * not used by gpio-remap but is provided "as is" to the * driver callback(s). @@ -104,14 +138,18 @@ struct gpio_regmap_config { unsigned long regmap_irq_flags; #endif =20 - 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_operatio= n, + unsigned int base, unsigned int offset, + unsigned int *reg, unsigned int *mask); =20 int (*init_valid_mask)(struct gpio_chip *gc, unsigned long *valid_mask, unsigned int ngpios); =20 + 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; }; =20 --=20 2.43.0 From nobody Sat Jul 25 01:35:29 2026 Received: from rtits2.realtek.com.tw (rtits2.realtek.com [211.75.126.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0D2C442A17E; Tue, 21 Jul 2026 06:58:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.75.126.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617116; cv=none; b=VWIBZZq8UfSEMJBKvPO7c43emUxIiisA8cBiosSKsRqVrsXZN71zY2lh4yXeEvZJZbIoTyAF94Hm45hDFB7HPZgnhyzfepKXJV1LqQPAjIJ+J97OiCNYbKCmu8VYPzBTiDnCJzZPHpaT+VN0aMQ+e3bom+4FzKe7dMUAunfoSvc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617116; c=relaxed/simple; bh=rA8a6r/yhAKBcah1k3fbfgq08wg/I4nEhbo24pEnEJk=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=RZhyB5hx2u+KGdi+EdTV7VNVFmGjK+G16Eu3brG4FWLVYs3/5P8AggZ3VyumowTeroM8TsbZyKDQaoWv0CZwwgH+6NIRb99k1G9k9+F4eQEqG7fvC/lO3oRbdA/bmmaetZIYncJOMIJnXBA5Fuuj+LCh9CZe4J6KtaWCpC0vRio= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com; spf=pass smtp.mailfrom=realtek.com; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b=SNz9i7Ae; arc=none smtp.client-ip=211.75.126.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=realtek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b="SNz9i7Ae" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 66L6w6v253014056, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realtek.com; s=dkim; t=1784617086; bh=tErcWa7vawdhi8WJ5LaFGHq3z1tLEYUJnYrQNLu8spw=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=SNz9i7AemElws6opKXAStX+L2qBRH0uw0tTjA9g+gNOhqmnBzVZx0j0TQYuWOkWlx It/CQ420KiwaEybfuCqf98Bre/h7F9z9JB1+0CCTIkwhAbfSVm0AJyWTS+NP1cLpra bmYrZoTZ6UONQyuJf/Naidg1jzvUvMAHq6nV6JhvLgAERbcXasMQZbwT/CPE78fHEu ki6H1fYBB2vpG/RPot2U2WPbwSMdrnY3P9UoVng0c7QTsmxMDdSsS7SDBZRKjB/0y7 9qlb52jYBQOEUA94JPEXq/6vGhrmf0z0Ej5G2BNG5xV97FJgP21+VC4h1NIDZFRV9c FlvAUAHHyerAA== Received: from mail.realtek.com (rtkexhmbs04.realtek.com.tw[10.21.1.54]) by rtits2.realtek.com.tw (8.15.2/3.29/5.94) with ESMTPS id 66L6w6v253014056 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 21 Jul 2026 14:58:06 +0800 Received: from RTKEXHMBS06.realtek.com.tw (10.21.1.56) by RTKEXHMBS04.realtek.com.tw (10.21.1.54) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 21 Jul 2026 14:58:07 +0800 Received: from RTKEXHMBS05.realtek.com.tw (10.21.1.55) by RTKEXHMBS06.realtek.com.tw (10.21.1.56) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 21 Jul 2026 14:58:06 +0800 Received: from cn1dhc-k02 (172.21.252.101) by RTKEXHMBS05.realtek.com.tw (10.21.1.55) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Tue, 21 Jul 2026 14:58:06 +0800 From: Yu-Chun Lin To: , , , , , , , , , , , , , , CC: , , , , , , , Subject: [PATCH v6 6/8] gpio: regmap: Add set_config callback Date: Tue, 21 Jul 2026 14:58:00 +0800 Message-ID: <20260721065802.689530-7-eleanor.lin@realtek.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260721065802.689530-1-eleanor.lin@realtek.com> References: <20260721065802.689530-1-eleanor.lin@realtek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a new set_config callback to struct gpio_regmap_config to allow drivers to implement hardware-specific configuration such as debounce settings, or other platform-specific GPIO properties. Reviewed-by: Andy Shevchenko Signed-off-by: Yu-Chun Lin --- Changes in v6: - None. --- drivers/gpio/gpio-regmap.c | 1 + include/linux/gpio/regmap.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index aecc35f610dd..b856326ff01c 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -454,6 +454,7 @@ struct gpio_regmap *gpio_regmap_register(const struct g= pio_regmap_config *config gpio->reg_mask_xlate =3D gpio_regmap_simple_xlate; =20 gpio->value_xlate =3D config->value_xlate; + chip->set_config =3D config->set_config; =20 ret =3D gpiochip_add_data(chip, gpio); if (ret < 0) diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h index 45a30f50043f..23460995c1d1 100644 --- a/include/linux/gpio/regmap.h +++ b/include/linux/gpio/regmap.h @@ -89,6 +89,9 @@ enum gpio_regmap_operation { * mask before writing. This allows driver-specific logic * to append additional bits (like write-enable masks) * dynamically based on the current operation. + * @set_config: (Optional) Callback for setting GPIO configuration such + * as debounce, drive strength, or other hardware specific + * settings. * @drvdata: (Optional) Pointer to driver specific data which is * not used by gpio-remap but is provided "as is" to the * driver callback(s). @@ -150,6 +153,8 @@ struct gpio_regmap_config { unsigned int base, unsigned int offset, unsigned int reg, unsigned int *mask, unsigned int *val); =20 + int (*set_config)(struct gpio_chip *gc, unsigned int offset, unsigned lon= g config); + void *drvdata; }; =20 --=20 2.43.0 From nobody Sat Jul 25 01:35:29 2026 Received: from rtits2.realtek.com.tw (rtits2.realtek.com [211.75.126.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4977442B302; Tue, 21 Jul 2026 06:58:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.75.126.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617116; cv=none; b=AfBLCYizePwefT/4MNfPt1vztEwPxNHVRa+GKUXRBIFL/Qgi23T6hxkFx29PkNWRtrp/Mb5bcDV4FXRtWnsLQ9kN9G/nvdkKs5dxYnf2KC2Vk/+5LLAGvbEUgqtiVYsaHTcy7YyNZP8Jb0/Ovev0QvAX2x0mTS3AMBRh6MPbAH0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617116; c=relaxed/simple; bh=U6I3z8gdwxAvkhCmHnL7Qya4aQZmvqWUn4deA2dua04=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=PGhFCWV3kCsSJFdHhGNfxJ5bWwRpcaJK+QupvsSvtJyObAXfS9jKvvYv/3c/AbepqXkoxj5i6KBS+H+phv+kwqwA8sr1OgO1Tzv8hC5l6Yj/g8mug/5Jn13eeoD9+WJOoWXVeeX9fyzRC/XkaKsxDDnrcdMDpOOqcYbSbUXG0ig= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com; spf=pass smtp.mailfrom=realtek.com; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b=LREICTB0; arc=none smtp.client-ip=211.75.126.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=realtek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b="LREICTB0" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 66L6w6v453014056, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realtek.com; s=dkim; t=1784617086; bh=1FajypsTNcpyVsGIWUH/7huhGoEjymV0DRkxHBIAb4k=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=LREICTB0hzjIKYp4LDRKfaYYZoudMmKoIUiZ/ZgIx+DZPgi2UX5ZHXdXAZ/YFiefx okQSmeg3zMUnc/D4+GeK2M6/iIquifbIG+lWHcDhhb5Ei51zPrtKt4ln5JhDPN0UoC rI3t94znhESX6pHbQ6HhCM1UFc56vi+an8wLVN3KAlMMVmrqXpN+MyMxniu9T3dw8I vwTUXpqk8iw177stjjWrBR9i7kgc8geeYLGL2g8T/q6pEwSM3uuDaLaP6HzkR0pjJr VR/UBNsWP0O2nBYC1IFcTEKTMKv8c0xTssa1qPRlGdeImAyR3TgsArF0BHThSdM+UJ NTKLKekp82XDw== Received: from mail.realtek.com (rtkexhmbs04.realtek.com.tw[10.21.1.54]) by rtits2.realtek.com.tw (8.15.2/3.29/5.94) with ESMTPS id 66L6w6v453014056 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 21 Jul 2026 14:58:06 +0800 Received: from RTKEXHMBS05.realtek.com.tw (10.21.1.55) by RTKEXHMBS04.realtek.com.tw (10.21.1.54) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 21 Jul 2026 14:58:07 +0800 Received: from RTKEXHMBS05.realtek.com.tw (10.21.1.55) by RTKEXHMBS05.realtek.com.tw (10.21.1.55) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 21 Jul 2026 14:58:07 +0800 Received: from cn1dhc-k02 (172.21.252.101) by RTKEXHMBS05.realtek.com.tw (10.21.1.55) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Tue, 21 Jul 2026 14:58:07 +0800 From: Yu-Chun Lin To: , , , , , , , , , , , , , , CC: , , , , , , , , Andy Shevchenko Subject: [PATCH v6 7/8] gpio: regmap: Add IRQ enable/disable helpers Date: Tue, 21 Jul 2026 14:58:01 +0800 Message-ID: <20260721065802.689530-8-eleanor.lin@realtek.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260721065802.689530-1-eleanor.lin@realtek.com> References: <20260721065802.689530-1-eleanor.lin@realtek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add gpio_regmap_enable_irq() and gpio_regmap_disable_irq(). Since struct gpio_regmap is opaque, drivers cannot access the embedded gpio_chip directl= y. Suggested-by: Andy Shevchenko Signed-off-by: Yu-Chun Lin Reviewed-by: Andy Shevchenko Reviewed-by: Michael Walle --- Changes in v6: - A new patch. --- drivers/gpio/gpio-regmap.c | 12 ++++++++++++ include/linux/gpio/regmap.h | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index b856326ff01c..5c6fdff20cf8 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -345,6 +345,18 @@ void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio) } EXPORT_SYMBOL_GPL(gpio_regmap_get_drvdata); =20 +void gpio_regmap_enable_irq(struct gpio_regmap *gpio, irq_hw_number_t hwir= q) +{ + 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 hwi= rq) +{ + gpiochip_disable_irq(&gpio->gpio_chip, hwirq); +} +EXPORT_SYMBOL_GPL(gpio_regmap_disable_irq); + /** * gpio_regmap_register() - Register a generic regmap GPIO controller * @config: configuration for gpio_regmap diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h index 23460995c1d1..8042e620621d 100644 --- a/include/linux/gpio/regmap.h +++ b/include/linux/gpio/regmap.h @@ -3,6 +3,8 @@ #ifndef _LINUX_GPIO_REGMAP_H #define _LINUX_GPIO_REGMAP_H =20 +#include + struct device; struct fwnode_handle; struct gpio_regmap; @@ -167,4 +169,7 @@ void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio); int gpio_regmap_reqres_irq(struct gpio_regmap *gpio, unsigned int offset); void gpio_regmap_relres_irq(struct gpio_regmap *gpio, unsigned int offset); =20 +void gpio_regmap_enable_irq(struct gpio_regmap *gpio, irq_hw_number_t hwir= q); +void gpio_regmap_disable_irq(struct gpio_regmap *gpio, irq_hw_number_t hwi= rq); + #endif /* _LINUX_GPIO_REGMAP_H */ --=20 2.43.0 From nobody Sat Jul 25 01:35:29 2026 Received: from rtits2.realtek.com.tw (rtits2.realtek.com [211.75.126.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9847642A785; Tue, 21 Jul 2026 06:58:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.75.126.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617118; cv=none; b=QFmlnXZJSFI0/bTSP5atmFVDRBV5Pf0h5trlDByfAEzx3VcJlxaBnbfbKY1icPvP26+p4MKx01mbFwy2OtGcGSDEsk2a2b9VujLpPZse4oX7CFqoowD+mu+1kCEGZmkUC1uWSbg3lwf1D5bRsT6SKuK1TFVMYfp/7bTMOO4rU5A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784617118; c=relaxed/simple; bh=sikA/6xtkHfSWLkwZU42nrYVa7S+LWQMstRiq2AdaJ8=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=N0up4xpdQqmV5VhnGZLzeOeUrrYtZZII4p/3TGsjOmakjSouHJOkQh7jfgsHeMJlIO7Isulmgm/wf+n1cgCoJlvMfOizUO19lR5pzMsEhYtxX1+rFaNulJQ2HwWasI0R8rgkY3M04mwX6oOq1LdVm09WVg3CGQBnUNeeZwkc7vk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com; spf=pass smtp.mailfrom=realtek.com; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b=mhL9QzVH; arc=none smtp.client-ip=211.75.126.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=realtek.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=realtek.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=realtek.com header.i=@realtek.com header.b="mhL9QzVH" X-SpamFilter-By: ArmorX SpamTrap 5.80 with qID 66L6w6Wb93014061, This message is accepted by code: ctloc85258 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=realtek.com; s=dkim; t=1784617087; bh=5nAAuHqUlTWv+ETfy1/3cS7yW5ihQzHUYBxrWPSo5ek=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Content-Type; b=mhL9QzVHidbvpYX5EG0nxxVdQw9ktDJj6H5o0IxEwyuby6qGhlW2uo48GR+wwYeFt HCijipPo3347zvHV54MWJ5n8SpTosTVMkywAqfWblSpUCqCsFVfDo8ml4FSP+LwxHD rFTV76ZnHc6etblYZWFtWCiMqxvelfMo+Ud/831zUzmZvNodGjCKS4GekibyOWvNn/ 2yzTmGvK2ILvZjeF3QF5kVZixIROEcFVjXffjsdNFTSIOxhJFcJpbATmUiOSzGUGSu crQ88forwLlAo4HRFVCJ8m59woJZ842uzFOwTWWYQJM6ROjzZYN/bqKcw6afCvRIGy sggI8VledAmfA== Received: from mail.realtek.com (rtkexhmbs03.realtek.com.tw[10.21.1.53]) by rtits2.realtek.com.tw (8.15.2/3.29/5.94) with ESMTPS id 66L6w6Wb93014061 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 21 Jul 2026 14:58:06 +0800 Received: from RTKEXHMBS05.realtek.com.tw (10.21.1.55) by RTKEXHMBS03.realtek.com.tw (10.21.1.53) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Tue, 21 Jul 2026 14:58:07 +0800 Received: from cn1dhc-k02 (172.21.252.101) by RTKEXHMBS05.realtek.com.tw (10.21.1.55) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Tue, 21 Jul 2026 14:58:07 +0800 From: Yu-Chun Lin To: , , , , , , , , , , , , , , CC: , , , , , , , Subject: [PATCH v6 8/8] gpio: realtek: Add driver for Realtek DHC RTD1625 SoC Date: Tue, 21 Jul 2026 14:58:02 +0800 Message-ID: <20260721065802.689530-9-eleanor.lin@realtek.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260721065802.689530-1-eleanor.lin@realtek.com> References: <20260721065802.689530-1-eleanor.lin@realtek.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Tzuyi Chang Add support for the GPIO controller found on Realtek DHC RTD1625 SoCs. Unlike the existing Realtek GPIO driver (drivers/gpio/gpio-rtd.c), which manages pins via shared bank registers, the RTD1625 introduces a per-pin register architecture. Each GPIO line now has its own dedicated 32-bit control register to manage configuration independently, including direction, output value, input value, interrupt enable, and debounce. Therefore, this distinct hardware design requires a separate driver. The RTD1625 GPIO controller has a hardware quirk where both 'assert' and 'de-assert' interrupts are fired simultaneously on any edge toggle. The driver works around this quirk to correctly handle edge interrupts. Interrupt support is optional for this device, matching the dt-bindings. If the interrupts property is not provided, the driver simply skips IRQ initialization and operates purely as a basic GPIO controller. Signed-off-by: Tzuyi Chang Co-developed-by: Yu-Chun Lin Signed-off-by: Yu-Chun Lin --- Changes in v6: - Add 'select REGMAP_MMIO' into Kconfig. - Replace GPIOCHIP_IRQ_RESOURCE_HELPERS with explicit irq_request_resources and irq_release_resources callbacks using gpio_regmap_reqres_irq() and gpio_regmap_relres_irq() introduced by Andy's patches. - Replace the '*mask =3D 0' hack with 'return -ENOTSUPP'. - Move variable operations out of scoped_guard(). - Add 'struct lock_class_key' to irq_domain map for proper lockdep annotati= on. - Remove redundant 'ret' variable. - Make regmap disable_locking depend on CONFIG_DEBUG_GPIO to avoid dropping debugfs support unconditionally. - Replace irq_domain_add_linear() with irq_domain_create_linear() using dev_fwnode(dev), and manage lifetime with devm_add_action_or_reset(). --- drivers/gpio/Kconfig | 14 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-rtd1625.c | 667 ++++++++++++++++++++++++++++++++++++ 3 files changed, 682 insertions(+) create mode 100644 drivers/gpio/gpio-rtd1625.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ed2bc3113374..3b402ac505f1 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -656,6 +656,20 @@ config GPIO_RTD Say yes here to support GPIO functionality and GPIO interrupt on Realtek DHC SoCs. =20 +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) +=3D gpio-realtek-otto= .o obj-$(CONFIG_GPIO_REG) +=3D gpio-reg.o obj-$(CONFIG_GPIO_ROCKCHIP) +=3D gpio-rockchip.o obj-$(CONFIG_GPIO_RTD) +=3D gpio-rtd.o +obj-$(CONFIG_GPIO_RTD1625) +=3D gpio-rtd1625.o obj-$(CONFIG_ARCH_SA1100) +=3D gpio-sa1100.o obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) +=3D gpio-sama5d2-piobu.o obj-$(CONFIG_GPIO_SCH311X) +=3D gpio-sch311x.o diff --git a/drivers/gpio/gpio-rtd1625.c b/drivers/gpio/gpio-rtd1625.c new file mode 100644 index 000000000000..0aa9816b4669 --- /dev/null +++ b/drivers/gpio/gpio-rtd1625.c @@ -0,0 +1,667 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Realtek DHC RTD1625 gpio driver + * + * Copyright (c) 2023-2026 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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, uns= igned int offset) +{ + return data->info->gpa_offset + ((offset / 32) * 4); +} + +static unsigned int rtd1625_gpio_gpda_offset(struct rtd1625_gpio *data, un= signed int offset) +{ + return data->info->gpda_offset + ((offset / 32) * 4); +} + +static unsigned int rtd1625_gpio_level_offset(struct rtd1625_gpio *data, u= nsigned int offset) +{ + return data->info->level_offset + ((offset / 32) * 4); +} + +static int rtd1625_reg_mask_xlate(struct gpio_regmap *gpio, enum gpio_regm= ap_operation op, + unsigned int base, unsigned int offset, unsigned int *reg, + unsigned int *mask) +{ + /* Each GPIO has its own dedicated 32-bit register */ + *reg =3D base + offset * 4; + + switch (op) { + case GPIO_REGMAP_IN: + *mask =3D RTD1625_GPIO_IN; + break; + + case GPIO_REGMAP_OUT: + *mask =3D RTD1625_GPIO_OUT; + break; + + case GPIO_REGMAP_SET_OP: + *mask =3D RTD1625_GPIO_OUT; + break; + + case GPIO_REGMAP_GET_OP: + case GPIO_REGMAP_GET_DIR_OP: + case GPIO_REGMAP_SET_DIR_OP: + *mask =3D RTD1625_GPIO_DIR; + break; + + default: + return -ENOTSUPP; + } + + return 0; +} + +static int rtd1625_value_xlate(struct gpio_regmap *gpio, + enum gpio_regmap_operation op, + unsigned int base, unsigned int offset, + unsigned int reg, unsigned int *mask, + unsigned int *val) +{ + switch (op) { + case GPIO_REGMAP_SET_OP: + *val |=3D RTD1625_GPIO_WREN(RTD1625_GPIO_OUT); + *mask |=3D RTD1625_GPIO_WREN(RTD1625_GPIO_OUT); + break; + + case GPIO_REGMAP_SET_DIR_OP: + *val |=3D RTD1625_GPIO_WREN(RTD1625_GPIO_DIR); + *mask |=3D RTD1625_GPIO_WREN(RTD1625_GPIO_DIR); + break; + + default: + return -ENOTSUPP; + } + + return 0; +} + +static int rtd1625_gpio_set_debounce(struct gpio_chip *chip, unsigned int = offset, + unsigned int debounce) +{ + struct rtd1625_gpio *data =3D gpiochip_get_data(chip); + u8 deb_val; + u32 val; + int ret; + + switch (debounce) { + case 1: + deb_val =3D RTD1625_GPIO_DEBOUNCE_1US; + break; + case 10: + deb_val =3D RTD1625_GPIO_DEBOUNCE_10US; + break; + case 100: + deb_val =3D RTD1625_GPIO_DEBOUNCE_100US; + break; + case 1000: + deb_val =3D RTD1625_GPIO_DEBOUNCE_1MS; + break; + case 10000: + deb_val =3D RTD1625_GPIO_DEBOUNCE_10MS; + break; + case 20000: + deb_val =3D RTD1625_GPIO_DEBOUNCE_20MS; + break; + case 30000: + deb_val =3D RTD1625_GPIO_DEBOUNCE_30MS; + break; + case 50000: + deb_val =3D RTD1625_GPIO_DEBOUNCE_50MS; + break; + default: + return -ENOTSUPP; + } + + val =3D FIELD_PREP(RTD1625_GPIO_DEBOUNCE, deb_val) | RTD1625_GPIO_DEBOUNC= E_WREN; + + scoped_guard(raw_spinlock_irqsave, &data->lock) + ret =3D regmap_write(data->regmap, data->info->base_offset + GPIO_CONTRO= L(offset), + val); + + return ret; +} + +static int rtd1625_gpio_set_config(struct gpio_chip *chip, unsigned int of= fset, + unsigned long config) +{ + u32 debounce; + + if (pinconf_to_config_param(config) =3D=3D PIN_CONFIG_INPUT_DEBOUNCE) { + debounce =3D pinconf_to_config_argument(config); + return rtd1625_gpio_set_debounce(chip, offset, debounce); + } + + return gpiochip_generic_config(chip, offset, config); +} + +static void rtd1625_gpio_irq_handle(struct irq_desc *desc) +{ + unsigned int (*get_reg_offset)(struct rtd1625_gpio *gpio, unsigned int of= fset); + struct rtd1625_gpio *data =3D irq_desc_get_handler_data(desc); + struct irq_chip *chip =3D irq_desc_get_chip(desc); + unsigned int irq =3D irq_desc_get_irq(desc); + struct irq_domain *domain =3D data->domain; + unsigned int reg_offset, i, j, val; + irq_hw_number_t hwirq; + unsigned long status; + u32 irq_type; + + if (irq =3D=3D data->irqs[RTD1625_IRQ_ASSERT]) + get_reg_offset =3D &rtd1625_gpio_gpa_offset; + else if (irq =3D=3D data->irqs[RTD1625_IRQ_DEASSERT]) + get_reg_offset =3D &rtd1625_gpio_gpda_offset; + else if (irq =3D=3D data->irqs[RTD1625_IRQ_LEVEL]) + get_reg_offset =3D &rtd1625_gpio_level_offset; + else + return; + + chained_irq_enter(chip, desc); + + for (i =3D 0; i < data->info->num_gpios; i +=3D 32) { + reg_offset =3D get_reg_offset(data, i); + regmap_read(data->regmap, reg_offset, &val); + + status =3D 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 !=3D data->irqs[RTD1625_IRQ_LEVEL]) + regmap_write(data->regmap, reg_offset, status); + + for_each_set_bit(j, &status, 32) { + hwirq =3D i + j; + irq_type =3D 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 =3D=3D data->irqs[RTD1625_IRQ_DEASSERT] && + irq_type !=3D 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 =3D irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq =3D irqd_to_hwirq(d); + u32 irq_type =3D irqd_get_trigger_type(d); + u32 bit_mask =3D BIT(hwirq % 32); + int reg_offset; + + if (irq_type & IRQ_TYPE_LEVEL_MASK) { + reg_offset =3D 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 =3D rtd1625_gpio_gpda_offset(data, hwirq); + int gpa_reg_offset =3D rtd1625_gpio_gpa_offset(data, hwirq); + u32 clr_mask =3D 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 =3D RTD1625_GPIO_EDGE_INT_EN | RTD1625_GPIO_WREN(RTD1625_GPIO_EDGE_IN= T_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_h= w_number_t hwirq) +{ + u32 val; + + guard(raw_spinlock_irqsave)(&data->lock); + + val =3D 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_h= w_number_t hwirq) +{ + int level_reg_offset =3D rtd1625_gpio_level_offset(data, hwirq); + u32 clr_mask =3D BIT(hwirq % 32); + u32 val; + + guard(raw_spinlock_irqsave)(&data->lock); + + regmap_write(data->regmap, level_reg_offset, clr_mask); + val =3D 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 =3D 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 =3D irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq =3D irqd_to_hwirq(d); + u32 irq_type =3D 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 =3D irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq =3D irqd_to_hwirq(d); + u32 irq_type =3D 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 =3D RTD1625_GPIO_WREN(RTD1625_GPIO_LEVEL_INT_DP); + irq_hw_number_t hwirq =3D irqd_to_hwirq(d); + struct rtd1625_gpio *data; + int ret; + + data =3D irq_data_get_irq_chip_data(d); + if (!(data->info->irq_type_support & IRQ_TYPE_LEVEL_MASK)) + return -EINVAL; + + if (level) + val |=3D RTD1625_GPIO_LEVEL_INT_DP; + + scoped_guard(raw_spinlock_irqsave, &data->lock) + ret =3D regmap_write(data->regmap, data->info->base_offset + GPIO_CONTRO= L(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 polarit= y) +{ + struct rtd1625_gpio *data =3D irq_data_get_irq_chip_data(d); + u32 val =3D RTD1625_GPIO_WREN(RTD1625_GPIO_EDGE_INT_DP); + irq_hw_number_t hwirq =3D irqd_to_hwirq(d); + int ret; + + if (!(data->info->irq_type_support & IRQ_TYPE_EDGE_BOTH)) + return -EINVAL; + + if (polarity) + val |=3D RTD1625_GPIO_EDGE_INT_DP; + + scoped_guard(raw_spinlock_irqsave, &data->lock) + ret =3D regmap_write(data->regmap, data->info->base_offset + GPIO_CONTRO= L(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 =3D 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 =3D 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 =3D { + .name =3D "rtd1625-gpio", + .irq_ack =3D rtd1625_gpio_ack_irq, + .irq_mask =3D rtd1625_gpio_disable_irq, + .irq_unmask =3D rtd1625_gpio_enable_irq, + .irq_set_type =3D rtd1625_gpio_irq_set_type, + .flags =3D IRQCHIP_IMMUTABLE | IRQCHIP_SKIP_SET_WAKE, + .irq_request_resources =3D rtd1625_gpio_irq_request_resources, + .irq_release_resources =3D rtd1625_gpio_irq_release_resources, +}; + +static int rtd1625_gpio_setup_irq(struct platform_device *pdev, struct rtd= 1625_gpio *data) +{ + unsigned int num_irqs; + int irq; + + irq =3D platform_get_irq_optional(pdev, 0); + if (irq =3D=3D -ENXIO) + return 0; + if (irq < 0) + return irq; + + num_irqs =3D (data->info->irq_type_support & IRQ_TYPE_LEVEL_MASK) ? 3 : 2; + + for (unsigned int i =3D 0; i < num_irqs; i++) { + irq =3D platform_get_irq(pdev, i); + if (irq < 0) + return irq; + + data->irqs[i] =3D 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 ir= q, + irq_hw_number_t hwirq) +{ + struct rtd1625_gpio *data =3D 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 =3D { + .map =3D rtd1625_gpio_irq_map, + .xlate =3D irq_domain_xlate_twocell, +}; + +static const struct regmap_config rtd1625_gpio_regmap_config =3D { + .reg_bits =3D 32, + .reg_stride =3D 4, + .val_bits =3D 32, +#ifndef CONFIG_DEBUG_GPIO + .disable_locking =3D true, +#endif +}; + +static int rtd1625_gpio_probe(struct platform_device *pdev) +{ + struct gpio_regmap_config config =3D {}; + struct device *dev =3D &pdev->dev; + struct gpio_regmap *gpio_reg; + struct rtd1625_gpio *data; + void __iomem *irq_base; + int ret; + + data =3D devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->info =3D device_get_match_data(dev); + if (!data->info) + return -EINVAL; + + irq_base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(irq_base)) + return PTR_ERR(irq_base); + + data->regmap =3D devm_regmap_init_mmio(dev, irq_base, &rtd1625_gpio_regma= p_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 =3D devm_kcalloc(dev, data->info->num_gpios, sizeof(*data= ->save_regs), + GFP_KERNEL); + if (!data->save_regs) + return -ENOMEM; + + config.parent =3D dev; + config.regmap =3D data->regmap; + config.ngpio =3D data->info->num_gpios; + config.reg_dat_base =3D data->info->base_offset; + config.reg_set_base =3D data->info->base_offset; + config.reg_dir_out_base =3D data->info->base_offset; + + config.reg_mask_xlate =3D rtd1625_reg_mask_xlate; + config.set_config =3D rtd1625_gpio_set_config; + config.value_xlate =3D rtd1625_value_xlate; + + data->domain =3D irq_domain_create_linear(dev_fwnode(dev), + data->info->num_gpios, + &rtd1625_gpio_irq_domain_ops, + data); + if (!data->domain) + return -ENOMEM; + + ret =3D devm_add_action_or_reset(dev, (void (*)(void *))irq_domain_remove= , data->domain); + if (ret) + return ret; + + ret =3D rtd1625_gpio_setup_irq(pdev, data); + if (ret) + return ret; + + config.irq_domain =3D data->domain; + config.drvdata =3D data; + + gpio_reg =3D devm_gpio_regmap_register(dev, &config); + if (IS_ERR(gpio_reg)) + return PTR_ERR(gpio_reg); + + data->gpio_reg =3D gpio_reg; + + return 0; +} + +static const struct rtd1625_gpio_info rtd1625_iso_gpio_info =3D { + .num_gpios =3D 166, + .irq_type_support =3D IRQ_TYPE_EDGE_BOTH, + .base_offset =3D 0x100, + .gpa_offset =3D 0x000, + .gpda_offset =3D 0x020, + .write_en_all =3D RTD1625_ISO_GPIO_WREN_ALL, +}; + +static const struct rtd1625_gpio_info rtd1625_isom_gpio_info =3D { + .num_gpios =3D 4, + .irq_type_support =3D IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_LEVEL_LOW | + IRQ_TYPE_LEVEL_HIGH, + .base_offset =3D 0x20, + .gpa_offset =3D 0x00, + .gpda_offset =3D 0x04, + .level_offset =3D 0x18, + .write_en_all =3D RTD1625_ISOM_GPIO_WREN_ALL, +}; + +static int rtd1625_gpio_suspend(struct device *dev) +{ + struct rtd1625_gpio *data =3D dev_get_drvdata(dev); + const struct rtd1625_gpio_info *info =3D data->info; + int ret; + + for (unsigned int i =3D 0; i < info->num_gpios; i++) { + ret =3D 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 =3D dev_get_drvdata(dev); + const struct rtd1625_gpio_info *info =3D data->info; + int ret; + + for (unsigned int i =3D 0; i < info->num_gpios; i++) { + ret =3D regmap_write(data->regmap, data->info->base_offset + GPIO_CONTRO= L(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[] =3D { + { .compatible =3D "realtek,rtd1625-iso-gpio", .data =3D &rtd1625_iso_gpio= _info }, + { .compatible =3D "realtek,rtd1625-isom-gpio", .data =3D &rtd1625_isom_gp= io_info }, + { } +}; +MODULE_DEVICE_TABLE(of, rtd1625_gpio_of_matches); + +static struct platform_driver rtd1625_gpio_platform_driver =3D { + .driver =3D { + .name =3D "gpio-rtd1625", + .of_match_table =3D rtd1625_gpio_of_matches, + .pm =3D pm_sleep_ptr(&rtd1625_gpio_pm_ops), + }, + .probe =3D 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"); --=20 2.43.0