Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755401AbbK0Vgk (ORCPT ); Fri, 27 Nov 2015 16:36:40 -0500 Received: from mail.lysator.liu.se ([130.236.254.3]:40298 "EHLO mail.lysator.liu.se" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754835AbbK0Vge (ORCPT ); Fri, 27 Nov 2015 16:36:34 -0500 From: Peter Rosin To: linux-gpio@vger.kernel.org Cc: Linus Walleij , Alexandre Courbot , Jean-Christophe Plagniol-Villard , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Peter Rosin , Peter Rosin Subject: [RFC PATCH 2/2] pinctrl: at91: expose the isr bit Date: Fri, 27 Nov 2015 22:36:13 +0100 Message-Id: <1448660173-29214-3-git-send-email-peda@lysator.liu.se> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1448660173-29214-1-git-send-email-peda@lysator.liu.se> References: <1448660173-29214-1-git-send-email-peda@lysator.liu.se> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4662 Lines: 147 From: Peter Rosin This is a bit horrible, as reading the isr register will interfere with interrupts on other pins in the same pio. So, be careful... Signed-off-by: Peter Rosin --- drivers/pinctrl/pinctrl-at91.c | 50 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 2deb1309fcac..6ae615264e6a 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,8 @@ struct at91_gpio_chip { int pioc_hwirq; /* PIO bank interrupt identifier on AIC */ int pioc_virq; /* PIO bank Linux virtual interrupt */ int pioc_idx; /* PIO bank index */ + spinlock_t isr_lock; /* PIO_ISR cache lock */ + unsigned isr_cache; /* PIO_ISR cache */ void __iomem *regbase; /* PIO bank virtual address */ struct clk *clock; /* associated clock */ struct at91_pinctrl_mux_ops *ops; /* ops */ @@ -737,7 +740,9 @@ static int at91_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, continue; mask = pin_to_mask(pin->pin); + spin_lock(&gpio_chips[pin->bank]->isr_lock); at91_mux_disable_interrupt(pio, mask); + spin_unlock(&gpio_chips[pin->bank]->isr_lock); switch (pin->mux) { case AT91_MUX_GPIO: at91_mux_gpio_enable(pio, mask, 1); @@ -1331,6 +1336,29 @@ static int at91_gpio_get(struct gpio_chip *chip, unsigned offset) return (pdsr & mask) != 0; } +static int at91_gpio_get_isr(struct gpio_chip *chip, unsigned offset) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + int res; + + spin_lock(&at91_gpio->isr_lock); + if (readl_relaxed(pio + PIO_IMR)) { + /* do not clobber PIO_ISR if any interrupts are enabled */ + res = -EBUSY; + goto out; + } + + at91_gpio->isr_cache |= readl_relaxed(pio + PIO_ISR); + res = (at91_gpio->isr_cache & mask) != 0; + at91_gpio->isr_cache &= ~mask; + + out: + spin_unlock(&at91_gpio->isr_lock); + return res; +} + static void at91_gpio_set(struct gpio_chip *chip, unsigned offset, int val) { @@ -1425,8 +1453,12 @@ static void gpio_irq_mask(struct irq_data *d) void __iomem *pio = at91_gpio->regbase; unsigned mask = 1 << d->hwirq; - if (pio) - writel_relaxed(mask, pio + PIO_IDR); + if (!pio) + return; + + spin_lock(&at91_gpio->isr_lock); + writel_relaxed(mask, pio + PIO_IDR); + spin_unlock(&at91_gpio->isr_lock); } static void gpio_irq_unmask(struct irq_data *d) @@ -1435,8 +1467,12 @@ static void gpio_irq_unmask(struct irq_data *d) void __iomem *pio = at91_gpio->regbase; unsigned mask = 1 << d->hwirq; - if (pio) - writel_relaxed(mask, pio + PIO_IER); + if (!pio) + return; + + spin_lock(&at91_gpio->isr_lock); + writel_relaxed(mask, pio + PIO_IER); + spin_unlock(&at91_gpio->isr_lock); } static int gpio_irq_type(struct irq_data *d, unsigned type) @@ -1562,8 +1598,10 @@ void at91_pinctrl_gpio_suspend(void) pio = gpio_chips[i]->regbase; backups[i] = readl_relaxed(pio + PIO_IMR); + spin_lock(&gpio_chips[i]->isr_lock); writel_relaxed(backups[i], pio + PIO_IDR); writel_relaxed(wakeups[i], pio + PIO_IER); + spin_unlock(&gpio_chips[i]->isr_lock); if (!wakeups[i]) clk_disable_unprepare(gpio_chips[i]->clock); @@ -1588,8 +1626,10 @@ void at91_pinctrl_gpio_resume(void) if (!wakeups[i]) clk_prepare_enable(gpio_chips[i]->clock); + spin_lock(&gpio_chips[i]->isr_lock); writel_relaxed(wakeups[i], pio + PIO_IDR); writel_relaxed(backups[i], pio + PIO_IER); + spin_unlock(&gpio_chips[i]->isr_lock); } } @@ -1713,6 +1753,7 @@ static struct gpio_chip at91_gpio_template = { .get_direction = at91_gpio_get_direction, .direction_input = at91_gpio_direction_input, .get = at91_gpio_get, + .get_isr = at91_gpio_get_isr, .direction_output = at91_gpio_direction_output, .set = at91_gpio_set, .set_multiple = at91_gpio_set_multiple, @@ -1789,6 +1830,7 @@ static int at91_gpio_probe(struct platform_device *pdev) } at91_chip->chip = at91_gpio_template; + spin_lock_init(&at91_chip->isr_lock); chip = &at91_chip->chip; chip->of_node = np; -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/