[PATCH 2/2] gpio: davinci: Add level support via extended registers
COOLING4d
From: Aniket Limaye <hidden>
Date: 2026-09-23 12:58:29
Also in:
linux-gpio, lkml
Subsystem:
gpio subsystem, the rest, ti davinci series gpio driver · Maintainers:
Linus Walleij, Bartosz Golaszewski, Linus Torvalds, Keerthy
Add support for level-triggered interrupts (IRQ_TYPE_LEVEL_HIGH and IRQ_TYPE_LEVEL_LOW) for TDA54 GPIO controller via extended register sets. Signed-off-by: Aniket Limaye <redacted> --- drivers/gpio/gpio-davinci.c | 103 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 6 deletions(-)
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index cccbaea1dec2..e5a3abe6b9d3 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c@@ -39,12 +39,20 @@ struct davinci_gpio_regs { u32 intstat; }; +struct davinci_gpio_regs_ext { + u32 set_high; + u32 clr_high; + u32 set_low; + u32 clr_low; +}; + typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq); #define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */ static void __iomem *gpio_base; static unsigned int offset_array[5] = {0x10, 0x38, 0x60, 0x88, 0xb0}; +static unsigned int offset_array_ext[5] = {0xd8, 0xe8, 0xf8, 0x108, 0x118}; struct davinci_gpio_irq_data { void __iomem *regs;
@@ -58,9 +66,11 @@ struct davinci_gpio_controller { /* Serialize access to GPIO registers */ spinlock_t lock; void __iomem *regs[MAX_REGS_BANKS]; + void __iomem *regs_ext[MAX_REGS_BANKS]; int gpio_unbanked; int irqs[MAX_INT_PER_BANK]; struct davinci_gpio_regs context[MAX_REGS_BANKS]; + struct davinci_gpio_regs_ext context_ext[MAX_REGS_BANKS]; u32 binten_context; };
@@ -168,6 +178,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) unsigned int ngpio, nbank, nirq, gpio_unbanked; struct davinci_gpio_controller *chips; struct device *dev = &pdev->dev; + bool ext_reg = false; /* * The gpio banks conceptually expose a segmented bitmap,
@@ -190,6 +201,9 @@ static int davinci_gpio_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "Failed to get the unbanked GPIOs property\n"); + if (device_is_compatible(dev, "ti,tda54-gpio")) + ext_reg = true; + if (gpio_unbanked) nirq = gpio_unbanked; else
@@ -235,8 +249,11 @@ static int davinci_gpio_probe(struct platform_device *pdev) chips->gpio_unbanked = gpio_unbanked; nbank = DIV_ROUND_UP(ngpio, 32); - for (bank = 0; bank < nbank; bank++) + for (bank = 0; bank < nbank; bank++) { chips->regs[bank] = gpio_base + offset_array[bank]; + if (ext_reg) + chips->regs_ext[bank] = gpio_base + offset_array_ext[bank]; + } ret = devm_gpiochip_add_data(dev, &chips->chip, chips); if (ret)
@@ -267,10 +284,15 @@ static void gpio_irq_mask(struct irq_data *d) struct davinci_gpio_controller *chips = irq_data_get_irq_chip_data(d); irq_hw_number_t hwirq = irqd_to_hwirq(d); struct davinci_gpio_regs __iomem *g = chips->regs[hwirq / 32]; + struct davinci_gpio_regs_ext __iomem *g_ext = chips->regs_ext[hwirq / 32]; uintptr_t mask = (uintptr_t)irq_data_get_irq_handler_data(d); writel_relaxed(mask, &g->clr_falling); writel_relaxed(mask, &g->clr_rising); + if (g_ext) { + writel_relaxed(mask, &g_ext->clr_high); + writel_relaxed(mask, &g_ext->clr_low); + } gpiochip_disable_irq(&chips->chip, hwirq); }
@@ -280,12 +302,14 @@ static void gpio_irq_unmask(struct irq_data *d) struct davinci_gpio_controller *chips = irq_data_get_irq_chip_data(d); irq_hw_number_t hwirq = irqd_to_hwirq(d); struct davinci_gpio_regs __iomem *g = chips->regs[hwirq / 32]; + struct davinci_gpio_regs_ext __iomem *g_ext = chips->regs_ext[hwirq / 32]; uintptr_t mask = (uintptr_t)irq_data_get_irq_handler_data(d); unsigned status = irqd_get_trigger_type(d); + unsigned int ext_status = g_ext ? (IRQ_TYPE_LEVEL_MASK) : 0; gpiochip_enable_irq(&chips->chip, hwirq); - status &= IRQ_TYPE_EDGE_BOTH; + status &= IRQ_TYPE_EDGE_BOTH | ext_status; if (!status) status = IRQ_TYPE_EDGE_BOTH;
@@ -293,6 +317,18 @@ static void gpio_irq_unmask(struct irq_data *d) writel_relaxed(mask, &g->set_falling); if (status & IRQ_TYPE_EDGE_RISING) writel_relaxed(mask, &g->set_rising); + if (status & IRQ_TYPE_LEVEL_HIGH) + writel_relaxed(mask, &g_ext->set_high); + if (status & IRQ_TYPE_LEVEL_LOW) + writel_relaxed(mask, &g_ext->set_low); +} + +static int gpio_irq_type_ext(struct irq_data *d, unsigned int trigger) +{ + if (trigger & ~(IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_LEVEL_MASK)) + return -EINVAL; + + return 0; } static int gpio_irq_type(struct irq_data *d, unsigned trigger)
@@ -303,6 +339,15 @@ static int gpio_irq_type(struct irq_data *d, unsigned trigger) return 0; } +static const struct irq_chip gpio_irqchip_ext = { + .name = "GPIO", + .irq_unmask = gpio_irq_unmask, + .irq_mask = gpio_irq_mask, + .irq_set_type = gpio_irq_type_ext, + .flags = IRQCHIP_IMMUTABLE | IRQCHIP_SET_TYPE_MASKED | IRQCHIP_SKIP_SET_WAKE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + static const struct irq_chip gpio_irqchip = { .name = "GPIO", .irq_unmask = gpio_irq_unmask,
@@ -387,10 +432,13 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger) { struct davinci_gpio_controller *d; struct davinci_gpio_regs __iomem *g; + struct davinci_gpio_regs_ext __iomem *g_ext; u32 mask, i; + u32 ext_trigger; d = (struct davinci_gpio_controller *)irq_data_get_irq_handler_data(data); g = (struct davinci_gpio_regs __iomem *)d->regs[0]; + g_ext = (struct davinci_gpio_regs_ext __iomem *)d->regs_ext[0]; for (i = 0; i < MAX_INT_PER_BANK; i++) if (data->irq == d->irqs[i]) break;
@@ -400,13 +448,21 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger) mask = __gpio_mask(i); - if (trigger & ~IRQ_TYPE_EDGE_BOTH) + ext_trigger = g_ext ? (IRQ_TYPE_LEVEL_MASK) : 0; + + if (trigger & ~(IRQ_TYPE_EDGE_BOTH | ext_trigger)) return -EINVAL; writel_relaxed(mask, (trigger & IRQ_TYPE_EDGE_FALLING) ? &g->set_falling : &g->clr_falling); writel_relaxed(mask, (trigger & IRQ_TYPE_EDGE_RISING) ? &g->set_rising : &g->clr_rising); + if (ext_trigger) { + writel_relaxed(mask, (trigger & IRQ_TYPE_LEVEL_HIGH) + ? &g_ext->set_high : &g_ext->clr_high); + writel_relaxed(mask, (trigger & IRQ_TYPE_LEVEL_LOW) + ? &g_ext->set_low : &g_ext->clr_low); + } return 0; }
@@ -418,8 +474,12 @@ davinci_gpio_irq_map(struct irq_domain *d, unsigned int irq, struct davinci_gpio_controller *chips = (struct davinci_gpio_controller *)d->host_data; - irq_set_chip_and_handler_name(irq, &gpio_irqchip, handle_simple_irq, - "davinci_gpio"); + if (chips->regs_ext[0]) + irq_set_chip_and_handler_name(irq, &gpio_irqchip_ext, handle_simple_irq, + "davinci_gpio"); + else + irq_set_chip_and_handler_name(irq, &gpio_irqchip, handle_simple_irq, + "davinci_gpio"); irq_set_irq_type(irq, IRQ_TYPE_NONE); irq_set_chip_data(irq, (__force void *)chips); irq_set_handler_data(irq, (void *)(uintptr_t)__gpio_mask(hw));
@@ -469,6 +529,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) struct device *dev = &pdev->dev; struct davinci_gpio_controller *chips = platform_get_drvdata(pdev); struct davinci_gpio_regs __iomem *g; + struct davinci_gpio_regs_ext __iomem *g_ext; struct irq_domain *irq_domain = NULL; struct irq_chip *irq_chip; struct davinci_gpio_irq_data *irqdata;
@@ -495,9 +556,9 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) dev_err(dev, "Couldn't allocate IRQ numbers\n"); return irq; } - irq_domain = irq_domain_create_legacy(dev_fwnode(dev), ngpio, irq, 0, &davinci_gpio_irq_ops, chips); + if (!irq_domain) { dev_err(dev, "Couldn't register an IRQ domain\n"); return -ENODEV;
@@ -534,6 +595,11 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) g = chips->regs[0]; writel_relaxed(~0, &g->set_falling); writel_relaxed(~0, &g->set_rising); + g_ext = chips->regs_ext[0]; + if (g_ext) { + writel_relaxed(~0, &g_ext->set_high); + writel_relaxed(~0, &g_ext->set_low); + } /* set the direct IRQs up to use that irqchip */ for (gpio = 0; gpio < chips->gpio_unbanked; gpio++) {
@@ -558,6 +624,12 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) g = chips->regs[bank / 2]; writel_relaxed(~0, &g->clr_falling); writel_relaxed(~0, &g->clr_rising); + g_ext = chips->regs_ext[bank / 2]; + if (g_ext) { + writel_relaxed(~0, &g_ext->clr_high); + writel_relaxed(~0, &g_ext->clr_low); + } + /* * Each chip handles 32 gpios, and each irq bank consists of 16
@@ -597,7 +669,9 @@ static void davinci_gpio_save_context(struct davinci_gpio_controller *chips, u32 nbank) { struct davinci_gpio_regs __iomem *g; + struct davinci_gpio_regs_ext __iomem *g_ext; struct davinci_gpio_regs *context; + struct davinci_gpio_regs_ext *context_ext; u32 bank; void __iomem *base;
@@ -611,6 +685,12 @@ static void davinci_gpio_save_context(struct davinci_gpio_controller *chips, context->set_data = readl_relaxed(&g->set_data); context->set_rising = readl_relaxed(&g->set_rising); context->set_falling = readl_relaxed(&g->set_falling); + g_ext = chips->regs_ext[bank]; + if (g_ext) { + context_ext = &chips->context_ext[bank]; + context_ext->set_high = readl_relaxed(&g_ext->set_high); + context_ext->set_low = readl_relaxed(&g_ext->set_low); + } } /* Clear all interrupt status registers */
@@ -621,7 +701,9 @@ static void davinci_gpio_restore_context(struct davinci_gpio_controller *chips, u32 nbank) { struct davinci_gpio_regs __iomem *g; + struct davinci_gpio_regs_ext __iomem *g_ext; struct davinci_gpio_regs *context; + struct davinci_gpio_regs_ext *context_ext; u32 bank; void __iomem *base;
@@ -641,6 +723,14 @@ static void davinci_gpio_restore_context(struct davinci_gpio_controller *chips, writel_relaxed(context->set_rising, &g->set_rising); if (readl_relaxed(&g->set_falling) != context->set_falling) writel_relaxed(context->set_falling, &g->set_falling); + g_ext = chips->regs_ext[bank]; + if (g_ext) { + context_ext = &chips->context_ext[bank]; + if (readl_relaxed(&g_ext->set_high) != context_ext->set_high) + writel_relaxed(context_ext->set_high, &g_ext->set_high); + if (readl_relaxed(&g_ext->set_low) != context_ext->set_low) + writel_relaxed(context_ext->set_low, &g_ext->set_low); + } } }
@@ -671,6 +761,7 @@ static const struct of_device_id davinci_gpio_ids[] = { { .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip}, { .compatible = "ti,am654-gpio", keystone_gpio_get_irq_chip}, { .compatible = "ti,dm6441-gpio", davinci_gpio_get_irq_chip}, + { .compatible = "ti,tda54-gpio", keystone_gpio_get_irq_chip}, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, davinci_gpio_ids);
--
2.53.0