|
@@ -16,9 +16,6 @@
|
|
|
#include <linux/of_irq.h>
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/interrupt.h>
|
|
|
-#include <linux/irq.h>
|
|
|
-#include <linux/irqdomain.h>
|
|
|
-#include <linux/irqchip/chained_irq.h>
|
|
|
#include <linux/io.h>
|
|
|
#include <linux/gpio.h>
|
|
|
#include <linux/pinctrl/machine.h>
|
|
@@ -47,7 +44,6 @@ struct at91_gpio_chip {
|
|
|
int pioc_idx; /* PIO bank index */
|
|
|
void __iomem *regbase; /* PIO bank virtual address */
|
|
|
struct clk *clock; /* associated clock */
|
|
|
- struct irq_domain *domain; /* associated irq domain */
|
|
|
struct at91_pinctrl_mux_ops *ops; /* ops */
|
|
|
};
|
|
|
|
|
@@ -1192,21 +1188,6 @@ static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int at91_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
|
|
-{
|
|
|
- struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
|
|
|
- int virq;
|
|
|
-
|
|
|
- if (offset < chip->ngpio)
|
|
|
- virq = irq_create_mapping(at91_gpio->domain, offset);
|
|
|
- else
|
|
|
- virq = -ENXIO;
|
|
|
-
|
|
|
- dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
|
|
|
- chip->label, offset + chip->base, virq);
|
|
|
- return virq;
|
|
|
-}
|
|
|
-
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
|
static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
|
|
{
|
|
@@ -1336,6 +1317,11 @@ static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void gpio_irq_ack(struct irq_data *d)
|
|
|
+{
|
|
|
+ /* the interrupt is already cleared before by reading ISR */
|
|
|
+}
|
|
|
+
|
|
|
static unsigned int gpio_irq_startup(struct irq_data *d)
|
|
|
{
|
|
|
struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
|
|
@@ -1435,6 +1421,7 @@ void at91_pinctrl_gpio_resume(void)
|
|
|
|
|
|
static struct irq_chip gpio_irqchip = {
|
|
|
.name = "GPIO",
|
|
|
+ .irq_ack = gpio_irq_ack,
|
|
|
.irq_startup = gpio_irq_startup,
|
|
|
.irq_shutdown = gpio_irq_shutdown,
|
|
|
.irq_disable = gpio_irq_mask,
|
|
@@ -1446,9 +1433,11 @@ static struct irq_chip gpio_irqchip = {
|
|
|
|
|
|
static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
|
|
|
{
|
|
|
- struct irq_chip *chip = irq_desc_get_chip(desc);
|
|
|
- struct irq_data *idata = irq_desc_get_irq_data(desc);
|
|
|
- struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
|
|
|
+ struct irq_chip *chip = irq_get_chip(irq);
|
|
|
+ struct gpio_chip *gpio_chip = irq_desc_get_handler_data(desc);
|
|
|
+ struct at91_gpio_chip *at91_gpio = container_of(gpio_chip,
|
|
|
+ struct at91_gpio_chip, chip);
|
|
|
+
|
|
|
void __iomem *pio = at91_gpio->regbase;
|
|
|
unsigned long isr;
|
|
|
int n;
|
|
@@ -1469,81 +1458,19 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
|
|
|
}
|
|
|
|
|
|
for_each_set_bit(n, &isr, BITS_PER_LONG) {
|
|
|
- generic_handle_irq(irq_find_mapping(at91_gpio->domain, n));
|
|
|
+ generic_handle_irq(irq_find_mapping(
|
|
|
+ gpio_chip->irqdomain, n));
|
|
|
}
|
|
|
}
|
|
|
chained_irq_exit(chip, desc);
|
|
|
/* now it may re-trigger */
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * This lock class tells lockdep that GPIO irqs are in a different
|
|
|
- * category than their parents, so it won't report false recursion.
|
|
|
- */
|
|
|
-static struct lock_class_key gpio_lock_class;
|
|
|
-
|
|
|
-static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
|
|
|
- irq_hw_number_t hw)
|
|
|
-{
|
|
|
- struct at91_gpio_chip *at91_gpio = h->host_data;
|
|
|
- void __iomem *pio = at91_gpio->regbase;
|
|
|
- u32 mask = 1 << hw;
|
|
|
-
|
|
|
- irq_set_lockdep_class(virq, &gpio_lock_class);
|
|
|
-
|
|
|
- /*
|
|
|
- * Can use the "simple" and not "edge" handler since it's
|
|
|
- * shorter, and the AIC handles interrupts sanely.
|
|
|
- */
|
|
|
- irq_set_chip(virq, &gpio_irqchip);
|
|
|
- if ((at91_gpio->ops == &at91sam9x5_ops) &&
|
|
|
- (readl_relaxed(pio + PIO_AIMMR) & mask) &&
|
|
|
- (readl_relaxed(pio + PIO_ELSR) & mask))
|
|
|
- irq_set_handler(virq, handle_level_irq);
|
|
|
- else
|
|
|
- irq_set_handler(virq, handle_simple_irq);
|
|
|
- set_irq_flags(virq, IRQF_VALID);
|
|
|
- irq_set_chip_data(virq, at91_gpio);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int at91_gpio_irq_domain_xlate(struct irq_domain *d,
|
|
|
- struct device_node *ctrlr,
|
|
|
- const u32 *intspec, unsigned int intsize,
|
|
|
- irq_hw_number_t *out_hwirq,
|
|
|
- unsigned int *out_type)
|
|
|
-{
|
|
|
- struct at91_gpio_chip *at91_gpio = d->host_data;
|
|
|
- int ret;
|
|
|
- int pin = at91_gpio->chip.base + intspec[0];
|
|
|
-
|
|
|
- if (WARN_ON(intsize < 2))
|
|
|
- return -EINVAL;
|
|
|
- *out_hwirq = intspec[0];
|
|
|
- *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
|
|
|
-
|
|
|
- ret = gpio_request(pin, ctrlr->full_name);
|
|
|
- if (ret)
|
|
|
- return ret;
|
|
|
-
|
|
|
- ret = gpio_direction_input(pin);
|
|
|
- if (ret)
|
|
|
- return ret;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static struct irq_domain_ops at91_gpio_ops = {
|
|
|
- .map = at91_gpio_irq_map,
|
|
|
- .xlate = at91_gpio_irq_domain_xlate,
|
|
|
-};
|
|
|
-
|
|
|
static int at91_gpio_of_irq_setup(struct device_node *node,
|
|
|
struct at91_gpio_chip *at91_gpio)
|
|
|
{
|
|
|
- struct at91_gpio_chip *prev = NULL;
|
|
|
struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq);
|
|
|
+ int ret;
|
|
|
|
|
|
at91_gpio->pioc_hwirq = irqd_to_hwirq(d);
|
|
|
|
|
@@ -1553,26 +1480,25 @@ static int at91_gpio_of_irq_setup(struct device_node *node,
|
|
|
/* Disable irqs of this PIO controller */
|
|
|
writel_relaxed(~0, at91_gpio->regbase + PIO_IDR);
|
|
|
|
|
|
- /* Setup irq domain */
|
|
|
- at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
|
|
|
- &at91_gpio_ops, at91_gpio);
|
|
|
- if (!at91_gpio->domain)
|
|
|
+ /*
|
|
|
+ * Let the generic code handle this edge IRQ, the the chained
|
|
|
+ * handler will perform the actual work of handling the parent
|
|
|
+ * interrupt.
|
|
|
+ */
|
|
|
+ ret = gpiochip_irqchip_add(&at91_gpio->chip,
|
|
|
+ &gpio_irqchip,
|
|
|
+ 0,
|
|
|
+ handle_edge_irq,
|
|
|
+ IRQ_TYPE_EDGE_BOTH);
|
|
|
+ if (ret)
|
|
|
panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
|
|
|
at91_gpio->pioc_idx);
|
|
|
|
|
|
- /* Setup chained handler */
|
|
|
- if (at91_gpio->pioc_idx)
|
|
|
- prev = gpio_chips[at91_gpio->pioc_idx - 1];
|
|
|
-
|
|
|
- /* The top level handler handles one bank of GPIOs, except
|
|
|
- * on some SoC it can handle up to three...
|
|
|
- * We only set up the handler for the first of the list.
|
|
|
- */
|
|
|
- if (prev && prev->next == at91_gpio)
|
|
|
- return 0;
|
|
|
-
|
|
|
- irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
|
|
|
- irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
|
|
|
+ /* Then register the chain on the parent IRQ */
|
|
|
+ gpiochip_set_chained_irqchip(&at91_gpio->chip,
|
|
|
+ &gpio_irqchip,
|
|
|
+ at91_gpio->pioc_virq,
|
|
|
+ gpio_irq_handler);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -1586,7 +1512,6 @@ static struct gpio_chip at91_gpio_template = {
|
|
|
.get = at91_gpio_get,
|
|
|
.direction_output = at91_gpio_direction_output,
|
|
|
.set = at91_gpio_set,
|
|
|
- .to_irq = at91_gpio_to_irq,
|
|
|
.dbg_show = at91_gpio_dbg_show,
|
|
|
.can_sleep = false,
|
|
|
.ngpio = MAX_NB_GPIO_PER_BANK,
|