linux-gpio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/4] riscv: spacemit: add gpio support for K1 SoC
@ 2025-01-21  3:38 Yixun Lan
  2025-01-21  3:38 ` [PATCH v4 1/4] dt-bindings: gpio: spacemit: add " Yixun Lan
                   ` (3 more replies)
  0 siblings, 4 replies; 27+ messages in thread
From: Yixun Lan @ 2025-01-21  3:38 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt
  Cc: Yangyu Chen, Jisheng Zhang, Jesse Taube, Inochi Amaoto,
	Icenowy Zheng, Meng Zhang, linux-gpio, devicetree, linux-kernel,
	linux-riscv, Yixun Lan

The gpio controller of K1 support basic GPIO functions,
which capable of enabling as input, output. It can also be used
as GPIO interrupt which able to detect rising edge, falling edge,
or both. There are four GPIO ports, each consisting of 32 pins and
has indepedent register sets, while still sharing IRQ line and clocks.

The GPIO controller request the clock source from APBC block,
In this series, I haven't added the clock support, but plan
to fix it after clock driver is merged.

Due to first three GPIO ports has interleave register settings, some
resources (IRQ, clock) are shared by all pins, so all GPIO ports have
been organized as sub nodes in the device tree.

The GPIO docs of K1 SoC can be found here, chapter 16.4 GPIO [1]

Note, this patch is based on 'for-next' branch of SpacemiT's SoC tree [4],
due to there is DT dependency.

This patch series has been tested on Bananapi-F3 board,
with following GPIO cases passed:
 1) gpio input
 2) gpio output - set to high, low
 3) gpio interrupt - rising trigger, falling trigger, both edge trigger

Link: https://developer.spacemit.com/documentation?token=Rn9Kw3iFHirAMgkIpTAcV2Arnkf [1]
Link: https://lore.kernel.org/all/20240730-k1-01-basic-dt-v5-0-98263aae83be@gentoo.org [2]
Link: https://lore.kernel.org/all/20241016-02-k1-pinctrl-v5-0-03d395222e4f@gentoo.org/ [3]
Link: https://github.com/spacemit-com/linux [4]
Signed-off-by: Yixun Lan <dlan@gentoo.org>
---
Changes in v4:
- gpio: re-construct gpio as four independent ports, also leverage gpio mmio API
- gpio interrupt: convert to generic gpio irqchip
- Link to v3: https://lore.kernel.org/r/20241225-03-k1-gpio-v3-0-27bb7b441d62@gentoo.org

Changes in v3:
- dt: drop ranges, interrupt-names property
- Link to v2: https://lore.kernel.org/r/20241219-03-k1-gpio-v2-0-28444fd221cd@gentoo.org

Changes in v2:
- address dt-bindings comments, simplify example
- rebase to 6.13-rc3 
- Link to v1: https://lore.kernel.org/r/20240904-03-k1-gpio-v1-0-6072ebeecae0@gentoo.org

---
Yixun Lan (4):
      dt-bindings: gpio: spacemit: add support for K1 SoC
      gpio: spacemit: add support for K1 SoC
      riscv: dts: spacemit: add gpio support for K1 SoC
      riscv: dts: spacemit: add gpio LED for system heartbeat

 .../devicetree/bindings/gpio/spacemit,k1-gpio.yaml | 116 ++++++++
 arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts    |  11 +
 arch/riscv/boot/dts/spacemit/k1.dtsi               |  55 ++++
 drivers/gpio/Kconfig                               |   7 +
 drivers/gpio/Makefile                              |   1 +
 drivers/gpio/gpio-spacemit-k1.c                    | 295 +++++++++++++++++++++
 6 files changed, 485 insertions(+)
---
base-commit: 3d72d603afa72082501e9076eed61e0531339ef8
change-id: 20240828-03-k1-gpio-61bf92f9032c

Best regards,
-- 
Yixun Lan


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

* [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-01-21  3:38 [PATCH v4 0/4] riscv: spacemit: add gpio support for K1 SoC Yixun Lan
@ 2025-01-21  3:38 ` Yixun Lan
  2025-01-22 20:03   ` Olof Johansson
  2025-01-21  3:38 ` [PATCH v4 2/4] " Yixun Lan
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 27+ messages in thread
From: Yixun Lan @ 2025-01-21  3:38 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt
  Cc: Yangyu Chen, Jisheng Zhang, Jesse Taube, Inochi Amaoto,
	Icenowy Zheng, Meng Zhang, linux-gpio, devicetree, linux-kernel,
	linux-riscv, Yixun Lan

The GPIO controller of K1 support basic functions as input/output,
all pins can be used as interrupt which route to one IRQ line,
trigger type can be select between rising edge, failing edge, or both.
There are four GPIO ports, each consisting of 32 pins.

Signed-off-by: Yixun Lan <dlan@gentoo.org>
---
 .../devicetree/bindings/gpio/spacemit,k1-gpio.yaml | 116 +++++++++++++++++++++
 1 file changed, 116 insertions(+)

diff --git a/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml b/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..dd9459061aecfcba84e6a3c5052fbcddf6c61150
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/spacemit,k1-gpio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SpacemiT K1 GPIO controller
+
+maintainers:
+  - Yixun Lan <dlan@gentoo.org>
+
+description:
+  The controller's registers are organized as sets of eight 32-bit
+  registers with each set of port controlling 32 pins.  A single
+  interrupt line is shared for all of the pins by the controller.
+  Each port will be represented as child nodes with the generic
+  GPIO-controller properties in this bindings file.
+
+properties:
+  $nodename:
+    pattern: "^gpio@[0-9a-f]+$"
+
+  compatible:
+    const: spacemit,k1-gpio
+
+  reg:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+patternProperties:
+  "^gpio-port@[0-9a-f]+$":
+    type: object
+    properties:
+      compatible:
+        const: spacemit,k1-gpio-port
+
+      reg:
+        maxItems: 1
+
+      gpio-controller: true
+
+      "#gpio-cells":
+        const: 2
+
+      gpio-ranges: true
+
+      interrupts:
+        maxItems: 1
+
+      interrupt-controller: true
+
+      "#interrupt-cells":
+        const: 2
+        description:
+          The first cell is the GPIO number, the second should specify interrupt
+          flag. The controller does not support level interrupts, so flags of
+          IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_LOW should not be used.
+          Refer <dt-bindings/interrupt-controller/irq.h> for valid flags.
+
+    required:
+      - compatible
+      - reg
+      - gpio-controller
+      - "#gpio-cells"
+
+    dependencies:
+      interrupt-controller: [ interrupts ]
+
+    additionalProperties: false
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+
+examples:
+  - |
+    gpio: gpio@d4019000 {
+      compatible = "spacemit,k1-gpio";
+      reg = <0xd4019000 0x800>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      port0: gpio-port@0 {
+        compatible = "spacemit,k1-gpio-port";
+        reg = <0>;
+        gpio-controller;
+        #gpio-cells = <2>;
+        interrupt-parent = <&plic>;
+        interrupts = <58>;
+        interrupt-controller;
+        #interrupt-cells = <2>;
+        gpio-ranges = <&pinctrl 0 0 32>;
+      };
+
+      port1: gpio-port@4 {
+        compatible = "spacemit,k1-gpio-port";
+        reg = <4>;
+        gpio-controller;
+        #gpio-cells = <2>;
+        interrupt-parent = <&plic>;
+        interrupts = <58>;
+        interrupt-controller;
+        #interrupt-cells = <2>;
+        gpio-ranges = <&pinctrl 0 32 32>;
+      };
+    };
+...

-- 
2.48.0


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

* [PATCH v4 2/4] gpio: spacemit: add support for K1 SoC
  2025-01-21  3:38 [PATCH v4 0/4] riscv: spacemit: add gpio support for K1 SoC Yixun Lan
  2025-01-21  3:38 ` [PATCH v4 1/4] dt-bindings: gpio: spacemit: add " Yixun Lan
@ 2025-01-21  3:38 ` Yixun Lan
  2025-02-07 10:56   ` Yixun Lan
  2025-02-15 21:11   ` Alex Elder
  2025-01-21  3:38 ` [PATCH v4 3/4] riscv: dts: spacemit: add gpio " Yixun Lan
  2025-01-21  3:38 ` [PATCH v4 4/4] riscv: dts: spacemit: add gpio LED for system heartbeat Yixun Lan
  3 siblings, 2 replies; 27+ messages in thread
From: Yixun Lan @ 2025-01-21  3:38 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt
  Cc: Yangyu Chen, Jisheng Zhang, Jesse Taube, Inochi Amaoto,
	Icenowy Zheng, Meng Zhang, linux-gpio, devicetree, linux-kernel,
	linux-riscv, Yixun Lan

Implement GPIO functionality which capable of setting pin as
input, output. Also, each pin can be used as interrupt which
support rising, failing, or both edge type trigger.

Signed-off-by: Yixun Lan <dlan@gentoo.org>
---
 drivers/gpio/Kconfig            |   7 +
 drivers/gpio/Makefile           |   1 +
 drivers/gpio/gpio-spacemit-k1.c | 295 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 303 insertions(+)

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 56fee58e281e7cac7f287eb04e4c17a17f75ed04..c153f5439649da020ee42c38e88cb8df31a8e307 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -654,6 +654,13 @@ config GPIO_SNPS_CREG
 	  where only several fields in register belong to GPIO lines and
 	  each GPIO line owns a field with different length and on/off value.
 
+config GPIO_SPACEMIT_K1
+	bool "SPACEMIT K1 GPIO support"
+	depends on ARCH_SPACEMIT || COMPILE_TEST
+	select GPIOLIB_IRQCHIP
+	help
+	  Say yes here to support the SpacemiT's K1 GPIO device.
+
 config GPIO_SPEAR_SPICS
 	bool "ST SPEAr13xx SPI Chip Select as GPIO support"
 	depends on PLAT_SPEAR
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index af3ba4d81b583842893ea69e677fbe2abf31bc7b..6709ce511a0cf10310a94521c85a2d382dcfa696 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -156,6 +156,7 @@ obj-$(CONFIG_GPIO_SIOX)			+= gpio-siox.o
 obj-$(CONFIG_GPIO_SL28CPLD)		+= gpio-sl28cpld.o
 obj-$(CONFIG_GPIO_SLOPPY_LOGIC_ANALYZER) += gpio-sloppy-logic-analyzer.o
 obj-$(CONFIG_GPIO_SODAVILLE)		+= gpio-sodaville.o
+obj-$(CONFIG_GPIO_SPACEMIT_K1)		+= gpio-spacemit-k1.o
 obj-$(CONFIG_GPIO_SPEAR_SPICS)		+= gpio-spear-spics.o
 obj-$(CONFIG_GPIO_SPRD)			+= gpio-sprd.o
 obj-$(CONFIG_GPIO_STMPE)		+= gpio-stmpe.o
diff --git a/drivers/gpio/gpio-spacemit-k1.c b/drivers/gpio/gpio-spacemit-k1.c
new file mode 100644
index 0000000000000000000000000000000000000000..de0491af494c10f528095efee9b3a140bdcc0b0d
--- /dev/null
+++ b/drivers/gpio/gpio-spacemit-k1.c
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/*
+ * Copyright (C) 2023-2025 SpacemiT (Hangzhou) Technology Co. Ltd
+ * Copyright (c) 2025 Yixun Lan <dlan@gentoo.org>
+ */
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/gpio/driver.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+
+/* register offset */
+#define GPLR		0x00
+#define GPDR		0x0c
+#define GPSR		0x18
+#define GPCR		0x24
+#define GRER		0x30
+#define GFER		0x3c
+#define GEDR		0x48
+#define GSDR		0x54
+#define GCDR		0x60
+#define GSRER		0x6c
+#define GCRER		0x78
+#define GSFER		0x84
+#define GCFER		0x90
+#define GAPMASK		0x9c
+#define GCPMASK		0xa8
+
+#define K1_BANK_GPIO_NUMBER	(32)
+
+#define to_spacemit_gpio_port(x) container_of((x), struct spacemit_gpio_port, gc)
+
+struct spacemit_gpio;
+
+struct spacemit_gpio_port {
+	struct gpio_chip		gc;
+	struct spacemit_gpio		*gpio;
+	struct fwnode_handle		*fwnode;
+	void __iomem			*base;
+	int				irq;
+	u32				irq_mask;
+	u32				irq_rising_edge;
+	u32				irq_falling_edge;
+	u32				index;
+};
+
+struct spacemit_gpio {
+	struct	device			*dev;
+	struct spacemit_gpio_port	*ports;
+	u32				nr_ports;
+};
+
+static inline void spacemit_clear_edge_detection(struct spacemit_gpio_port *port, u32 bit)
+{
+	writel(bit, port->base + GCRER);
+	writel(bit, port->base + GCFER);
+}
+
+static inline void spacemit_set_edge_detection(struct spacemit_gpio_port *port, u32 bit)
+{
+	writel(bit & port->irq_rising_edge,  port->base + GSRER);
+	writel(bit & port->irq_falling_edge, port->base + GSFER);
+}
+
+static inline void spacemit_reset_edge_detection(struct spacemit_gpio_port *port)
+{
+	writel(0xffffffff, port->base + GCFER);
+	writel(0xffffffff, port->base + GCRER);
+	writel(0xffffffff, port->base + GAPMASK);
+}
+
+static int spacemit_gpio_irq_type(struct irq_data *d, unsigned int type)
+{
+	struct spacemit_gpio_port *port = irq_data_get_irq_chip_data(d);
+	u32 bit = BIT(irqd_to_hwirq(d));
+
+	if (type & IRQ_TYPE_EDGE_RISING) {
+		port->irq_rising_edge |= bit;
+		writel(bit, port->base + GSRER);
+	} else {
+		port->irq_rising_edge &= ~bit;
+		writel(bit, port->base + GCRER);
+	}
+
+	if (type & IRQ_TYPE_EDGE_FALLING) {
+		port->irq_falling_edge |= bit;
+		writel(bit, port->base + GSFER);
+	} else {
+		port->irq_falling_edge &= ~bit;
+		writel(bit, port->base + GCFER);
+	}
+
+	return 0;
+}
+
+static irqreturn_t spacemit_gpio_irq_handler(int irq, void *dev_id)
+{
+	struct spacemit_gpio_port *port = dev_id;
+	unsigned long pending;
+	u32 n, gedr;
+
+	gedr = readl(port->base + GEDR);
+	if (!gedr)
+		return IRQ_NONE;
+
+	writel(gedr, port->base + GEDR);
+	gedr = gedr & port->irq_mask;
+
+	if (!gedr)
+		return IRQ_NONE;
+
+	pending = gedr;
+
+	for_each_set_bit(n, &pending, BITS_PER_LONG)
+		handle_nested_irq(irq_find_mapping(port->gc.irq.domain, n));
+
+	return IRQ_HANDLED;
+}
+
+static void spacemit_ack_muxed_gpio(struct irq_data *d)
+{
+	struct spacemit_gpio_port *port = irq_data_get_irq_chip_data(d);
+
+	writel(BIT(irqd_to_hwirq(d)), port->base + GEDR);
+}
+
+static void spacemit_mask_muxed_gpio(struct irq_data *d)
+{
+	struct spacemit_gpio_port *port = irq_data_get_irq_chip_data(d);
+	u32 bit = BIT(irqd_to_hwirq(d));
+
+	port->irq_mask &= ~bit;
+
+	spacemit_clear_edge_detection(port, bit);
+}
+
+static void spacemit_unmask_muxed_gpio(struct irq_data *d)
+{
+	struct spacemit_gpio_port *port = irq_data_get_irq_chip_data(d);
+	u32 bit = BIT(irqd_to_hwirq(d));
+
+	port->irq_mask |= bit;
+
+	spacemit_set_edge_detection(port, bit);
+}
+
+static void spacemit_irq_print_chip(struct irq_data *data, struct seq_file *p)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+	struct spacemit_gpio_port *port = to_spacemit_gpio_port(gc);
+
+	seq_printf(p, "%s-%d", dev_name(gc->parent), port->index);
+}
+
+static struct irq_chip spacemit_muxed_gpio_chip = {
+	.name		= "k1-gpio-irqchip",
+	.irq_ack	= spacemit_ack_muxed_gpio,
+	.irq_mask	= spacemit_mask_muxed_gpio,
+	.irq_unmask	= spacemit_unmask_muxed_gpio,
+	.irq_set_type	= spacemit_gpio_irq_type,
+	.irq_print_chip	= spacemit_irq_print_chip,
+	.flags		= IRQCHIP_IMMUTABLE,
+	GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
+static int spacemit_gpio_get_ports(struct device *dev, struct spacemit_gpio *gpio,
+				   void __iomem *regs)
+{
+	struct spacemit_gpio_port *port;
+	u32 i = 0, offset;
+
+	gpio->nr_ports = device_get_child_node_count(dev);
+	if (gpio->nr_ports == 0)
+		return -ENODEV;
+
+	gpio->ports = devm_kcalloc(dev, gpio->nr_ports, sizeof(*gpio->ports), GFP_KERNEL);
+	if (!gpio->ports)
+		return -ENOMEM;
+
+	device_for_each_child_node_scoped(dev, fwnode)  {
+		port		= &gpio->ports[i];
+		port->fwnode	= fwnode;
+		port->index	= i++;
+
+		if (fwnode_property_read_u32(fwnode, "reg", &offset))
+			return -EINVAL;
+
+		port->base	= regs + offset;
+		port->irq	= fwnode_irq_get(fwnode, 0);
+	}
+
+	return 0;
+}
+
+static int spacemit_gpio_add_port(struct spacemit_gpio *gpio, int index)
+{
+	struct spacemit_gpio_port *port;
+	struct device *dev = gpio->dev;
+	struct gpio_irq_chip *girq;
+	void __iomem *dat, *set, *clr, *dirin, *dirout;
+	int ret;
+
+	port = &gpio->ports[index];
+	port->gpio = gpio;
+
+	dat	= port->base + GPLR;
+	set	= port->base + GPSR;
+	clr	= port->base + GPCR;
+	dirin	= port->base + GCDR;
+	dirout	= port->base + GSDR;
+
+	/* This registers 32 GPIO lines per port */
+	ret = bgpio_init(&port->gc, dev, 4, dat, set, clr, dirout, dirin,
+			 BGPIOF_UNREADABLE_REG_SET | BGPIOF_UNREADABLE_REG_DIR);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to init gpio chip for port\n");
+
+	port->gc.label		= dev_name(dev);
+	port->gc.fwnode		= port->fwnode;
+	port->gc.request	= gpiochip_generic_request;
+	port->gc.free		= gpiochip_generic_free;
+	port->gc.ngpio		= K1_BANK_GPIO_NUMBER;
+	port->gc.base		= -1;
+
+	girq			= &port->gc.irq;
+	girq->threaded		= true;
+	girq->handler		= handle_simple_irq;
+
+	gpio_irq_chip_set_chip(girq, &spacemit_muxed_gpio_chip);
+
+	spacemit_reset_edge_detection(port);
+
+	ret = devm_request_threaded_irq(dev, port->irq, NULL,
+					spacemit_gpio_irq_handler,
+					IRQF_ONESHOT | IRQF_SHARED,
+					port->gc.label, port);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "failed to request IRQ\n");
+
+	return devm_gpiochip_add_data(dev, &port->gc, port);
+}
+
+static int spacemit_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct spacemit_gpio *gpio;
+	struct resource *res;
+	void __iomem *regs;
+	int i, ret;
+
+	gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
+	if (!gpio)
+		return -ENOMEM;
+
+	gpio->dev = dev;
+
+	regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	ret = spacemit_gpio_get_ports(dev, gpio, regs);
+	if (ret)
+		return dev_err_probe(dev, ret, "fail to get gpio ports\n");
+
+	for (i = 0; i < gpio->nr_ports; i++) {
+		ret = spacemit_gpio_add_port(gpio, i);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id spacemit_gpio_dt_ids[] = {
+	{ .compatible = "spacemit,k1-gpio" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver spacemit_gpio_driver = {
+	.probe		= spacemit_gpio_probe,
+	.driver		= {
+		.name	= "k1-gpio",
+		.of_match_table = spacemit_gpio_dt_ids,
+	},
+};
+module_platform_driver(spacemit_gpio_driver);
+
+MODULE_AUTHOR("Yixun Lan <dlan@gentoo.org>");
+MODULE_DESCRIPTION("GPIO driver for SpacemiT K1 SoC");
+MODULE_LICENSE("GPL");

-- 
2.48.0


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

* [PATCH v4 3/4] riscv: dts: spacemit: add gpio support for K1 SoC
  2025-01-21  3:38 [PATCH v4 0/4] riscv: spacemit: add gpio support for K1 SoC Yixun Lan
  2025-01-21  3:38 ` [PATCH v4 1/4] dt-bindings: gpio: spacemit: add " Yixun Lan
  2025-01-21  3:38 ` [PATCH v4 2/4] " Yixun Lan
@ 2025-01-21  3:38 ` Yixun Lan
  2025-01-21  3:38 ` [PATCH v4 4/4] riscv: dts: spacemit: add gpio LED for system heartbeat Yixun Lan
  3 siblings, 0 replies; 27+ messages in thread
From: Yixun Lan @ 2025-01-21  3:38 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt
  Cc: Yangyu Chen, Jisheng Zhang, Jesse Taube, Inochi Amaoto,
	Icenowy Zheng, Meng Zhang, linux-gpio, devicetree, linux-kernel,
	linux-riscv, Yixun Lan

Populate the GPIO node in the device tree for SpacemiT K1 SoC.
Each of 32 pins will act as one port and map to the pinctrl controller.

Signed-off-by: Yixun Lan <dlan@gentoo.org>
---
 arch/riscv/boot/dts/spacemit/k1.dtsi | 55 ++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/arch/riscv/boot/dts/spacemit/k1.dtsi b/arch/riscv/boot/dts/spacemit/k1.dtsi
index c670ebf8fa12917aa6493fcd89fdd1409529538b..005f24b95d9ddae686dda07932d0086379cff219 100644
--- a/arch/riscv/boot/dts/spacemit/k1.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k1.dtsi
@@ -404,6 +404,61 @@ uart9: serial@d4017800 {
 			status = "disabled";
 		};
 
+		gpio: gpio@d4019000 {
+			compatible = "spacemit,k1-gpio";
+			reg = <0x0 0xd4019000 0x0 0x800>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port0: gpio-port@0 {
+				compatible = "spacemit,k1-gpio-port";
+				reg = <0x0>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupts = <58>;
+				interrupt-parent = <&plic>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				gpio-ranges = <&pinctrl 0 0 32>;
+			};
+
+			port1: gpio-port@4 {
+				compatible = "spacemit,k1-gpio-port";
+				reg = <0x4>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupts = <58>;
+				interrupt-parent = <&plic>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				gpio-ranges = <&pinctrl 0 32 32>;
+			};
+
+			port2: gpio-port@8 {
+				compatible = "spacemit,k1-gpio-port";
+				reg = <0x8>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupts = <58>;
+				interrupt-parent = <&plic>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				gpio-ranges = <&pinctrl 0 64 32>;
+			};
+
+			port3: gpio-port@100 {
+				compatible = "spacemit,k1-gpio-port";
+				reg = <0x100>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupts = <58>;
+				interrupt-parent = <&plic>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				gpio-ranges = <&pinctrl 0 96 32>;
+			};
+		};
+
 		pinctrl: pinctrl@d401e000 {
 			compatible = "spacemit,k1-pinctrl";
 			reg = <0x0 0xd401e000 0x0 0x400>;

-- 
2.48.0


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

* [PATCH v4 4/4] riscv: dts: spacemit: add gpio LED for system heartbeat
  2025-01-21  3:38 [PATCH v4 0/4] riscv: spacemit: add gpio support for K1 SoC Yixun Lan
                   ` (2 preceding siblings ...)
  2025-01-21  3:38 ` [PATCH v4 3/4] riscv: dts: spacemit: add gpio " Yixun Lan
@ 2025-01-21  3:38 ` Yixun Lan
  3 siblings, 0 replies; 27+ messages in thread
From: Yixun Lan @ 2025-01-21  3:38 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt
  Cc: Yangyu Chen, Jisheng Zhang, Jesse Taube, Inochi Amaoto,
	Icenowy Zheng, Meng Zhang, linux-gpio, devicetree, linux-kernel,
	linux-riscv, Yixun Lan

Leverage GPIO to support system LED to indicate activity of CPUs.

Signed-off-by: Yixun Lan <dlan@gentoo.org>
---
 arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
index 1d617b40a2d51ee464b57234d248798aeb218643..6113e7523109076b99c493c8ac9ba69efd734620 100644
--- a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
+++ b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
@@ -17,6 +17,17 @@ aliases {
 	chosen {
 		stdout-path = "serial0";
 	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led1 {
+			label = "sys-led";
+			gpios = <&port3 0 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+			default-state = "on";
+		};
+	};
 };
 
 &uart0 {

-- 
2.48.0


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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-01-21  3:38 ` [PATCH v4 1/4] dt-bindings: gpio: spacemit: add " Yixun Lan
@ 2025-01-22 20:03   ` Olof Johansson
  2025-01-23 11:30     ` Yixun Lan
  0 siblings, 1 reply; 27+ messages in thread
From: Olof Johansson @ 2025-01-22 20:03 UTC (permalink / raw)
  To: Yixun Lan
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

Hi,

On Tue, Jan 21, 2025 at 11:38:11AM +0800, Yixun Lan wrote:
> The GPIO controller of K1 support basic functions as input/output,
> all pins can be used as interrupt which route to one IRQ line,
> trigger type can be select between rising edge, failing edge, or both.
> There are four GPIO ports, each consisting of 32 pins.
> 
> Signed-off-by: Yixun Lan <dlan@gentoo.org>
> ---
>  .../devicetree/bindings/gpio/spacemit,k1-gpio.yaml | 116 +++++++++++++++++++++
>  1 file changed, 116 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml b/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml
> new file mode 100644
> index 0000000000000000000000000000000000000000..dd9459061aecfcba84e6a3c5052fbcddf6c61150
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml
> @@ -0,0 +1,116 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/gpio/spacemit,k1-gpio.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: SpacemiT K1 GPIO controller
> +
> +maintainers:
> +  - Yixun Lan <dlan@gentoo.org>
> +
> +description:
> +  The controller's registers are organized as sets of eight 32-bit
> +  registers with each set of port controlling 32 pins.  A single
> +  interrupt line is shared for all of the pins by the controller.
> +  Each port will be represented as child nodes with the generic
> +  GPIO-controller properties in this bindings file.

There's only one interrupt line for all ports, but you have a binding that
duplicates them for every set of ports. That seems overly complicated,
doesn't it? They'd all bind the same handler, so there's no benefit in
providing the flexibility,.

> +properties:
> +  $nodename:
> +    pattern: "^gpio@[0-9a-f]+$"
> +
> +  compatible:
> +    const: spacemit,k1-gpio
> +
> +  reg:
> +    maxItems: 1
> +
> +  "#address-cells":
> +    const: 1
> +
> +  "#size-cells":
> +    const: 0
> +
> +patternProperties:
> +  "^gpio-port@[0-9a-f]+$":
> +    type: object
> +    properties:
> +      compatible:
> +        const: spacemit,k1-gpio-port
> +
> +      reg:
> +        maxItems: 1
> +
> +      gpio-controller: true
> +
> +      "#gpio-cells":
> +        const: 2
> +
> +      gpio-ranges: true
> +
> +      interrupts:
> +        maxItems: 1
> +
> +      interrupt-controller: true
> +
> +      "#interrupt-cells":
> +        const: 2
> +        description:
> +          The first cell is the GPIO number, the second should specify interrupt
> +          flag. The controller does not support level interrupts, so flags of
> +          IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_LOW should not be used.
> +          Refer <dt-bindings/interrupt-controller/irq.h> for valid flags.

Same here, since there's no real flexibility between the banks, it might
make sense to consider a 3-cell GPIO specifier instead, and having
the first cell indicate bank. I could see this argument go in either
direction, but I'm not sure I understand why to provide a gpio-controller
per bank.

Comparing to say Rockchip, where each bank has a separate interrupt line
-- so there the granularity makes sense.


-Olof

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-01-22 20:03   ` Olof Johansson
@ 2025-01-23 11:30     ` Yixun Lan
  2025-01-23 23:19       ` Olof Johansson
  0 siblings, 1 reply; 27+ messages in thread
From: Yixun Lan @ 2025-01-23 11:30 UTC (permalink / raw)
  To: Olof Johansson
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

Hi Olof:
 thanks for your reivew

On 12:03 Wed 22 Jan     , Olof Johansson wrote:
> Hi,
> 
> On Tue, Jan 21, 2025 at 11:38:11AM +0800, Yixun Lan wrote:
> > The GPIO controller of K1 support basic functions as input/output,
> > all pins can be used as interrupt which route to one IRQ line,
> > trigger type can be select between rising edge, failing edge, or both.
> > There are four GPIO ports, each consisting of 32 pins.
> > 
> > Signed-off-by: Yixun Lan <dlan@gentoo.org>
> > ---
> >  .../devicetree/bindings/gpio/spacemit,k1-gpio.yaml | 116 +++++++++++++++++++++
> >  1 file changed, 116 insertions(+)
> > 
> > diff --git a/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml b/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..dd9459061aecfcba84e6a3c5052fbcddf6c61150
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml
> > @@ -0,0 +1,116 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/gpio/spacemit,k1-gpio.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: SpacemiT K1 GPIO controller
> > +
> > +maintainers:
> > +  - Yixun Lan <dlan@gentoo.org>
> > +
> > +description:
> > +  The controller's registers are organized as sets of eight 32-bit
> > +  registers with each set of port controlling 32 pins.  A single
> > +  interrupt line is shared for all of the pins by the controller.
> > +  Each port will be represented as child nodes with the generic
> > +  GPIO-controller properties in this bindings file.
> 
> There's only one interrupt line for all ports, but you have a binding that
> duplicates them for every set of ports. That seems overly complicated,
> doesn't it? They'd all bind the same handler, so there's no benefit in
> providing the flexibility,.
> 
yes, all ports share same interrupt line, but each port has its own
irq related handling register, so it make sense to describe as per gpio irqchip

also see comments below

> > +properties:
> > +  $nodename:
> > +    pattern: "^gpio@[0-9a-f]+$"
> > +
> > +  compatible:
> > +    const: spacemit,k1-gpio
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  "#address-cells":
> > +    const: 1
> > +
> > +  "#size-cells":
> > +    const: 0
> > +
> > +patternProperties:
> > +  "^gpio-port@[0-9a-f]+$":
> > +    type: object
> > +    properties:
> > +      compatible:
> > +        const: spacemit,k1-gpio-port
> > +
> > +      reg:
> > +        maxItems: 1
> > +
> > +      gpio-controller: true
> > +
> > +      "#gpio-cells":
> > +        const: 2
> > +
> > +      gpio-ranges: true
> > +
> > +      interrupts:
> > +        maxItems: 1
> > +
> > +      interrupt-controller: true
> > +
> > +      "#interrupt-cells":
> > +        const: 2
> > +        description:
> > +          The first cell is the GPIO number, the second should specify interrupt
> > +          flag. The controller does not support level interrupts, so flags of
> > +          IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_LOW should not be used.
> > +          Refer <dt-bindings/interrupt-controller/irq.h> for valid flags.
> 
> Same here, since there's no real flexibility between the banks, it might
> make sense to consider a 3-cell GPIO specifier instead, and having
how to handle the fourth gpio port? I would like to have uniform driver for all ports

> the first cell indicate bank. I could see this argument go in either
> direction, but I'm not sure I understand why to provide a gpio-controller
> per bank.
> 

IIUC, your suggestion here was same as the implementation of patch v3 of this driver[1],
 while combining all four ports into one irqchip, which NACKed by maintainer[2].
 I tend to agree having a gpio-controller per bank provide more flexibility,
 easy to leverage generic gpio framework, even each port can be disabled or enabled,
 and IMO having shared irq handler isn't really a problem..

[1] https://lore.kernel.org/r/20241225-03-k1-gpio-v3-0-27bb7b441d62@gentoo.org
[2] https://lore.kernel.org/r/CACRpkdZPD2C2iPwOX_kW1Ug8jVkdHhhc7iFycHtzj5LQ0XWNgQ@mail.gmail.com
https://lore.kernel.org/r/CACRpkdYgGho=VQabonq4HccEiXBH2qM76K45oDaV1Jyi0xZ-YA@mail.gmail.com


> Comparing to say Rockchip, where each bank has a separate interrupt line
> -- so there the granularity makes sense.
> 
> 
> -Olof

-- 
Yixun Lan (dlan)
Gentoo Linux Developer
GPG Key ID AABEFD55

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-01-23 11:30     ` Yixun Lan
@ 2025-01-23 23:19       ` Olof Johansson
  2025-01-27 18:17         ` Rob Herring
  0 siblings, 1 reply; 27+ messages in thread
From: Olof Johansson @ 2025-01-23 23:19 UTC (permalink / raw)
  To: Yixun Lan
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

On Thu, Jan 23, 2025 at 11:30:42AM +0000, Yixun Lan wrote:
> Hi Olof:
>  thanks for your reivew
> 
> On 12:03 Wed 22 Jan     , Olof Johansson wrote:
> > Hi,
> > 
> > On Tue, Jan 21, 2025 at 11:38:11AM +0800, Yixun Lan wrote:
> > > The GPIO controller of K1 support basic functions as input/output,
> > > all pins can be used as interrupt which route to one IRQ line,
> > > trigger type can be select between rising edge, failing edge, or both.
> > > There are four GPIO ports, each consisting of 32 pins.
> > > 
> > > Signed-off-by: Yixun Lan <dlan@gentoo.org>
> > > ---
> > >  .../devicetree/bindings/gpio/spacemit,k1-gpio.yaml | 116 +++++++++++++++++++++
> > >  1 file changed, 116 insertions(+)
> > > 
> > > diff --git a/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml b/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml
> > > new file mode 100644
> > > index 0000000000000000000000000000000000000000..dd9459061aecfcba84e6a3c5052fbcddf6c61150
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml
> > > @@ -0,0 +1,116 @@
> > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/gpio/spacemit,k1-gpio.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: SpacemiT K1 GPIO controller
> > > +
> > > +maintainers:
> > > +  - Yixun Lan <dlan@gentoo.org>
> > > +
> > > +description:
> > > +  The controller's registers are organized as sets of eight 32-bit
> > > +  registers with each set of port controlling 32 pins.  A single
> > > +  interrupt line is shared for all of the pins by the controller.
> > > +  Each port will be represented as child nodes with the generic
> > > +  GPIO-controller properties in this bindings file.
> > 
> > There's only one interrupt line for all ports, but you have a binding that
> > duplicates them for every set of ports. That seems overly complicated,
> > doesn't it? They'd all bind the same handler, so there's no benefit in
> > providing the flexibility,.
> > 
> yes, all ports share same interrupt line, but each port has its own
> irq related handling register, so it make sense to describe as per gpio irqchip
> 
> also see comments below
> 
> > > +properties:
> > > +  $nodename:
> > > +    pattern: "^gpio@[0-9a-f]+$"
> > > +
> > > +  compatible:
> > > +    const: spacemit,k1-gpio
> > > +
> > > +  reg:
> > > +    maxItems: 1
> > > +
> > > +  "#address-cells":
> > > +    const: 1
> > > +
> > > +  "#size-cells":
> > > +    const: 0
> > > +
> > > +patternProperties:
> > > +  "^gpio-port@[0-9a-f]+$":
> > > +    type: object
> > > +    properties:
> > > +      compatible:
> > > +        const: spacemit,k1-gpio-port
> > > +
> > > +      reg:
> > > +        maxItems: 1
> > > +
> > > +      gpio-controller: true
> > > +
> > > +      "#gpio-cells":
> > > +        const: 2
> > > +
> > > +      gpio-ranges: true
> > > +
> > > +      interrupts:
> > > +        maxItems: 1
> > > +
> > > +      interrupt-controller: true
> > > +
> > > +      "#interrupt-cells":
> > > +        const: 2
> > > +        description:
> > > +          The first cell is the GPIO number, the second should specify interrupt
> > > +          flag. The controller does not support level interrupts, so flags of
> > > +          IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_LOW should not be used.
> > > +          Refer <dt-bindings/interrupt-controller/irq.h> for valid flags.
> > 
> > Same here, since there's no real flexibility between the banks, it might
> > make sense to consider a 3-cell GPIO specifier instead, and having
> how to handle the fourth gpio port? I would like to have uniform driver for all ports
> 
> > the first cell indicate bank. I could see this argument go in either
> > direction, but I'm not sure I understand why to provide a gpio-controller
> > per bank.
> > 
> 
> IIUC, your suggestion here was same as the implementation of patch v3 of this driver[1],
>  while combining all four ports into one irqchip, which NACKed by maintainer[2].
>  I tend to agree having a gpio-controller per bank provide more flexibility,
>  easy to leverage generic gpio framework, even each port can be disabled or enabled,
>  and IMO having shared irq handler isn't really a problem..
> 
> [1] https://lore.kernel.org/r/20241225-03-k1-gpio-v3-0-27bb7b441d62@gentoo.org
> [2] https://lore.kernel.org/r/CACRpkdZPD2C2iPwOX_kW1Ug8jVkdHhhc7iFycHtzj5LQ0XWNgQ@mail.gmail.com
> https://lore.kernel.org/r/CACRpkdYgGho=VQabonq4HccEiXBH2qM76K45oDaV1Jyi0xZ-YA@mail.gmail.com

Hmm, I don't understand the reasoning there, but it's not my subsystem.

It seems worse to me to misdescribe the hardware as separate blocks
with a device-tree binding that no longer describes the actual hardware,
but it's not up to me.

Let's get the platform support merged, ignore my feedback here -- we need more
SoCs supported upstream and this code is good enough to go in as-is.


-Olof

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-01-23 23:19       ` Olof Johansson
@ 2025-01-27 18:17         ` Rob Herring
  2025-01-28  3:17           ` Yixun Lan
  2025-01-28 15:47           ` Linus Walleij
  0 siblings, 2 replies; 27+ messages in thread
From: Rob Herring @ 2025-01-27 18:17 UTC (permalink / raw)
  To: Olof Johansson
  Cc: Yixun Lan, Linus Walleij, Bartosz Golaszewski,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

On Thu, Jan 23, 2025 at 03:19:18PM -0800, Olof Johansson wrote:
> On Thu, Jan 23, 2025 at 11:30:42AM +0000, Yixun Lan wrote:
> > Hi Olof:
> >  thanks for your reivew
> > 
> > On 12:03 Wed 22 Jan     , Olof Johansson wrote:
> > > Hi,
> > > 
> > > On Tue, Jan 21, 2025 at 11:38:11AM +0800, Yixun Lan wrote:
> > > > The GPIO controller of K1 support basic functions as input/output,
> > > > all pins can be used as interrupt which route to one IRQ line,
> > > > trigger type can be select between rising edge, failing edge, or both.
> > > > There are four GPIO ports, each consisting of 32 pins.
> > > > 
> > > > Signed-off-by: Yixun Lan <dlan@gentoo.org>
> > > > ---
> > > >  .../devicetree/bindings/gpio/spacemit,k1-gpio.yaml | 116 +++++++++++++++++++++
> > > >  1 file changed, 116 insertions(+)
> > > > 
> > > > diff --git a/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml b/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml
> > > > new file mode 100644
> > > > index 0000000000000000000000000000000000000000..dd9459061aecfcba84e6a3c5052fbcddf6c61150
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml
> > > > @@ -0,0 +1,116 @@
> > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > > +%YAML 1.2
> > > > +---
> > > > +$id: http://devicetree.org/schemas/gpio/spacemit,k1-gpio.yaml#
> > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > +
> > > > +title: SpacemiT K1 GPIO controller
> > > > +
> > > > +maintainers:
> > > > +  - Yixun Lan <dlan@gentoo.org>
> > > > +
> > > > +description:
> > > > +  The controller's registers are organized as sets of eight 32-bit
> > > > +  registers with each set of port controlling 32 pins.  A single
> > > > +  interrupt line is shared for all of the pins by the controller.
> > > > +  Each port will be represented as child nodes with the generic
> > > > +  GPIO-controller properties in this bindings file.
> > > 
> > > There's only one interrupt line for all ports, but you have a binding that
> > > duplicates them for every set of ports. That seems overly complicated,
> > > doesn't it? They'd all bind the same handler, so there's no benefit in
> > > providing the flexibility,.
> > > 
> > yes, all ports share same interrupt line, but each port has its own
> > irq related handling register, so it make sense to describe as per gpio irqchip
> > 
> > also see comments below
> > 
> > > > +properties:
> > > > +  $nodename:
> > > > +    pattern: "^gpio@[0-9a-f]+$"
> > > > +
> > > > +  compatible:
> > > > +    const: spacemit,k1-gpio
> > > > +
> > > > +  reg:
> > > > +    maxItems: 1
> > > > +
> > > > +  "#address-cells":
> > > > +    const: 1
> > > > +
> > > > +  "#size-cells":
> > > > +    const: 0
> > > > +
> > > > +patternProperties:
> > > > +  "^gpio-port@[0-9a-f]+$":
> > > > +    type: object
> > > > +    properties:
> > > > +      compatible:
> > > > +        const: spacemit,k1-gpio-port
> > > > +
> > > > +      reg:
> > > > +        maxItems: 1
> > > > +
> > > > +      gpio-controller: true
> > > > +
> > > > +      "#gpio-cells":
> > > > +        const: 2
> > > > +
> > > > +      gpio-ranges: true
> > > > +
> > > > +      interrupts:
> > > > +        maxItems: 1
> > > > +
> > > > +      interrupt-controller: true
> > > > +
> > > > +      "#interrupt-cells":
> > > > +        const: 2
> > > > +        description:
> > > > +          The first cell is the GPIO number, the second should specify interrupt
> > > > +          flag. The controller does not support level interrupts, so flags of
> > > > +          IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_LOW should not be used.
> > > > +          Refer <dt-bindings/interrupt-controller/irq.h> for valid flags.
> > > 
> > > Same here, since there's no real flexibility between the banks, it might
> > > make sense to consider a 3-cell GPIO specifier instead, and having
> > how to handle the fourth gpio port? I would like to have uniform driver for all ports
> > 
> > > the first cell indicate bank. I could see this argument go in either
> > > direction, but I'm not sure I understand why to provide a gpio-controller
> > > per bank.
> > > 
> > 
> > IIUC, your suggestion here was same as the implementation of patch v3 of this driver[1],
> >  while combining all four ports into one irqchip, which NACKed by maintainer[2].
> >  I tend to agree having a gpio-controller per bank provide more flexibility,
> >  easy to leverage generic gpio framework, even each port can be disabled or enabled,
> >  and IMO having shared irq handler isn't really a problem..
> > 
> > [1] https://lore.kernel.org/r/20241225-03-k1-gpio-v3-0-27bb7b441d62@gentoo.org
> > [2] https://lore.kernel.org/r/CACRpkdZPD2C2iPwOX_kW1Ug8jVkdHhhc7iFycHtzj5LQ0XWNgQ@mail.gmail.com
> > https://lore.kernel.org/r/CACRpkdYgGho=VQabonq4HccEiXBH2qM76K45oDaV1Jyi0xZ-YA@mail.gmail.com
> 
> Hmm, I don't understand the reasoning there, but it's not my subsystem.
> 
> It seems worse to me to misdescribe the hardware as separate blocks
> with a device-tree binding that no longer describes the actual hardware,
> but it's not up to me.

I agree. It's clearly 1 block given the first 3 banks are interleaved.

If Linux can't handle 1 node for N gpio_chip's, then that's a Linux 
problem. Maybe it can, IDK. The lookup from a DT node to gpio_chip just 
needs to match on more than just DT node pointer, but look at the node 
ptr and arg cells.

Rob

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-01-27 18:17         ` Rob Herring
@ 2025-01-28  3:17           ` Yixun Lan
  2025-01-28 16:03             ` Linus Walleij
  2025-01-28 15:47           ` Linus Walleij
  1 sibling, 1 reply; 27+ messages in thread
From: Yixun Lan @ 2025-01-28  3:17 UTC (permalink / raw)
  To: Rob Herring
  Cc: Olof Johansson, Linus Walleij, Bartosz Golaszewski,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

Hi Rob:

On 12:17 Mon 27 Jan     , Rob Herring wrote:
> On Thu, Jan 23, 2025 at 03:19:18PM -0800, Olof Johansson wrote:
> > On Thu, Jan 23, 2025 at 11:30:42AM +0000, Yixun Lan wrote:
> > > Hi Olof:
> > >  thanks for your reivew
> > > 
> > > On 12:03 Wed 22 Jan     , Olof Johansson wrote:
> > > > Hi,
> > > > 
> > > > On Tue, Jan 21, 2025 at 11:38:11AM +0800, Yixun Lan wrote:
> > > > > The GPIO controller of K1 support basic functions as input/output,
> > > > > all pins can be used as interrupt which route to one IRQ line,
> > > > > trigger type can be select between rising edge, failing edge, or both.
> > > > > There are four GPIO ports, each consisting of 32 pins.
> > > > > 
> > > > > Signed-off-by: Yixun Lan <dlan@gentoo.org>
> > > > > ---
> > > > >  .../devicetree/bindings/gpio/spacemit,k1-gpio.yaml | 116 +++++++++++++++++++++
> > > > >  1 file changed, 116 insertions(+)
> > > > > 
> > > > > diff --git a/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml b/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml
> > > > > new file mode 100644
> > > > > index 0000000000000000000000000000000000000000..dd9459061aecfcba84e6a3c5052fbcddf6c61150
> > > > > --- /dev/null
> > > > > +++ b/Documentation/devicetree/bindings/gpio/spacemit,k1-gpio.yaml
> > > > > @@ -0,0 +1,116 @@
> > > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > > > +%YAML 1.2
> > > > > +---
> > > > > +$id: http://devicetree.org/schemas/gpio/spacemit,k1-gpio.yaml#
> > > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > > +
> > > > > +title: SpacemiT K1 GPIO controller
> > > > > +
> > > > > +maintainers:
> > > > > +  - Yixun Lan <dlan@gentoo.org>
> > > > > +
> > > > > +description:
> > > > > +  The controller's registers are organized as sets of eight 32-bit
> > > > > +  registers with each set of port controlling 32 pins.  A single
> > > > > +  interrupt line is shared for all of the pins by the controller.
> > > > > +  Each port will be represented as child nodes with the generic
> > > > > +  GPIO-controller properties in this bindings file.
> > > > 
> > > > There's only one interrupt line for all ports, but you have a binding that
> > > > duplicates them for every set of ports. That seems overly complicated,
> > > > doesn't it? They'd all bind the same handler, so there's no benefit in
> > > > providing the flexibility,.
> > > > 
> > > yes, all ports share same interrupt line, but each port has its own
> > > irq related handling register, so it make sense to describe as per gpio irqchip
> > > 
> > > also see comments below
> > > 
> > > > > +properties:
> > > > > +  $nodename:
> > > > > +    pattern: "^gpio@[0-9a-f]+$"
> > > > > +
> > > > > +  compatible:
> > > > > +    const: spacemit,k1-gpio
> > > > > +
> > > > > +  reg:
> > > > > +    maxItems: 1
> > > > > +
> > > > > +  "#address-cells":
> > > > > +    const: 1
> > > > > +
> > > > > +  "#size-cells":
> > > > > +    const: 0
> > > > > +
> > > > > +patternProperties:
> > > > > +  "^gpio-port@[0-9a-f]+$":
> > > > > +    type: object
> > > > > +    properties:
> > > > > +      compatible:
> > > > > +        const: spacemit,k1-gpio-port
> > > > > +
> > > > > +      reg:
> > > > > +        maxItems: 1
> > > > > +
> > > > > +      gpio-controller: true
> > > > > +
> > > > > +      "#gpio-cells":
> > > > > +        const: 2
> > > > > +
> > > > > +      gpio-ranges: true
> > > > > +
> > > > > +      interrupts:
> > > > > +        maxItems: 1
> > > > > +
> > > > > +      interrupt-controller: true
> > > > > +
> > > > > +      "#interrupt-cells":
> > > > > +        const: 2
> > > > > +        description:
> > > > > +          The first cell is the GPIO number, the second should specify interrupt
> > > > > +          flag. The controller does not support level interrupts, so flags of
> > > > > +          IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_LEVEL_LOW should not be used.
> > > > > +          Refer <dt-bindings/interrupt-controller/irq.h> for valid flags.
> > > > 
> > > > Same here, since there's no real flexibility between the banks, it might
> > > > make sense to consider a 3-cell GPIO specifier instead, and having
> > > how to handle the fourth gpio port? I would like to have uniform driver for all ports
> > > 
> > > > the first cell indicate bank. I could see this argument go in either
> > > > direction, but I'm not sure I understand why to provide a gpio-controller
> > > > per bank.
> > > > 
> > > 
> > > IIUC, your suggestion here was same as the implementation of patch v3 of this driver[1],
> > >  while combining all four ports into one irqchip, which NACKed by maintainer[2].
> > >  I tend to agree having a gpio-controller per bank provide more flexibility,
> > >  easy to leverage generic gpio framework, even each port can be disabled or enabled,
> > >  and IMO having shared irq handler isn't really a problem..
> > > 
> > > [1] https://lore.kernel.org/r/20241225-03-k1-gpio-v3-0-27bb7b441d62@gentoo.org
> > > [2] https://lore.kernel.org/r/CACRpkdZPD2C2iPwOX_kW1Ug8jVkdHhhc7iFycHtzj5LQ0XWNgQ@mail.gmail.com
> > > https://lore.kernel.org/r/CACRpkdYgGho=VQabonq4HccEiXBH2qM76K45oDaV1Jyi0xZ-YA@mail.gmail.com
> > 
> > Hmm, I don't understand the reasoning there, but it's not my subsystem.
> > 
> > It seems worse to me to misdescribe the hardware as separate blocks
> > with a device-tree binding that no longer describes the actual hardware,
> > but it's not up to me.
> 
> I agree. It's clearly 1 block given the first 3 banks are interleaved.
> 
yes, it's kind of weird hardware design, the first 3 gpio are register interleaved,
while the 4th has independent space

> If Linux can't handle 1 node for N gpio_chip's, then that's a Linux 
> problem. Maybe it can, IDK. 
I haven't seen somthing like this to register 1 node for multi gpio_chips..
To gpio/pinctrl maintainer (Linus Walleij), do you have suggestion on this?

>The lookup from a DT node to gpio_chip just 
> needs to match on more than just DT node pointer, but look at the node 
> ptr and arg cells.
> 
IIUC, are you suggesting to add a index cells to match additional gpio bank?
so the underlying driver can still register 4 gpio chips?

               gpio: gpio@d4019000 {
                        compatible = "spacemit,k1-gpio";
                        reg = <0x0 0xd4019000 0x0 0x800>;
                        interrupt-controller;
			#interrupt-cells = <3>; // additional cell
                        gpio-controller;
                        #gpio-cells = <3>; // additional cell
			...
		};

on comsumer side, it will be something like this:
		gpios = <&gpio INDEX0 0 GPIO_ACTIVE_HIGH>;
		interrupts = <&gpio INDEX0 0 IRQ_TYPE_EDGE_RISING>;
(INDEX0 possiblely can be numeric vale (0, 1, 2, 3) or register base: 0x0 0x4 0x8 0x100)

one thing I'm not sure about how to map the pinctrl pins via "gpio-ranges" to each gpio_chip,
currently, in v4 verion, this info is populated via sub node of gpios (port1, port2 ...)

I will investigate more on this.. but need suggestion to know if I proceed at right direction

-- 
Yixun Lan (dlan)
Gentoo Linux Developer
GPG Key ID AABEFD55

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-01-27 18:17         ` Rob Herring
  2025-01-28  3:17           ` Yixun Lan
@ 2025-01-28 15:47           ` Linus Walleij
  1 sibling, 0 replies; 27+ messages in thread
From: Linus Walleij @ 2025-01-28 15:47 UTC (permalink / raw)
  To: Rob Herring
  Cc: Olof Johansson, Yixun Lan, Bartosz Golaszewski,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

On Mon, Jan 27, 2025 at 7:17 PM Rob Herring <robh@kernel.org> wrote:
> [Olof]
> > It seems worse to me to misdescribe the hardware as separate blocks
> > with a device-tree binding that no longer describes the actual hardware,
> > but it's not up to me.
>
> I agree. It's clearly 1 block given the first 3 banks are interleaved.
>
> If Linux can't handle 1 node for N gpio_chip's, then that's a Linux
> problem. Maybe it can, IDK. The lookup from a DT node to gpio_chip just
> needs to match on more than just DT node pointer, but look at the node
> ptr and arg cells.

Any operating system benefits from modeling the GPIOs such that
one set of 32bit registers [r0, r1 .. rn] becomes a discrete entity for
the OS.

Reasoning: any OS will want to be able to control several lines in
a single hardware operation, such as a register write, for example
to shake a clock and data line with a single write_to_register()
operation. If the hardware is described in chunks of 32 bit registers,
this is easy - Data Out Register, Data In Register, Direction
Register n bits, if an multiple-write/read operation hits this entity, we
know it can be handled with a single register write or read.

Yes, the same can be achieved by hardcoding this split into the
driver. But having the binding like such encourages it.

foo-gpios = <&gpio2 0>, <&gpio2 7>;

both need to be set high at outset, well they are in the same
entity and controlled by a single register, so (+/- overhead):

fooreg = fooreg | (1 << 0) | (1 << 7);

I agree this hardware is harder to classify as such since the blocks
share a single IRQ line - if they had individual IRQ lines it would be
a done deal, they are subblocks - yet shared IRQ lines are not *that*
uncommon.

Does this modeling reflect how the hardware actually looks? Likely.

The way GPIOs are built up from silicon io-cells are not that complex.
All the 32 bits from the set of registers will be routed to consecutive
pins, looking at the pin layout of the SoC would confirm if subsequent
bits map to subsequent pins.

Yours,
Linus Walleij

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-01-28  3:17           ` Yixun Lan
@ 2025-01-28 16:03             ` Linus Walleij
  2025-01-28 16:58               ` Rob Herring
  2025-02-06  9:18               ` Linus Walleij
  0 siblings, 2 replies; 27+ messages in thread
From: Linus Walleij @ 2025-01-28 16:03 UTC (permalink / raw)
  To: Yixun Lan
  Cc: Rob Herring, Olof Johansson, Bartosz Golaszewski,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

On Tue, Jan 28, 2025 at 4:17 AM Yixun Lan <dlan@gentoo.org> wrote:

> [Rob]
> > If Linux can't handle 1 node for N gpio_chip's, then that's a Linux
> > problem. Maybe it can, IDK.
>
> I haven't seen somthing like this to register 1 node for multi gpio_chips..
> To gpio/pinctrl maintainer (Linus Walleij), do you have suggestion on this?

For Linux we can call bgpio_init() three times and
devm_gpiochip_add_data() three times on the result and if we use the
approach with three cells (where the second is instance 0,1,2 and the
last one the offset 0..31) then it will work all just the same I guess?

foo-gpios <&gpio 2 7 GPIO_ACTIVE_LOW>;

for offset 7 on block 2 for example.

We need a custom xlate function I suppose.

It just has not been done that way before, everybody just did
2-cell GPIOs.

Yours,
Linus Walleij

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-01-28 16:03             ` Linus Walleij
@ 2025-01-28 16:58               ` Rob Herring
  2025-01-28 18:50                 ` Samuel Holland
  2025-02-06  9:18               ` Linus Walleij
  1 sibling, 1 reply; 27+ messages in thread
From: Rob Herring @ 2025-01-28 16:58 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Yixun Lan, Olof Johansson, Bartosz Golaszewski,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

On Tue, Jan 28, 2025 at 10:03 AM Linus Walleij <linus.walleij@linaro.org> wrote:
>
> On Tue, Jan 28, 2025 at 4:17 AM Yixun Lan <dlan@gentoo.org> wrote:
>
> > [Rob]
> > > If Linux can't handle 1 node for N gpio_chip's, then that's a Linux
> > > problem. Maybe it can, IDK.
> >
> > I haven't seen somthing like this to register 1 node for multi gpio_chips..
> > To gpio/pinctrl maintainer (Linus Walleij), do you have suggestion on this?
>
> For Linux we can call bgpio_init() three times and
> devm_gpiochip_add_data() three times on the result and if we use the
> approach with three cells (where the second is instance 0,1,2 and the
> last one the offset 0..31) then it will work all just the same I guess?
>
> foo-gpios <&gpio 2 7 GPIO_ACTIVE_LOW>;
>
> for offset 7 on block 2 for example.
>
> We need a custom xlate function I suppose.
>
> It just has not been done that way before, everybody just did
> 2-cell GPIOs.

You can do either 3 cells or 2 cells splitting the 1st cell into
<bank><index>. I'm pretty sure we have some cases of the latter.

Rob

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-01-28 16:58               ` Rob Herring
@ 2025-01-28 18:50                 ` Samuel Holland
  0 siblings, 0 replies; 27+ messages in thread
From: Samuel Holland @ 2025-01-28 18:50 UTC (permalink / raw)
  To: Rob Herring, Linus Walleij
  Cc: devicetree, Conor Dooley, Meng Zhang, Yixun Lan, linux-gpio,
	Bartosz Golaszewski, linux-kernel, Conor Dooley, Yangyu Chen,
	Palmer Dabbelt, Jesse Taube, Jisheng Zhang, Paul Walmsley,
	Olof Johansson, Inochi Amaoto, Krzysztof Kozlowski, linux-riscv

On 2025-01-28 10:58 AM, Rob Herring wrote:
> On Tue, Jan 28, 2025 at 10:03 AM Linus Walleij <linus.walleij@linaro.org> wrote:
>>
>> On Tue, Jan 28, 2025 at 4:17 AM Yixun Lan <dlan@gentoo.org> wrote:
>>
>>> [Rob]
>>>> If Linux can't handle 1 node for N gpio_chip's, then that's a Linux
>>>> problem. Maybe it can, IDK.
>>>
>>> I haven't seen somthing like this to register 1 node for multi gpio_chips..
>>> To gpio/pinctrl maintainer (Linus Walleij), do you have suggestion on this?
>>
>> For Linux we can call bgpio_init() three times and
>> devm_gpiochip_add_data() three times on the result and if we use the
>> approach with three cells (where the second is instance 0,1,2 and the
>> last one the offset 0..31) then it will work all just the same I guess?
>>
>> foo-gpios <&gpio 2 7 GPIO_ACTIVE_LOW>;
>>
>> for offset 7 on block 2 for example.
>>
>> We need a custom xlate function I suppose.
>>
>> It just has not been done that way before, everybody just did
>> 2-cell GPIOs.
> 
> You can do either 3 cells or 2 cells splitting the 1st cell into
> <bank><index>. I'm pretty sure we have some cases of the latter.

There is also at least one example of 3-cell GPIOs:

Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml

It supports controllers with varying numbers of pins per bank and banks in each
instance. Compared to the design described above, it shares a single gpio_chip
across all banks in a controller instance.

Regards,
Samuel


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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-01-28 16:03             ` Linus Walleij
  2025-01-28 16:58               ` Rob Herring
@ 2025-02-06  9:18               ` Linus Walleij
  2025-02-06 10:39                 ` Yixun Lan
  2025-02-06 13:31                 ` Yixun Lan
  1 sibling, 2 replies; 27+ messages in thread
From: Linus Walleij @ 2025-02-06  9:18 UTC (permalink / raw)
  To: Yixun Lan
  Cc: Rob Herring, Olof Johansson, Bartosz Golaszewski,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

Hi Yixun,

On Tue, Jan 28, 2025 at 5:03 PM Linus Walleij <linus.walleij@linaro.org> wrote:
> On Tue, Jan 28, 2025 at 4:17 AM Yixun Lan <dlan@gentoo.org> wrote:
>
> > [Rob]
> > > If Linux can't handle 1 node for N gpio_chip's, then that's a Linux
> > > problem. Maybe it can, IDK.
> >
> > I haven't seen somthing like this to register 1 node for multi gpio_chips..
> > To gpio/pinctrl maintainer (Linus Walleij), do you have suggestion on this?
>
> For Linux we can call bgpio_init() three times and
> devm_gpiochip_add_data() three times on the result and if we use the
> approach with three cells (where the second is instance 0,1,2 and the
> last one the offset 0..31) then it will work all just the same I guess?
>
> foo-gpios <&gpio 2 7 GPIO_ACTIVE_LOW>;
>
> for offset 7 on block 2 for example.
>
> We need a custom xlate function I suppose.
>
> It just has not been done that way before, everybody just did
> 2-cell GPIOs.

does this approach work for you? I think it's the most diplomatic.

I'm sorry about the hopeless back-and-forth with the bindings, also
for contributing to the messy debate. I do want developers to feel
encouraged to contribute and not get stuck in too long debates.

Yours,
Linus Walleij

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-02-06  9:18               ` Linus Walleij
@ 2025-02-06 10:39                 ` Yixun Lan
  2025-02-06 13:31                 ` Yixun Lan
  1 sibling, 0 replies; 27+ messages in thread
From: Yixun Lan @ 2025-02-06 10:39 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Olof Johansson, Bartosz Golaszewski,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

hi Linus

Thanks for the ping..

On 10:18 Thu 06 Feb     , Linus Walleij wrote:
> Hi Yixun,
> 
> On Tue, Jan 28, 2025 at 5:03 PM Linus Walleij <linus.walleij@linaro.org> wrote:
> > On Tue, Jan 28, 2025 at 4:17 AM Yixun Lan <dlan@gentoo.org> wrote:
> >
> > > [Rob]
> > > > If Linux can't handle 1 node for N gpio_chip's, then that's a Linux
> > > > problem. Maybe it can, IDK.
> > >
> > > I haven't seen somthing like this to register 1 node for multi gpio_chips..
> > > To gpio/pinctrl maintainer (Linus Walleij), do you have suggestion on this?
> >
> > For Linux we can call bgpio_init() three times and
> > devm_gpiochip_add_data() three times on the result and if we use the
yes, even I've already done this in v4

> > approach with three cells (where the second is instance 0,1,2 and the
> > last one the offset 0..31) then it will work all just the same I guess?
> >
agree, I just need to connect dots.. parse dts & adjust the driver code

> > foo-gpios <&gpio 2 7 GPIO_ACTIVE_LOW>;
> >
> > for offset 7 on block 2 for example.
> >
> > We need a custom xlate function I suppose.
> >
> > It just has not been done that way before, everybody just did
> > 2-cell GPIOs.
> 
> does this approach work for you? I think it's the most diplomatic.
> 
I like the approach which make sense

> I'm sorry about the hopeless back-and-forth with the bindings, also
> for contributing to the messy debate. I do want developers to feel
> encouraged to contribute and not get stuck in too long debates.
> 
no problem, thanks for the encouragement..

I planed to go for the implementation, and raise any actual problem I
may find, but it turns out taking more time than I expected (some reason
to due long chinese new year holiday..)

> Yours,
> Linus Walleij

-- 
Yixun Lan (dlan)
Gentoo Linux Developer
GPG Key ID AABEFD55

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-02-06  9:18               ` Linus Walleij
  2025-02-06 10:39                 ` Yixun Lan
@ 2025-02-06 13:31                 ` Yixun Lan
  2025-02-13 13:07                   ` Linus Walleij
  1 sibling, 1 reply; 27+ messages in thread
From: Yixun Lan @ 2025-02-06 13:31 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Olof Johansson, Bartosz Golaszewski,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

Hi Linus and DT maintainers:

On 10:18 Thu 06 Feb     , Linus Walleij wrote:
> Hi Yixun,
> 
> On Tue, Jan 28, 2025 at 5:03 PM Linus Walleij <linus.walleij@linaro.org> wrote:
> > On Tue, Jan 28, 2025 at 4:17 AM Yixun Lan <dlan@gentoo.org> wrote:
> >
> > > [Rob]
> > > > If Linux can't handle 1 node for N gpio_chip's, then that's a Linux
> > > > problem. Maybe it can, IDK.
> > >
> > > I haven't seen somthing like this to register 1 node for multi gpio_chips..
> > > To gpio/pinctrl maintainer (Linus Walleij), do you have suggestion on this?
> >
> > For Linux we can call bgpio_init() three times and
> > devm_gpiochip_add_data() three times on the result and if we use the
> > approach with three cells (where the second is instance 0,1,2 and the
> > last one the offset 0..31) then it will work all just the same I guess?
> >
both bgpio_init() and devm_gpiochip_add_data() operate on per "struct gpio_chip" bias,
which mean they need to request three independent gpio chips..

> > foo-gpios <&gpio 2 7 GPIO_ACTIVE_LOW>;
if we model the dts as above, then "&gpio" will register itself as one sole "struct gpio_chip",
 which mean one gpio chip combine three banks.. I've looked at the sunxi driver which
Samuel pointed, imply same example as this.

if taking "one gpio chip support multi banks" direction, then it will be reverted back as patch V1,
then, even the three gpio-cells model is unnecessary needed, as we can map gpio number
 to the <bank, offset> array in the underlying gpio driver

the v4 patch is very similar to drivers/gpio/gpio-dwapb.c

If had to choose the direction between v1 and v4, I personally would favor the latter,
 as from hw perspective, each gpio bank is quite indepedent - has its own io/irq registers,
 merely has interleaved io memory space, one shared IRQ line.. also the patch v4 leverage
 lots underlying generic gpio APIs, result in much simplified/clean code base..

> >
> > for offset 7 on block 2 for example.
> >
> > We need a custom xlate function I suppose.
> >
> > It just has not been done that way before, everybody just did
> > 2-cell GPIOs.
> 
> does this approach work for you? I think it's the most diplomatic.
> 
> I'm sorry about the hopeless back-and-forth with the bindings, also
> for contributing to the messy debate. I do want developers to feel
> encouraged to contribute and not get stuck in too long debates.
> 
> Yours,
> Linus Walleij

-- 
Yixun Lan (dlan)
Gentoo Linux Developer
GPG Key ID AABEFD55

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

* Re: [PATCH v4 2/4] gpio: spacemit: add support for K1 SoC
  2025-01-21  3:38 ` [PATCH v4 2/4] " Yixun Lan
@ 2025-02-07 10:56   ` Yixun Lan
  2025-02-15 21:11   ` Alex Elder
  1 sibling, 0 replies; 27+ messages in thread
From: Yixun Lan @ 2025-02-07 10:56 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt
  Cc: Yangyu Chen, Jisheng Zhang, Jesse Taube, Inochi Amaoto,
	Icenowy Zheng, Meng Zhang, Emil Renner Berthing, linux-gpio,
	devicetree, linux-kernel, linux-riscv, spacemit

On 11:38 Tue 21 Jan     , Yixun Lan wrote:
> Implement GPIO functionality which capable of setting pin as
> input, output. Also, each pin can be used as interrupt which
> support rising, failing, or both edge type trigger.
> 
> Signed-off-by: Yixun Lan <dlan@gentoo.org>
> ---
>  drivers/gpio/Kconfig            |   7 +
>  drivers/gpio/Makefile           |   1 +
>  drivers/gpio/gpio-spacemit-k1.c | 295 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 303 insertions(+)
> 
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index 56fee58e281e7cac7f287eb04e4c17a17f75ed04..c153f5439649da020ee42c38e88cb8df31a8e307 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -654,6 +654,13 @@ config GPIO_SNPS_CREG
>  	  where only several fields in register belong to GPIO lines and
>  	  each GPIO line owns a field with different length and on/off value.
>  
> +config GPIO_SPACEMIT_K1
> +	bool "SPACEMIT K1 GPIO support"
> +	depends on ARCH_SPACEMIT || COMPILE_TEST
> +	select GPIOLIB_IRQCHIP
> +	help
> +	  Say yes here to support the SpacemiT's K1 GPIO device.
> +
>  config GPIO_SPEAR_SPICS
>  	bool "ST SPEAr13xx SPI Chip Select as GPIO support"
>  	depends on PLAT_SPEAR
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index af3ba4d81b583842893ea69e677fbe2abf31bc7b..6709ce511a0cf10310a94521c85a2d382dcfa696 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -156,6 +156,7 @@ obj-$(CONFIG_GPIO_SIOX)			+= gpio-siox.o
>  obj-$(CONFIG_GPIO_SL28CPLD)		+= gpio-sl28cpld.o
>  obj-$(CONFIG_GPIO_SLOPPY_LOGIC_ANALYZER) += gpio-sloppy-logic-analyzer.o
>  obj-$(CONFIG_GPIO_SODAVILLE)		+= gpio-sodaville.o
> +obj-$(CONFIG_GPIO_SPACEMIT_K1)		+= gpio-spacemit-k1.o
>  obj-$(CONFIG_GPIO_SPEAR_SPICS)		+= gpio-spear-spics.o
>  obj-$(CONFIG_GPIO_SPRD)			+= gpio-sprd.o
>  obj-$(CONFIG_GPIO_STMPE)		+= gpio-stmpe.o
> diff --git a/drivers/gpio/gpio-spacemit-k1.c b/drivers/gpio/gpio-spacemit-k1.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..de0491af494c10f528095efee9b3a140bdcc0b0d
> --- /dev/null
> +++ b/drivers/gpio/gpio-spacemit-k1.c
> @@ -0,0 +1,295 @@
> +// SPDX-License-Identifier: GPL-2.0 OR MIT
> +/*
> + * Copyright (C) 2023-2025 SpacemiT (Hangzhou) Technology Co. Ltd
> + * Copyright (c) 2025 Yixun Lan <dlan@gentoo.org>
> + */
> +
omit ..
> +static int spacemit_gpio_get_ports(struct device *dev, struct spacemit_gpio *gpio,
> +				   void __iomem *regs)
> +{
> +	struct spacemit_gpio_port *port;
> +	u32 i = 0, offset;
> +
> +	gpio->nr_ports = device_get_child_node_count(dev);
> +	if (gpio->nr_ports == 0)
> +		return -ENODEV;
> +
> +	gpio->ports = devm_kcalloc(dev, gpio->nr_ports, sizeof(*gpio->ports), GFP_KERNEL);
> +	if (!gpio->ports)
> +		return -ENOMEM;
> +
> +	device_for_each_child_node_scoped(dev, fwnode)  {
> +		port		= &gpio->ports[i];
> +		port->fwnode	= fwnode;
> +		port->index	= i++;
> +
> +		if (fwnode_property_read_u32(fwnode, "reg", &offset))
> +			return -EINVAL;
> +
> +		port->base	= regs + offset;
> +		port->irq	= fwnode_irq_get(fwnode, 0);
> +	}
> +
> +	return 0;
> +}
> +
> +static int spacemit_gpio_add_port(struct spacemit_gpio *gpio, int index)
> +{
> +	struct spacemit_gpio_port *port;
> +	struct device *dev = gpio->dev;
> +	struct gpio_irq_chip *girq;
> +	void __iomem *dat, *set, *clr, *dirin, *dirout;
> +	int ret;
> +
> +	port = &gpio->ports[index];
> +	port->gpio = gpio;
> +
> +	dat	= port->base + GPLR;
> +	set	= port->base + GPSR;
> +	clr	= port->base + GPCR;
> +	dirin	= port->base + GCDR;
> +	dirout	= port->base + GSDR;
> +
> +	/* This registers 32 GPIO lines per port */
> +	ret = bgpio_init(&port->gc, dev, 4, dat, set, clr, dirout, dirin,
> +			 BGPIOF_UNREADABLE_REG_SET | BGPIOF_UNREADABLE_REG_DIR);

Esmil point out bgpio_init() require a GPIO_GENERIC dependency, will fix it

-- 
Yixun Lan (dlan)
Gentoo Linux Developer
GPG Key ID AABEFD55

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-02-06 13:31                 ` Yixun Lan
@ 2025-02-13 13:07                   ` Linus Walleij
  2025-02-14 11:54                     ` Yixun Lan
  0 siblings, 1 reply; 27+ messages in thread
From: Linus Walleij @ 2025-02-13 13:07 UTC (permalink / raw)
  To: Yixun Lan
  Cc: Rob Herring, Olof Johansson, Bartosz Golaszewski,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

On Thu, Feb 6, 2025 at 2:32 PM Yixun Lan <dlan@gentoo.org> wrote:

> > > foo-gpios <&gpio 2 7 GPIO_ACTIVE_LOW>;
>
> if we model the dts as above, then "&gpio" will register itself as one sole "struct gpio_chip",
>  which mean one gpio chip combine three banks..

Not really: the fact that there is just one gpio node in the device
tree does not
mean that it needs to correspond to one single gpio_chip instance inside the
Linux kernel.

It's just what the current existing bindings and the code in the GPIO subsystem
assumes. It does not have to assume that: we can change it.

I'm sorry if this is not entirely intuitive :(

One node can very well spawn three gpio_chip instances, but it requires
some core changes. But I think it's the most elegant.

> if taking "one gpio chip support multi banks" direction, then it will be reverted back as patch V1,
> then, even the three gpio-cells model is unnecessary needed, as we can map gpio number
>  to the <bank, offset> array in the underlying gpio driver
>
> the v4 patch is very similar to drivers/gpio/gpio-dwapb.c
>
> If had to choose the direction between v1 and v4, I personally would favor the latter,
>  as from hw perspective, each gpio bank is quite indepedent - has its own io/irq registers,
>  merely has interleaved io memory space, one shared IRQ line.. also the patch v4 leverage
>  lots underlying generic gpio APIs, result in much simplified/clean code base..

So what I would suggest is a combination of the two.

One gpio node in the device tree, like the DT maintainers want it.

Three struct gpio_chip instances inside the driver, all three spawn from
that single gpio device, and from that single platform_device.

What we are suggesting is a three-cell phandle in the device tree:

foo-gpios = <&gpio 0 7 GPIO_ACTIVE_HIGH>;
bar-gpios = <&gpio 2 31 GPIO_ACTIVE_HIGH>;

Notice the new first cell which is 0 or 2.

The first one is what was previously called gpio 7.
The second one is what was 2*32+31 = gpio 95.

So internally in the driver it is easy to use the first cell (0 or 2) to map to
the right struct gpio_chip if you have it in your driver something like this:

struct spacemit_gpio {
    struct gpio_chip gcs[3];
...
};

struct spacemit_gpio *sg;
struct gpio_chip *gc;
int ret;

for (i = 0; i++; i < 3) {
     ret = devm_gpiochip_add_data(dev, &sg->gcs[i], sg);
     if (ret)
        return ret;
     gc = sg->gcs[i];
     .... do stuff with this instance ....
}

Callbacks etc should work as before.

Then these phandles needs to be properly translated, which is done with the
struct gpio_chip .of_xlate() callback. (If you look inside gpiolib-of.c
you will see that chip->of_xlate() is called to map the phandle cells
to a certain GPIO line).

In most cases, drivers do not assign the chip->of_xlate callback
(one exception is gpio-pxa.c) and then it is default-assigned to
of_gpio_simple_xlate() which you can find in gpiolib-of.c as well.

You need to copy this callback to your driver and augment it
properly.

The xlate callback is used to locate the struct gpio_chip and
struct gpio_device as well, by just calling the xlate callback, so if
you code up the right xlate callback, everything should just
work by itself.

this is a guess on what it would look like (just dry coding,
but hopefully the idea works!):

static int spacemit_gpio_xlate(struct gpio_chip *gc,
                                const struct of_phandle_args *gpiospec,
                                u32 *flags)
{
        struct spacemit_gpio *sg = gpiochip_get_data(gc);
        int i;

        if (gc->of_gpio_n_cells != 3)
                return -EINVAL;

        if (gpiospec->args_count < gc->of_gpio_n_cells)
                return -EINVAL;

        /* We support maximum 3 gpio_chip instances */
        i = gpiospec->args[0];
        if (i >= 3)
                return -EINVAL;

        /* OK is this the right gpio_chip out of the three ? */
        if (gc != sg->gcs[i])
                return -EINVAL;

        /* Are we in range for this GPIO chip */
        if (gpiospec->args[1] >= gc->ngpio)
                return -EINVAL;

        if (flags)
                *flags = gpiospec->args[2];

        /* Return the hw index */
        return gpiospec->args[1];
}

...
gc->of_gpio_n_cells = 3;
gc->of_xlate = spacemit_gpio_xlate;

If it works as I hope, this will make the code in gpiolib-of.c in
of_find_gpio_device_by_xlate() calling gpio_device_find()
(which will iterate over all registered gpio_chips and then
of_gpiochip_match_node_and_xlate() will call this custom function
to see if it's the right one and return > 0 when we have the right
chip.

This should work for gpios *only*. When we then come to irqs,
these assume (see gpiolib.c) that we are using
irq_domain_xlate_twocell() when using GPIOLIB_IRQCHIP, so
you either need to roll your own irqchip code or we should fix
the core (I can help with this if the above works).

Several gpio chips use their own domain translation outside
of the gpiolib so you can use this as an intermediate step:
git grep irq_domain_ops drivers/gpio/
... but if you get here, let's patch the core to deal with custom
irqdomain xlate functions in the same manner as above.

I hope this isn't terribly unclear or complicated?
Otherwise tell me and I will try to ... explain more or give
up and say you can use a single 96-pin gpio_chip.

Yours,
Linus Walleij

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-02-13 13:07                   ` Linus Walleij
@ 2025-02-14 11:54                     ` Yixun Lan
  2025-02-14 13:08                       ` Yixun Lan
  2025-02-18  9:44                       ` Linus Walleij
  0 siblings, 2 replies; 27+ messages in thread
From: Yixun Lan @ 2025-02-14 11:54 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Olof Johansson, Bartosz Golaszewski,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

Hi Linus:

On 14:07 Thu 13 Feb     , Linus Walleij wrote:
> On Thu, Feb 6, 2025 at 2:32 PM Yixun Lan <dlan@gentoo.org> wrote:
> 
> > > > foo-gpios <&gpio 2 7 GPIO_ACTIVE_LOW>;
> >
> > if we model the dts as above, then "&gpio" will register itself as one sole "struct gpio_chip",
> >  which mean one gpio chip combine three banks..
> 
> Not really: the fact that there is just one gpio node in the device
> tree does not
> mean that it needs to correspond to one single gpio_chip instance inside the
> Linux kernel.
> 
> It's just what the current existing bindings and the code in the GPIO subsystem
> assumes. It does not have to assume that: we can change it.
> 
> I'm sorry if this is not entirely intuitive :(
> 
> One node can very well spawn three gpio_chip instances, but it requires
> some core changes. But I think it's the most elegant.
> 
> > if taking "one gpio chip support multi banks" direction, then it will be reverted back as patch V1,
> > then, even the three gpio-cells model is unnecessary needed, as we can map gpio number
> >  to the <bank, offset> array in the underlying gpio driver
> >
> > the v4 patch is very similar to drivers/gpio/gpio-dwapb.c
> >
> > If had to choose the direction between v1 and v4, I personally would favor the latter,
> >  as from hw perspective, each gpio bank is quite indepedent - has its own io/irq registers,
> >  merely has interleaved io memory space, one shared IRQ line.. also the patch v4 leverage
> >  lots underlying generic gpio APIs, result in much simplified/clean code base..
> 
> So what I would suggest is a combination of the two.
> 
> One gpio node in the device tree, like the DT maintainers want it.
> 
> Three struct gpio_chip instances inside the driver, all three spawn from
> that single gpio device, and from that single platform_device.
> 
> What we are suggesting is a three-cell phandle in the device tree:
> 
> foo-gpios = <&gpio 0 7 GPIO_ACTIVE_HIGH>;
> bar-gpios = <&gpio 2 31 GPIO_ACTIVE_HIGH>;
> 
> Notice the new first cell which is 0 or 2.
> 
> The first one is what was previously called gpio 7.
> The second one is what was 2*32+31 = gpio 95.
> 
> So internally in the driver it is easy to use the first cell (0 or 2) to map to
> the right struct gpio_chip if you have it in your driver something like this:
> 
> struct spacemit_gpio {
>     struct gpio_chip gcs[3];
> ...
> };
> 
> struct spacemit_gpio *sg;
> struct gpio_chip *gc;
> int ret;
> 
> for (i = 0; i++; i < 3) {
>      ret = devm_gpiochip_add_data(dev, &sg->gcs[i], sg);
>      if (ret)
>         return ret;
>      gc = sg->gcs[i];
>      .... do stuff with this instance ....
> }
> 
> Callbacks etc should work as before.
> 
> Then these phandles needs to be properly translated, which is done with the
> struct gpio_chip .of_xlate() callback. (If you look inside gpiolib-of.c
> you will see that chip->of_xlate() is called to map the phandle cells
> to a certain GPIO line).
> 
> In most cases, drivers do not assign the chip->of_xlate callback
> (one exception is gpio-pxa.c) and then it is default-assigned to
> of_gpio_simple_xlate() which you can find in gpiolib-of.c as well.
> 
> You need to copy this callback to your driver and augment it
> properly.
> 
> The xlate callback is used to locate the struct gpio_chip and
> struct gpio_device as well, by just calling the xlate callback, so if
> you code up the right xlate callback, everything should just
> work by itself.
> 
> this is a guess on what it would look like (just dry coding,
> but hopefully the idea works!):
> 
> static int spacemit_gpio_xlate(struct gpio_chip *gc,
>                                 const struct of_phandle_args *gpiospec,
>                                 u32 *flags)
> {
>         struct spacemit_gpio *sg = gpiochip_get_data(gc);
>         int i;
> 
>         if (gc->of_gpio_n_cells != 3)
>                 return -EINVAL;
> 
>         if (gpiospec->args_count < gc->of_gpio_n_cells)
>                 return -EINVAL;
> 
>         /* We support maximum 3 gpio_chip instances */
>         i = gpiospec->args[0];
>         if (i >= 3)
>                 return -EINVAL;
> 
>         /* OK is this the right gpio_chip out of the three ? */
>         if (gc != sg->gcs[i])
>                 return -EINVAL;
> 
>         /* Are we in range for this GPIO chip */
>         if (gpiospec->args[1] >= gc->ngpio)
>                 return -EINVAL;
> 
>         if (flags)
>                 *flags = gpiospec->args[2];
> 
>         /* Return the hw index */
>         return gpiospec->args[1];
> }
> 
thanks for this very detail prototype! it works mostly, with one problem:

how to map gpio correctly to the pin from pinctrl subsystem?

for example, I specify gpio-ranges in dts, then 
                gpio0: gpio@d4019000 {
                        compatible = "spacemit,k1-gpio";
                        reg = <0x0 0xd4019000 0x0 0x100>;
			...
                        gpio-ranges = <&pinctrl 0 0 96>;
                };

		foo-gpios = <&gpio0 2 28 GPIO_ACTIVE_LOW>;

It should get GPIO_92 ( 92 = 2 * 32 + 28), but turns out GPIO_28

Probably there is something I missed...
> ...
> gc->of_gpio_n_cells = 3;
> gc->of_xlate = spacemit_gpio_xlate;
> 
> If it works as I hope, this will make the code in gpiolib-of.c in
> of_find_gpio_device_by_xlate() calling gpio_device_find()
> (which will iterate over all registered gpio_chips and then
> of_gpiochip_match_node_and_xlate() will call this custom function
> to see if it's the right one and return > 0 when we have the right
> chip.
> 
> This should work for gpios *only*. When we then come to irqs,
> these assume (see gpiolib.c) that we are using
> irq_domain_xlate_twocell() when using GPIOLIB_IRQCHIP, so
> you either need to roll your own irqchip code or we should fix
Sounds I should implement something like irq_domain_xlate_threecell()?

> the core (I can help with this if the above works).
> 
> Several gpio chips use their own domain translation outside
> of the gpiolib so you can use this as an intermediate step:
> git grep irq_domain_ops drivers/gpio/
..
> ... but if you get here, let's patch the core to deal with custom
> irqdomain xlate functions in the same manner as above.
> 
I like this direction, but how we should proceed?

> I hope this isn't terribly unclear or complicated?
> Otherwise tell me and I will try to ... explain more or give
> up and say you can use a single 96-pin gpio_chip.
> 
Let's try first, sounds it's a feasible way.

Many thanks!

> Yours,
> Linus Walleij

-- 
Yixun Lan (dlan)
Gentoo Linux Developer
GPG Key ID AABEFD55

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-02-14 11:54                     ` Yixun Lan
@ 2025-02-14 13:08                       ` Yixun Lan
  2025-02-18  9:44                       ` Linus Walleij
  1 sibling, 0 replies; 27+ messages in thread
From: Yixun Lan @ 2025-02-14 13:08 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Olof Johansson, Bartosz Golaszewski,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

Hi Linus:

On 11:54 Fri 14 Feb     , Yixun Lan wrote:
> Hi Linus:
> 
> On 14:07 Thu 13 Feb     , Linus Walleij wrote:
> > On Thu, Feb 6, 2025 at 2:32 PM Yixun Lan <dlan@gentoo.org> wrote:
> > 
> > > > > foo-gpios <&gpio 2 7 GPIO_ACTIVE_LOW>;
> > >
> > > if we model the dts as above, then "&gpio" will register itself as one sole "struct gpio_chip",
> > >  which mean one gpio chip combine three banks..
> > 
> > Not really: the fact that there is just one gpio node in the device
> > tree does not
> > mean that it needs to correspond to one single gpio_chip instance inside the
> > Linux kernel.
> > 
> > It's just what the current existing bindings and the code in the GPIO subsystem
> > assumes. It does not have to assume that: we can change it.
> > 
> > I'm sorry if this is not entirely intuitive :(
> > 
> > One node can very well spawn three gpio_chip instances, but it requires
> > some core changes. But I think it's the most elegant.
> > 
> > > if taking "one gpio chip support multi banks" direction, then it will be reverted back as patch V1,
> > > then, even the three gpio-cells model is unnecessary needed, as we can map gpio number
> > >  to the <bank, offset> array in the underlying gpio driver
> > >
> > > the v4 patch is very similar to drivers/gpio/gpio-dwapb.c
> > >
> > > If had to choose the direction between v1 and v4, I personally would favor the latter,
> > >  as from hw perspective, each gpio bank is quite indepedent - has its own io/irq registers,
> > >  merely has interleaved io memory space, one shared IRQ line.. also the patch v4 leverage
> > >  lots underlying generic gpio APIs, result in much simplified/clean code base..
> > 
> > So what I would suggest is a combination of the two.
> > 
> > One gpio node in the device tree, like the DT maintainers want it.
> > 
> > Three struct gpio_chip instances inside the driver, all three spawn from
> > that single gpio device, and from that single platform_device.
> > 
> > What we are suggesting is a three-cell phandle in the device tree:
> > 
> > foo-gpios = <&gpio 0 7 GPIO_ACTIVE_HIGH>;
> > bar-gpios = <&gpio 2 31 GPIO_ACTIVE_HIGH>;
> > 
> > Notice the new first cell which is 0 or 2.
> > 
> > The first one is what was previously called gpio 7.
> > The second one is what was 2*32+31 = gpio 95.
> > 
> > So internally in the driver it is easy to use the first cell (0 or 2) to map to
> > the right struct gpio_chip if you have it in your driver something like this:
> > 
> > struct spacemit_gpio {
> >     struct gpio_chip gcs[3];
> > ...
> > };
> > 
> > struct spacemit_gpio *sg;
> > struct gpio_chip *gc;
> > int ret;
> > 
> > for (i = 0; i++; i < 3) {
> >      ret = devm_gpiochip_add_data(dev, &sg->gcs[i], sg);
> >      if (ret)
> >         return ret;
> >      gc = sg->gcs[i];
> >      .... do stuff with this instance ....
> > }
> > 
> > Callbacks etc should work as before.
> > 
> > Then these phandles needs to be properly translated, which is done with the
> > struct gpio_chip .of_xlate() callback. (If you look inside gpiolib-of.c
> > you will see that chip->of_xlate() is called to map the phandle cells
> > to a certain GPIO line).
> > 
> > In most cases, drivers do not assign the chip->of_xlate callback
> > (one exception is gpio-pxa.c) and then it is default-assigned to
> > of_gpio_simple_xlate() which you can find in gpiolib-of.c as well.
> > 
> > You need to copy this callback to your driver and augment it
> > properly.
> > 
> > The xlate callback is used to locate the struct gpio_chip and
> > struct gpio_device as well, by just calling the xlate callback, so if
> > you code up the right xlate callback, everything should just
> > work by itself.
> > 
> > this is a guess on what it would look like (just dry coding,
> > but hopefully the idea works!):
> > 
> > static int spacemit_gpio_xlate(struct gpio_chip *gc,
> >                                 const struct of_phandle_args *gpiospec,
> >                                 u32 *flags)
> > {
> >         struct spacemit_gpio *sg = gpiochip_get_data(gc);
> >         int i;
> > 
> >         if (gc->of_gpio_n_cells != 3)
> >                 return -EINVAL;
> > 
> >         if (gpiospec->args_count < gc->of_gpio_n_cells)
> >                 return -EINVAL;
> > 
> >         /* We support maximum 3 gpio_chip instances */
> >         i = gpiospec->args[0];
> >         if (i >= 3)
> >                 return -EINVAL;
> > 
> >         /* OK is this the right gpio_chip out of the three ? */
> >         if (gc != sg->gcs[i])
> >                 return -EINVAL;
> > 
> >         /* Are we in range for this GPIO chip */
> >         if (gpiospec->args[1] >= gc->ngpio)
> >                 return -EINVAL;
> > 
> >         if (flags)
> >                 *flags = gpiospec->args[2];
> > 
> >         /* Return the hw index */
> >         return gpiospec->args[1];
> > }
> > 
> thanks for this very detail prototype! it works mostly, with one problem:
> 
> how to map gpio correctly to the pin from pinctrl subsystem?
> 
> for example, I specify gpio-ranges in dts, then 
>                 gpio0: gpio@d4019000 {
>                         compatible = "spacemit,k1-gpio";
>                         reg = <0x0 0xd4019000 0x0 0x100>;
> 			...
>                         gpio-ranges = <&pinctrl 0 0 96>;
>                 };
> 
> 		foo-gpios = <&gpio0 2 28 GPIO_ACTIVE_LOW>;
> 
> It should get GPIO_92 ( 92 = 2 * 32 + 28), but turns out GPIO_28
> 
> Probably there is something I missed...
to make the gpio part work, we need additional custom gpio-ranges parser,
which should similar to of_gpiochip_add_pin_range() in gpiolib-of.c
(at least gpio core need to adjust to call custom this function)

-- 
Yixun Lan (dlan)
Gentoo Linux Developer
GPG Key ID AABEFD55

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

* Re: [PATCH v4 2/4] gpio: spacemit: add support for K1 SoC
  2025-01-21  3:38 ` [PATCH v4 2/4] " Yixun Lan
  2025-02-07 10:56   ` Yixun Lan
@ 2025-02-15 21:11   ` Alex Elder
  2025-02-16 12:56     ` Yixun Lan
  1 sibling, 1 reply; 27+ messages in thread
From: Alex Elder @ 2025-02-15 21:11 UTC (permalink / raw)
  To: Yixun Lan, Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt
  Cc: Yangyu Chen, Jisheng Zhang, Jesse Taube, Inochi Amaoto,
	Icenowy Zheng, Meng Zhang, linux-gpio, devicetree, linux-kernel,
	linux-riscv

On 1/20/25 9:38 PM, Yixun Lan wrote:
> Implement GPIO functionality which capable of setting pin as
> input, output. Also, each pin can be used as interrupt which
> support rising, failing, or both edge type trigger.
> 
> Signed-off-by: Yixun Lan <dlan@gentoo.org>

It sounds like the hardware will be modeled in DTS with
explicit banks, which makes sense.  The hardware looks like:

     GPIO controller ---> bank0 --> GPIOs 0..31
                     |
                     |--> bank1 --> GPIOs 0..31
                     |
                     |--> bank2 --> GPIOs 0..31
                     |
                     ---> bank3 --> GPIOs 0..31

Each bank has its own set of 15 registers, but all are managed
by the same controller (driver instance).

Anyway, I'm going to comment on just the code...

> ---
>   drivers/gpio/Kconfig            |   7 +
>   drivers/gpio/Makefile           |   1 +
>   drivers/gpio/gpio-spacemit-k1.c | 295 ++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 303 insertions(+)
> 
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index 56fee58e281e7cac7f287eb04e4c17a17f75ed04..c153f5439649da020ee42c38e88cb8df31a8e307 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -654,6 +654,13 @@ config GPIO_SNPS_CREG
>   	  where only several fields in register belong to GPIO lines and
>   	  each GPIO line owns a field with different length and on/off value.
>   
> +config GPIO_SPACEMIT_K1
> +	bool "SPACEMIT K1 GPIO support"
> +	depends on ARCH_SPACEMIT || COMPILE_TEST
> +	select GPIOLIB_IRQCHIP
> +	help
> +	  Say yes here to support the SpacemiT's K1 GPIO device.
> +
>   config GPIO_SPEAR_SPICS
>   	bool "ST SPEAr13xx SPI Chip Select as GPIO support"
>   	depends on PLAT_SPEAR
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index af3ba4d81b583842893ea69e677fbe2abf31bc7b..6709ce511a0cf10310a94521c85a2d382dcfa696 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -156,6 +156,7 @@ obj-$(CONFIG_GPIO_SIOX)			+= gpio-siox.o
>   obj-$(CONFIG_GPIO_SL28CPLD)		+= gpio-sl28cpld.o
>   obj-$(CONFIG_GPIO_SLOPPY_LOGIC_ANALYZER) += gpio-sloppy-logic-analyzer.o
>   obj-$(CONFIG_GPIO_SODAVILLE)		+= gpio-sodaville.o
> +obj-$(CONFIG_GPIO_SPACEMIT_K1)		+= gpio-spacemit-k1.o
>   obj-$(CONFIG_GPIO_SPEAR_SPICS)		+= gpio-spear-spics.o
>   obj-$(CONFIG_GPIO_SPRD)			+= gpio-sprd.o
>   obj-$(CONFIG_GPIO_STMPE)		+= gpio-stmpe.o
> diff --git a/drivers/gpio/gpio-spacemit-k1.c b/drivers/gpio/gpio-spacemit-k1.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..de0491af494c10f528095efee9b3a140bdcc0b0d
> --- /dev/null
> +++ b/drivers/gpio/gpio-spacemit-k1.c
> @@ -0,0 +1,295 @@
> +// SPDX-License-Identifier: GPL-2.0 OR MIT
> +/*
> + * Copyright (C) 2023-2025 SpacemiT (Hangzhou) Technology Co. Ltd
> + * Copyright (c) 2025 Yixun Lan <dlan@gentoo.org>
> + */
> +
> +#include <linux/io.h>
> +#include <linux/init.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/gpio/driver.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/seq_file.h>
> +#include <linux/module.h>
> +
> +/* register offset */

Please add one-line comments explaining the purpose of these registers.
I explain my understanding below but you can maybe shorten it and add
something to the right of each definition.

> +#define GPLR		0x00

Current port (or pin?) level (port value, regardless of in or out) (r)

> +#define GPDR		0x0c

Current port direction (clear/0 = in, set/1 = out) (r)
This is currently never used.

> +#define GPSR		0x18

Set port value (set output level high for any set bits) (w)

> +#define GPCR		0x24

Clear port value (set output level low for any set bits) (w)

> +#define GRER		0x30

Ports configured for rising edge detect (r)
This is currently never used.

> +#define GFER		0x3c

Ports configured for falling edge detect (r)
This is currently never used.

> +#define GEDR		0x48

Edge detect status register (set bits indicate edge detected) (r/w)

> +#define GSDR		0x54

Set port direction (set bits indicate output pins) (w)

> +#define GCDR		0x60

Clear port direction (set bits indicate input pins) (w)

> +#define GSRER		0x6c

Enable rising edge detect (set bits indicate rising edge detect) (w)

> +#define GCRER		0x78

Disable rising edge detect (w)

> +#define GSFER		0x84

Enable falling edge detect (set bits indicate falling edge detect) (w)

> +#define GCFER		0x90

Disable falling edge detect (w)

> +#define GAPMASK		0x9c

I don't know what this is.  You write it with ~0 after you
clear both rising and falling edge detection on all 32 pins.

> +#define GCPMASK		0xa8

I don't know what this is.  It's currently never used.

> +
> +#define K1_BANK_GPIO_NUMBER	(32)

No need for parentheses around a simple constant.

> +
> +#define to_spacemit_gpio_port(x) container_of((x), struct spacemit_gpio_port, gc)
> +
> +struct spacemit_gpio;
> +

I might just not understand what a "port" means in this context
(I think here it represents a "bank" of 32 GPIOs.)  Based on the
DT discussion it seems like your structures might change, and
I'd like to know what you'll call them.

Here are terms I'll use:  There will be a top-level "controller"
structure which will be able to access four distinct "banks",
each of which has 32 "ports".

> +struct spacemit_gpio_port {
> +	struct gpio_chip		gc;
> +	struct spacemit_gpio		*gpio;
> +	struct fwnode_handle		*fwnode;
> +	void __iomem			*base;
> +	int				irq;
> +	u32				irq_mask;
> +	u32				irq_rising_edge;
> +	u32				irq_falling_edge;
> +	u32				index;
> +};
> +
> +struct spacemit_gpio {
> +	struct	device			*dev;
> +	struct spacemit_gpio_port	*ports;
> +	u32				nr_ports;
> +};
> +

Basically all of the write registers allow you to specify an
entire mask of bits, where the register write changes the
state of every port in a bank whose corresponding bit is set.
That capability is probably worth exposing, even though the
driver currently doesn't use it.

Meanwhile, most (maybe all) of your functions are only used
to update the state of a single port in a bank.

I think the argument names should distinguish these two cases.
I find the argument name "bit" (which now represents a 32-bit
mask with only one bit set) to be ambiguous.

If exactly one port is affected, maybe its number (0-31) can
be passed as the argument.  But where multiple ports in a
bank can be affected by the same operation, pass a "mask".

> +static inline void spacemit_clear_edge_detection(struct spacemit_gpio_port *port, u32 bit)
> +{

I'd do:
	if (bit & port->irq_rising_edge)
		writel(bit, port->base + GSRER);

(And similar below, and in spacemit_set_edge_detection().)

> +	writel(bit, port->base + GCRER);
> +	writel(bit, port->base + GCFER);
> +}
> +

Two comments about the function above and the next one:
- I think their names should be about masking IRQs, not about
   edge detection.
- Each is called only once, and they're trivial enough that I
   don't think encapsulating them in a function adds any value.
   Just open-code them where they're used.

> +static inline void spacemit_set_edge_detection(struct spacemit_gpio_port *port, u32 bit)
> +{
> +	writel(bit & port->irq_rising_edge,  port->base + GSRER);
> +	writel(bit & port->irq_falling_edge, port->base + GSFER);
> +}
> +

This is used to disable IRQ generation on all ports in a bank.
I would offer the same two comments about this function as I
gave above.

> +static inline void spacemit_reset_edge_detection(struct spacemit_gpio_port *port)
> +{
> +	writel(0xffffffff, port->base + GCFER);
> +	writel(0xffffffff, port->base + GCRER);
> +	writel(0xffffffff, port->base + GAPMASK);
> +}
> +

Use names that align with the callback function names.  I.e.,
this should be spacemit_irq_set_type().

> +static int spacemit_gpio_irq_type(struct irq_data *d, unsigned int type)
> +{
> +	struct spacemit_gpio_port *port = irq_data_get_irq_chip_data(d);
> +	u32 bit = BIT(irqd_to_hwirq(d));
> +
> +	if (type & IRQ_TYPE_EDGE_RISING) {
> +		port->irq_rising_edge |= bit;

Here too, maybe avoid doing the write if the bit was already
set in the rising edge mask.

> +		writel(bit, port->base + GSRER);
> +	} else {
> +		port->irq_rising_edge &= ~bit;
> +		writel(bit, port->base + GCRER);
> +	}
> +
> +	if (type & IRQ_TYPE_EDGE_FALLING) {
> +		port->irq_falling_edge |= bit;
> +		writel(bit, port->base + GSFER);
> +	} else {
> +		port->irq_falling_edge &= ~bit;
> +		writel(bit, port->base + GCFER);
> +	}
> +
> +	return 0;
> +}
> +
> +static irqreturn_t spacemit_gpio_irq_handler(int irq, void *dev_id)
> +{
> +	struct spacemit_gpio_port *port = dev_id;
> +	unsigned long pending;
> +	u32 n, gedr;
> +
> +	gedr = readl(port->base + GEDR);
> +	if (!gedr)
> +		return IRQ_NONE;
> +
> +	writel(gedr, port->base + GEDR);

I'd have the blank line here, instead of above the writel().

> +	gedr = gedr & port->irq_mask;

	pending = gedr & port->irq_mask;
	if (!pending)

> +
> +	if (!gedr)
> +		return IRQ_NONE;
> +
> +	pending = gedr;
> +
> +	for_each_set_bit(n, &pending, BITS_PER_LONG)
> +		handle_nested_irq(irq_find_mapping(port->gc.irq.domain, n));
> +
> +	return IRQ_HANDLED;
> +}
> +

I don't think "muxed" is necessary in these names.  Just call
this spacemit_irq_ack().

> +static void spacemit_ack_muxed_gpio(struct irq_data *d)
> +{
> +	struct spacemit_gpio_port *port = irq_data_get_irq_chip_data(d);
> +
> +	writel(BIT(irqd_to_hwirq(d)), port->base + GEDR);
> +}
> +

spacemit_irq_mask()

> +static void spacemit_mask_muxed_gpio(struct irq_data *d)
> +{
> +	struct spacemit_gpio_port *port = irq_data_get_irq_chip_data(d);
> +	u32 bit = BIT(irqd_to_hwirq(d));
> +
> +	port->irq_mask &= ~bit;
> +

As I said earlier, I think you should just open-code the two
writes done by the next function.

> +	spacemit_clear_edge_detection(port, bit);
> +}
> +

spacemit_irq_unmask()

> +static void spacemit_unmask_muxed_gpio(struct irq_data *d)
> +{
> +	struct spacemit_gpio_port *port = irq_data_get_irq_chip_data(d);
> +	u32 bit = BIT(irqd_to_hwirq(d));
> +
> +	port->irq_mask |= bit;
> +

Open-code this call too.

> +	spacemit_set_edge_detection(port, bit);
> +}
> +
> +static void spacemit_irq_print_chip(struct irq_data *data, struct seq_file *p)
> +{
> +	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
> +	struct spacemit_gpio_port *port = to_spacemit_gpio_port(gc);
> +
> +	seq_printf(p, "%s-%d", dev_name(gc->parent), port->index);
> +}
> +
> +static struct irq_chip spacemit_muxed_gpio_chip = {
> +	.name		= "k1-gpio-irqchip",
> +	.irq_ack	= spacemit_ack_muxed_gpio,
> +	.irq_mask	= spacemit_mask_muxed_gpio,
> +	.irq_unmask	= spacemit_unmask_muxed_gpio,
> +	.irq_set_type	= spacemit_gpio_irq_type,
> +	.irq_print_chip	= spacemit_irq_print_chip,
> +	.flags		= IRQCHIP_IMMUTABLE,
> +	GPIOCHIP_IRQ_RESOURCE_HELPERS,
> +};
> +
> +static int spacemit_gpio_get_ports(struct device *dev, struct spacemit_gpio *gpio,
> +				   void __iomem *regs)
> +{
> +	struct spacemit_gpio_port *port;
> +	u32 i = 0, offset;
> +
> +	gpio->nr_ports = device_get_child_node_count(dev);
> +	if (gpio->nr_ports == 0)
> +		return -ENODEV;
> +
> +	gpio->ports = devm_kcalloc(dev, gpio->nr_ports, sizeof(*gpio->ports), GFP_KERNEL);
> +	if (!gpio->ports)
> +		return -ENOMEM;
> +
> +	device_for_each_child_node_scoped(dev, fwnode)  {

Make sure i never exceeds gpio->nr_ports.

> +		port		= &gpio->ports[i];
> +		port->fwnode	= fwnode;
> +		port->index	= i++;
> +
> +		if (fwnode_property_read_u32(fwnode, "reg", &offset))
> +			return -EINVAL;
> +
> +		port->base	= regs + offset;
> +		port->irq	= fwnode_irq_get(fwnode, 0);
> +	}
> +
> +	return 0;
> +}
> +
> +static int spacemit_gpio_add_port(struct spacemit_gpio *gpio, int index)
> +{
> +	struct spacemit_gpio_port *port;
> +	struct device *dev = gpio->dev;
> +	struct gpio_irq_chip *girq;
> +	void __iomem *dat, *set, *clr, *dirin, *dirout;
> +	int ret;
> +
> +	port = &gpio->ports[index];
> +	port->gpio = gpio;
> +
> +	dat	= port->base + GPLR;
> +	set	= port->base + GPSR;
> +	clr	= port->base + GPCR;
> +	dirin	= port->base + GCDR;
> +	dirout	= port->base + GSDR;
> +
> +	/* This registers 32 GPIO lines per port */
> +	ret = bgpio_init(&port->gc, dev, 4, dat, set, clr, dirout, dirin,
> +			 BGPIOF_UNREADABLE_REG_SET | BGPIOF_UNREADABLE_REG_DIR);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to init gpio chip for port\n");
> +
> +	port->gc.label		= dev_name(dev);
> +	port->gc.fwnode		= port->fwnode;
> +	port->gc.request	= gpiochip_generic_request;
> +	port->gc.free		= gpiochip_generic_free;
> +	port->gc.ngpio		= K1_BANK_GPIO_NUMBER;
> +	port->gc.base		= -1;
> +
> +	girq			= &port->gc.irq;
> +	girq->threaded		= true;
> +	girq->handler		= handle_simple_irq;
> +
> +	gpio_irq_chip_set_chip(girq, &spacemit_muxed_gpio_chip);
> +
> +	spacemit_reset_edge_detection(port);
> +

I *think* you should call devm_gpiochip_add_data() *before*
you register the interrupt handler, because conceivably an
interrupt could fire the instant it's registered.  Maybe it
doesn't matter though.

					-Alex

> +	ret = devm_request_threaded_irq(dev, port->irq, NULL,
> +					spacemit_gpio_irq_handler,
> +					IRQF_ONESHOT | IRQF_SHARED,
> +					port->gc.label, port);
> +	if (ret < 0)
> +		return dev_err_probe(dev, ret, "failed to request IRQ\n");
> +
> +	return devm_gpiochip_add_data(dev, &port->gc, port);
> +}
> +
> +static int spacemit_gpio_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct spacemit_gpio *gpio;
> +	struct resource *res;
> +	void __iomem *regs;
> +	int i, ret;
> +
> +	gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
> +	if (!gpio)
> +		return -ENOMEM;
> +
> +	gpio->dev = dev;
> +
> +	regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
> +	if (IS_ERR(regs))
> +		return PTR_ERR(regs);
> +
> +	ret = spacemit_gpio_get_ports(dev, gpio, regs);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "fail to get gpio ports\n");
> +
> +	for (i = 0; i < gpio->nr_ports; i++) {
> +		ret = spacemit_gpio_add_port(gpio, i);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id spacemit_gpio_dt_ids[] = {
> +	{ .compatible = "spacemit,k1-gpio" },
> +	{ /* sentinel */ }
> +};
> +
> +static struct platform_driver spacemit_gpio_driver = {
> +	.probe		= spacemit_gpio_probe,
> +	.driver		= {
> +		.name	= "k1-gpio",
> +		.of_match_table = spacemit_gpio_dt_ids,
> +	},
> +};
> +module_platform_driver(spacemit_gpio_driver);
> +
> +MODULE_AUTHOR("Yixun Lan <dlan@gentoo.org>");
> +MODULE_DESCRIPTION("GPIO driver for SpacemiT K1 SoC");
> +MODULE_LICENSE("GPL");
> 


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

* Re: [PATCH v4 2/4] gpio: spacemit: add support for K1 SoC
  2025-02-15 21:11   ` Alex Elder
@ 2025-02-16 12:56     ` Yixun Lan
  0 siblings, 0 replies; 27+ messages in thread
From: Yixun Lan @ 2025-02-16 12:56 UTC (permalink / raw)
  To: Alex Elder
  Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

Hi Alex:

thanks for your fully review

On 15:11 Sat 15 Feb     , Alex Elder wrote:
> On 1/20/25 9:38 PM, Yixun Lan wrote:
> > Implement GPIO functionality which capable of setting pin as
> > input, output. Also, each pin can be used as interrupt which
> > support rising, failing, or both edge type trigger.
> > 
> > Signed-off-by: Yixun Lan <dlan@gentoo.org>
> 
> It sounds like the hardware will be modeled in DTS with
> explicit banks, which makes sense.  The hardware looks like:
> 
>      GPIO controller ---> bank0 --> GPIOs 0..31
>                      |
>                      |--> bank1 --> GPIOs 0..31
>                      |
>                      |--> bank2 --> GPIOs 0..31
>                      |
>                      ---> bank3 --> GPIOs 0..31
> 
> Each bank has its own set of 15 registers, but all are managed
> by the same controller (driver instance).
> 
Yes, this is the hardware, the driver will populate each bank with one gpio chip

and notice that, we've got some comments from DT maintainer that it's better to
fold children nodes into parent and switch to three cells gpio node.
see following link for more detail discussion
https://lore.kernel.org/all/CACRpkdZYYZ5tUR4gJXuCrix0k56rPPB2TUGP3KpwqMgjs_Vd5w@mail.gmail.com/

so, probably I will massively re-construct this driver in next version...

> Anyway, I'm going to comment on just the code...
> 
> > ---
> >   drivers/gpio/Kconfig            |   7 +
> >   drivers/gpio/Makefile           |   1 +
> >   drivers/gpio/gpio-spacemit-k1.c | 295 ++++++++++++++++++++++++++++++++++++++++
> >   3 files changed, 303 insertions(+)
> > 
> > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> > index 56fee58e281e7cac7f287eb04e4c17a17f75ed04..c153f5439649da020ee42c38e88cb8df31a8e307 100644
> > --- a/drivers/gpio/Kconfig
> > +++ b/drivers/gpio/Kconfig
> > @@ -654,6 +654,13 @@ config GPIO_SNPS_CREG
> >   	  where only several fields in register belong to GPIO lines and
> >   	  each GPIO line owns a field with different length and on/off value.
> >   
> > +config GPIO_SPACEMIT_K1
> > +	bool "SPACEMIT K1 GPIO support"
> > +	depends on ARCH_SPACEMIT || COMPILE_TEST
> > +	select GPIOLIB_IRQCHIP
> > +	help
> > +	  Say yes here to support the SpacemiT's K1 GPIO device.
> > +
> >   config GPIO_SPEAR_SPICS
> >   	bool "ST SPEAr13xx SPI Chip Select as GPIO support"
> >   	depends on PLAT_SPEAR
> > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> > index af3ba4d81b583842893ea69e677fbe2abf31bc7b..6709ce511a0cf10310a94521c85a2d382dcfa696 100644
> > --- a/drivers/gpio/Makefile
> > +++ b/drivers/gpio/Makefile
> > @@ -156,6 +156,7 @@ obj-$(CONFIG_GPIO_SIOX)			+= gpio-siox.o
> >   obj-$(CONFIG_GPIO_SL28CPLD)		+= gpio-sl28cpld.o
> >   obj-$(CONFIG_GPIO_SLOPPY_LOGIC_ANALYZER) += gpio-sloppy-logic-analyzer.o
> >   obj-$(CONFIG_GPIO_SODAVILLE)		+= gpio-sodaville.o
> > +obj-$(CONFIG_GPIO_SPACEMIT_K1)		+= gpio-spacemit-k1.o
> >   obj-$(CONFIG_GPIO_SPEAR_SPICS)		+= gpio-spear-spics.o
> >   obj-$(CONFIG_GPIO_SPRD)			+= gpio-sprd.o
> >   obj-$(CONFIG_GPIO_STMPE)		+= gpio-stmpe.o
> > diff --git a/drivers/gpio/gpio-spacemit-k1.c b/drivers/gpio/gpio-spacemit-k1.c
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..de0491af494c10f528095efee9b3a140bdcc0b0d
> > --- /dev/null
> > +++ b/drivers/gpio/gpio-spacemit-k1.c
> > @@ -0,0 +1,295 @@
> > +// SPDX-License-Identifier: GPL-2.0 OR MIT
> > +/*
> > + * Copyright (C) 2023-2025 SpacemiT (Hangzhou) Technology Co. Ltd
> > + * Copyright (c) 2025 Yixun Lan <dlan@gentoo.org>
> > + */
> > +
> > +#include <linux/io.h>
> > +#include <linux/init.h>
> > +#include <linux/irq.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/gpio/driver.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/property.h>
> > +#include <linux/seq_file.h>
> > +#include <linux/module.h>
> > +
> > +/* register offset */
> 
> Please add one-line comments explaining the purpose of these registers.
> I explain my understanding below but you can maybe shorten it and add
> something to the right of each definition.
> 
I didn't consider to add comments in the first place, it's kind of tedious,
 also it will mostly duplicate what in the docs from spacemit

but I can do this, I will try to come up with a short version,
if it's not enough, then people can always consult the documentation

> > +#define GPLR		0x00
> 
> Current port (or pin?) level (port value, regardless of in or out) (r)
> 
#define GPLR               0x00	/* GPIO port level register */

> > +#define GPDR		0x0c
> 
> Current port direction (clear/0 = in, set/1 = out) (r)
> This is currently never used.
> 
#define GPDR               0x0c /* GPIO port direction register - R/W */

> > +#define GPSR		0x18
> 
> Set port value (set output level high for any set bits) (w)
> 
#define GPSR               0x18	/* GPIO port set register - W */
> > +#define GPCR		0x24
> 
> Clear port value (set output level low for any set bits) (w)
#define GPCR               0x24 /* GPIO port clear register - W */
> 
..
> > +#define GRER		0x30
> 
> Ports configured for rising edge detect (r)
> This is currently never used.
> 
#define GRER               0x30 /* GPIO port rising edge register R/W */
> > +#define GFER		0x3c
> 
> Ports configured for falling edge detect (r)
> This is currently never used.
> 
#define GFER               0x3c /* GPIO port falling edge register R/W */

No, the above two registers are not used, as I think it's has duplicated functionality
 with GSRER, GCRER, GSFER, GCFER

but, I don't know why the hw design like this, may need more clarification from vendor
the code from vendor also doesn't touch these two registers
from my testing, the GPIO interrupt's rising/falling edge trigger works fine without them

> > +#define GEDR		0x48
> 
> Edge detect status register (set bits indicate edge detected) (r/w)
> 
#define GEDR               0x48 /* GPIO Edge Detect Status Registers - R/W1C */

> > +#define GSDR		0x54
> 
> Set port direction (set bits indicate output pins) (w)
> 
#define GSDR               0x54 /*  GPIO (set) Direction Registers - W */

> > +#define GCDR		0x60
> 
> Clear port direction (set bits indicate input pins) (w)
> 
#define GCDR               0x60 /* GPIO (clear) Direction Registers - W */
> > +#define GSRER		0x6c
> 
> Enable rising edge detect (set bits indicate rising edge detect) (w)
> 
#define GSRER              0x6c /* GPIO (set) rising edge detect enable register - W */


> > +#define GCRER		0x78
> 
> Disable rising edge detect (w)
> 
#define GCRER              0x78 /* GPIO (clear) rising edge detect enable register - W */

> > +#define GSFER		0x84
> 
> Enable falling edge detect (set bits indicate falling edge detect) (w)
> 

#define GSFER              0x84 /* GPIO (set) falling edge detect enable register - W */

> > +#define GCFER		0x90
> 
> Disable falling edge detect (w)
> 
#define GCFER              0x90 /* GPIO (clear) falling edge detect enable register - W */

> > +#define GAPMASK		0x9c
> 
> I don't know what this is.  You write it with ~0 after you
> clear both rising and falling edge detection on all 32 pins.
> 
I haven't found documentation from spacemit's web, just copied the logic from vendor code..

from my understanding (best guess), it's the mask bit to AP (application processor)
writing 1 should enable GPIO interrupt functionality to AP?

> > +#define GCPMASK		0xa8
> 
> I don't know what this is.  It's currently never used.
> 
my guess, it's used to mask bits to disable interrupt to AP? 
since we don't need to do this, so not used 

> > +
> > +#define K1_BANK_GPIO_NUMBER	(32)
> 
> No need for parentheses around a simple constant.
> 
Ok

> > +
> > +#define to_spacemit_gpio_port(x) container_of((x), struct spacemit_gpio_port, gc)
> > +
> > +struct spacemit_gpio;
> > +
> 
> I might just not understand what a "port" means in this context
> (I think here it represents a "bank" of 32 GPIOs.)  Based on the
> DT discussion it seems like your structures might change, and
> I'd like to know what you'll call them.
> 
> Here are terms I'll use:  There will be a top-level "controller"
> structure which will be able to access four distinct "banks",
> each of which has 32 "ports".
> 
what I mean is "ports == banks", but after looking at docs and take your suggestion here,
we'd might better rename "ports" to "banks"

> > +struct spacemit_gpio_port {
> > +	struct gpio_chip		gc;
> > +	struct spacemit_gpio		*gpio;
> > +	struct fwnode_handle		*fwnode;
> > +	void __iomem			*base;
> > +	int				irq;
> > +	u32				irq_mask;
> > +	u32				irq_rising_edge;
> > +	u32				irq_falling_edge;
> > +	u32				index;
> > +};
> > +
> > +struct spacemit_gpio {
> > +	struct	device			*dev;
> > +	struct spacemit_gpio_port	*ports;
> > +	u32				nr_ports;
> > +};
> > +
> 
> Basically all of the write registers allow you to specify an
> entire mask of bits, where the register write changes the
> state of every port in a bank whose corresponding bit is set.
yes, these registers are only able to W1 (write), not readable,
also write 0 takes no effect

> That capability is probably worth exposing, even though the
> driver currently doesn't use it.
> 
no idea how to expose, or where it can be used..

> Meanwhile, most (maybe all) of your functions are only used
> to update the state of a single port in a bank.
> 
right

> I think the argument names should distinguish these two cases.
> I find the argument name "bit" (which now represents a 32-bit
> mask with only one bit set) to be ambiguous.
> 
> If exactly one port is affected, maybe its number (0-31) can
> be passed as the argument.  But where multiple ports in a
> bank can be affected by the same operation, pass a "mask".
> 
I got your idea, and I will see what I can do..

> > +static inline void spacemit_clear_edge_detection(struct spacemit_gpio_port *port, u32 bit)
> > +{
> 
> I'd do:
> 	if (bit & port->irq_rising_edge)
> 		writel(bit, port->base + GSRER);
> 
Ok, strictly we can add extra checking

> (And similar below, and in spacemit_set_edge_detection().)
> 
> > +	writel(bit, port->base + GCRER);
> > +	writel(bit, port->base + GCFER);
> > +}
> > +
> 
> Two comments about the function above and the next one:
> - I think their names should be about masking IRQs, not about
>    edge detection.
> - Each is called only once, and they're trivial enough that I
>    don't think encapsulating them in a function adds any value.
>    Just open-code them where they're used.
> 
I thought giving a function name would make it more readable,
it shouldn't bring extra price as compiler will inline it

but, I'm open mind with this, "open-code + one line comment" is also fine

> > +static inline void spacemit_set_edge_detection(struct spacemit_gpio_port *port, u32 bit)
> > +{
> > +	writel(bit & port->irq_rising_edge,  port->base + GSRER);
> > +	writel(bit & port->irq_falling_edge, port->base + GSFER);
> > +}
> > +
> 
> This is used to disable IRQ generation on all ports in a bank.
> I would offer the same two comments about this function as I
> gave above.
> 
ok

> > +static inline void spacemit_reset_edge_detection(struct spacemit_gpio_port *port)
> > +{
> > +	writel(0xffffffff, port->base + GCFER);
> > +	writel(0xffffffff, port->base + GCRER);
> > +	writel(0xffffffff, port->base + GAPMASK);
> > +
> 
> Use names that align with the callback function names.  I.e.,
> this should be spacemit_irq_set_type().
> 
ok
> > +static int spacemit_gpio_irq_type(struct irq_data *d, unsigned int type)
> > +{
> > +	struct spacemit_gpio_port *port = irq_data_get_irq_chip_data(d);
> > +	u32 bit = BIT(irqd_to_hwirq(d));
> > +
> > +	if (type & IRQ_TYPE_EDGE_RISING) {
> > +		port->irq_rising_edge |= bit;
> 
> Here too, maybe avoid doing the write if the bit was already
> set in the rising edge mask.
> 
I thought it's tedious to do extra checking.. kind of unnecessary
making the mask bit match underlying hw write operation is more intuitive

> > +		writel(bit, port->base + GSRER);
> > +	} else {
> > +		port->irq_rising_edge &= ~bit;
> > +		writel(bit, port->base + GCRER);
> > +	}
> > +
> > +	if (type & IRQ_TYPE_EDGE_FALLING) {
> > +		port->irq_falling_edge |= bit;
> > +		writel(bit, port->base + GSFER);
> > +	} else {
> > +		port->irq_falling_edge &= ~bit;
> > +		writel(bit, port->base + GCFER);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static irqreturn_t spacemit_gpio_irq_handler(int irq, void *dev_id)
> > +{
> > +	struct spacemit_gpio_port *port = dev_id;
> > +	unsigned long pending;
> > +	u32 n, gedr;
> > +
> > +	gedr = readl(port->base + GEDR);
> > +	if (!gedr)
> > +		return IRQ_NONE;
> > +
> > +	writel(gedr, port->base + GEDR);
> 
> I'd have the blank line here, instead of above the writel().
> 
ok

> > +	gedr = gedr & port->irq_mask;
> 
> 	pending = gedr & port->irq_mask;
> 	if (!pending)
> 
> > +
> > +	if (!gedr)
> > +		return IRQ_NONE;
> > +
> > +	pending = gedr;
> > +
> > +	for_each_set_bit(n, &pending, BITS_PER_LONG)
> > +		handle_nested_irq(irq_find_mapping(port->gc.irq.domain, n));
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> 
> I don't think "muxed" is necessary in these names.  Just call
> this spacemit_irq_ack().
> 
ok
> > +static void spacemit_ack_muxed_gpio(struct irq_data *d)
> > +{
> > +	struct spacemit_gpio_port *port = irq_data_get_irq_chip_data(d);
> > +
> > +	writel(BIT(irqd_to_hwirq(d)), port->base + GEDR);
> > +}
> > +
> 
> spacemit_irq_mask()
> 
ok
> > +static void spacemit_mask_muxed_gpio(struct irq_data *d)
> > +{
> > +	struct spacemit_gpio_port *port = irq_data_get_irq_chip_data(d);
> > +	u32 bit = BIT(irqd_to_hwirq(d));
> > +
> > +	port->irq_mask &= ~bit;
> > +
> 
> As I said earlier, I think you should just open-code the two
> writes done by the next function.
> 
ok
> > +	spacemit_clear_edge_detection(port, bit);
> > +}
> > +
> 
> spacemit_irq_unmask()
> 
ok
> > +static void spacemit_unmask_muxed_gpio(struct irq_data *d)
> > +{
> > +	struct spacemit_gpio_port *port = irq_data_get_irq_chip_data(d);
> > +	u32 bit = BIT(irqd_to_hwirq(d));
> > +
> > +	port->irq_mask |= bit;
> > +
> 
> Open-code this call too.
> 
ok
> > +	spacemit_set_edge_detection(port, bit);
> > +}
> > +
> > +static void spacemit_irq_print_chip(struct irq_data *data, struct seq_file *p)
> > +{
> > +	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
> > +	struct spacemit_gpio_port *port = to_spacemit_gpio_port(gc);
> > +
> > +	seq_printf(p, "%s-%d", dev_name(gc->parent), port->index);
> > +}
> > +
> > +static struct irq_chip spacemit_muxed_gpio_chip = {
> > +	.name		= "k1-gpio-irqchip",
> > +	.irq_ack	= spacemit_ack_muxed_gpio,
> > +	.irq_mask	= spacemit_mask_muxed_gpio,
> > +	.irq_unmask	= spacemit_unmask_muxed_gpio,
> > +	.irq_set_type	= spacemit_gpio_irq_type,
> > +	.irq_print_chip	= spacemit_irq_print_chip,
> > +	.flags		= IRQCHIP_IMMUTABLE,
> > +	GPIOCHIP_IRQ_RESOURCE_HELPERS,
> > +};
> > +
> > +static int spacemit_gpio_get_ports(struct device *dev, struct spacemit_gpio *gpio,
> > +				   void __iomem *regs)
> > +{
> > +	struct spacemit_gpio_port *port;
> > +	u32 i = 0, offset;
> > +
> > +	gpio->nr_ports = device_get_child_node_count(dev);
> > +	if (gpio->nr_ports == 0)
> > +		return -ENODEV;
> > +
> > +	gpio->ports = devm_kcalloc(dev, gpio->nr_ports, sizeof(*gpio->ports), GFP_KERNEL);
> > +	if (!gpio->ports)
> > +		return -ENOMEM;
> > +
> > +	device_for_each_child_node_scoped(dev, fwnode)  {
> 
> Make sure i never exceeds gpio->nr_ports.
> 
Ok, will see, as this function need to refactor

> > +		port		= &gpio->ports[i];
> > +		port->fwnode	= fwnode;
> > +		port->index	= i++;
> > +
> > +		if (fwnode_property_read_u32(fwnode, "reg", &offset))
> > +			return -EINVAL;
> > +
> > +		port->base	= regs + offset;
> > +		port->irq	= fwnode_irq_get(fwnode, 0);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int spacemit_gpio_add_port(struct spacemit_gpio *gpio, int index)
> > +{
> > +	struct spacemit_gpio_port *port;
> > +	struct device *dev = gpio->dev;
> > +	struct gpio_irq_chip *girq;
> > +	void __iomem *dat, *set, *clr, *dirin, *dirout;
> > +	int ret;
> > +
> > +	port = &gpio->ports[index];
> > +	port->gpio = gpio;
> > +
> > +	dat	= port->base + GPLR;
> > +	set	= port->base + GPSR;
> > +	clr	= port->base + GPCR;
> > +	dirin	= port->base + GCDR;
> > +	dirout	= port->base + GSDR;
> > +
> > +	/* This registers 32 GPIO lines per port */
> > +	ret = bgpio_init(&port->gc, dev, 4, dat, set, clr, dirout, dirin,
> > +			 BGPIOF_UNREADABLE_REG_SET | BGPIOF_UNREADABLE_REG_DIR);
> > +	if (ret)
> > +		return dev_err_probe(dev, ret, "failed to init gpio chip for port\n");
> > +
> > +	port->gc.label		= dev_name(dev);
> > +	port->gc.fwnode		= port->fwnode;
> > +	port->gc.request	= gpiochip_generic_request;
> > +	port->gc.free		= gpiochip_generic_free;
> > +	port->gc.ngpio		= K1_BANK_GPIO_NUMBER;
> > +	port->gc.base		= -1;
> > +
> > +	girq			= &port->gc.irq;
> > +	girq->threaded		= true;
> > +	girq->handler		= handle_simple_irq;
> > +
> > +	gpio_irq_chip_set_chip(girq, &spacemit_muxed_gpio_chip);
> > +
> > +	spacemit_reset_edge_detection(port);
> > +
> 
> I *think* you should call devm_gpiochip_add_data() *before*
> you register the interrupt handler, because conceivably an
> interrupt could fire the instant it's registered.  Maybe it
> doesn't matter though.
> 
good point, I will check this, we probably better to enable(unmask) interrupt
 after all registration is done

> 					-Alex
> 
> > +	ret = devm_request_threaded_irq(dev, port->irq, NULL,
> > +					spacemit_gpio_irq_handler,
> > +					IRQF_ONESHOT | IRQF_SHARED,
> > +					port->gc.label, port);
> > +	if (ret < 0)
> > +		return dev_err_probe(dev, ret, "failed to request IRQ\n");
> > +
> > +	return devm_gpiochip_add_data(dev, &port->gc, port);
> > +}
> > +
> > +static int spacemit_gpio_probe(struct platform_device *pdev)
> > +{
> > +	struct device *dev = &pdev->dev;
> > +	struct spacemit_gpio *gpio;
> > +	struct resource *res;
> > +	void __iomem *regs;
> > +	int i, ret;
> > +
> > +	gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
> > +	if (!gpio)
> > +		return -ENOMEM;
> > +
> > +	gpio->dev = dev;
> > +
> > +	regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
> > +	if (IS_ERR(regs))
> > +		return PTR_ERR(regs);
> > +
> > +	ret = spacemit_gpio_get_ports(dev, gpio, regs);
> > +	if (ret)
> > +		return dev_err_probe(dev, ret, "fail to get gpio ports\n");
> > +
> > +	for (i = 0; i < gpio->nr_ports; i++) {
> > +		ret = spacemit_gpio_add_port(gpio, i);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct of_device_id spacemit_gpio_dt_ids[] = {
> > +	{ .compatible = "spacemit,k1-gpio" },
> > +	{ /* sentinel */ }
> > +};
> > +
> > +static struct platform_driver spacemit_gpio_driver = {
> > +	.probe		= spacemit_gpio_probe,
> > +	.driver		= {
> > +		.name	= "k1-gpio",
> > +		.of_match_table = spacemit_gpio_dt_ids,
> > +	},
> > +};
> > +module_platform_driver(spacemit_gpio_driver);
> > +
> > +MODULE_AUTHOR("Yixun Lan <dlan@gentoo.org>");
> > +MODULE_DESCRIPTION("GPIO driver for SpacemiT K1 SoC");
> > +MODULE_LICENSE("GPL");
> > 
> 

-- 
Yixun Lan (dlan)
Gentoo Linux Developer
GPG Key ID AABEFD55

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-02-14 11:54                     ` Yixun Lan
  2025-02-14 13:08                       ` Yixun Lan
@ 2025-02-18  9:44                       ` Linus Walleij
  2025-02-18  9:55                         ` Yixun Lan
  1 sibling, 1 reply; 27+ messages in thread
From: Linus Walleij @ 2025-02-18  9:44 UTC (permalink / raw)
  To: Yixun Lan
  Cc: Rob Herring, Olof Johansson, Bartosz Golaszewski,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

On Fri, Feb 14, 2025 at 12:54 PM Yixun Lan <dlan@gentoo.org> wrote:

> thanks for this very detail prototype! it works mostly, with one problem:
>
> how to map gpio correctly to the pin from pinctrl subsystem?
>
> for example, I specify gpio-ranges in dts, then
>                 gpio0: gpio@d4019000 {
>                         compatible = "spacemit,k1-gpio";
>                         reg = <0x0 0xd4019000 0x0 0x100>;
>                         ...
>                         gpio-ranges = <&pinctrl 0 0 96>;
>                 };
>
>                 foo-gpios = <&gpio0 2 28 GPIO_ACTIVE_LOW>;
>
> It should get GPIO_92 ( 92 = 2 * 32 + 28), but turns out GPIO_28
>
> Probably there is something I missed...

No it's just me missing the complexity!

> to make the gpio part work, we need additional custom gpio-ranges parser,
> which should similar to of_gpiochip_add_pin_range() in gpiolib-of.c
> (at least gpio core need to adjust to call custom this function)

Let me send a patch set to bring threecell into the core instead,
and see if it works for you!

I will post it real soon.

Yours,
Linus Walleij

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-02-18  9:44                       ` Linus Walleij
@ 2025-02-18  9:55                         ` Yixun Lan
  2025-02-18 10:17                           ` Linus Walleij
  0 siblings, 1 reply; 27+ messages in thread
From: Yixun Lan @ 2025-02-18  9:55 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Olof Johansson, Bartosz Golaszewski,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

Hi Linus:

On 10:44 Tue 18 Feb     , Linus Walleij wrote:
> On Fri, Feb 14, 2025 at 12:54 PM Yixun Lan <dlan@gentoo.org> wrote:
> 
> > thanks for this very detail prototype! it works mostly, with one problem:
> >
> > how to map gpio correctly to the pin from pinctrl subsystem?
> >
> > for example, I specify gpio-ranges in dts, then
> >                 gpio0: gpio@d4019000 {
> >                         compatible = "spacemit,k1-gpio";
> >                         reg = <0x0 0xd4019000 0x0 0x100>;
> >                         ...
> >                         gpio-ranges = <&pinctrl 0 0 96>;
> >                 };
> >
> >                 foo-gpios = <&gpio0 2 28 GPIO_ACTIVE_LOW>;
> >
> > It should get GPIO_92 ( 92 = 2 * 32 + 28), but turns out GPIO_28
> >
> > Probably there is something I missed...
> 
> No it's just me missing the complexity!
> 
> > to make the gpio part work, we need additional custom gpio-ranges parser,
> > which should similar to of_gpiochip_add_pin_range() in gpiolib-of.c
> > (at least gpio core need to adjust to call custom this function)
> 
> Let me send a patch set to bring threecell into the core instead,
> and see if it works for you!
> 
> I will post it real soon.
> 
can you check the v5 of the patch here [1]? which I just sent out yesterday
it does 1) implement xlate() 2) instroduce custom add_pin_page()
the gpio part works as I tested, the gpio irq probably need more testing

> Yours,
> Linus Walleij

[1] https://lore.kernel.org/spacemit/20250217-03-k1-gpio-v5-0-2863ec3e7b67@gentoo.org/

-- 
Yixun Lan (dlan)
Gentoo Linux Developer
GPG Key ID AABEFD55

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-02-18  9:55                         ` Yixun Lan
@ 2025-02-18 10:17                           ` Linus Walleij
  2025-02-18 10:59                             ` Yixun Lan
  0 siblings, 1 reply; 27+ messages in thread
From: Linus Walleij @ 2025-02-18 10:17 UTC (permalink / raw)
  To: Yixun Lan
  Cc: Rob Herring, Olof Johansson, Bartosz Golaszewski,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

On Tue, Feb 18, 2025 at 10:55 AM Yixun Lan <dlan@gentoo.org> wrote:

> > I will post it real soon.
> >
> can you check the v5 of the patch here [1]? which I just sent out yesterday
> it does 1) implement xlate() 2) instroduce custom add_pin_page()
> the gpio part works as I tested, the gpio irq probably need more testing

Ah nice! I have the same idea, but I just bring all the stuff you
need to reimplement in your driver into the core instead.

Your driver and bindings will look the same, you will just do
not need to reimplement the translation functions (if my code
works as I intended...)

Yours,
Linus Walleij

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

* Re: [PATCH v4 1/4] dt-bindings: gpio: spacemit: add support for K1 SoC
  2025-02-18 10:17                           ` Linus Walleij
@ 2025-02-18 10:59                             ` Yixun Lan
  0 siblings, 0 replies; 27+ messages in thread
From: Yixun Lan @ 2025-02-18 10:59 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Olof Johansson, Bartosz Golaszewski,
	Krzysztof Kozlowski, Conor Dooley, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Yangyu Chen, Jisheng Zhang, Jesse Taube,
	Inochi Amaoto, Icenowy Zheng, Meng Zhang, linux-gpio, devicetree,
	linux-kernel, linux-riscv

Hi Linus:

On 11:17 Tue 18 Feb     , Linus Walleij wrote:
> On Tue, Feb 18, 2025 at 10:55 AM Yixun Lan <dlan@gentoo.org> wrote:
> 
> > > I will post it real soon.
> > >
> > can you check the v5 of the patch here [1]? which I just sent out yesterday
> > it does 1) implement xlate() 2) instroduce custom add_pin_page()
> > the gpio part works as I tested, the gpio irq probably need more testing
> 
> Ah nice! I have the same idea, but I just bring all the stuff you
> need to reimplement in your driver into the core instead.
> 
> Your driver and bindings will look the same, you will just do
> not need to reimplement the translation functions (if my code
> works as I intended...)
> 
great! I will test and let you know if it works, many thanks..

> Yours,
> Linus Walleij

-- 
Yixun Lan (dlan)
Gentoo Linux Developer
GPG Key ID AABEFD55

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

end of thread, other threads:[~2025-02-18 10:59 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-21  3:38 [PATCH v4 0/4] riscv: spacemit: add gpio support for K1 SoC Yixun Lan
2025-01-21  3:38 ` [PATCH v4 1/4] dt-bindings: gpio: spacemit: add " Yixun Lan
2025-01-22 20:03   ` Olof Johansson
2025-01-23 11:30     ` Yixun Lan
2025-01-23 23:19       ` Olof Johansson
2025-01-27 18:17         ` Rob Herring
2025-01-28  3:17           ` Yixun Lan
2025-01-28 16:03             ` Linus Walleij
2025-01-28 16:58               ` Rob Herring
2025-01-28 18:50                 ` Samuel Holland
2025-02-06  9:18               ` Linus Walleij
2025-02-06 10:39                 ` Yixun Lan
2025-02-06 13:31                 ` Yixun Lan
2025-02-13 13:07                   ` Linus Walleij
2025-02-14 11:54                     ` Yixun Lan
2025-02-14 13:08                       ` Yixun Lan
2025-02-18  9:44                       ` Linus Walleij
2025-02-18  9:55                         ` Yixun Lan
2025-02-18 10:17                           ` Linus Walleij
2025-02-18 10:59                             ` Yixun Lan
2025-01-28 15:47           ` Linus Walleij
2025-01-21  3:38 ` [PATCH v4 2/4] " Yixun Lan
2025-02-07 10:56   ` Yixun Lan
2025-02-15 21:11   ` Alex Elder
2025-02-16 12:56     ` Yixun Lan
2025-01-21  3:38 ` [PATCH v4 3/4] riscv: dts: spacemit: add gpio " Yixun Lan
2025-01-21  3:38 ` [PATCH v4 4/4] riscv: dts: spacemit: add gpio LED for system heartbeat Yixun Lan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).