public inbox for devicetree@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 1/3] dt-bindings: gpio: add Phytium GPIO controller
       [not found] <20260302095147.2483-1-1536943441@qq.com>
@ 2026-03-02  9:51 ` Zhu Ling
  2026-03-03  6:49   ` Krzysztof Kozlowski
  2026-03-03  8:28   ` Krzysztof Kozlowski
  2026-03-02  9:51 ` [PATCH v1 2/3] gpio: add support for Phytium platform " Zhu Ling
  2026-03-02  9:51 ` [PATCH v1 3/3] MAINTAINERS: add entry for Phytium platform GPIO driver Zhu Ling
  2 siblings, 2 replies; 8+ messages in thread
From: Zhu Ling @ 2026-03-02  9:51 UTC (permalink / raw)
  To: linux-gpio, devicetree
  Cc: linux-kernel, linus.walleij, brgl, andy, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, chenbaozi, Zhu Ling

Add the devicetree binding schema for the Phytium platform GPIO
controller.

Register the "phytium" vendor prefix used by the compatible string.

Use ngpios as the preferred child-node property and keep nr-gpios as
deprecated for compatibility with existing firmware descriptions.

Signed-off-by: Zhu Ling <1536943441@qq.com>
---
 .../bindings/gpio/phytium,gpio.yaml           | 134 ++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 2 files changed, 136 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/phytium,gpio.yaml

diff --git a/Documentation/devicetree/bindings/gpio/phytium,gpio.yaml b/Documentation/devicetree/bindings/gpio/phytium,gpio.yaml
new file mode 100644
index 000000000..1b9200c57
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/phytium,gpio.yaml
@@ -0,0 +1,134 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/phytium,gpio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Phytium GPIO controller
+
+description: |
+  Phytium GPIO controllers expose one GPIO/interrupt controller and up to
+  two configurable ports. Child nodes describe per-port configuration.
+
+maintainers:
+  - Chen Baozi <chenbaozi@phytium.com.cn>
+
+properties:
+  $nodename:
+    pattern: "^gpio@[0-9a-f]+$"
+
+  compatible:
+    const: phytium,gpio
+
+  reg:
+    maxItems: 1
+
+  gpio-controller: true
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  '#gpio-cells':
+    const: 2
+
+  interrupts:
+    description: |
+      The interrupts to the parent controller raised when GPIOs generate
+      the interrupts. If the controller provides one combined interrupt
+      for all GPIOs, specify a single interrupt. If the controller provides
+      one interrupt for each GPIO, provide a list of interrupts that
+      correspond to each of the GPIO pins.
+    minItems: 1
+    maxItems: 32
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 2
+
+patternProperties:
+  "^gpio-port@[0-9a-f]+$":
+    type: object
+    properties:
+      compatible:
+        const: phytium,gpio-port
+
+      reg:
+        maxItems: 1
+
+      gpio-controller: true
+
+      '#gpio-cells':
+        const: 2
+
+      ngpios:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: The number of GPIO pins exported by the port.
+        default: 32
+        minimum: 1
+        maximum: 32
+
+      nr-gpios:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: The number of GPIO pins exported by the port.
+        deprecated: true
+        default: 32
+        minimum: 1
+        maximum: 32
+
+    required:
+      - compatible
+      - reg
+      - gpio-controller
+      - '#gpio-cells'
+
+    additionalProperties: false
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - gpio-controller
+  - "#gpio-cells"
+  - interrupts
+  - interrupt-controller
+  - "#interrupt-cells"
+  - "#address-cells"
+  - "#size-cells"
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    gpio: gpio@28004000 {
+      compatible = "phytium,gpio";
+      reg = <0x28004000 0x1000>;
+      gpio-controller;
+      #gpio-cells = <2>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+      interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+      interrupt-controller;
+      #interrupt-cells = <2>;
+
+      porta: gpio-port@0 {
+        compatible = "phytium,gpio-port";
+        reg = <0>;
+        gpio-controller;
+        #gpio-cells = <2>;
+        ngpios = <8>;
+      };
+
+      portb: gpio-port@1 {
+        compatible = "phytium,gpio-port";
+        reg = <1>;
+        gpio-controller;
+        #gpio-cells = <2>;
+        ngpios = <8>;
+      };
+    };
+...
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index ee7fd3cfe..2c3f9777d 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1265,6 +1265,8 @@ patternProperties:
     description: PHICOMM Co., Ltd.
   "^phontech,.*":
     description: Phontech
+  "^phytium,.*":
+    description: Phytium Technology Co., Ltd.
   "^phytec,.*":
     description: PHYTEC Messtechnik GmbH
   "^picochip,.*":
-- 
2.34.1


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

* [PATCH v1 2/3] gpio: add support for Phytium platform GPIO controller
       [not found] <20260302095147.2483-1-1536943441@qq.com>
  2026-03-02  9:51 ` [PATCH v1 1/3] dt-bindings: gpio: add Phytium GPIO controller Zhu Ling
@ 2026-03-02  9:51 ` Zhu Ling
  2026-03-02 10:14   ` Andy Shevchenko
  2026-03-23 14:34   ` Linus Walleij
  2026-03-02  9:51 ` [PATCH v1 3/3] MAINTAINERS: add entry for Phytium platform GPIO driver Zhu Ling
  2 siblings, 2 replies; 8+ messages in thread
From: Zhu Ling @ 2026-03-02  9:51 UTC (permalink / raw)
  To: linux-gpio, devicetree
  Cc: linux-kernel, linus.walleij, brgl, andy, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, chenbaozi, Zhu Ling

Add support for the Phytium platform GPIO controller with:
- shared core helpers and irqchip implementation
- platform probe path for OF/ACPI
- Kconfig/Makefile integration

The driver supports GPIO direction and value configuration, plus
interrupt delivery for platform devices.

Signed-off-by: Zhu Ling <1536943441@qq.com>
---
 drivers/gpio/Kconfig                 |  16 +
 drivers/gpio/Makefile                |   2 +
 drivers/gpio/gpio-phytium-core.c     | 444 +++++++++++++++++++++++++++
 drivers/gpio/gpio-phytium-core.h     |  90 ++++++
 drivers/gpio/gpio-phytium-platform.c | 226 ++++++++++++++
 5 files changed, 778 insertions(+)
 create mode 100644 drivers/gpio/gpio-phytium-core.c
 create mode 100644 drivers/gpio/gpio-phytium-core.h
 create mode 100644 drivers/gpio/gpio-phytium-platform.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index b45fb799e..65643c78e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -128,6 +128,10 @@ config GPIO_SWNODE_UNDEFINED
 config GPIO_MAX730X
 	tristate
 
+# This symbol is selected by Phytium platform frontend
+config GPIO_PHYTIUM_CORE
+	tristate
+
 config GPIO_IDIO_16
 	tristate
 	select REGMAP_IRQ
@@ -561,6 +565,18 @@ config GPIO_OMAP
 	help
 	  Say yes here to enable GPIO support for TI OMAP SoCs.
 
+config GPIO_PHYTIUM_PLAT
+	tristate "Phytium GPIO platform support"
+	depends on (ARM64 || COMPILE_TEST) && (ACPI || OF_GPIO)
+	select GPIO_PHYTIUM_CORE
+	select GPIOLIB_IRQCHIP
+	help
+	  Say yes here to support the platform GPIO controller
+	  found in Phytium SoCs.
+
+	  This driver supports GPIO line configuration and
+	  interrupt delivery.
+
 config GPIO_PL061
 	tristate "PrimeCell PL061 GPIO support"
 	depends on ARM_AMBA || COMPILE_TEST
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index c05f7d795..fe8050529 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -144,6 +144,8 @@ obj-$(CONFIG_GPIO_PCF857X)		+= gpio-pcf857x.o
 obj-$(CONFIG_GPIO_PCH)			+= gpio-pch.o
 obj-$(CONFIG_GPIO_PCIE_IDIO_24)		+= gpio-pcie-idio-24.o
 obj-$(CONFIG_GPIO_PCI_IDIO_16)		+= gpio-pci-idio-16.o
+obj-$(CONFIG_GPIO_PHYTIUM_CORE)		+= gpio-phytium-core.o
+obj-$(CONFIG_GPIO_PHYTIUM_PLAT)		+= gpio-phytium-platform.o
 obj-$(CONFIG_GPIO_PISOSR)		+= gpio-pisosr.o
 obj-$(CONFIG_GPIO_PL061)		+= gpio-pl061.o
 obj-$(CONFIG_GPIO_PMIC_EIC_SPRD)	+= gpio-pmic-eic-sprd.o
diff --git a/drivers/gpio/gpio-phytium-core.c b/drivers/gpio/gpio-phytium-core.c
new file mode 100644
index 000000000..bff94adb4
--- /dev/null
+++ b/drivers/gpio/gpio-phytium-core.c
@@ -0,0 +1,444 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019-2023, Phytium Technology Co., Ltd.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+
+#include "gpio-phytium-core.h"
+
+static int get_pin_location(struct phytium_gpio *gpio, unsigned int offset,
+			    struct pin_loc *pl)
+{
+	int ret;
+
+	if (offset < gpio->ngpio[0]) {
+		pl->port = 0;
+		pl->offset = offset;
+		ret = 0;
+	} else if (offset < (gpio->ngpio[0] + gpio->ngpio[1])) {
+		pl->port = 1;
+		pl->offset = offset - gpio->ngpio[0];
+		ret = 0;
+	} else {
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void phytium_gpio_toggle_trigger(struct phytium_gpio *gpio,
+					unsigned int offset)
+{
+	struct gpio_chip *gc;
+	u32 pol;
+	int val;
+
+	/* Only port A can provide interrupt source */
+	if (offset >= gpio->ngpio[0])
+		return;
+
+	gc = &gpio->gc;
+
+	pol = readl(gpio->regs + GPIO_INT_POLARITY);
+	/* Just read the current value right out of the data register */
+	val = gc->get(gc, offset);
+	if (val)
+		pol &= ~BIT(offset);
+	else
+		pol |= BIT(offset);
+
+	writel(pol, gpio->regs + GPIO_INT_POLARITY);
+}
+
+int phytium_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+	struct phytium_gpio *gpio = gpiochip_get_data(gc);
+	struct pin_loc loc;
+	void __iomem *dat;
+
+	if (get_pin_location(gpio, offset, &loc))
+		return -EINVAL;
+
+	dat = gpio->regs + GPIO_EXT_PORTA + (loc.port * GPIO_PORT_STRIDE);
+
+	return !!(readl(dat) & BIT(loc.offset));
+}
+EXPORT_SYMBOL_GPL(phytium_gpio_get);
+
+int phytium_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+	struct phytium_gpio *gpio = gpiochip_get_data(gc);
+	struct pin_loc loc;
+	void __iomem *dr;
+	unsigned long flags;
+	u32 mask;
+
+	if (get_pin_location(gpio, offset, &loc))
+		return -EINVAL;
+	dr = gpio->regs + GPIO_SWPORTA_DR + (loc.port * GPIO_PORT_STRIDE);
+
+	raw_spin_lock_irqsave(&gpio->lock, flags);
+
+	if (value)
+		mask = readl(dr) | BIT(loc.offset);
+	else
+		mask = readl(dr) & ~BIT(loc.offset);
+
+	writel(mask, dr);
+
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(phytium_gpio_set);
+
+int phytium_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
+{
+	struct phytium_gpio *gpio = gpiochip_get_data(gc);
+	struct pin_loc loc;
+	unsigned long flags;
+	void __iomem *ddr;
+
+	if (get_pin_location(gpio, offset, &loc))
+		return -EINVAL;
+	ddr = gpio->regs + GPIO_SWPORTA_DDR + (loc.port * GPIO_PORT_STRIDE);
+
+	raw_spin_lock_irqsave(&gpio->lock, flags);
+
+	writel(readl(ddr) & ~(BIT(loc.offset)), ddr);
+
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(phytium_gpio_direction_input);
+
+int phytium_gpio_direction_output(struct gpio_chip *gc, unsigned int offset,
+				  int value)
+{
+	struct phytium_gpio *gpio = gpiochip_get_data(gc);
+	struct pin_loc loc;
+	unsigned long flags;
+	void __iomem *ddr;
+
+	if (get_pin_location(gpio, offset, &loc))
+		return -EINVAL;
+	ddr = gpio->regs + GPIO_SWPORTA_DDR + (loc.port * GPIO_PORT_STRIDE);
+
+	phytium_gpio_set(gc, offset, value);
+	raw_spin_lock_irqsave(&gpio->lock, flags);
+
+	writel(readl(ddr) | BIT(loc.offset), ddr);
+
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(phytium_gpio_direction_output);
+
+void phytium_gpio_irq_ack(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct phytium_gpio *gpio = gpiochip_get_data(gc);
+	u32 val = BIT(irqd_to_hwirq(d));
+
+	raw_spin_lock(&gpio->lock);
+
+	writel(val, gpio->regs + GPIO_PORTA_EOI);
+
+	raw_spin_unlock(&gpio->lock);
+}
+EXPORT_SYMBOL_GPL(phytium_gpio_irq_ack);
+
+void phytium_gpio_irq_mask(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct phytium_gpio *gpio = gpiochip_get_data(gc);
+	u32 val;
+
+	/* Only port A can provide interrupt source */
+	if (irqd_to_hwirq(d) >= gpio->ngpio[0])
+		return;
+
+	raw_spin_lock(&gpio->lock);
+
+	val = readl(gpio->regs + GPIO_INTMASK);
+	val |= BIT(irqd_to_hwirq(d));
+	writel(val, gpio->regs + GPIO_INTMASK);
+
+	raw_spin_unlock(&gpio->lock);
+
+	gpiochip_disable_irq(gc, irqd_to_hwirq(d));
+}
+EXPORT_SYMBOL_GPL(phytium_gpio_irq_mask);
+
+void phytium_gpio_irq_unmask(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct phytium_gpio *gpio = gpiochip_get_data(gc);
+	u32 val;
+
+	/* Only port A can provide interrupt source */
+	if (irqd_to_hwirq(d) >= gpio->ngpio[0])
+		return;
+
+	gpiochip_enable_irq(gc, irqd_to_hwirq(d));
+
+	raw_spin_lock(&gpio->lock);
+
+	val = readl(gpio->regs + GPIO_INTMASK);
+	val &= ~BIT(irqd_to_hwirq(d));
+	writel(val, gpio->regs + GPIO_INTMASK);
+
+	raw_spin_unlock(&gpio->lock);
+}
+EXPORT_SYMBOL_GPL(phytium_gpio_irq_unmask);
+
+int phytium_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct phytium_gpio *gpio = gpiochip_get_data(gc);
+	int hwirq = irqd_to_hwirq(d);
+	unsigned long flags, lvl, pol;
+
+	if (hwirq < 0 || hwirq >= gpio->ngpio[0])
+		return -EINVAL;
+
+	if ((flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) &&
+	    (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))) {
+		dev_err(gc->parent,
+			"trying to configure line %d for both level and edge detection, choose one!\n",
+			hwirq);
+		return -EINVAL;
+	}
+
+	raw_spin_lock_irqsave(&gpio->lock, flags);
+
+	lvl = readl(gpio->regs + GPIO_INTTYPE_LEVEL);
+	pol = readl(gpio->regs + GPIO_INT_POLARITY);
+
+	switch (flow_type) {
+	case IRQ_TYPE_EDGE_BOTH:
+		lvl |= BIT(hwirq);
+		phytium_gpio_toggle_trigger(gpio, hwirq);
+		irq_set_handler_locked(d, handle_edge_irq);
+		dev_dbg(gc->parent, "line %d: IRQ on both edges\n", hwirq);
+		break;
+	case IRQ_TYPE_EDGE_RISING:
+		lvl |= BIT(hwirq);
+		pol |= BIT(hwirq);
+		irq_set_handler_locked(d, handle_edge_irq);
+		dev_dbg(gc->parent, "line %d: IRQ on RISING edge\n", hwirq);
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		lvl |= BIT(hwirq);
+		pol &= ~BIT(hwirq);
+		irq_set_handler_locked(d, handle_edge_irq);
+		dev_dbg(gc->parent, "line %d: IRQ on FALLING edge\n", hwirq);
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		lvl &= ~BIT(hwirq);
+		pol |= BIT(hwirq);
+		irq_set_handler_locked(d, handle_level_irq);
+		dev_dbg(gc->parent, "line %d: IRQ on HIGH level\n", hwirq);
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		lvl &= ~BIT(hwirq);
+		pol &= ~BIT(hwirq);
+		irq_set_handler_locked(d, handle_level_irq);
+		dev_dbg(gc->parent, "line %d: IRQ on LOW level\n", hwirq);
+		break;
+	}
+
+	writel(lvl, gpio->regs + GPIO_INTTYPE_LEVEL);
+	if (flow_type != IRQ_TYPE_EDGE_BOTH)
+		writel(pol, gpio->regs + GPIO_INT_POLARITY);
+
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(phytium_gpio_irq_set_type);
+
+void phytium_gpio_irq_enable(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct phytium_gpio *gpio = gpiochip_get_data(gc);
+	unsigned long flags;
+	u32 val;
+
+	if (gpio->is_resuming)
+		return;
+	/* Only port A can provide interrupt source */
+	if (irqd_to_hwirq(d) >= gpio->ngpio[0])
+		return;
+
+	raw_spin_lock_irqsave(&gpio->lock, flags);
+
+	val = readl(gpio->regs + GPIO_INTEN);
+	val |= BIT(irqd_to_hwirq(d));
+	writel(val, gpio->regs + GPIO_INTEN);
+
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
+}
+EXPORT_SYMBOL_GPL(phytium_gpio_irq_enable);
+
+void phytium_gpio_irq_disable(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct phytium_gpio *gpio = gpiochip_get_data(gc);
+	unsigned long flags;
+	u32 val;
+
+	/* Only port A can provide interrupt source */
+	if (irqd_to_hwirq(d) >= gpio->ngpio[0])
+		return;
+
+	raw_spin_lock_irqsave(&gpio->lock, flags);
+
+	val = readl(gpio->regs + GPIO_INTEN);
+	val &= ~BIT(irqd_to_hwirq(d));
+	writel(val, gpio->regs + GPIO_INTEN);
+
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
+}
+EXPORT_SYMBOL_GPL(phytium_gpio_irq_disable);
+
+void phytium_gpio_irq_print_chip(struct irq_data *data, struct seq_file *p)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+
+	seq_printf(p, dev_name(gc->parent));
+}
+EXPORT_SYMBOL_GPL(phytium_gpio_irq_print_chip);
+
+void phytium_gpio_irq_handler(struct irq_desc *desc)
+{
+	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+	struct phytium_gpio *gpio = gpiochip_get_data(gc);
+	struct irq_chip *irqchip = irq_desc_get_chip(desc);
+	unsigned long pending;
+	unsigned int parent_irq = irq_desc_get_irq(desc);
+	int offset;
+	int index = -1;
+	unsigned int index_found = 0;
+
+	chained_irq_enter(irqchip, desc);
+
+	pending = readl(gpio->regs + GPIO_INTSTATUS);
+
+	if (gc->irq.num_parents > 1) {
+		for (index = 0 ; index < gc->irq.num_parents; index++) {
+			if (gc->irq.parents[index] == parent_irq) {
+				index_found = 1;
+				break;
+			}
+		}
+		if (!index_found)
+			goto out;
+	}
+
+	if (pending) {
+		for_each_set_bit(offset, &pending, gpio->ngpio[0]) {
+			if (index == -1 || offset == index) {
+				int gpio_irq = irq_find_mapping(gc->irq.domain,
+						offset);
+
+				if (!gpio_irq)
+					continue;
+				generic_handle_irq(gpio_irq);
+				if ((irq_get_trigger_type(gpio_irq) &
+					IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
+					phytium_gpio_toggle_trigger(gpio, offset);
+			}
+		}
+	}
+
+out:
+	chained_irq_exit(irqchip, desc);
+}
+EXPORT_SYMBOL_GPL(phytium_gpio_irq_handler);
+
+int phytium_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+	struct phytium_gpio *gpio = gpiochip_get_data(gc);
+	struct pin_loc loc;
+	void __iomem *ddr;
+
+	if (get_pin_location(gpio, offset, &loc))
+		return -EINVAL;
+	ddr = gpio->regs + GPIO_SWPORTA_DDR + (loc.port * GPIO_PORT_STRIDE);
+
+	return !(readl(ddr) & BIT(loc.offset));
+}
+EXPORT_SYMBOL_GPL(phytium_gpio_get_direction);
+
+int phytium_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct phytium_gpio *gpio = gpiochip_get_data(gc);
+	irq_hw_number_t bit = irqd_to_hwirq(d);
+	int parent_irq;
+	unsigned long flags;
+	int ret;
+
+	if (bit >= ARRAY_SIZE(gpio->irq))
+		return -EINVAL;
+
+	parent_irq = gpio->irq[bit] > 0 ? gpio->irq[bit] : gpio->irq[0];
+	if (parent_irq <= 0)
+		return -EINVAL;
+
+	ret = irq_set_irq_wake(parent_irq, enable);
+
+	if (ret < 0)
+		return ret;
+
+	raw_spin_lock_irqsave(&gpio->lock, flags);
+
+	if (enable) {
+		gpio->wake_en |= BIT(bit);
+		if (gpio->is_resuming == 1) {
+			writel(~gpio->wake_en, gpio->regs + GPIO_INTMASK);
+			writel(gpio->wake_en, gpio->regs + GPIO_INTEN);
+		}
+	} else {
+		gpio->wake_en &= ~BIT(bit);
+	}
+
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(phytium_gpio_irq_set_wake);
+
+int phytium_gpio_irq_set_affinity(struct irq_data *d,
+				  const struct cpumask *mask_val, bool force)
+{
+	int hwirq = irqd_to_hwirq(d);
+	struct gpio_chip *chip_data = irq_data_get_irq_chip_data(d);
+	struct irq_chip *chip;
+	struct irq_data *data;
+
+	if (chip_data->irq.num_parents == 1)
+		hwirq = 0;
+
+	chip = irq_get_chip(chip_data->irq.parents[hwirq]);
+	data = irq_get_irq_data(chip_data->irq.parents[hwirq]);
+
+	if (chip && chip->irq_set_affinity)
+		return chip->irq_set_affinity(data, mask_val, force);
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(phytium_gpio_irq_set_affinity);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Phytium GPIO Controller core");
diff --git a/drivers/gpio/gpio-phytium-core.h b/drivers/gpio/gpio-phytium-core.h
new file mode 100644
index 000000000..963aac511
--- /dev/null
+++ b/drivers/gpio/gpio-phytium-core.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021-2023, Phytium Technology Co., Ltd.
+ */
+
+#ifndef _GPIO_PHYTIUM_H
+#define _GPIO_PHYTIUM_H
+
+#include <linux/gpio/driver.h>
+#include <linux/spinlock.h>
+
+#include "gpiolib.h"
+
+#define GPIO_SWPORTA_DR		0x00 /* WR Port A Output Data Register */
+#define GPIO_SWPORTA_DDR	0x04 /* WR Port A Data Direction Register */
+#define GPIO_EXT_PORTA		0x08 /* RO Port A Input Data Register */
+#define GPIO_SWPORTB_DR		0x0c /* WR Port B Output Data Register */
+#define GPIO_SWPORTB_DDR	0x10 /* WR Port B Data Direction Register */
+#define GPIO_EXT_PORTB		0x14 /* RO Port B Input Data Register */
+
+#define GPIO_INTEN		0x18 /* WR Port A Interrput Enable Register */
+#define GPIO_INTMASK		0x1c /* WR Port A Interrupt Mask Register */
+#define GPIO_INTTYPE_LEVEL	0x20 /* WR Port A Interrupt Level Register */
+#define GPIO_INT_POLARITY	0x24 /* WR Port A Interrupt Polarity Register */
+#define GPIO_INTSTATUS		0x28 /* RO Port A Interrupt Status Register */
+#define GPIO_RAW_INTSTATUS	0x2c /* RO Port A Raw Interrupt Status Register */
+#define GPIO_LS_SYNC		0x30 /* WR Level-sensitive Synchronization Enable Register */
+#define GPIO_DEBOUNCE		0x34 /* WR Debounce Enable Register */
+#define GPIO_PORTA_EOI		0x38 /* WO Port A Clear Interrupt Register */
+
+#define MAX_NPORTS		2
+#define NGPIO_DEFAULT		8
+#define NGPIO_MAX		32
+#define GPIO_PORT_STRIDE	(GPIO_EXT_PORTB - GPIO_EXT_PORTA)
+#define GPIO_CLEAR_IRQ		0xffffffff
+
+struct pin_loc {
+	unsigned int port;
+	unsigned int offset;
+};
+
+#ifdef CONFIG_PM_SLEEP
+struct phytium_gpio_ctx {
+	u32 swporta_dr;
+	u32 swporta_ddr;
+	u32 swportb_dr;
+	u32 swportb_ddr;
+	u32 inten;
+	u32 intmask;
+	u32 inttype_level;
+	u32 int_polarity;
+	u32 intstatus;
+	u32 raw_intstatus;
+	u32 ls_sync;
+	u32 debounce;
+	u32 wake_en;
+};
+#endif
+
+struct phytium_gpio {
+	raw_spinlock_t		lock;
+	void __iomem		*regs;
+	struct gpio_chip	gc;
+	unsigned int		ngpio[2];
+	int			irq[32];
+	u32			wake_en;
+	int			is_resuming;
+#ifdef CONFIG_PM_SLEEP
+	struct phytium_gpio_ctx	ctx;
+#endif
+};
+
+int phytium_gpio_get(struct gpio_chip *gc, unsigned int offset);
+int phytium_gpio_set(struct gpio_chip *gc, unsigned int offset, int value);
+
+int phytium_gpio_get_direction(struct gpio_chip *gc, unsigned int offset);
+int phytium_gpio_direction_input(struct gpio_chip *gc, unsigned int offset);
+int phytium_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int value);
+
+void phytium_gpio_irq_ack(struct irq_data *d);
+void phytium_gpio_irq_mask(struct irq_data *d);
+void phytium_gpio_irq_unmask(struct irq_data *d);
+int phytium_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type);
+void phytium_gpio_irq_print_chip(struct irq_data *data, struct seq_file *p);
+void phytium_gpio_irq_enable(struct irq_data *d);
+void phytium_gpio_irq_disable(struct irq_data *d);
+void phytium_gpio_irq_handler(struct irq_desc *desc);
+int phytium_gpio_irq_set_wake(struct irq_data *d, unsigned int enable);
+int phytium_gpio_irq_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force);
+#endif
diff --git a/drivers/gpio/gpio-phytium-platform.c b/drivers/gpio/gpio-phytium-platform.c
new file mode 100644
index 000000000..16fa520a4
--- /dev/null
+++ b/drivers/gpio/gpio-phytium-platform.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support functions for Phytium GPIO
+ *
+ * Copyright (c) 2019-2023, Phytium Technology Co., Ltd.
+ *
+ * Derived from drivers/gpio/gpio-pl061.c
+ *   Copyright (C) 2008, 2009 Provigent Ltd.
+ */
+
+#include <linux/acpi.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#include "gpio-phytium-core.h"
+
+static const struct of_device_id phytium_gpio_of_match[] = {
+	{ .compatible = "phytium,gpio", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, phytium_gpio_of_match);
+
+static const struct acpi_device_id phytium_gpio_acpi_match[] = {
+	{ "PHYT0001", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, phytium_gpio_acpi_match);
+
+static const struct irq_chip phytium_gpio_irq_chip = {
+	.irq_ack		= phytium_gpio_irq_ack,
+	.irq_mask		= phytium_gpio_irq_mask,
+	.irq_unmask		= phytium_gpio_irq_unmask,
+	.irq_set_type		= phytium_gpio_irq_set_type,
+	.irq_print_chip		= phytium_gpio_irq_print_chip,
+	.irq_enable		= phytium_gpio_irq_enable,
+	.irq_disable		= phytium_gpio_irq_disable,
+	.irq_set_wake		= phytium_gpio_irq_set_wake,
+	.irq_set_affinity	= phytium_gpio_irq_set_affinity,
+	.flags			= IRQCHIP_IMMUTABLE,
+	GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
+static int phytium_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct phytium_gpio *gpio;
+	struct gpio_irq_chip *girq;
+	struct fwnode_handle *fwnode;
+	int i;
+	int err, irq_count;
+
+	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+	if (!gpio)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	gpio->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(gpio->regs))
+		return PTR_ERR(gpio->regs);
+
+	if (!device_get_child_node_count(dev))
+		return -ENODEV;
+
+	device_for_each_child_node(dev, fwnode) {
+		int idx;
+
+		if (fwnode_property_read_u32(fwnode, "reg", &idx) ||
+		    idx >= MAX_NPORTS) {
+			dev_err(dev, "missing/invalid port index\n");
+			fwnode_handle_put(fwnode);
+			return -EINVAL;
+		}
+
+		if ((fwnode_property_read_u32(fwnode, "ngpios",
+					      &gpio->ngpio[idx])) &&
+		    (fwnode_property_read_u32(fwnode, "nr-gpios",
+					      &gpio->ngpio[idx]))) {
+			dev_info(dev,
+				 "failed to get number of gpios for Port%c\n",
+				 idx ? 'B' : 'A');
+			gpio->ngpio[idx] = NGPIO_DEFAULT;
+		}
+	}
+
+	/* irq_chip support */
+	raw_spin_lock_init(&gpio->lock);
+
+	writel(0, gpio->regs + GPIO_INTEN);
+	writel(GPIO_CLEAR_IRQ, gpio->regs + GPIO_PORTA_EOI);
+
+	gpio->gc.base = -1;
+	gpio->gc.get_direction = phytium_gpio_get_direction;
+	gpio->gc.direction_input = phytium_gpio_direction_input;
+	gpio->gc.direction_output = phytium_gpio_direction_output;
+	gpio->gc.get = phytium_gpio_get;
+	gpio->gc.set = phytium_gpio_set;
+	gpio->gc.ngpio = gpio->ngpio[0] + gpio->ngpio[1];
+	gpio->gc.label = dev_name(dev);
+	gpio->gc.parent = dev;
+	gpio->gc.owner = THIS_MODULE;
+
+	girq = &gpio->gc.irq;
+	girq->handler = handle_bad_irq;
+	girq->default_type = IRQ_TYPE_NONE;
+
+	for (i = 0; i < ARRAY_SIZE(gpio->irq); i++)
+		gpio->irq[i] = -ENXIO;
+
+	irq_count = platform_irq_count(pdev);
+	if (irq_count < 0)
+		return irq_count;
+	if (irq_count > ARRAY_SIZE(gpio->irq))
+		return dev_err_probe(dev, -EINVAL,
+				     "too many parent IRQs: %d\n", irq_count);
+
+	for (i = 0; i < irq_count; i++) {
+		gpio->irq[i] = platform_get_irq(pdev, i);
+		if (gpio->irq[i] < 0)
+			return gpio->irq[i];
+	}
+
+	if (!i)
+		return dev_err_probe(dev, -EINVAL, "no parent IRQ is found\n");
+
+	irq_count = i;
+
+	girq->num_parents = irq_count;
+	girq->parents = gpio->irq;
+	girq->parent_handler = phytium_gpio_irq_handler;
+
+	gpio_irq_chip_set_chip(girq, &phytium_gpio_irq_chip);
+
+	err = devm_gpiochip_add_data(dev, &gpio->gc, gpio);
+	if (err)
+		return err;
+
+	platform_set_drvdata(pdev, gpio);
+	dev_info(dev, "Phytium GPIO controller @%pa registered\n",
+		 &res->start);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int phytium_gpio_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct phytium_gpio *gpio = platform_get_drvdata(pdev);
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&gpio->lock, flags);
+
+	gpio->ctx.swporta_dr = readl(gpio->regs + GPIO_SWPORTA_DR);
+	gpio->ctx.swporta_ddr = readl(gpio->regs + GPIO_SWPORTA_DDR);
+	gpio->ctx.swportb_dr = readl(gpio->regs + GPIO_SWPORTB_DR);
+	gpio->ctx.swportb_ddr = readl(gpio->regs + GPIO_SWPORTB_DDR);
+
+	gpio->ctx.inten = readl(gpio->regs + GPIO_INTEN);
+	gpio->is_resuming = 1;
+	gpio->ctx.intmask = readl(gpio->regs + GPIO_INTMASK);
+	gpio->ctx.inttype_level = readl(gpio->regs + GPIO_INTTYPE_LEVEL);
+	gpio->ctx.int_polarity = readl(gpio->regs + GPIO_INT_POLARITY);
+	gpio->ctx.debounce = readl(gpio->regs + GPIO_DEBOUNCE);
+
+	writel(~gpio->wake_en, gpio->regs + GPIO_INTMASK);
+	writel(gpio->wake_en, gpio->regs + GPIO_INTEN);
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
+
+	return 0;
+}
+
+static int phytium_gpio_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct phytium_gpio *gpio = platform_get_drvdata(pdev);
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&gpio->lock, flags);
+
+	writel(gpio->ctx.swporta_dr, gpio->regs + GPIO_SWPORTA_DR);
+	writel(gpio->ctx.swporta_ddr, gpio->regs + GPIO_SWPORTA_DDR);
+	writel(gpio->ctx.swportb_dr, gpio->regs + GPIO_SWPORTB_DR);
+	writel(gpio->ctx.swportb_ddr, gpio->regs + GPIO_SWPORTB_DDR);
+
+	writel(gpio->ctx.intmask, gpio->regs + GPIO_INTMASK);
+	writel(gpio->ctx.inttype_level, gpio->regs + GPIO_INTTYPE_LEVEL);
+	writel(gpio->ctx.int_polarity, gpio->regs + GPIO_INT_POLARITY);
+	writel(gpio->ctx.debounce, gpio->regs + GPIO_DEBOUNCE);
+
+	writel(GPIO_CLEAR_IRQ, gpio->regs + GPIO_PORTA_EOI);
+
+	writel(gpio->ctx.inten, gpio->regs + GPIO_INTEN);
+	gpio->is_resuming = 0;
+
+	raw_spin_unlock_irqrestore(&gpio->lock, flags);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(phytium_gpio_pm_ops, phytium_gpio_suspend,
+			 phytium_gpio_resume);
+
+static struct platform_driver phytium_gpio_driver = {
+	.driver		= {
+		.name	= "gpio-phytium-platform",
+		.pm	= &phytium_gpio_pm_ops,
+		.of_match_table = of_match_ptr(phytium_gpio_of_match),
+		.acpi_match_table = ACPI_PTR(phytium_gpio_acpi_match),
+	},
+	.probe		= phytium_gpio_probe,
+};
+
+module_platform_driver(phytium_gpio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Chen Baozi <chenbaozi@phytium.com.cn>");
+MODULE_DESCRIPTION("Phytium GPIO driver");
-- 
2.34.1


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

* [PATCH v1 3/3] MAINTAINERS: add entry for Phytium platform GPIO driver
       [not found] <20260302095147.2483-1-1536943441@qq.com>
  2026-03-02  9:51 ` [PATCH v1 1/3] dt-bindings: gpio: add Phytium GPIO controller Zhu Ling
  2026-03-02  9:51 ` [PATCH v1 2/3] gpio: add support for Phytium platform " Zhu Ling
@ 2026-03-02  9:51 ` Zhu Ling
  2026-03-02 10:03   ` Andy Shevchenko
  2 siblings, 1 reply; 8+ messages in thread
From: Zhu Ling @ 2026-03-02  9:51 UTC (permalink / raw)
  To: linux-gpio, devicetree
  Cc: linux-kernel, linus.walleij, brgl, andy, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, chenbaozi, Zhu Ling

Add maintainer contacts and file patterns for the Phytium platform
GPIO binding and driver files.

Signed-off-by: Zhu Ling <1536943441@qq.com>
---
 MAINTAINERS | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 61bf550fd..164553f86 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10963,6 +10963,16 @@ K:	(devm_)?gpio_(request|free|direction|get|set)
 K:	GPIOD_FLAGS_BIT_NONEXCLUSIVE
 K:	devm_gpiod_unhinge
 
+PHYTIUM GPIO DRIVERS
+M:	Zhu Ling <1536943441@qq.com>
+M:	Chen Baozi <chenbaozi@phytium.com.cn>
+L:	linux-gpio@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/gpio/phytium,gpio.yaml
+F:	drivers/gpio/gpio-phytium-core.c
+F:	drivers/gpio/gpio-phytium-core.h
+F:	drivers/gpio/gpio-phytium-platform.c
+
 GPIO UAPI
 M:	Bartosz Golaszewski <brgl@kernel.org>
 R:	Kent Gibson <warthog618@gmail.com>
-- 
2.34.1


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

* Re: [PATCH v1 3/3] MAINTAINERS: add entry for Phytium platform GPIO driver
  2026-03-02  9:51 ` [PATCH v1 3/3] MAINTAINERS: add entry for Phytium platform GPIO driver Zhu Ling
@ 2026-03-02 10:03   ` Andy Shevchenko
  0 siblings, 0 replies; 8+ messages in thread
From: Andy Shevchenko @ 2026-03-02 10:03 UTC (permalink / raw)
  To: Zhu Ling
  Cc: linux-gpio, devicetree, linux-kernel, linus.walleij, brgl, andy,
	robh+dt, krzysztof.kozlowski+dt, conor+dt, chenbaozi

On Mon, Mar 02, 2026 at 05:51:47PM +0800, Zhu Ling wrote:
> Add maintainer contacts and file patterns for the Phytium platform
> GPIO binding and driver files.

Doesn't look like this placed correctly. There is a script to sort the
MAINTAINERS database, please use it to find a better location for a new record.
scripts/parse-maintainers.pl

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v1 2/3] gpio: add support for Phytium platform GPIO controller
  2026-03-02  9:51 ` [PATCH v1 2/3] gpio: add support for Phytium platform " Zhu Ling
@ 2026-03-02 10:14   ` Andy Shevchenko
  2026-03-23 14:34   ` Linus Walleij
  1 sibling, 0 replies; 8+ messages in thread
From: Andy Shevchenko @ 2026-03-02 10:14 UTC (permalink / raw)
  To: Zhu Ling
  Cc: linux-gpio, devicetree, linux-kernel, linus.walleij, brgl, andy,
	robh+dt, krzysztof.kozlowski+dt, conor+dt, chenbaozi

On Mon, Mar 02, 2026 at 05:51:46PM +0800, Zhu Ling wrote:
> Add support for the Phytium platform GPIO controller with:
> - shared core helpers and irqchip implementation
> - platform probe path for OF/ACPI
> - Kconfig/Makefile integration

Why you can't use one of the gpio-regmap, gpio-mmio?

> The driver supports GPIO direction and value configuration, plus
> interrupt delivery for platform devices.

...

> +/*
> + * Copyright (c) 2019-2023, Phytium Technology Co., Ltd.

My calendar shows 2026...

> + */

...

> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/module.h>
> +#include <linux/bitops.h>
> +#include <linux/seq_file.h>
> +#include <linux/interrupt.h>

Follow IWYU principle.

...

I'm not going to review the rest as gpio-remap (or gpio-mmio) should make this
driver much better and smaller.

Take your time to study existing cases.

...

> +EXPORT_SYMBOL_GPL(phytium_gpio_irq_disable);

No way.  And if it's really needed, must be namespaced.

Btw, why the three files and not a standalone single one?

...

> + * Derived from drivers/gpio/gpio-pl061.c

Why? Does it uses the same or similar register layout?

> + *   Copyright (C) 2008, 2009 Provigent Ltd.
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/err.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>

> +#include <linux/kernel.h>

No way this header should be anyhow needed in this driver.

> +#include <linux/module.h>

> +#include <linux/of.h>



> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +
> +#include "gpio-phytium-core.h"

...

> +static const struct of_device_id phytium_gpio_of_match[] = {
> +	{ .compatible = "phytium,gpio", },

No inner comma.

> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, phytium_gpio_of_match);
> +
> +static const struct acpi_device_id phytium_gpio_acpi_match[] = {
> +	{ "PHYT0001", 0 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(acpi, phytium_gpio_acpi_match);

These tables should be moved closer to their user.

...

> +	struct device *dev = &pdev->dev;
> +	struct resource *res;
> +	struct phytium_gpio *gpio;
> +	struct gpio_irq_chip *girq;
> +	struct fwnode_handle *fwnode;

> +	int i;

Why is 'i' signed?

> +	int err, irq_count;

...

> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	gpio->regs = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(gpio->regs))
> +		return PTR_ERR(gpio->regs);

There is a combined call devm_platform_...().


> +	if (!device_get_child_node_count(dev))
> +		return -ENODEV;

Why?!

...

> +	device_for_each_child_node(dev, fwnode) {

Use _scoped() variant

> +		int idx;
> +
> +		if (fwnode_property_read_u32(fwnode, "reg", &idx) ||
> +		    idx >= MAX_NPORTS) {
> +			dev_err(dev, "missing/invalid port index\n");

			return dev_err_probe(...);

> +			fwnode_handle_put(fwnode);
> +			return -EINVAL;
> +		}
> +
> +		if ((fwnode_property_read_u32(fwnode, "ngpios",
> +					      &gpio->ngpio[idx])) &&
> +		    (fwnode_property_read_u32(fwnode, "nr-gpios",
> +					      &gpio->ngpio[idx]))) {
> +			dev_info(dev,
> +				 "failed to get number of gpios for Port%c\n",
> +				 idx ? 'B' : 'A');

It rings a bell. Do you really have to create a brand new driver? Please check
existing ones and clarify why the brand new driver is required.

> +			gpio->ngpio[idx] = NGPIO_DEFAULT;
> +		}
> +	}

...

> +	dev_info(dev, "Phytium GPIO controller @%pa registered\n",
> +		 &res->start);

The successfully probed device is kept silent in the logs.

...

> +#ifdef CONFIG_PM_SLEEP

No way, please, use modern PM macros from pm.h.

> +static int phytium_gpio_suspend(struct device *dev)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct phytium_gpio *gpio = platform_get_drvdata(pdev);

dev_get_drvdata()

> +	unsigned long flags;
> +
> +	raw_spin_lock_irqsave(&gpio->lock, flags);
> +
> +	gpio->ctx.swporta_dr = readl(gpio->regs + GPIO_SWPORTA_DR);
> +	gpio->ctx.swporta_ddr = readl(gpio->regs + GPIO_SWPORTA_DDR);
> +	gpio->ctx.swportb_dr = readl(gpio->regs + GPIO_SWPORTB_DR);
> +	gpio->ctx.swportb_ddr = readl(gpio->regs + GPIO_SWPORTB_DDR);
> +
> +	gpio->ctx.inten = readl(gpio->regs + GPIO_INTEN);
> +	gpio->is_resuming = 1;
> +	gpio->ctx.intmask = readl(gpio->regs + GPIO_INTMASK);
> +	gpio->ctx.inttype_level = readl(gpio->regs + GPIO_INTTYPE_LEVEL);
> +	gpio->ctx.int_polarity = readl(gpio->regs + GPIO_INT_POLARITY);
> +	gpio->ctx.debounce = readl(gpio->regs + GPIO_DEBOUNCE);
> +
> +	writel(~gpio->wake_en, gpio->regs + GPIO_INTMASK);
> +	writel(gpio->wake_en, gpio->regs + GPIO_INTEN);
> +	raw_spin_unlock_irqrestore(&gpio->lock, flags);
> +
> +	return 0;
> +}
> +
> +static int phytium_gpio_resume(struct device *dev)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct phytium_gpio *gpio = platform_get_drvdata(pdev);

Ditto.

> +	unsigned long flags;
> +
> +	raw_spin_lock_irqsave(&gpio->lock, flags);

Use guard()().

> +	writel(gpio->ctx.swporta_dr, gpio->regs + GPIO_SWPORTA_DR);
> +	writel(gpio->ctx.swporta_ddr, gpio->regs + GPIO_SWPORTA_DDR);
> +	writel(gpio->ctx.swportb_dr, gpio->regs + GPIO_SWPORTB_DR);
> +	writel(gpio->ctx.swportb_ddr, gpio->regs + GPIO_SWPORTB_DDR);
> +
> +	writel(gpio->ctx.intmask, gpio->regs + GPIO_INTMASK);
> +	writel(gpio->ctx.inttype_level, gpio->regs + GPIO_INTTYPE_LEVEL);
> +	writel(gpio->ctx.int_polarity, gpio->regs + GPIO_INT_POLARITY);
> +	writel(gpio->ctx.debounce, gpio->regs + GPIO_DEBOUNCE);
> +
> +	writel(GPIO_CLEAR_IRQ, gpio->regs + GPIO_PORTA_EOI);
> +
> +	writel(gpio->ctx.inten, gpio->regs + GPIO_INTEN);
> +	gpio->is_resuming = 0;
> +
> +	raw_spin_unlock_irqrestore(&gpio->lock, flags);
> +
> +	return 0;
> +}
> +#endif

...

> +static SIMPLE_DEV_PM_OPS(phytium_gpio_pm_ops, phytium_gpio_suspend,
> +			 phytium_gpio_resume);

Use new PM macros.

...

> +static struct platform_driver phytium_gpio_driver = {
> +	.driver		= {
> +		.name	= "gpio-phytium-platform",
> +		.pm	= &phytium_gpio_pm_ops,

> +		.of_match_table = of_match_ptr(phytium_gpio_of_match),
> +		.acpi_match_table = ACPI_PTR(phytium_gpio_acpi_match),

No way of_match_ptr() and/or ACPI_PTR() should appear in a new code.

> +	},
> +	.probe		= phytium_gpio_probe,
> +};

> +

Redundant blank line.

> +module_platform_driver(phytium_gpio_driver);

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v1 1/3] dt-bindings: gpio: add Phytium GPIO controller
  2026-03-02  9:51 ` [PATCH v1 1/3] dt-bindings: gpio: add Phytium GPIO controller Zhu Ling
@ 2026-03-03  6:49   ` Krzysztof Kozlowski
  2026-03-03  8:28   ` Krzysztof Kozlowski
  1 sibling, 0 replies; 8+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-03  6:49 UTC (permalink / raw)
  To: Zhu Ling
  Cc: linux-gpio, devicetree, linux-kernel, linus.walleij, brgl, andy,
	robh+dt, krzysztof.kozlowski+dt, conor+dt, chenbaozi

On Mon, Mar 02, 2026 at 05:51:45PM +0800, Zhu Ling wrote:
> Add the devicetree binding schema for the Phytium platform GPIO
> controller.

What is Phytium platform?

> 
> Register the "phytium" vendor prefix used by the compatible string.
> 
> Use ngpios as the preferred child-node property and keep nr-gpios as
> deprecated for compatibility with existing firmware descriptions.

NAK, you cannot add new deprecated properties. "existing firmware" does
not matter, because this is the first posting, thus the firmware starts
existing from now.

> 
> Signed-off-by: Zhu Ling <1536943441@qq.com>
> ---
>  .../bindings/gpio/phytium,gpio.yaml           | 134 ++++++++++++++++++
>  .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
>  2 files changed, 136 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/gpio/phytium,gpio.yaml
> 
> diff --git a/Documentation/devicetree/bindings/gpio/phytium,gpio.yaml b/Documentation/devicetree/bindings/gpio/phytium,gpio.yaml
> new file mode 100644
> index 000000000..1b9200c57
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/gpio/phytium,gpio.yaml
> @@ -0,0 +1,134 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/gpio/phytium,gpio.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Phytium GPIO controller
> +
> +description: |

Do not need '|' unless you need to preserve formatting.

> +  Phytium GPIO controllers expose one GPIO/interrupt controller and up to
> +  two configurable ports. Child nodes describe per-port configuration.
> +
> +maintainers:
> +  - Chen Baozi <chenbaozi@phytium.com.cn>
> +
> +properties:
> +  $nodename:
> +    pattern: "^gpio@[0-9a-f]+$"

Drop

> +
> +  compatible:
> +    const: phytium,gpio

This is way too generic. Phytium made or will ever make only one controller?

> +
> +  reg:
> +    maxItems: 1
> +
> +  gpio-controller: true
> +
> +  "#address-cells":
> +    const: 1
> +
> +  "#size-cells":
> +    const: 0
> +
> +  '#gpio-cells':
> +    const: 2

Why do you need cells here and in the children?

> +
> +  interrupts:
> +    description: |
> +      The interrupts to the parent controller raised when GPIOs generate
> +      the interrupts. If the controller provides one combined interrupt
> +      for all GPIOs, specify a single interrupt. If the controller provides
> +      one interrupt for each GPIO, provide a list of interrupts that
> +      correspond to each of the GPIO pins.
> +    minItems: 1
> +    maxItems: 32

Why is this flexible? You have one fixed device, no?

> +
> +  interrupt-controller: true
> +
> +  '#interrupt-cells':
> +    const: 2
> +
> +patternProperties:
> +  "^gpio-port@[0-9a-f]+$":
> +    type: object
> +    properties:
> +      compatible:
> +        const: phytium,gpio-port

Drop compatible

> +
> +      reg:
> +        maxItems: 1
> +
> +      gpio-controller: true

So what is the controller exactly?

> +
> +      '#gpio-cells':
> +        const: 2
> +
> +      ngpios:
> +        $ref: /schemas/types.yaml#/definitions/uint32
> +        description: The number of GPIO pins exported by the port.
> +        default: 32
> +        minimum: 1
> +        maximum: 32
> +
> +      nr-gpios:

Drop, why do you create duplicated properties for everything?

> +        $ref: /schemas/types.yaml#/definitions/uint32
> +        description: The number of GPIO pins exported by the port.
> +        deprecated: true
> +        default: 32
> +        minimum: 1
> +        maximum: 32
> +
> +    required:
> +      - compatible
> +      - reg
> +      - gpio-controller
> +      - '#gpio-cells'
> +
> +    additionalProperties: false
> +
> +additionalProperties: false

This goes after required: block

> +
> +required:
> +  - compatible
> +  - reg
> +  - gpio-controller
> +  - "#gpio-cells"
> +  - interrupts
> +  - interrupt-controller
> +  - "#interrupt-cells"
> +  - "#address-cells"
> +  - "#size-cells"
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +    gpio: gpio@28004000 {

Drop unused label

> +      compatible = "phytium,gpio";
> +      reg = <0x28004000 0x1000>;
> +      gpio-controller;
> +      #gpio-cells = <2>;
> +      #address-cells = <1>;
> +      #size-cells = <0>;
> +      interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
> +      interrupt-controller;
> +      #interrupt-cells = <2>;
> +
> +      porta: gpio-port@0 {
> +        compatible = "phytium,gpio-port";
> +        reg = <0>;
> +        gpio-controller;
> +        #gpio-cells = <2>;
> +        ngpios = <8>;
> +      };
> +
> +      portb: gpio-port@1 {
> +        compatible = "phytium,gpio-port";
> +        reg = <1>;
> +        gpio-controller;
> +        #gpio-cells = <2>;
> +        ngpios = <8>;
> +      };
> +    };
> +...
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> index ee7fd3cfe..2c3f9777d 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> @@ -1265,6 +1265,8 @@ patternProperties:
>      description: PHICOMM Co., Ltd.
>    "^phontech,.*":
>      description: Phontech
> +  "^phytium,.*":

Keep proper sorting.

> +    description: Phytium Technology Co., Ltd.
>    "^phytec,.*":
>      description: PHYTEC Messtechnik GmbH
>    "^picochip,.*":
> -- 
> 2.34.1
> 

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

* Re: [PATCH v1 1/3] dt-bindings: gpio: add Phytium GPIO controller
  2026-03-02  9:51 ` [PATCH v1 1/3] dt-bindings: gpio: add Phytium GPIO controller Zhu Ling
  2026-03-03  6:49   ` Krzysztof Kozlowski
@ 2026-03-03  8:28   ` Krzysztof Kozlowski
  1 sibling, 0 replies; 8+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-03  8:28 UTC (permalink / raw)
  To: Zhu Ling, linux-gpio, devicetree
  Cc: linux-kernel, linus.walleij, brgl, andy, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, chenbaozi

On 02/03/2026 10:51, Zhu Ling wrote:
> Add the devicetree binding schema for the Phytium platform GPIO
> controller.
> 
> Register the "phytium" vendor prefix used by the compatible string.
> 
> Use ngpios as the preferred child-node property and keep nr-gpios as
> deprecated for compatibility with existing firmware descriptions.
> 

You Cc-ed inactive address, not existing in the kernel for like 2 years,
so clearly this was based on some old kernel.

No, you must work on mainline, not two years old stuff.

Please use scripts/get_maintainers.pl to get a list of necessary people
and lists to CC (and consider --no-git-fallback argument, so you will
not CC people just because they made one commit years ago). It might
happen, that command when run on an older kernel, gives you outdated
entries. Therefore please be sure you base your patches on recent Linux
kernel.

Tools like b4 or scripts/get_maintainer.pl provide you proper list of
people, so fix your workflow. Tools might also fail if you work on some
ancient tree (don't, instead use mainline) or work on fork of kernel
(don't, instead use mainline). Just use b4 and everything should be
fine, although remember about `b4 prep --auto-to-cc` if you added new
patches to the patchset.

Best regards,
Krzysztof

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

* Re: [PATCH v1 2/3] gpio: add support for Phytium platform GPIO controller
  2026-03-02  9:51 ` [PATCH v1 2/3] gpio: add support for Phytium platform " Zhu Ling
  2026-03-02 10:14   ` Andy Shevchenko
@ 2026-03-23 14:34   ` Linus Walleij
  1 sibling, 0 replies; 8+ messages in thread
From: Linus Walleij @ 2026-03-23 14:34 UTC (permalink / raw)
  To: Zhu Ling
  Cc: linux-gpio, devicetree, linux-kernel, linus.walleij, brgl, andy,
	robh+dt, krzysztof.kozlowski+dt, conor+dt, chenbaozi

Hi Zhu,

thanks for your patch!

some quick remarks below:

On Mon, Mar 2, 2026 at 10:52 AM Zhu Ling <1536943441@qq.com> wrote:

> Add support for the Phytium platform GPIO controller with:
> - shared core helpers and irqchip implementation
> - platform probe path for OF/ACPI
> - Kconfig/Makefile integration
>
> The driver supports GPIO direction and value configuration, plus
> interrupt delivery for platform devices.
>
> Signed-off-by: Zhu Ling <1536943441@qq.com>

>  drivers/gpio/gpio-phytium-core.c     | 444 +++++++++++++++++++++++++++
>  drivers/gpio/gpio-phytium-core.h     |  90 ++++++
>  drivers/gpio/gpio-phytium-platform.c | 226 ++++++++++++++

Why this split? Put it all into one file.

Rewrite the driver to use the GPIO_GENERIC (MMIO) library,
select GPIO_GENERIC, look at other generic MMIO drivers
such as gpio-ftgpio010.c for inspiration.

Yours,
Linus Walleij

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

end of thread, other threads:[~2026-03-23 14:34 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20260302095147.2483-1-1536943441@qq.com>
2026-03-02  9:51 ` [PATCH v1 1/3] dt-bindings: gpio: add Phytium GPIO controller Zhu Ling
2026-03-03  6:49   ` Krzysztof Kozlowski
2026-03-03  8:28   ` Krzysztof Kozlowski
2026-03-02  9:51 ` [PATCH v1 2/3] gpio: add support for Phytium platform " Zhu Ling
2026-03-02 10:14   ` Andy Shevchenko
2026-03-23 14:34   ` Linus Walleij
2026-03-02  9:51 ` [PATCH v1 3/3] MAINTAINERS: add entry for Phytium platform GPIO driver Zhu Ling
2026-03-02 10:03   ` Andy Shevchenko

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