diff options
Diffstat (limited to 'drivers/pinctrl/sirf/pinctrl-sirf.c')
-rw-r--r-- | drivers/pinctrl/sirf/pinctrl-sirf.c | 51 |
1 files changed, 39 insertions, 12 deletions
diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c index b81e388..a0d6152 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -468,7 +468,8 @@ static inline int sirfsoc_gpio_to_irq(struct gpio_chip *chip, unsigned offset) struct sirfsoc_gpio_bank *bank = container_of(to_of_mm_gpio_chip(chip), struct sirfsoc_gpio_bank, chip); - return irq_create_mapping(bank->domain, offset); + return irq_create_mapping(bank->domain, offset + bank->id * + SIRFSOC_GPIO_BANK_SIZE); } static inline int sirfsoc_gpio_to_offset(unsigned int gpio) @@ -559,7 +560,7 @@ static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type) spin_lock_irqsave(&sgpio_lock, flags); val = readl(bank->chip.regs + offset); - val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK; + val &= ~(SIRFSOC_GPIO_CTL_INTR_STS_MASK | SIRFSOC_GPIO_CTL_OUT_EN_MASK); switch (type) { case IRQ_TYPE_NONE: @@ -593,12 +594,34 @@ static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type) return 0; } +static unsigned int sirfsoc_gpio_irq_startup(struct irq_data *d) +{ + struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq)) + dev_err(bank->chip.gc.dev, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); + sirfsoc_gpio_irq_unmask(d); + return 0; +} + +static void sirfsoc_gpio_irq_shutdown(struct irq_data *d) +{ + struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); + + sirfsoc_gpio_irq_mask(d); + gpio_unlock_as_irq(&bank->chip.gc, d->hwirq); +} + static struct irq_chip sirfsoc_irq_chip = { .name = "sirf-gpio-irq", .irq_ack = sirfsoc_gpio_irq_ack, .irq_mask = sirfsoc_gpio_irq_mask, .irq_unmask = sirfsoc_gpio_irq_unmask, .irq_set_type = sirfsoc_gpio_irq_type, + .irq_startup = sirfsoc_gpio_irq_startup, + .irq_shutdown = sirfsoc_gpio_irq_shutdown, }; static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) @@ -629,7 +652,8 @@ static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) if ((status & 0x1) && (ctrl & SIRFSOC_GPIO_CTL_INTR_EN_MASK)) { pr_debug("%s: gpio id %d idx %d happens\n", __func__, bank->id, idx); - generic_handle_irq(irq_find_mapping(bank->domain, idx)); + generic_handle_irq(irq_find_mapping(bank->domain, idx + + bank->id * SIRFSOC_GPIO_BANK_SIZE)); } idx++; @@ -786,7 +810,7 @@ static int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq, irq_set_chip(irq, &sirfsoc_irq_chip); irq_set_handler(irq, handle_level_irq); - irq_set_chip_data(irq, bank); + irq_set_chip_data(irq, bank + hwirq / SIRFSOC_GPIO_BANK_SIZE); set_irq_flags(irq, IRQF_VALID); return 0; @@ -835,6 +859,7 @@ static int sirfsoc_gpio_probe(struct device_node *np) struct sirfsoc_gpio_bank *bank; void __iomem *regs; struct platform_device *pdev; + struct irq_domain *domain; bool is_marco = false; u32 pullups[SIRFSOC_GPIO_NO_OF_BANKS], pulldowns[SIRFSOC_GPIO_NO_OF_BANKS]; @@ -850,6 +875,14 @@ static int sirfsoc_gpio_probe(struct device_node *np) if (of_device_is_compatible(np, "sirf,marco-pinctrl")) is_marco = 1; + domain = irq_domain_add_linear(np, SIRFSOC_GPIO_BANK_SIZE * SIRFSOC_GPIO_NO_OF_BANKS, + &sirfsoc_gpio_irq_simple_ops, sgpio_bank); + if (!domain) { + pr_err("%s: Failed to create irqdomain\n", np->full_name); + err = -ENOSYS; + goto out; + } + for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { bank = &sgpio_bank[i]; spin_lock_init(&bank->lock); @@ -866,6 +899,7 @@ static int sirfsoc_gpio_probe(struct device_node *np) bank->chip.gc.of_node = np; bank->chip.gc.of_xlate = sirfsoc_gpio_of_xlate; bank->chip.gc.of_gpio_n_cells = 2; + bank->chip.gc.dev = &pdev->dev; bank->chip.regs = regs; bank->id = i; bank->is_marco = is_marco; @@ -882,14 +916,7 @@ static int sirfsoc_gpio_probe(struct device_node *np) goto out; } - bank->domain = irq_domain_add_linear(np, SIRFSOC_GPIO_BANK_SIZE, - &sirfsoc_gpio_irq_simple_ops, bank); - - if (!bank->domain) { - pr_err("%s: Failed to create irqdomain\n", np->full_name); - err = -ENOSYS; - goto out; - } + bank->domain = domain; irq_set_chained_handler(bank->parent_irq, sirfsoc_gpio_handle_irq); irq_set_handler_data(bank->parent_irq, bank); |