From nobody Tue Apr 7 22:04:34 2026 Received: from smtpfb1-g21.free.fr (smtpfb1-g21.free.fr [212.27.42.9]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6976B3B3C07; Wed, 11 Mar 2026 14:38:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=212.27.42.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773239893; cv=none; b=BomT3PMQtaOS77O+x9lfxMrxQqGYRbUjEvttskW/vj9Gf5sxfRkwPRz+JAV6lD4yFrD4U3dI5VcwMeKfEuJfxAqqXyImKjmySCBgdSlWEz/+dJwK1Qey30yQy47MSWxkTdb9uvRLIuTqDVXqU+tJhjzE3DCZLQIQyoBrV23F5V0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773239893; c=relaxed/simple; bh=eqbx4mwZTaA0wRRinohHZ5IqBH8K0UTIbag01Jsx3mY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=pmyWQ8ldFzQoALaxOfvR1/iGcySyH1C1CAcXdcjG39/C/k0Cg61OvYo15ktJachPPyIBZ1/p/THkiNZgPF2sT/ox9xotgqOSA2o+yn+xsMUbyVwQhWpsCvVepElGPM9UR6A0DlGd91kuo4BRPFnVAu9Y2n1cjldZbH/EM4+yswU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=lht.dlh.de; spf=pass smtp.mailfrom=free.fr; arc=none smtp.client-ip=212.27.42.9 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=lht.dlh.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=free.fr Received: from smtp2-g21.free.fr (smtp2-g21.free.fr [212.27.42.2]) by smtpfb1-g21.free.fr (Postfix) with ESMTP id 098B8DF922A; Wed, 11 Mar 2026 15:31:47 +0100 (CET) Received: from albans-vm.. (unknown [213.61.141.186]) (Authenticated sender: albeu@free.fr) by smtp2-g21.free.fr (Postfix) with ESMTPSA id E866C2003FC; Wed, 11 Mar 2026 15:31:31 +0100 (CET) From: Alban Bedel To: linux-gpio@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Lee Jones , Bartosz Golaszewski , Linus Walleij , Alban Bedel Subject: [PATCH 1/4] gpio: kempld: Simplify the bit level register accesses Date: Wed, 11 Mar 2026 15:31:17 +0100 Message-Id: <20260311143120.2179347-2-alban.bedel@lht.dlh.de> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260311143120.2179347-1-alban.bedel@lht.dlh.de> References: <20260311143120.2179347-1-alban.bedel@lht.dlh.de> 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" The hardware uses 8 bit registers but supports configurations with up to 16 GPIO, so all GPIO registers come in pairs. Most accesses to single bits is done using the kempld_gpio_bitop() and kempld_gpio_get_bit() functions, which take a register index and bit offset as parameter. These functions apply a modulo on the bit offset but leave the register index as is, so callers have to use an additional macro to fix the register index before the call. Simplify things by also handling the register index offsetting in the bitop functions. Signed-off-by: Alban Bedel --- drivers/gpio/gpio-kempld.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index 923aad3ab4d45..532e4000879ab 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -17,8 +17,8 @@ =20 #define KEMPLD_GPIO_MAX_NUM 16 #define KEMPLD_GPIO_MASK(x) (BIT((x) % 8)) -#define KEMPLD_GPIO_DIR_NUM(x) (0x40 + (x) / 8) -#define KEMPLD_GPIO_LVL_NUM(x) (0x42 + (x) / 8) +#define KEMPLD_GPIO_DIR 0x40 +#define KEMPLD_GPIO_LVL 0x42 #define KEMPLD_GPIO_EVT_LVL_EDGE 0x46 #define KEMPLD_GPIO_IEN 0x4A =20 @@ -32,24 +32,25 @@ struct kempld_gpio_data { * kempld_get_mutex must be called prior to calling this function. */ static void kempld_gpio_bitop(struct kempld_device_data *pld, - u8 reg, u8 bit, u8 val) + u8 reg, unsigned int bit, bool val) { u8 status; =20 - status =3D kempld_read8(pld, reg); + status =3D kempld_read8(pld, reg + (bit / 8)); if (val) status |=3D KEMPLD_GPIO_MASK(bit); else status &=3D ~KEMPLD_GPIO_MASK(bit); - kempld_write8(pld, reg, status); + kempld_write8(pld, reg + (bit / 8), status); } =20 -static int kempld_gpio_get_bit(struct kempld_device_data *pld, u8 reg, u8 = bit) +static int kempld_gpio_get_bit(struct kempld_device_data *pld, + u8 reg, unsigned int bit) { u8 status; =20 kempld_get_mutex(pld); - status =3D kempld_read8(pld, reg); + status =3D kempld_read8(pld, reg + (bit / 8)); kempld_release_mutex(pld); =20 return !!(status & KEMPLD_GPIO_MASK(bit)); @@ -60,7 +61,7 @@ static int kempld_gpio_get(struct gpio_chip *chip, unsign= ed offset) struct kempld_gpio_data *gpio =3D gpiochip_get_data(chip); struct kempld_device_data *pld =3D gpio->pld; =20 - return !!kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL_NUM(offset), offset); + return !!kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL, offset); } =20 static int kempld_gpio_set(struct gpio_chip *chip, unsigned int offset, @@ -70,7 +71,7 @@ static int kempld_gpio_set(struct gpio_chip *chip, unsign= ed int offset, struct kempld_device_data *pld =3D gpio->pld; =20 kempld_get_mutex(pld); - kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value); + kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL, offset, value); kempld_release_mutex(pld); =20 return 0; @@ -82,7 +83,7 @@ static int kempld_gpio_direction_input(struct gpio_chip *= chip, unsigned offset) struct kempld_device_data *pld =3D gpio->pld; =20 kempld_get_mutex(pld); - kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 0); + kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR, offset, 0); kempld_release_mutex(pld); =20 return 0; @@ -95,8 +96,8 @@ static int kempld_gpio_direction_output(struct gpio_chip = *chip, unsigned offset, struct kempld_device_data *pld =3D gpio->pld; =20 kempld_get_mutex(pld); - kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value); - kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 1); + kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL, offset, value); + kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR, offset, 1); kempld_release_mutex(pld); =20 return 0; @@ -107,7 +108,7 @@ static int kempld_gpio_get_direction(struct gpio_chip *= chip, unsigned offset) struct kempld_gpio_data *gpio =3D gpiochip_get_data(chip); struct kempld_device_data *pld =3D gpio->pld; =20 - if (kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset)) + if (kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR, offset)) return GPIO_LINE_DIRECTION_OUT; =20 return GPIO_LINE_DIRECTION_IN; --=20 2.39.5 From nobody Tue Apr 7 22:04:34 2026 Received: from smtp2-g21.free.fr (smtp2-g21.free.fr [212.27.42.2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A872A4A33; Wed, 11 Mar 2026 14:31:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=212.27.42.2 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773239510; cv=none; b=ie6BeHhbLnRePFLwoToQh9t8gyumiAYOrpgWYRbF9DdK+P1RomxGJ9Z6kMpkkISY02iCvY/ChH3YfyTKdMU8FIXVJdZ0JQJR2UHrbhQF8DlsfG+l36aB+W/k1uyXYg0t1PFKWGuaKWn056g4jkJ0mw2nVAoeMSXJmaUhLalrdb8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773239510; c=relaxed/simple; bh=IXCHHr0AVw+UM6yYDHyR16+zS9h0vhrU0De7rfhXb8w=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=cxyzsqu/hTavONjo3JjGkxsWPsy9lJCO0vNmyZMlxJxyts9Pablrx3QMr0qTr9FZnlBwXH6vq7LnKKqhToJYJNZ2ObX3VlpRf8lTjptOhEV2NUWXBc1eTzXfeml9Qa1F6xu4NFZJDyEhTLlWiqS/5+0r7YIqbmdyGT1KZAe0hM0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=lht.dlh.de; spf=pass smtp.mailfrom=free.fr; arc=none smtp.client-ip=212.27.42.2 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=lht.dlh.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=free.fr Received: from albans-vm.. (unknown [213.61.141.186]) (Authenticated sender: albeu@free.fr) by smtp2-g21.free.fr (Postfix) with ESMTPSA id 0FBAC2003DA; Wed, 11 Mar 2026 15:31:38 +0100 (CET) From: Alban Bedel To: linux-gpio@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Lee Jones , Bartosz Golaszewski , Linus Walleij , Alban Bedel Subject: [PATCH 2/4] gpio: kempld: Add support for PLD version >= 2.8 Date: Wed, 11 Mar 2026 15:31:18 +0100 Message-Id: <20260311143120.2179347-3-alban.bedel@lht.dlh.de> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260311143120.2179347-1-alban.bedel@lht.dlh.de> References: <20260311143120.2179347-1-alban.bedel@lht.dlh.de> 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" Starting with version 2.8 there is a dedicated register to configure the output level. Read the PLD version in the probe and select the correct register to use for the set operations. Signed-off-by: Alban Bedel --- drivers/gpio/gpio-kempld.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index 532e4000879ab..2263de77d40e9 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -25,6 +25,7 @@ struct kempld_gpio_data { struct gpio_chip chip; struct kempld_device_data *pld; + u8 out_lvl_reg; }; =20 /* @@ -71,7 +72,7 @@ static int kempld_gpio_set(struct gpio_chip *chip, unsign= ed int offset, struct kempld_device_data *pld =3D gpio->pld; =20 kempld_get_mutex(pld); - kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL, offset, value); + kempld_gpio_bitop(pld, gpio->out_lvl_reg, offset, value); kempld_release_mutex(pld); =20 return 0; @@ -96,7 +97,7 @@ static int kempld_gpio_direction_output(struct gpio_chip = *chip, unsigned offset, struct kempld_device_data *pld =3D gpio->pld; =20 kempld_get_mutex(pld); - kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL, offset, value); + kempld_gpio_bitop(pld, gpio->out_lvl_reg, offset, value); kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR, offset, 1); kempld_release_mutex(pld); =20 @@ -153,6 +154,15 @@ static int kempld_gpio_probe(struct platform_device *p= dev) if (!gpio) return -ENOMEM; =20 + /* Starting with version 2.8 there is a dedicated register for the + * output state, earlier versions share the register used to read + * the line level. + */ + if (pld->info.spec_major > 2 || pld->info.spec_minor >=3D 8) + gpio->out_lvl_reg =3D KEMPLD_GPIO_OUT_LVL; + else + gpio->out_lvl_reg =3D KEMPLD_GPIO_LVL; + gpio->pld =3D pld; =20 platform_set_drvdata(pdev, gpio); --=20 2.39.5 From nobody Tue Apr 7 22:04:34 2026 Received: from smtp2-g21.free.fr (smtp2-g21.free.fr [212.27.42.2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 41896361DAE; Wed, 11 Mar 2026 14:31:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=212.27.42.2 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773239516; cv=none; b=WD77dXyo3KVUgEIxbOLQQpXuJUIB7nmbFh2vQaxT6xfiYCHwaNB//0KL7FN87fZjJN+BcdAm6g5nlbBCc5OMAmiA4ribWV/15MHak/ZQAhJfr3RuFME24K+4i1QmMMg+lQ3qbK1rwTr/yaMkR9hYFhh7soDGH/j2MED1T4qFHT8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773239516; c=relaxed/simple; bh=xwzDJldw2ScjgAZdF++yq28RL5rFT7+4YXOLSPkJCW4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=MvaXHBpBraDq7SsItQBAzM0klub/kvt6DtqdUgblzHOgT4Uu15osCMJ+A5W0wCotarzWQ8ZUB32SE+RuPKguJf3O572fg4GXmDh1/0y29cYyunJs9jt6nWtw1BpqUtodLaccQx9cI3iaZf5Bv/hRTIklDBVaFTa3qfqxttfOXA4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=lht.dlh.de; spf=pass smtp.mailfrom=free.fr; arc=none smtp.client-ip=212.27.42.2 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=lht.dlh.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=free.fr Received: from albans-vm.. (unknown [213.61.141.186]) (Authenticated sender: albeu@free.fr) by smtp2-g21.free.fr (Postfix) with ESMTPSA id E41A72003F6; Wed, 11 Mar 2026 15:31:45 +0100 (CET) From: Alban Bedel To: linux-gpio@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Lee Jones , Bartosz Golaszewski , Linus Walleij , Alban Bedel Subject: [PATCH 3/4] gpio: kempld: Add support for get/set multiple Date: Wed, 11 Mar 2026 15:31:19 +0100 Message-Id: <20260311143120.2179347-4-alban.bedel@lht.dlh.de> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260311143120.2179347-1-alban.bedel@lht.dlh.de> References: <20260311143120.2179347-1-alban.bedel@lht.dlh.de> 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" As the bus accesses are quiet slow with this device, supporting the get/set multiple API can help with performences. The implementation tries to keep the number of bus access to a minimum by checking the mask to only read or write the needed bytes. Signed-off-by: Alban Bedel --- drivers/gpio/gpio-kempld.c | 60 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index 2263de77d40e9..7dd94ff6f2df4 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -65,6 +65,33 @@ static int kempld_gpio_get(struct gpio_chip *chip, unsig= ned offset) return !!kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL, offset); } =20 +static int kempld_gpio_get_multiple(struct gpio_chip *chip, unsigned long = *mask, + unsigned long *bits) +{ + struct kempld_gpio_data *gpio =3D gpiochip_get_data(chip); + struct kempld_device_data *pld =3D gpio->pld; + u8 reg =3D KEMPLD_GPIO_LVL; + unsigned int shift; + + bits[0] &=3D ~mask[0]; + + kempld_get_mutex(pld); + + /* Try to reduce to a single 8 bits access if possible */ + for (shift =3D 0; shift < gpio->chip.ngpio; shift +=3D 8, reg++) { + unsigned long msk =3D (mask[0] >> shift) & 0xff; + + if (!msk) + continue; + + bits[0] |=3D (kempld_read8(pld, reg) & msk) << shift; + } + + kempld_release_mutex(pld); + + return 0; +} + static int kempld_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { @@ -78,6 +105,37 @@ static int kempld_gpio_set(struct gpio_chip *chip, unsi= gned int offset, return 0; } =20 +static int kempld_gpio_set_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct kempld_gpio_data *gpio =3D gpiochip_get_data(chip); + struct kempld_device_data *pld =3D gpio->pld; + u8 reg =3D gpio->out_lvl_reg; + unsigned int shift; + + kempld_get_mutex(pld); + + /* Try to reduce to a single 8 bits access if possible */ + for (shift =3D 0; shift < gpio->chip.ngpio; shift +=3D 8, reg++) { + u8 val, msk =3D mask[0] >> shift; + + if (!msk) + continue; + + if (msk !=3D 0xFF) + val =3D kempld_read8(pld, reg) & ~msk; + else + val =3D 0; + + val |=3D (bits[0] >> shift) & msk; + kempld_write8(pld, reg, val); + } + + kempld_release_mutex(pld); + + return 0; +} + static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned of= fset) { struct kempld_gpio_data *gpio =3D gpiochip_get_data(chip); @@ -180,7 +238,9 @@ static int kempld_gpio_probe(struct platform_device *pd= ev) chip->direction_output =3D kempld_gpio_direction_output; chip->get_direction =3D kempld_gpio_get_direction; chip->get =3D kempld_gpio_get; + chip->get_multiple =3D kempld_gpio_get_multiple; chip->set =3D kempld_gpio_set; + chip->set_multiple =3D kempld_gpio_set_multiple; chip->ngpio =3D kempld_gpio_pincount(pld); if (chip->ngpio =3D=3D 0) { dev_err(dev, "No GPIO pins detected\n"); --=20 2.39.5 From nobody Tue Apr 7 22:04:34 2026 Received: from smtp2-g21.free.fr (smtp2-g21.free.fr [212.27.42.2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1C50F3B3C08; Wed, 11 Mar 2026 14:32:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=212.27.42.2 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773239522; cv=none; b=jQ8s+b10xIcN4EwF4r9szJMBJ/XmxG34QNVMspocgx5fCWw5PJ2UxnN5rlEhqSFJbIhMjY8cpoHZSKdTaT9xY1nJqeALgM96so51HgwZMHbUEDin6oF6jONlu0RNepVs9XBxr2oAVW8AcaY4vs2jO/7pWy+vTK5hPssYvNs9DM0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773239522; c=relaxed/simple; bh=3fLjRvaafSLcQi5YKpaSyMkRNdXOQyeg8bJZ30btBow=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=JVFC4SSt8uwo6PnGYBaq7k/Y/9YruR97lO5x8chfXDmGJXcQ+cIhcBYWnRqsfcxjCUaxa849/cZ8NLEM0pJL5caIR1nEnZxe59VoVT/Ss4TFSqKMBOIBeNP3WLqjZs4lTaOSKbE3FQq/rp7MGl2xuIcMecnbZ4nt5TH+XWbLHGM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=lht.dlh.de; spf=pass smtp.mailfrom=free.fr; arc=none smtp.client-ip=212.27.42.2 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=lht.dlh.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=free.fr Received: from albans-vm.. (unknown [213.61.141.186]) (Authenticated sender: albeu@free.fr) by smtp2-g21.free.fr (Postfix) with ESMTPSA id 0AF4C20040F; Wed, 11 Mar 2026 15:31:52 +0100 (CET) From: Alban Bedel To: linux-gpio@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Lee Jones , Bartosz Golaszewski , Linus Walleij , Alban Bedel Subject: [PATCH 4/4] gpio: kempld: Implement the interrupt controller Date: Wed, 11 Mar 2026 15:31:20 +0100 Message-Id: <20260311143120.2179347-5-alban.bedel@lht.dlh.de> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260311143120.2179347-1-alban.bedel@lht.dlh.de> References: <20260311143120.2179347-1-alban.bedel@lht.dlh.de> 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 GPIO IRQ chip implementation for the kempld GPIO controller. Of note is only how the parent IRQ is obtained. The IRQ for the GPIO controller can be configured in the BIOS, along with the IRQ for the I2C controller. These IRQ are returned by ACPI but this information is only usable if both IRQ are configured. When only one is configured, only one is returned making it impossible to know which one it is. Luckily the BIOS will set the configured IRQ in the PLD registers, so it can be read from there instead, and that also work on platforms without ACPI. The vendor driver allowed to override the IRQ using a module parameters, so there are boards in field which used this parameter instead of properly configuring the BIOS. This implementation provides this as well for compatibility. Signed-off-by: Alban Bedel --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-kempld.c | 192 +++++++++++++++++++++++++++++++++++++ include/linux/mfd/kempld.h | 1 + 3 files changed, 194 insertions(+) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b45fb799e36c1..d665afe197097 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1440,6 +1440,7 @@ config GPIO_JANZ_TTL config GPIO_KEMPLD tristate "Kontron ETX / COMexpress GPIO" depends on MFD_KEMPLD + select GPIOLIB_IRQCHIP help This enables support for the PLD GPIO interface on some Kontron ETX and COMexpress (ETXexpress) modules. diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index 7dd94ff6f2df4..5a63df3ea5fa7 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -19,13 +20,26 @@ #define KEMPLD_GPIO_MASK(x) (BIT((x) % 8)) #define KEMPLD_GPIO_DIR 0x40 #define KEMPLD_GPIO_LVL 0x42 +#define KEMPLD_GPIO_STS 0x44 #define KEMPLD_GPIO_EVT_LVL_EDGE 0x46 +#define KEMPLD_GPIO_EVT_LOW_HIGH 0x48 #define KEMPLD_GPIO_IEN 0x4A +#define KEMPLD_GPIO_OUT_LVL 0x4E + +/* The IRQ to use if none was configured in the BIOS */ +static unsigned int gpio_irq; +module_param_hw(gpio_irq, uint, irq, 0444); +MODULE_PARM_DESC(gpio_irq, "Set legacy GPIO IRQ (1-15)"); =20 struct kempld_gpio_data { struct gpio_chip chip; struct kempld_device_data *pld; u8 out_lvl_reg; + + struct mutex irq_lock; + u16 ien; + u16 evt_low_high; + u16 evt_lvl_edge; }; =20 /* @@ -193,6 +207,180 @@ static int kempld_gpio_pincount(struct kempld_device_= data *pld) return evt ? __ffs(evt) : 16; } =20 +static void kempld_irq_mask(struct irq_data *data) +{ + struct gpio_chip *chip =3D irq_data_get_irq_chip_data(data); + struct kempld_gpio_data *gpio =3D gpiochip_get_data(chip); + + gpio->ien &=3D ~BIT(irqd_to_hwirq(data)); + gpiochip_disable_irq(chip, irqd_to_hwirq(data)); +} + +static void kempld_irq_unmask(struct irq_data *data) +{ + struct gpio_chip *chip =3D irq_data_get_irq_chip_data(data); + struct kempld_gpio_data *gpio =3D gpiochip_get_data(chip); + + gpiochip_enable_irq(chip, irqd_to_hwirq(data)); + gpio->ien |=3D BIT(irqd_to_hwirq(data)); +} + +static int kempld_irq_set_type(struct irq_data *data, unsigned int type) +{ + struct gpio_chip *chip =3D irq_data_get_irq_chip_data(data); + struct kempld_gpio_data *gpio =3D gpiochip_get_data(chip); + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + gpio->evt_low_high |=3D BIT(data->hwirq); + gpio->evt_lvl_edge |=3D BIT(data->hwirq); + break; + case IRQ_TYPE_EDGE_FALLING: + gpio->evt_low_high &=3D ~BIT(data->hwirq); + gpio->evt_lvl_edge |=3D BIT(data->hwirq); + break; + case IRQ_TYPE_LEVEL_HIGH: + gpio->evt_low_high |=3D BIT(data->hwirq); + gpio->evt_lvl_edge &=3D ~BIT(data->hwirq); + break; + case IRQ_TYPE_LEVEL_LOW: + gpio->evt_low_high &=3D ~BIT(data->hwirq); + gpio->evt_lvl_edge &=3D ~BIT(data->hwirq); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void kempld_irq_bus_lock(struct irq_data *data) +{ + struct gpio_chip *chip =3D irq_data_get_irq_chip_data(data); + struct kempld_gpio_data *gpio =3D gpiochip_get_data(chip); + + mutex_lock(&gpio->irq_lock); +} + +static void kempld_irq_bus_sync_unlock(struct irq_data *data) +{ + struct gpio_chip *chip =3D irq_data_get_irq_chip_data(data); + struct kempld_gpio_data *gpio =3D gpiochip_get_data(chip); + struct kempld_device_data *pld =3D gpio->pld; + + kempld_get_mutex(pld); + kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, gpio->evt_lvl_edge); + kempld_write16(pld, KEMPLD_GPIO_EVT_LOW_HIGH, gpio->evt_low_high); + kempld_write16(pld, KEMPLD_GPIO_IEN, gpio->ien); + kempld_release_mutex(pld); + + mutex_unlock(&gpio->irq_lock); +} + +static const struct irq_chip kempld_irqchip =3D { + .name =3D "kempld-gpio", + .irq_mask =3D kempld_irq_mask, + .irq_unmask =3D kempld_irq_unmask, + .irq_set_type =3D kempld_irq_set_type, + .irq_bus_lock =3D kempld_irq_bus_lock, + .irq_bus_sync_unlock =3D kempld_irq_bus_sync_unlock, + .flags =3D IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static irqreturn_t kempld_gpio_irq_handler(int irq, void *data) +{ + struct kempld_gpio_data *gpio =3D data; + struct gpio_chip *chip =3D &gpio->chip; + unsigned int pin, child_irq; + unsigned long status; + + kempld_get_mutex(gpio->pld); + + status =3D kempld_read16(gpio->pld, KEMPLD_GPIO_STS); + if (status) + kempld_write16(gpio->pld, KEMPLD_GPIO_STS, status); + + kempld_release_mutex(gpio->pld); + + status &=3D gpio->ien; + if (!status) + return IRQ_NONE; + + for_each_set_bit(pin, &status, chip->ngpio) { + child_irq =3D irq_find_mapping(chip->irq.domain, pin); + handle_nested_irq(child_irq); + } + + return IRQ_HANDLED; +} + +static int kempld_gpio_irq_init(struct device *dev, + struct kempld_gpio_data *gpio) +{ + struct kempld_device_data *pld =3D gpio->pld; + struct gpio_chip *chip =3D &gpio->chip; + struct gpio_irq_chip *girq; + unsigned int irq; + int ret; + + /* Get the IRQ configured by the BIOS in the PLD */ + kempld_get_mutex(pld); + irq =3D kempld_read8(pld, KEMPLD_IRQ_GPIO); + kempld_release_mutex(pld); + + if (irq =3D=3D 0xff) { + dev_info(dev, "GPIO controller has no IRQ support\n"); + return 0; + } + + /* Allow overriding the IRQ with the module parameter */ + if (gpio_irq > 0) { + dev_warn(dev, "Forcing IRQ to %d\n", gpio_irq); + irq &=3D ~KEMPLD_IRQ_GPIO_MASK; + irq |=3D gpio_irq & KEMPLD_IRQ_GPIO_MASK; + } + + if (!(irq & KEMPLD_IRQ_GPIO_MASK)) { + dev_warn(dev, "No IRQ configured\n"); + return 0; + } + + /* Get the current config, disable all child interrupts, clear them + * and set the parent IRQ + */ + kempld_get_mutex(pld); + gpio->evt_low_high =3D kempld_read16(pld, KEMPLD_GPIO_EVT_LOW_HIGH); + gpio->evt_lvl_edge =3D kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE); + kempld_write16(pld, KEMPLD_GPIO_IEN, 0); + kempld_write16(pld, KEMPLD_GPIO_STS, 0xFFFF); + kempld_write16(pld, KEMPLD_IRQ_GPIO, irq); + kempld_release_mutex(pld); + + girq =3D &chip->irq; + gpio_irq_chip_set_chip(girq, &kempld_irqchip); + + 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; + girq->threaded =3D true; + + mutex_init(&gpio->irq_lock); + + ret =3D devm_request_threaded_irq(dev, irq & KEMPLD_IRQ_GPIO_MASK, + NULL, kempld_gpio_irq_handler, + IRQF_ONESHOT, chip->label, + gpio); + if (ret) { + dev_err(dev, "failed to request irq %d\n", irq); + return ret; + } + + return 0; +} + static int kempld_gpio_probe(struct platform_device *pdev) { struct device *dev =3D &pdev->dev; @@ -247,6 +435,10 @@ static int kempld_gpio_probe(struct platform_device *p= dev) return -ENODEV; } =20 + ret =3D kempld_gpio_irq_init(dev, gpio); + if (ret) + return ret; + ret =3D devm_gpiochip_add_data(dev, chip, gpio); if (ret) { dev_err(dev, "Could not register GPIO chip\n"); diff --git a/include/linux/mfd/kempld.h b/include/linux/mfd/kempld.h index 643c096b93ace..2dbd80abfd1d2 100644 --- a/include/linux/mfd/kempld.h +++ b/include/linux/mfd/kempld.h @@ -37,6 +37,7 @@ #define KEMPLD_SPEC_GET_MINOR(x) (x & 0x0f) #define KEMPLD_SPEC_GET_MAJOR(x) ((x >> 4) & 0x0f) #define KEMPLD_IRQ_GPIO 0x35 +#define KEMPLD_IRQ_GPIO_MASK 0x0f #define KEMPLD_IRQ_I2C 0x36 #define KEMPLD_CFG 0x37 #define KEMPLD_CFG_GPIO_I2C_MUX (1 << 0) --=20 2.39.5