diff options
Diffstat (limited to 'drivers/gpio/gpio-davinci.c')
-rw-r--r-- | drivers/gpio/gpio-davinci.c | 75 |
1 files changed, 66 insertions, 9 deletions
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 7629b4f12b7f..339f9dac591b 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -37,6 +37,8 @@ struct davinci_gpio_regs { u32 intstat; }; +typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq); + #define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */ #define chip2controller(chip) \ @@ -172,6 +174,27 @@ of_err: return NULL; } +#ifdef CONFIG_OF_GPIO +static int davinci_gpio_of_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + struct davinci_gpio_controller *chips = dev_get_drvdata(gc->dev); + struct davinci_gpio_platform_data *pdata = dev_get_platdata(gc->dev); + + if (gpiospec->args[0] > pdata->ngpio) + return -EINVAL; + + if (gc != &chips[gpiospec->args[0] / 32].chip) + return -EINVAL; + + if (flags) + *flags = gpiospec->args[1]; + + return gpiospec->args[0] % 32; +} +#endif + static int davinci_gpio_probe(struct platform_device *pdev) { int i, base; @@ -236,6 +259,9 @@ static int davinci_gpio_probe(struct platform_device *pdev) chips[i].chip.ngpio = 32; #ifdef CONFIG_OF_GPIO + chips[i].chip.of_gpio_n_cells = 2; + chips[i].chip.of_xlate = davinci_gpio_of_xlate; + chips[i].chip.dev = dev; chips[i].chip.of_node = dev->of_node; #endif spin_lock_init(&chips[i].lock); @@ -413,6 +439,26 @@ static const struct irq_domain_ops davinci_gpio_irq_ops = { .xlate = irq_domain_xlate_onetwocell, }; +static struct irq_chip *davinci_gpio_get_irq_chip(unsigned int irq) +{ + static struct irq_chip_type gpio_unbanked; + + gpio_unbanked = *container_of(irq_get_chip(irq), + struct irq_chip_type, chip); + + return &gpio_unbanked.chip; +}; + +static struct irq_chip *keystone_gpio_get_irq_chip(unsigned int irq) +{ + static struct irq_chip gpio_unbanked; + + gpio_unbanked = *irq_get_chip(irq); + return &gpio_unbanked; +}; + +static const struct of_device_id davinci_gpio_ids[]; + /* * NOTE: for suspend/resume, probably best to make a platform_device with * suspend_late/resume_resume calls hooking into results of the set_wake() @@ -423,7 +469,8 @@ static const struct irq_domain_ops davinci_gpio_irq_ops = { static int davinci_gpio_irq_setup(struct platform_device *pdev) { - unsigned gpio, irq, bank; + unsigned gpio, bank; + int irq; struct clk *clk; u32 binten = 0; unsigned ngpio, bank_irq; @@ -433,6 +480,18 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) struct davinci_gpio_platform_data *pdata = dev->platform_data; struct davinci_gpio_regs __iomem *g; struct irq_domain *irq_domain = NULL; + const struct of_device_id *match; + struct irq_chip *irq_chip; + gpio_get_irq_chip_cb_t gpio_get_irq_chip; + + /* + * Use davinci_gpio_get_irq_chip by default to handle non DT cases + */ + gpio_get_irq_chip = davinci_gpio_get_irq_chip; + match = of_match_device(of_match_ptr(davinci_gpio_ids), + dev); + if (match) + gpio_get_irq_chip = (gpio_get_irq_chip_cb_t)match->data; ngpio = pdata->ngpio; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); @@ -489,8 +548,6 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) * IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs. */ if (pdata->gpio_unbanked) { - static struct irq_chip_type gpio_unbanked; - /* pass "bank 0" GPIO IRQs to AINTC */ chips[0].chip.to_irq = gpio_to_irq_unbanked; chips[0].gpio_irq = bank_irq; @@ -499,10 +556,9 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) /* AINTC handles mask/unmask; GPIO handles triggering */ irq = bank_irq; - gpio_unbanked = *container_of(irq_get_chip(irq), - struct irq_chip_type, chip); - gpio_unbanked.chip.name = "GPIO-AINTC"; - gpio_unbanked.chip.irq_set_type = gpio_irq_type_unbanked; + irq_chip = gpio_get_irq_chip(irq); + irq_chip->name = "GPIO-AINTC"; + irq_chip->irq_set_type = gpio_irq_type_unbanked; /* default trigger: both edges */ g = gpio2regs(0); @@ -511,7 +567,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) /* set the direct IRQs up to use that irqchip */ for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++, irq++) { - irq_set_chip(irq, &gpio_unbanked.chip); + irq_set_chip(irq, irq_chip); irq_set_handler_data(irq, &chips[gpio / 32]); irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH); } @@ -554,7 +610,8 @@ done: #if IS_ENABLED(CONFIG_OF) static const struct of_device_id davinci_gpio_ids[] = { - { .compatible = "ti,dm6441-gpio", }, + { .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip}, + { .compatible = "ti,dm6441-gpio", davinci_gpio_get_irq_chip}, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, davinci_gpio_ids); |