mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/2] gpio: davinci: Add support for level-triggered interrupts
@ 2026-09-23 12:56 Aniket Limaye
  2026-09-23 12:56 ` [PATCH 1/2] dt-bindings: gpio: gpio-davinci: Add the tda54 support Aniket Limaye
  2026-09-23 12:56 ` [PATCH 2/2] gpio: davinci: Add level support via extended registers Aniket Limaye
  0 siblings, 2 replies; 4+ messages in thread
From: Aniket Limaye @ 2026-09-23 12:56 UTC (permalink / raw)
  To: Keerthy, Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: vigneshr, u-kumar1, nm, linux-gpio, devicetree, linux-kernel,
	Aniket Limaye

Add support for level-triggered interrupts (IRQ_TYPE_LEVEL_HIGH and
IRQ_TYPE_LEVEL_LOW) for TDA54 GPIO controller via extended register sets.
Update the dt-bindings to add support for ti,tda54-gpio.

Signed-off-by: Aniket Limaye <a-limaye@ti.com>
---
Aniket Limaye (2):
      dt-bindings: gpio: gpio-davinci: Add the tda54 support
      gpio: davinci: Add level support via extended registers

 .../devicetree/bindings/gpio/gpio-davinci.yaml     |   1 +
 drivers/gpio/gpio-davinci.c                        | 103 +++++++++++++++++++--
 2 files changed, 98 insertions(+), 6 deletions(-)
---
base-commit: 4220e7e54566d6d35ca26dbd166aaa5c7de44acc
change-id: 20260923-upstream-tda54-gpio-da6747dfd34b

Best regards,
-- 
Aniket Limaye <a-limaye@ti.com>


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] dt-bindings: gpio: gpio-davinci: Add the tda54 support
  2026-09-23 12:56 [PATCH 0/2] gpio: davinci: Add support for level-triggered interrupts Aniket Limaye
@ 2026-09-23 12:56 ` Aniket Limaye
  2026-09-23 13:57   ` Krzysztof Kozlowski
  2026-09-23 12:56 ` [PATCH 2/2] gpio: davinci: Add level support via extended registers Aniket Limaye
  1 sibling, 1 reply; 4+ messages in thread
From: Aniket Limaye @ 2026-09-23 12:56 UTC (permalink / raw)
  To: Keerthy, Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: vigneshr, u-kumar1, nm, linux-gpio, devicetree, linux-kernel,
	Aniket Limaye

New version of GPIO IP used in TDA54 SoCs adds support for level-triggered
interrupts via extended registers.
Add the device binding for ti,tda54-gpio.

Signed-off-by: Aniket Limaye <a-limaye@ti.com>
---
 Documentation/devicetree/bindings/gpio/gpio-davinci.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/gpio/gpio-davinci.yaml b/Documentation/devicetree/bindings/gpio/gpio-davinci.yaml
index 1434d08f8b74..02b6b9a436a6 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-davinci.yaml
+++ b/Documentation/devicetree/bindings/gpio/gpio-davinci.yaml
@@ -18,6 +18,7 @@ properties:
               - ti,am654-gpio
               - ti,j721e-gpio
               - ti,am64-gpio
+              - ti,tda54-gpio
           - const: ti,keystone-gpio
 
       - items:

-- 
2.53.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 2/2] gpio: davinci: Add level support via extended registers
  2026-09-23 12:56 [PATCH 0/2] gpio: davinci: Add support for level-triggered interrupts Aniket Limaye
  2026-09-23 12:56 ` [PATCH 1/2] dt-bindings: gpio: gpio-davinci: Add the tda54 support Aniket Limaye
@ 2026-09-23 12:56 ` Aniket Limaye
  1 sibling, 0 replies; 4+ messages in thread
From: Aniket Limaye @ 2026-09-23 12:56 UTC (permalink / raw)
  To: Keerthy, Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: vigneshr, u-kumar1, nm, linux-gpio, devicetree, linux-kernel,
	Aniket Limaye

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 <a-limaye@ti.com>
---
 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


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/2] dt-bindings: gpio: gpio-davinci: Add the tda54 support
  2026-09-23 12:56 ` [PATCH 1/2] dt-bindings: gpio: gpio-davinci: Add the tda54 support Aniket Limaye
@ 2026-09-23 13:57   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 4+ messages in thread
From: Krzysztof Kozlowski @ 2026-09-23 13:57 UTC (permalink / raw)
  To: Aniket Limaye, Keerthy, Linus Walleij, Bartosz Golaszewski,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: vigneshr, u-kumar1, nm, linux-gpio, devicetree, linux-kernel

On 23/09/2026 14:56, Aniket Limaye wrote:
> New version of GPIO IP used in TDA54 SoCs adds support for level-triggered
> interrupts via extended registers.
> Add the device binding for ti,tda54-gpio.
> 
> Signed-off-by: Aniket Limaye <a-limaye@ti.com>


Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-09-23 13:57 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-23 12:56 [PATCH 0/2] gpio: davinci: Add support for level-triggered interrupts Aniket Limaye
2026-09-23 12:56 ` [PATCH 1/2] dt-bindings: gpio: gpio-davinci: Add the tda54 support Aniket Limaye
2026-09-23 13:57   ` Krzysztof Kozlowski
2026-09-23 12:56 ` [PATCH 2/2] gpio: davinci: Add level support via extended registers Aniket Limaye

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®