From: Florian Fainelli <florian.fainelli@broadcom.com>
To: linux-kernel@vger.kernel.org
Cc: bcm-kernel-feedback-list@broadcom.com,
Florian Fainelli <florian.fainelli@broadcom.com>,
Ray Jui <rjui@broadcom.com>,
Scott Branden <sbranden@broadcom.com>,
Linus Walleij <linusw@kernel.org>,
Yendapally Reddy Dhananjaya Reddy <yrdreddy@broadcom.com>,
linux-arm-kernel@lists.infradead.org (moderated list:BROADCOM
IPROC ARM ARCHITECTURE),
linux-gpio@vger.kernel.org (open list:PIN CONTROL SUBSYSTEM)
Subject: [PATCH] pinctrl: nsp: support both-edge GPIO interrupts
Date: Wed, 21 Oct 2026 11:37:16 -0700 [thread overview]
Message-ID: <20261021183716.718318-1-florian.fainelli@broadcom.com> (raw)
The SFP core requests rising and falling edge interrupts for module
presence, loss of signal and transmit fault GPIOs. GPIO-A only has one
edge polarity bit per pin, so the driver rejects IRQ_TYPE_EDGE_BOTH and
makes the SFP core fall back to polling.
Emulate both-edge detection by arming the edge opposite to the current
input level, then rearm it after acknowledging each interrupt and before
unmasking. Resample the input while programming the polarity so an edge
during that sequence leaves the controller armed for the new level.
Fixes: 8bfcbbbcabe0 ("pinctrl: nsp: add gpio-a driver support for Broadcom NSP SoC")
Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
---
drivers/pinctrl/bcm/pinctrl-nsp-gpio.c | 35 +++++++++++++++++++++++++-
1 file changed, 34 insertions(+), 1 deletion(-)
diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
index 83fcc80d5967..cc990361b7b8 100644
--- a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
+++ b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
@@ -64,6 +64,7 @@ struct nsp_gpio {
struct pinctrl_dev *pctl;
struct pinctrl_desc pctldesc;
raw_spinlock_t lock;
+ unsigned long both_edges;
};
enum base_type {
@@ -122,6 +123,18 @@ static inline bool nsp_get_bit(struct nsp_gpio *chip, enum base_type address,
return !!(readl(chip->base + reg) & BIT(gpio));
}
+static void nsp_gpio_irq_rearm_both(struct nsp_gpio *chip, unsigned int gpio)
+{
+ bool level, new_level;
+
+ do {
+ level = nsp_get_bit(chip, REG, NSP_GPIO_DATA_IN, gpio);
+ /* A high input needs the falling edge and vice versa. */
+ nsp_set_bit(chip, REG, NSP_GPIO_EVENT_INT_POLARITY, gpio, level);
+ new_level = nsp_get_bit(chip, REG, NSP_GPIO_DATA_IN, gpio);
+ } while (level != new_level);
+}
+
static irqreturn_t nsp_gpio_irq_handler(int irq, void *data)
{
struct gpio_chip *gc = (struct gpio_chip *)data;
@@ -157,10 +170,18 @@ static void nsp_gpio_irq_ack(struct irq_data *d)
unsigned gpio = d->hwirq;
u32 val = BIT(gpio);
u32 trigger_type;
+ unsigned long flags;
trigger_type = irq_get_trigger_type(d->irq);
- if (trigger_type & IRQ_TYPE_EDGE_BOTH)
+ if (trigger_type & IRQ_TYPE_EDGE_BOTH) {
writel(val, chip->base + NSP_GPIO_EVENT);
+
+ if (test_bit(gpio, &chip->both_edges)) {
+ raw_spin_lock_irqsave(&chip->lock, flags);
+ nsp_gpio_irq_rearm_both(chip, gpio);
+ raw_spin_unlock_irqrestore(&chip->lock, flags);
+ }
+ }
}
/*
@@ -203,6 +224,8 @@ static void nsp_gpio_irq_unmask(struct irq_data *d)
gpiochip_enable_irq(gc, irqd_to_hwirq(d));
raw_spin_lock_irqsave(&chip->lock, flags);
+ if (test_bit(d->hwirq, &chip->both_edges))
+ nsp_gpio_irq_rearm_both(chip, d->hwirq);
nsp_gpio_irq_set_mask(d, true);
raw_spin_unlock_irqrestore(&chip->lock, flags);
}
@@ -229,6 +252,14 @@ static int nsp_gpio_irq_set_type(struct irq_data *d, unsigned int type)
falling = true;
break;
+ case IRQ_TYPE_EDGE_BOTH:
+ /* The controller has a single edge polarity bit. Emulate both
+ * edges by initially arming the edge opposite to the input and
+ * switching polarity after every interrupt.
+ */
+ falling = nsp_get_bit(chip, REG, NSP_GPIO_DATA_IN, gpio);
+ break;
+
case IRQ_TYPE_LEVEL_HIGH:
level_low = false;
break;
@@ -243,6 +274,8 @@ static int nsp_gpio_irq_set_type(struct irq_data *d, unsigned int type)
raw_spin_unlock_irqrestore(&chip->lock, flags);
return -EINVAL;
}
+ __assign_bit(gpio, &chip->both_edges,
+ (type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH);
nsp_set_bit(chip, REG, NSP_GPIO_EVENT_INT_POLARITY, gpio, falling);
nsp_set_bit(chip, REG, NSP_GPIO_INT_POLARITY, gpio, level_low);
--
2.53.0
reply other threads:[~2026-10-21 18:37 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261021183716.718318-1-florian.fainelli@broadcom.com \
--to=florian.fainelli@broadcom.com \
--cc=bcm-kernel-feedback-list@broadcom.com \
--cc=linusw@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=rjui@broadcom.com \
--cc=sbranden@broadcom.com \
--cc=yrdreddy@broadcom.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®