From nobody Sun May 24 19:33:37 2026 Received: from mail-wr1-f44.google.com (mail-wr1-f44.google.com [209.85.221.44]) (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 4452A38E8C4 for ; Fri, 22 May 2026 07:29:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779434953; cv=none; b=cB5w3Z/lXRjcSQhaZ44qWVeIFIg2gAZ9DI0nSYaukG6l7Z/kHG9+Tux34HBPN1uS/VCp3O4VqaX2AJS/BycSMiGrjy4WffdL/UgnU3/lmzgTahcZv3WhAKnHnXVT4E5ELNnSGbeURP6sVnUl99RQl99AHdb6Y8EyWpW8/PvARyE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779434953; c=relaxed/simple; bh=RGDVCkuX8L2jKRbDFlSgCZRa2aETj6u0TaeHrVW0G/g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=g0qEcuBC3myq/GnHBHVjXPGMZDM5FlHMarAvzFMKBHYzRRK58wZYRrvc3Fnp9iJVZnGLeaebSZEUpmPbDMuV5/gmXVphnLriI+tLwpjI4F/1+7NKMcV7IFIqntlHv5QrUchnu7Rad8knH/vwNvi34C0ush2nPIzZrw/MVt2MlLQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=e/WHGuGo; arc=none smtp.client-ip=209.85.221.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="e/WHGuGo" Received: by mail-wr1-f44.google.com with SMTP id ffacd0b85a97d-4585a116a4aso5847186f8f.3 for ; Fri, 22 May 2026 00:29:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779434950; x=1780039750; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ZP5HGEG7RkqBfIWelZAQ4wNFPRPuiwlQ3GodP84F42g=; b=e/WHGuGoIdOE6tz4gpzYPxrmTWb8cVq3d2q/vqP1oaPsgzDPyDNpLulmV1CuvNScm2 CBce2JoiCnUpq8B4bIChWjDCtQSt0o1wR4dbCOFnIe5l6gWDwoIqnxGqWt6ES6XkIlwt AjCuDrx/VfD3OJCIGi8mMRBWihcwy1H6suU51Bxwn2qdmVaW3SNfrE4PBle14zwtegvw 3L42bg+Ley+IzHJBxJrqJCS3dvTgyHIpFm94VGLDP8lrhgl3ELyZCRs2lXNHsh557PsN 2IC85As2mzDD6qbudu0rjkJKEuQeyLMW1OX8k2tGtDjixnN4rF5zcqyR6kpQxNChWikL nEvg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779434950; x=1780039750; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=ZP5HGEG7RkqBfIWelZAQ4wNFPRPuiwlQ3GodP84F42g=; b=tNvI6GaYxZPgUKbggIXDYU+Vwl0qKp8b0uE/Z/uV7/D02/+abNmzpO01JipXUCFE/r y5hhRcje0eXw1yaPYiRbdiUxdYFuS1SEFk2Twif4QaL+EnKtEtiD3nGp9GV/niRlaUH4 PkCbQKYP4uxfkiUjM/pSlwjYyWvurP77X6Gv6UIM5Rs6PD4EnIMkCheSczap3taiE8of Ayg5EwR6nauMoUe6lRdL9yxhCMAMxP8h0gdxbCtU9a3Zx2Z6jR8ym4azj9L06Kou7iMF 604Mo1N0kRSh6I4aTTCZnRUEWpIeZz4m5k2mwAD9D1XbgwrGdd2p3QQebYvsE/m9YnGI tgsQ== X-Forwarded-Encrypted: i=1; AFNElJ/D1B9D0Tx4FIczegrTR84NlcbF9AuX0ZO1ec0SF8hLgmGRpuq5Z8xfhN1ruG/0KdFNwUFRhvAtFG+bKYg=@vger.kernel.org X-Gm-Message-State: AOJu0Yx87wh3WDjyPxfZJBF0RYHAjPMECfg3gvhYlq2efakIRocBTAl6 X1XwntbB3rpfmLHUtgHAVMRMeIP/UoizLlFgo9wV8eIs8YLk0nzg8p37 X-Gm-Gg: Acq92OEmFW5uBKgDL/u9TX4aYOGhJA0xtALBPqTZNS6WR3OYtZ9g7yOzr8+Nu53glAc wx9J5C5xZOcIdVq4QJxMOd6ypOJMR1ZzQGEz/gbjVP+hxZ100vjIIOHiCSqJ/pWcWLM/w/2kZrk P6IC28xKVMwOe2+zi/xFf5J4FfX6iNqmwl8S+r/ubJL2LF4ge4k+Tka0mfNCVhA56Q2kPYulQ3s Gsu9Go92Anv12YTKbGvYmkmbahNFvT2YSkt3H8Hc1ZE5nNa90RJbknK9R/TREhQZZBuDh47dbMl vPdDrsYmiKyCCrW2RLrfyFJQbn3PQCovUOdesGeuwJRyeoHYaz352L/OkMeF55xlcc5DFDqeA6U 3M2MrI+f2V3KPYSg9p7O9p3QcrR4pvxfKMRza0gE92l9PA0nw9lEa/9kJw7RoF095yAKlrCy9jd jI4dxkYkpoLpLpl2ClYbaVFHxuurNxiJBugYFVF2u90Qr35MUsIC7EHx9QKR5SBxpz+31bcQ== X-Received: by 2002:a5d:64c2:0:b0:43d:7868:21f0 with SMTP id ffacd0b85a97d-45eb3670591mr2944276f8f.9.1779434949527; Fri, 22 May 2026 00:29:09 -0700 (PDT) Received: from camaron.. (147.red-88-9-50.dynamicip.rima-tde.net. [88.9.50.147]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-45eb6d5cb76sm1699970f8f.25.2026.05.22.00.29.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 May 2026 00:29:07 -0700 (PDT) From: Sergio Paracuellos To: linux-gpio@vger.kernel.org Cc: linusw@kernel.org, brgl@kernel.org, tglx@kernel.org, grant.likely@secretlab.ca, anna-maria@linutronix.de, vicencb@gmail.com, linux-kernel@vger.kernel.org Subject: [RFC PATCH] gpio: mt7621: fix interrupt banks mapping on gpio chips Date: Fri, 22 May 2026 09:29:04 +0200 Message-ID: <20260522072904.2028774-1-sergio.paracuellos@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: 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" Regarding the issue reported by Vicente[0], we have been trying different things and we are still having issues to make this work. I have noticed that the gpio-brcmstb is similar to our use case sharing one interrupt for all the banks and also using gpio chips instances with 32 pins each. That said, I tried to setup mt7621 driver in the same way as you can see=20 on the following proposed code. With these changes, we are able to make properly working the previous problem with the touchscreen that was registered on bank 2 instead of bank 0. Now it is properly registered on bank 0 and interrupts works perfect and the device is properly working. However, every single gpio-keys fail to claim the IRQ HW as follows: mt7621_gpio 10000600.gpio: Mapping irq 41 for gpio line 38 (bank 1) gpio gpiochip1: (10000600.gpio-bank1): unable to lock HW IRQ 38 for IRQ genirq: Failed to request resources for S3 (irq 41) on irqchip mt7621-gpio gpio-keys keys: error -EINVAL: request_irq(41) gpio_keys_gpio_isr 0x0 S3 gpio-keys keys: Unable to claim irq 41; error -22 gpio-keys keys: probe with driver gpio-keys failed with error -22 So IIUC the kernel is saying that the gpio chip is not IRQ-capable somehow. Once I touch the irq field just setting up the irq_chip_ops on gpio chip to= bypass=20 this issue:=20 gpio_irq_chip_set_chip(&rg->chip.gc.irq, &mt7621_irq_chip); the kernel stops calling our custom to_irq callback and calls gpiochip_to_i= rq callback instead and also warning as follows: gpio gpiochip0: (10000600.gpio-bank0): to_irq is redefined in gpiochip_irqchip_add_allocated_domain and you shouldn't rely on it gpio gpiochip1: (10000600.gpio-bank1): to_irq is redefined in gpiochip_irqchip_add_allocated_domain and you shouldn't rely on it gpio gpiochip2: (10000600.gpio-bank2): to_irq is redefined in gpiochip_irqchip_add_allocated_domain and you shouldn't rely on it This register gpio-keys and now are shown on /proc/interrupts but they are not working (touchscreen still works, don't really understand why): $ cat /proc/interrupts 40: 10 mt7621-gpio 0 ft6236 41: 0 mt7621-gpio 6 S3 42: 0 mt7621-gpio 7 S2 43: 0 mt7621-gpio 22 S1 I have tried also to get rid of custom to_irq compiling kernel with IRQ_DOMAIN_HIERARCHY and setting up the followings as replacement of custom to_irq: static int mt7621_gpio_child_to_parent_hwirq(struct gpio_chip *gc, unsigned int hwirq, unsigned int type, unsigned int *parent_hwirq, unsigned int *parent_type) { *parent_hwirq =3D gc->irq.child_offset_to_irq(gc, hwirq); *parent_type =3D type; =20 return 0; } static unsigned int mt7621_gpio_child_offset_to_irq(struct gpio_chip *gc, unsigned int offset) { return gc->offset + offset; } rg->chip.gc.irq.child_to_parent_hwirq =3D mt7621_gpio_child_to_parent_hwirq; rg->chip.gc.irq.child_offset_to_irq =3D mt7621_gpio_child_offset_to_irq; This return us to the original scenario where touchscreen is mapped in the wrong bank 2 instead of bank 0... Also tried to setup domain for every single gpio chip using Linus previous suggestion gpiochip_irqchip_add_domain() but ended up in kernel complaning also for IRQ HQ lock and getting a kernel panic: kernel panic "Unhandled kernel unaligned access[#1]") I am totally lost now. Can you point me out in the right way to make everyt= hing working? Thanks a lot in advance. Best regards, Sergio Paracuellos [0]: https://lore.kernel.org/linux-gpio/CAAMcf8C_A9dJ_v4QRKtb9eGNOpJ7BZNOGs= FP4i2WFOZxOVBPnQ@mail.gmail.com/T/#u diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c index 91230be51587..353dc56411eb 100644 --- a/drivers/gpio/gpio-mt7621.c +++ b/drivers/gpio/gpio-mt7621.c @@ -29,8 +29,8 @@ #define GPIO_REG_EDGE 0xA0 =20 struct mtk_gc { - struct irq_chip irq_chip; struct gpio_generic_chip chip; + struct mtk *parent_priv; int bank; u32 rising; u32 falling; @@ -43,18 +43,27 @@ struct mtk_gc { * data of the platform driver. It is 3 * separate gpio-chip each one with its * own irq_chip. - * @dev: device instance + * @pdev: platform device instance * @base: memory base address * @gpio_irq: irq number from the device tree * @gc_map: array of the gpio chips */ struct mtk { - struct device *dev; + struct platform_device *pdev; void __iomem *base; + struct irq_domain *irq_domain; int gpio_irq; + int num_gpios; struct mtk_gc gc_map[MTK_BANK_CNT]; }; =20 +static inline struct mtk * +mt7621_gpio_gc_to_priv(struct gpio_chip *gc) +{ + struct mtk_gc *bank =3D gpiochip_get_data(gc); + return bank->parent_priv; +} + static inline struct mtk_gc * to_mediatek_gpio(struct gpio_chip *chip) { @@ -67,7 +76,7 @@ static inline void mtk_gpio_w32(struct mtk_gc *rg, u32 offset, u32 val) { struct gpio_chip *gc =3D &rg->chip.gc; - struct mtk *mtk =3D gpiochip_get_data(gc); + struct mtk *mtk =3D mt7621_gpio_gc_to_priv(gc); =20 offset =3D (rg->bank * GPIO_BANK_STRIDE) + offset; gpio_generic_write_reg(&rg->chip, mtk->base + offset, val); @@ -77,60 +86,79 @@ static inline u32 mtk_gpio_r32(struct mtk_gc *rg, u32 offset) { struct gpio_chip *gc =3D &rg->chip.gc; - struct mtk *mtk =3D gpiochip_get_data(gc); + struct mtk *mtk =3D mt7621_gpio_gc_to_priv(gc); =20 offset =3D (rg->bank * GPIO_BANK_STRIDE) + offset; return gpio_generic_read_reg(&rg->chip, mtk->base + offset); } =20 -static irqreturn_t -mediatek_gpio_irq_handler(int irq, void *data) +static void +mt7621_gpio_irq_bank_handler(struct mtk_gc *bank) { - struct gpio_chip *gc =3D data; - struct mtk_gc *rg =3D to_mediatek_gpio(gc); - irqreturn_t ret =3D IRQ_NONE; + struct mtk *priv =3D bank->parent_priv; + struct irq_domain *domain =3D priv->irq_domain; + int hwbase =3D bank->chip.gc.offset; unsigned long pending; - int bit; + unsigned int offset; + + pending =3D mtk_gpio_r32(bank, GPIO_REG_STAT); + if (!pending) + return; + + mtk_gpio_w32(bank, GPIO_REG_STAT, pending); + + for_each_set_bit(offset, &pending, MTK_BANK_WIDTH) + generic_handle_domain_irq(domain, hwbase + offset); +} + +static void +mt7621_gpio_irq_handler(struct irq_desc *desc) +{ + struct mtk *priv =3D irq_desc_get_handler_data(desc); + struct irq_chip *chip =3D irq_desc_get_chip(desc); + int i; =20 - pending =3D mtk_gpio_r32(rg, GPIO_REG_STAT); + chained_irq_enter(chip, desc); + for (i =3D 0; i < MTK_BANK_CNT; i++) { + struct mtk_gc *bank =3D &priv->gc_map[i]; =20 - for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) { - generic_handle_domain_irq(gc->irq.domain, bit); - mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit)); - ret |=3D IRQ_HANDLED; + mt7621_gpio_irq_bank_handler(bank); } + chained_irq_exit(chip, desc); +} =20 - return ret; +static int +mt7621_gpio_hwirq_to_offset(irq_hw_number_t hwirq, struct mtk_gc *bank) +{ + return hwirq - bank->chip.gc.offset; } =20 static void mediatek_gpio_irq_unmask(struct irq_data *d) { struct gpio_chip *gc =3D irq_data_get_irq_chip_data(d); - struct mtk_gc *rg =3D to_mediatek_gpio(gc); - int pin =3D d->hwirq; + struct mtk_gc *rg =3D gpiochip_get_data(gc); + u32 mask =3D mt7621_gpio_hwirq_to_offset(d->hwirq, rg); u32 rise, fall, high, low; =20 - gpiochip_enable_irq(gc, d->hwirq); - guard(gpio_generic_lock_irqsave)(&rg->chip); =20 rise =3D mtk_gpio_r32(rg, GPIO_REG_REDGE); fall =3D mtk_gpio_r32(rg, GPIO_REG_FEDGE); high =3D mtk_gpio_r32(rg, GPIO_REG_HLVL); low =3D mtk_gpio_r32(rg, GPIO_REG_LLVL); - mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(pin) & rg->rising)); - mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(pin) & rg->falling)); - mtk_gpio_w32(rg, GPIO_REG_HLVL, high | (BIT(pin) & rg->hlevel)); - mtk_gpio_w32(rg, GPIO_REG_LLVL, low | (BIT(pin) & rg->llevel)); + mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(mask) & rg->rising)); + mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(mask) & rg->falling)); + mtk_gpio_w32(rg, GPIO_REG_HLVL, high | (BIT(mask) & rg->hlevel)); + mtk_gpio_w32(rg, GPIO_REG_LLVL, low | (BIT(mask) & rg->llevel)); } =20 static void mediatek_gpio_irq_mask(struct irq_data *d) { struct gpio_chip *gc =3D irq_data_get_irq_chip_data(d); - struct mtk_gc *rg =3D to_mediatek_gpio(gc); - int pin =3D d->hwirq; + struct mtk_gc *rg =3D gpiochip_get_data(gc); + u32 mask =3D mt7621_gpio_hwirq_to_offset(d->hwirq, rg); u32 rise, fall, high, low; =20 scoped_guard(gpio_generic_lock_irqsave, &rg->chip) { @@ -138,22 +166,19 @@ mediatek_gpio_irq_mask(struct irq_data *d) fall =3D mtk_gpio_r32(rg, GPIO_REG_FEDGE); high =3D mtk_gpio_r32(rg, GPIO_REG_HLVL); low =3D mtk_gpio_r32(rg, GPIO_REG_LLVL); - mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(pin)); - mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(pin)); - mtk_gpio_w32(rg, GPIO_REG_HLVL, high & ~BIT(pin)); - mtk_gpio_w32(rg, GPIO_REG_LLVL, low & ~BIT(pin)); + mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(mask)); + mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(mask)); + mtk_gpio_w32(rg, GPIO_REG_HLVL, high & ~BIT(mask)); + mtk_gpio_w32(rg, GPIO_REG_LLVL, low & ~BIT(mask)); } - - gpiochip_disable_irq(gc, d->hwirq); } =20 static int mediatek_gpio_irq_type(struct irq_data *d, unsigned int type) { struct gpio_chip *gc =3D irq_data_get_irq_chip_data(d); - struct mtk_gc *rg =3D to_mediatek_gpio(gc); - int pin =3D d->hwirq; - u32 mask =3D BIT(pin); + struct mtk_gc *rg =3D gpiochip_get_data(gc); + u32 mask =3D BIT(mt7621_gpio_hwirq_to_offset(d->hwirq, rg)); =20 if (type =3D=3D IRQ_TYPE_PROBE) { if ((rg->rising | rg->falling | @@ -216,10 +241,124 @@ static const struct irq_chip mt7621_irq_chip =3D { GPIOCHIP_IRQ_RESOURCE_HELPERS, }; =20 +static void mt7621_gpio_remove(struct platform_device *pdev) +{ + struct mtk *priv =3D platform_get_drvdata(pdev); + int i, offset, virq; + + if (priv->gpio_irq > 0) + irq_set_chained_handler_and_data(priv->gpio_irq, NULL, NULL); + + /* Remove all IRQ mappings and delete the domain */ + if (priv->irq_domain) { + for (offset =3D 0; offset < priv->num_gpios; offset++) { + virq =3D irq_find_mapping(priv->irq_domain, offset); + irq_dispose_mapping(virq); + } + irq_domain_remove(priv->irq_domain); + } + + for (i =3D 0; i < MTK_BANK_CNT; i++) { + struct mtk_gc *bank =3D &priv->gc_map[i]; + + gpiochip_remove(&bank->chip.gc); + } +} + +static struct mtk_gc * +mt7621_gpio_hwirq_to_bank(struct mtk *priv, irq_hw_number_t hwirq) +{ + int i; + + for (i =3D 0; i < MTK_BANK_CNT; i++) { + struct mtk_gc *bank =3D &priv->gc_map[i]; + + if (hwirq >=3D bank->chip.gc.offset && + hwirq < (bank->chip.gc.offset + bank->chip.gc.ngpio)) + return bank; + } + + return NULL; +} + static int -mediatek_gpio_bank_probe(struct device *dev, int bank) +mt7621_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct mtk *priv =3D d->host_data; + struct mtk_gc *bank =3D mt7621_gpio_hwirq_to_bank(priv, hwirq); + struct platform_device *pdev =3D priv->pdev; + int ret; + + if (!bank) + return -EINVAL; + + dev_dbg(&pdev->dev, "Mapping irq %d for gpio line %d (bank %d)\n", + irq, (int)hwirq, bank->bank); + + ret =3D irq_set_chip_data(irq, &bank->chip.gc); + if (ret < 0) + return ret; + + irq_set_chip_and_handler(irq, &mt7621_irq_chip, handle_simple_irq); + irq_set_noprobe(irq); + + return 0; +} + +static void +mt7621_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) +{ + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); +} + +static const struct irq_domain_ops mt7621_gpio_irq_domain_ops =3D { + .map =3D mt7621_gpio_irq_map, + .unmap =3D mt7621_gpio_irq_unmap, + .xlate =3D irq_domain_xlate_twocell, +}; + +static int +mt7621_gpio_irq_setup(struct platform_device *pdev, + struct mtk *priv) +{ + struct device *dev =3D &pdev->dev; + + priv->irq_domain =3D irq_domain_create_linear(dev_fwnode(dev), + priv->num_gpios, + &mt7621_gpio_irq_domain_ops, + priv); + if (!priv->irq_domain) { + dev_err(dev, "Couldn't allocate IRQ domain\n"); + return -ENXIO; + } + + irq_set_chained_handler_and_data(priv->gpio_irq, + mt7621_gpio_irq_handler, priv); + irq_set_status_flags(priv->gpio_irq, IRQ_DISABLE_UNLAZY); + + return 0; +} + +static int +mt7621_gpio_to_irq(struct gpio_chip *gc, unsigned int offset) +{ + struct mtk *priv =3D mt7621_gpio_gc_to_priv(gc); + /* gc_offset is relative to this gpio_chip; want real offset */ + int hwirq =3D offset + gc->offset; + + if (hwirq >=3D priv->num_gpios) + return -ENXIO; + + return irq_create_mapping(priv->irq_domain, hwirq); +} + +static int +mediatek_gpio_bank_probe(struct platform_device *pdev, int bank) { struct gpio_generic_chip_config config; + struct device *dev =3D &pdev->dev; struct mtk *mtk =3D dev_get_drvdata(dev); struct mtk_gc *rg; void __iomem *dat, *set, *ctrl, *diro; @@ -228,6 +367,7 @@ mediatek_gpio_bank_probe(struct device *dev, int bank) rg =3D &mtk->gc_map[bank]; memset(rg, 0, sizeof(*rg)); =20 + rg->parent_priv =3D mtk; rg->bank =3D bank; =20 dat =3D mtk->base + GPIO_REG_DATA + (rg->bank * GPIO_BANK_STRIDE); @@ -253,47 +393,25 @@ mediatek_gpio_bank_probe(struct device *dev, int bank) =20 rg->chip.gc.of_gpio_n_cells =3D 2; rg->chip.gc.of_xlate =3D mediatek_gpio_xlate; + rg->chip.gc.ngpio =3D MTK_BANK_WIDTH; rg->chip.gc.label =3D devm_kasprintf(dev, GFP_KERNEL, "%s-bank%d", dev_name(dev), bank); if (!rg->chip.gc.label) return -ENOMEM; =20 rg->chip.gc.offset =3D bank * MTK_BANK_WIDTH; + if (mtk->gpio_irq > 0) + rg->chip.gc.to_irq =3D mt7621_gpio_to_irq; =20 - if (mtk->gpio_irq) { - struct gpio_irq_chip *girq; - - /* - * Directly request the irq here instead of passing - * a flow-handler because the irq is shared. - */ - ret =3D devm_request_irq(dev, mtk->gpio_irq, - mediatek_gpio_irq_handler, IRQF_SHARED, - rg->chip.gc.label, &rg->chip.gc); - - if (ret) { - dev_err(dev, "Error requesting IRQ %d: %d\n", - mtk->gpio_irq, ret); - return ret; - } - - girq =3D &rg->chip.gc.irq; - gpio_irq_chip_set_chip(girq, &mt7621_irq_chip); - /* This will let us handle the parent IRQ in the driver */ - girq->parent_handler =3D NULL; - girq->num_parents =3D 0; - girq->parents =3D NULL; - girq->default_type =3D IRQ_TYPE_NONE; - girq->handler =3D handle_simple_irq; - } - - ret =3D devm_gpiochip_add_data(dev, &rg->chip.gc, mtk); + ret =3D devm_gpiochip_add_data(dev, &rg->chip.gc, rg); if (ret < 0) { dev_err(dev, "Could not register gpio %d, ret=3D%d\n", rg->chip.gc.ngpio, ret); return ret; } =20 + mtk->num_gpios +=3D rg->chip.gc.ngpio; + /* set polarity to low for all gpios */ mtk_gpio_w32(rg, GPIO_REG_POL, 0); =20 @@ -322,16 +440,26 @@ mediatek_gpio_probe(struct platform_device *pdev) if (mtk->gpio_irq < 0) return mtk->gpio_irq; =20 - mtk->dev =3D dev; + mtk->pdev =3D pdev; platform_set_drvdata(pdev, mtk); =20 for (i =3D 0; i < MTK_BANK_CNT; i++) { - ret =3D mediatek_gpio_bank_probe(dev, i); + ret =3D mediatek_gpio_bank_probe(pdev, i); if (ret) - return ret; + goto fail; + } + + if (mtk->gpio_irq > 0) { + ret =3D mt7621_gpio_irq_setup(pdev, mtk); + if (ret) + goto fail; } =20 return 0; + +fail: + (void)mt7621_gpio_remove(pdev); + return ret; } =20 static const struct of_device_id mediatek_gpio_match[] =3D {