[PATCH 2/2] gpio: spacemit: Add GPIO support for K3 SoC

Yixun Lan posted 2 patches 1 month, 1 week ago
There is a newer version of this series
[PATCH 2/2] gpio: spacemit: Add GPIO support for K3 SoC
Posted by Yixun Lan 1 month, 1 week ago
SpacemiT K3 SoC has changed gpio register layout while comparing
with previous generation, the register offset and bank offset
need to be adjusted, introduce a compatible data to extend the
driver to support this.

Signed-off-by: Yixun Lan <dlan@gentoo.org>
---
 drivers/gpio/gpio-spacemit-k1.c | 150 ++++++++++++++++++++++++++++------------
 1 file changed, 106 insertions(+), 44 deletions(-)

diff --git a/drivers/gpio/gpio-spacemit-k1.c b/drivers/gpio/gpio-spacemit-k1.c
index eb66a15c002f..02cc5c11b617 100644
--- a/drivers/gpio/gpio-spacemit-k1.c
+++ b/drivers/gpio/gpio-spacemit-k1.c
@@ -15,28 +15,19 @@
 #include <linux/platform_device.h>
 #include <linux/seq_file.h>
 
-/* register offset */
-#define SPACEMIT_GPLR		0x00 /* port level - R */
-#define SPACEMIT_GPDR		0x0c /* port direction - R/W */
-#define SPACEMIT_GPSR		0x18 /* port set - W */
-#define SPACEMIT_GPCR		0x24 /* port clear - W */
-#define SPACEMIT_GRER		0x30 /* port rising edge R/W */
-#define SPACEMIT_GFER		0x3c /* port falling edge R/W */
-#define SPACEMIT_GEDR		0x48 /* edge detect status - R/W1C */
-#define SPACEMIT_GSDR		0x54 /* (set) direction - W */
-#define SPACEMIT_GCDR		0x60 /* (clear) direction - W */
-#define SPACEMIT_GSRER		0x6c /* (set) rising edge detect enable - W */
-#define SPACEMIT_GCRER		0x78 /* (clear) rising edge detect enable - W */
-#define SPACEMIT_GSFER		0x84 /* (set) falling edge detect enable - W */
-#define SPACEMIT_GCFER		0x90 /* (clear) falling edge detect enable - W */
-#define SPACEMIT_GAPMASK	0x9c /* interrupt mask , 0 disable, 1 enable - R/W */
-
 #define SPACEMIT_NR_BANKS		4
 #define SPACEMIT_NR_GPIOS_PER_BANK	32
 
 #define to_spacemit_gpio_bank(x) container_of((x), struct spacemit_gpio_bank, gc)
+#define to_spacemit_gpio_regs(sg) ((sg)->data->reg_offsets)
 
 struct spacemit_gpio;
+struct spacemit_gpio_reg_offsets;
+
+struct spacemit_gpio_data {
+	struct spacemit_gpio_reg_offsets *reg_offsets;
+	u32 bank_offsets[4];
+};
 
 struct spacemit_gpio_bank {
 	struct gpio_generic_chip chip;
@@ -49,9 +40,28 @@ struct spacemit_gpio_bank {
 
 struct spacemit_gpio {
 	struct device *dev;
+	const struct spacemit_gpio_data *data;
 	struct spacemit_gpio_bank sgb[SPACEMIT_NR_BANKS];
 };
 
+struct spacemit_gpio_reg_offsets {
+	u32 gplr;      /* port level - R */
+	u32 gpdr;      /* port direction - R/W */
+	u32 gpsr;      /* port set - W */
+	u32 gpcr;      /* port clear - W */
+	u32 grer;      /* port rising edge R/W */
+	u32 gfer;      /* port falling edge R/W */
+	u32 gedr;      /* edge detect status - R/W1C */
+	u32 gsdr;      /* (set) direction - W */
+	u32 gcdr;      /* (clear) direction - W */
+	u32 gsrer;     /* (set) rising edge detect enable - W */
+	u32 gcrer;     /* (clear) rising edge detect enable - W */
+	u32 gsfer;     /* (set) falling edge detect enable - W */
+	u32 gcfer;     /* (clear) falling edge detect enable - W */
+	u32 gapmask;   /* interrupt mask , 0 disable, 1 enable - R/W */
+	u32 gcpmask;   /* interrupt mask for K3 */
+};
+
 static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
 {
 	return (u32)(gb - gb->sg->sgb);
@@ -60,13 +70,14 @@ static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
 static irqreturn_t spacemit_gpio_irq_handler(int irq, void *dev_id)
 {
 	struct spacemit_gpio_bank *gb = dev_id;
+	struct spacemit_gpio *sg = gb->sg;
 	unsigned long pending;
 	u32 n, gedr;
 
-	gedr = readl(gb->base + SPACEMIT_GEDR);
+	gedr = readl(gb->base + to_spacemit_gpio_regs(sg)->gedr);
 	if (!gedr)
 		return IRQ_NONE;
-	writel(gedr, gb->base + SPACEMIT_GEDR);
+	writel(gedr, gb->base + to_spacemit_gpio_regs(sg)->gedr);
 
 	pending = gedr & gb->irq_mask;
 	if (!pending)
@@ -81,60 +92,64 @@ static irqreturn_t spacemit_gpio_irq_handler(int irq, void *dev_id)
 static void spacemit_gpio_irq_ack(struct irq_data *d)
 {
 	struct spacemit_gpio_bank *gb = irq_data_get_irq_chip_data(d);
+	struct spacemit_gpio *sg = gb->sg;
 
-	writel(BIT(irqd_to_hwirq(d)), gb->base + SPACEMIT_GEDR);
+	writel(BIT(irqd_to_hwirq(d)), gb->base + to_spacemit_gpio_regs(sg)->gedr);
 }
 
 static void spacemit_gpio_irq_mask(struct irq_data *d)
 {
 	struct spacemit_gpio_bank *gb = irq_data_get_irq_chip_data(d);
+	struct spacemit_gpio *sg = gb->sg;
 	u32 bit = BIT(irqd_to_hwirq(d));
 
 	gb->irq_mask &= ~bit;
-	writel(gb->irq_mask, gb->base + SPACEMIT_GAPMASK);
+	writel(gb->irq_mask, gb->base + to_spacemit_gpio_regs(sg)->gapmask);
 
 	if (bit & gb->irq_rising_edge)
-		writel(bit, gb->base + SPACEMIT_GCRER);
+		writel(bit, gb->base + to_spacemit_gpio_regs(sg)->gcrer);
 
 	if (bit & gb->irq_falling_edge)
-		writel(bit, gb->base + SPACEMIT_GCFER);
+		writel(bit, gb->base + to_spacemit_gpio_regs(sg)->gcfer);
 }
 
 static void spacemit_gpio_irq_unmask(struct irq_data *d)
 {
 	struct spacemit_gpio_bank *gb = irq_data_get_irq_chip_data(d);
+	struct spacemit_gpio *sg = gb->sg;
 	u32 bit = BIT(irqd_to_hwirq(d));
 
 	gb->irq_mask |= bit;
 
 	if (bit & gb->irq_rising_edge)
-		writel(bit, gb->base + SPACEMIT_GSRER);
+		writel(bit, gb->base + to_spacemit_gpio_regs(sg)->gsrer);
 
 	if (bit & gb->irq_falling_edge)
-		writel(bit, gb->base + SPACEMIT_GSFER);
+		writel(bit, gb->base + to_spacemit_gpio_regs(sg)->gsfer);
 
-	writel(gb->irq_mask, gb->base + SPACEMIT_GAPMASK);
+	writel(gb->irq_mask, gb->base + to_spacemit_gpio_regs(sg)->gapmask);
 }
 
 static int spacemit_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	struct spacemit_gpio_bank *gb = irq_data_get_irq_chip_data(d);
+	struct spacemit_gpio *sg = gb->sg;
 	u32 bit = BIT(irqd_to_hwirq(d));
 
 	if (type & IRQ_TYPE_EDGE_RISING) {
 		gb->irq_rising_edge |= bit;
-		writel(bit, gb->base + SPACEMIT_GSRER);
+		writel(bit, gb->base + to_spacemit_gpio_regs(sg)->gsrer);
 	} else {
 		gb->irq_rising_edge &= ~bit;
-		writel(bit, gb->base + SPACEMIT_GCRER);
+		writel(bit, gb->base + to_spacemit_gpio_regs(sg)->gcrer);
 	}
 
 	if (type & IRQ_TYPE_EDGE_FALLING) {
 		gb->irq_falling_edge |= bit;
-		writel(bit, gb->base + SPACEMIT_GSFER);
+		writel(bit, gb->base + to_spacemit_gpio_regs(sg)->gsfer);
 	} else {
 		gb->irq_falling_edge &= ~bit;
-		writel(bit, gb->base + SPACEMIT_GCFER);
+		writel(bit, gb->base + to_spacemit_gpio_regs(sg)->gcfer);
 	}
 
 	return 0;
@@ -179,15 +194,15 @@ static int spacemit_gpio_add_bank(struct spacemit_gpio *sg,
 	struct device *dev = sg->dev;
 	struct gpio_irq_chip *girq;
 	void __iomem *dat, *set, *clr, *dirin, *dirout;
-	int ret, bank_base[] = { 0x0, 0x4, 0x8, 0x100 };
+	int ret;
 
-	gb->base = regs + bank_base[index];
+	gb->base = regs + sg->data->bank_offsets[index];
 
-	dat	= gb->base + SPACEMIT_GPLR;
-	set	= gb->base + SPACEMIT_GPSR;
-	clr	= gb->base + SPACEMIT_GPCR;
-	dirin	= gb->base + SPACEMIT_GCDR;
-	dirout	= gb->base + SPACEMIT_GSDR;
+	dat	= gb->base + to_spacemit_gpio_regs(sg)->gplr;
+	set	= gb->base + to_spacemit_gpio_regs(sg)->gpsr;
+	clr	= gb->base + to_spacemit_gpio_regs(sg)->gpcr;
+	dirin	= gb->base + to_spacemit_gpio_regs(sg)->gcdr;
+	dirout	= gb->base + to_spacemit_gpio_regs(sg)->gsdr;
 
 	config = (struct gpio_generic_chip_config) {
 		.dev = dev,
@@ -223,13 +238,13 @@ static int spacemit_gpio_add_bank(struct spacemit_gpio *sg,
 	gpio_irq_chip_set_chip(girq, &spacemit_gpio_chip);
 
 	/* Disable Interrupt */
-	writel(0, gb->base + SPACEMIT_GAPMASK);
+	writel(0, gb->base + to_spacemit_gpio_regs(sg)->gapmask);
 	/* Disable Edge Detection Settings */
-	writel(0x0, gb->base + SPACEMIT_GRER);
-	writel(0x0, gb->base + SPACEMIT_GFER);
+	writel(0x0, gb->base + to_spacemit_gpio_regs(sg)->grer);
+	writel(0x0, gb->base + to_spacemit_gpio_regs(sg)->gfer);
 	/* Clear Interrupt */
-	writel(0xffffffff, gb->base + SPACEMIT_GCRER);
-	writel(0xffffffff, gb->base + SPACEMIT_GCFER);
+	writel(0xffffffff, gb->base + to_spacemit_gpio_regs(sg)->gcrer);
+	writel(0xffffffff, gb->base + to_spacemit_gpio_regs(sg)->gcfer);
 
 	ret = devm_request_threaded_irq(dev, irq, NULL,
 					spacemit_gpio_irq_handler,
@@ -260,6 +275,10 @@ static int spacemit_gpio_probe(struct platform_device *pdev)
 	if (!sg)
 		return -ENOMEM;
 
+	sg->data = of_device_get_match_data(dev);
+	if (!sg->data)
+		return dev_err_probe(dev, -EINVAL, "No available compatible data.");
+
 	regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(regs))
 		return PTR_ERR(regs);
@@ -287,8 +306,51 @@ static int spacemit_gpio_probe(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct spacemit_gpio_data k1_gpio_data = {
+	.reg_offsets = &(struct spacemit_gpio_reg_offsets) {
+		.gplr    = 0x00,
+		.gpdr    = 0x0c,
+		.gpsr    = 0x18,
+		.gpcr    = 0x24,
+		.grer    = 0x30,
+		.gfer    = 0x3c,
+		.gedr    = 0x48,
+		.gsdr    = 0x54,
+		.gcdr    = 0x60,
+		.gsrer   = 0x6c,
+		.gcrer   = 0x78,
+		.gsfer   = 0x84,
+		.gcfer   = 0x90,
+		.gapmask = 0x9c,
+		.gcpmask = 0xA8,
+	},
+	.bank_offsets = { 0x0, 0x4, 0x8, 0x100 },
+};
+
+static const struct spacemit_gpio_data k3_gpio_data = {
+	.reg_offsets = &(struct spacemit_gpio_reg_offsets) {
+		.gplr    = 0x0,
+		.gpdr    = 0x4,
+		.gpsr    = 0x8,
+		.gpcr    = 0xc,
+		.grer    = 0x10,
+		.gfer    = 0x14,
+		.gedr    = 0x18,
+		.gsdr    = 0x1c,
+		.gcdr    = 0x20,
+		.gsrer   = 0x24,
+		.gcrer   = 0x28,
+		.gsfer   = 0x2c,
+		.gcfer   = 0x30,
+		.gapmask = 0x34,
+		.gcpmask = 0x38,
+	},
+	.bank_offsets = { 0x0, 0x40, 0x80, 0x100 },
+};
+
 static const struct of_device_id spacemit_gpio_dt_ids[] = {
-	{ .compatible = "spacemit,k1-gpio" },
+	{ .compatible = "spacemit,k1-gpio", .data = &k1_gpio_data },
+	{ .compatible = "spacemit,k3-gpio", .data = &k3_gpio_data },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, spacemit_gpio_dt_ids);
@@ -296,12 +358,12 @@ MODULE_DEVICE_TABLE(of, spacemit_gpio_dt_ids);
 static struct platform_driver spacemit_gpio_driver = {
 	.probe		= spacemit_gpio_probe,
 	.driver		= {
-		.name	= "k1-gpio",
+		.name	= "spacemit-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_DESCRIPTION("GPIO driver for SpacemiT K1/K3 SoC");
 MODULE_LICENSE("GPL");

-- 
2.52.0
Re: [PATCH 2/2] gpio: spacemit: Add GPIO support for K3 SoC
Posted by Bartosz Golaszewski 1 month, 1 week ago
On Mon, Dec 29, 2025 at 1:47 PM Yixun Lan <dlan@gentoo.org> wrote:
>
> SpacemiT K3 SoC has changed gpio register layout while comparing
> with previous generation, the register offset and bank offset
> need to be adjusted, introduce a compatible data to extend the
> driver to support this.
>
> Signed-off-by: Yixun Lan <dlan@gentoo.org>
> ---
>  drivers/gpio/gpio-spacemit-k1.c | 150 ++++++++++++++++++++++++++++------------
>  1 file changed, 106 insertions(+), 44 deletions(-)
>
> diff --git a/drivers/gpio/gpio-spacemit-k1.c b/drivers/gpio/gpio-spacemit-k1.c
> index eb66a15c002f..02cc5c11b617 100644
> --- a/drivers/gpio/gpio-spacemit-k1.c
> +++ b/drivers/gpio/gpio-spacemit-k1.c
> @@ -15,28 +15,19 @@
>  #include <linux/platform_device.h>
>  #include <linux/seq_file.h>
>
> -/* register offset */
> -#define SPACEMIT_GPLR          0x00 /* port level - R */
> -#define SPACEMIT_GPDR          0x0c /* port direction - R/W */
> -#define SPACEMIT_GPSR          0x18 /* port set - W */
> -#define SPACEMIT_GPCR          0x24 /* port clear - W */
> -#define SPACEMIT_GRER          0x30 /* port rising edge R/W */
> -#define SPACEMIT_GFER          0x3c /* port falling edge R/W */
> -#define SPACEMIT_GEDR          0x48 /* edge detect status - R/W1C */
> -#define SPACEMIT_GSDR          0x54 /* (set) direction - W */
> -#define SPACEMIT_GCDR          0x60 /* (clear) direction - W */
> -#define SPACEMIT_GSRER         0x6c /* (set) rising edge detect enable - W */
> -#define SPACEMIT_GCRER         0x78 /* (clear) rising edge detect enable - W */
> -#define SPACEMIT_GSFER         0x84 /* (set) falling edge detect enable - W */
> -#define SPACEMIT_GCFER         0x90 /* (clear) falling edge detect enable - W */
> -#define SPACEMIT_GAPMASK       0x9c /* interrupt mask , 0 disable, 1 enable - R/W */
> -
>  #define SPACEMIT_NR_BANKS              4
>  #define SPACEMIT_NR_GPIOS_PER_BANK     32
>
>  #define to_spacemit_gpio_bank(x) container_of((x), struct spacemit_gpio_bank, gc)
> +#define to_spacemit_gpio_regs(sg) ((sg)->data->reg_offsets)
>
>  struct spacemit_gpio;
> +struct spacemit_gpio_reg_offsets;

Why not move this structure here instead and avoid the forward declaration?

> +
> +struct spacemit_gpio_data {
> +       struct spacemit_gpio_reg_offsets *reg_offsets;
> +       u32 bank_offsets[4];
> +};
>
>  struct spacemit_gpio_bank {
>         struct gpio_generic_chip chip;
> @@ -49,9 +40,28 @@ struct spacemit_gpio_bank {
>
>  struct spacemit_gpio {
>         struct device *dev;
> +       const struct spacemit_gpio_data *data;
>         struct spacemit_gpio_bank sgb[SPACEMIT_NR_BANKS];
>  };
>
> +struct spacemit_gpio_reg_offsets {
> +       u32 gplr;      /* port level - R */
> +       u32 gpdr;      /* port direction - R/W */
> +       u32 gpsr;      /* port set - W */
> +       u32 gpcr;      /* port clear - W */
> +       u32 grer;      /* port rising edge R/W */
> +       u32 gfer;      /* port falling edge R/W */
> +       u32 gedr;      /* edge detect status - R/W1C */
> +       u32 gsdr;      /* (set) direction - W */
> +       u32 gcdr;      /* (clear) direction - W */
> +       u32 gsrer;     /* (set) rising edge detect enable - W */
> +       u32 gcrer;     /* (clear) rising edge detect enable - W */
> +       u32 gsfer;     /* (set) falling edge detect enable - W */
> +       u32 gcfer;     /* (clear) falling edge detect enable - W */
> +       u32 gapmask;   /* interrupt mask , 0 disable, 1 enable - R/W */
> +       u32 gcpmask;   /* interrupt mask for K3 */
> +};
> +
>  static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
>  {
>         return (u32)(gb - gb->sg->sgb);
> @@ -60,13 +70,14 @@ static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
>  static irqreturn_t spacemit_gpio_irq_handler(int irq, void *dev_id)
>  {
>         struct spacemit_gpio_bank *gb = dev_id;
> +       struct spacemit_gpio *sg = gb->sg;
>         unsigned long pending;
>         u32 n, gedr;
>
> -       gedr = readl(gb->base + SPACEMIT_GEDR);
> +       gedr = readl(gb->base + to_spacemit_gpio_regs(sg)->gedr);

Since you're already touching all these register accesses - can you
maybe provide dedicated wrapper functions around readl()/writel() and
avoid any file-wide changes in the future if anything requires further
modification?

Bart
Re: [PATCH 2/2] gpio: spacemit: Add GPIO support for K3 SoC
Posted by Yixun Lan 1 month, 1 week ago
Hi Bart,

On 12:10 Fri 02 Jan     , Bartosz Golaszewski wrote:
> On Mon, Dec 29, 2025 at 1:47 PM Yixun Lan <dlan@gentoo.org> wrote:
> >
> > SpacemiT K3 SoC has changed gpio register layout while comparing
> > with previous generation, the register offset and bank offset
> > need to be adjusted, introduce a compatible data to extend the
> > driver to support this.
> >
> > Signed-off-by: Yixun Lan <dlan@gentoo.org>
> > ---
> >  drivers/gpio/gpio-spacemit-k1.c | 150 ++++++++++++++++++++++++++++------------
> >  1 file changed, 106 insertions(+), 44 deletions(-)
> >
> > diff --git a/drivers/gpio/gpio-spacemit-k1.c b/drivers/gpio/gpio-spacemit-k1.c
> > index eb66a15c002f..02cc5c11b617 100644
> > --- a/drivers/gpio/gpio-spacemit-k1.c
> > +++ b/drivers/gpio/gpio-spacemit-k1.c
> > @@ -15,28 +15,19 @@
> >  #include <linux/platform_device.h>
> >  #include <linux/seq_file.h>
> >
> > -/* register offset */
> > -#define SPACEMIT_GPLR          0x00 /* port level - R */
> > -#define SPACEMIT_GPDR          0x0c /* port direction - R/W */
> > -#define SPACEMIT_GPSR          0x18 /* port set - W */
> > -#define SPACEMIT_GPCR          0x24 /* port clear - W */
> > -#define SPACEMIT_GRER          0x30 /* port rising edge R/W */
> > -#define SPACEMIT_GFER          0x3c /* port falling edge R/W */
> > -#define SPACEMIT_GEDR          0x48 /* edge detect status - R/W1C */
> > -#define SPACEMIT_GSDR          0x54 /* (set) direction - W */
> > -#define SPACEMIT_GCDR          0x60 /* (clear) direction - W */
> > -#define SPACEMIT_GSRER         0x6c /* (set) rising edge detect enable - W */
> > -#define SPACEMIT_GCRER         0x78 /* (clear) rising edge detect enable - W */
> > -#define SPACEMIT_GSFER         0x84 /* (set) falling edge detect enable - W */
> > -#define SPACEMIT_GCFER         0x90 /* (clear) falling edge detect enable - W */
> > -#define SPACEMIT_GAPMASK       0x9c /* interrupt mask , 0 disable, 1 enable - R/W */
> > -
> >  #define SPACEMIT_NR_BANKS              4
> >  #define SPACEMIT_NR_GPIOS_PER_BANK     32
> >
> >  #define to_spacemit_gpio_bank(x) container_of((x), struct spacemit_gpio_bank, gc)
> > +#define to_spacemit_gpio_regs(sg) ((sg)->data->reg_offsets)
> >
> >  struct spacemit_gpio;
> > +struct spacemit_gpio_reg_offsets;
> 
> Why not move this structure here instead and avoid the forward declaration?
> 
sure, I will do

> > +
> > +struct spacemit_gpio_data {
> > +       struct spacemit_gpio_reg_offsets *reg_offsets;
> > +       u32 bank_offsets[4];
> > +};
> >
> >  struct spacemit_gpio_bank {
> >         struct gpio_generic_chip chip;
> > @@ -49,9 +40,28 @@ struct spacemit_gpio_bank {
> >
> >  struct spacemit_gpio {
> >         struct device *dev;
> > +       const struct spacemit_gpio_data *data;
> >         struct spacemit_gpio_bank sgb[SPACEMIT_NR_BANKS];
> >  };
> >
> > +struct spacemit_gpio_reg_offsets {
> > +       u32 gplr;      /* port level - R */
> > +       u32 gpdr;      /* port direction - R/W */
> > +       u32 gpsr;      /* port set - W */
> > +       u32 gpcr;      /* port clear - W */
> > +       u32 grer;      /* port rising edge R/W */
> > +       u32 gfer;      /* port falling edge R/W */
> > +       u32 gedr;      /* edge detect status - R/W1C */
> > +       u32 gsdr;      /* (set) direction - W */
> > +       u32 gcdr;      /* (clear) direction - W */
> > +       u32 gsrer;     /* (set) rising edge detect enable - W */
> > +       u32 gcrer;     /* (clear) rising edge detect enable - W */
> > +       u32 gsfer;     /* (set) falling edge detect enable - W */
> > +       u32 gcfer;     /* (clear) falling edge detect enable - W */
> > +       u32 gapmask;   /* interrupt mask , 0 disable, 1 enable - R/W */
> > +       u32 gcpmask;   /* interrupt mask for K3 */
> > +};
> > +
> >  static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
> >  {
> >         return (u32)(gb - gb->sg->sgb);
> > @@ -60,13 +70,14 @@ static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
> >  static irqreturn_t spacemit_gpio_irq_handler(int irq, void *dev_id)
> >  {
> >         struct spacemit_gpio_bank *gb = dev_id;
> > +       struct spacemit_gpio *sg = gb->sg;
> >         unsigned long pending;
> >         u32 n, gedr;
> >
> > -       gedr = readl(gb->base + SPACEMIT_GEDR);
> > +       gedr = readl(gb->base + to_spacemit_gpio_regs(sg)->gedr);
> 
> Since you're already touching all these register accesses - can you
> maybe provide dedicated wrapper functions around readl()/writel() and
> avoid any file-wide changes in the future if anything requires further
> modification?
> 
can you elaborate a bit further on this?
I don't get how a wrapper helper could help to avoid file-wide changes..

-- 
Yixun Lan (dlan)
Re: [PATCH 2/2] gpio: spacemit: Add GPIO support for K3 SoC
Posted by Yixun Lan 1 month, 1 week ago
Hi bart,

On 19:36 Fri 02 Jan     , Yixun Lan wrote:
> Hi Bart,
> 
> On 12:10 Fri 02 Jan     , Bartosz Golaszewski wrote:
> > On Mon, Dec 29, 2025 at 1:47 PM Yixun Lan <dlan@gentoo.org> wrote:
> > >
> > > SpacemiT K3 SoC has changed gpio register layout while comparing
> > > with previous generation, the register offset and bank offset
> > > need to be adjusted, introduce a compatible data to extend the
> > > driver to support this.
> > >
> > > Signed-off-by: Yixun Lan <dlan@gentoo.org>
> > > ---
> > >  drivers/gpio/gpio-spacemit-k1.c | 150 ++++++++++++++++++++++++++++------------
> > >  1 file changed, 106 insertions(+), 44 deletions(-)
> > >
> > > diff --git a/drivers/gpio/gpio-spacemit-k1.c b/drivers/gpio/gpio-spacemit-k1.c
> > > index eb66a15c002f..02cc5c11b617 100644
> > > --- a/drivers/gpio/gpio-spacemit-k1.c
> > > +++ b/drivers/gpio/gpio-spacemit-k1.c
> > > @@ -15,28 +15,19 @@
> > >  #include <linux/platform_device.h>
> > >  #include <linux/seq_file.h>
> > >
[snip]...
> > >  static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
> > >  {
> > >         return (u32)(gb - gb->sg->sgb);
> > > @@ -60,13 +70,14 @@ static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
> > >  static irqreturn_t spacemit_gpio_irq_handler(int irq, void *dev_id)
> > >  {
> > >         struct spacemit_gpio_bank *gb = dev_id;
> > > +       struct spacemit_gpio *sg = gb->sg;
> > >         unsigned long pending;
> > >         u32 n, gedr;
> > >
> > > -       gedr = readl(gb->base + SPACEMIT_GEDR);
> > > +       gedr = readl(gb->base + to_spacemit_gpio_regs(sg)->gedr);
> > 
> > Since you're already touching all these register accesses - can you
> > maybe provide dedicated wrapper functions around readl()/writel() and
> > avoid any file-wide changes in the future if anything requires further
> > modification?
> > 
> can you elaborate a bit further on this?
> I don't get how a wrapper helper could help to avoid file-wide changes..
> 
here is my attempt to solve this, define a macro to register address:

#define to_spacemit_gpio_regs(gb) ((gb)->sg->data->reg_offsets)

#define SPACEMIT_GEDR(gb)      ((gb)->base + to_spacemit_gpio_regs(gb)->gedr)

	gedr = readl(SPACEMIT_GEDR(gb));

please let me know if this follow your suggestion or not

-- 
Yixun Lan (dlan)
Re: [PATCH 2/2] gpio: spacemit: Add GPIO support for K3 SoC
Posted by Bartosz Golaszewski 1 month, 1 week ago
On Fri, 2 Jan 2026 13:20:45 +0100, Yixun Lan <dlan@gentoo.org> said:
> Hi bart,
>
> On 19:36 Fri 02 Jan     , Yixun Lan wrote:
>> Hi Bart,
>>
>> On 12:10 Fri 02 Jan     , Bartosz Golaszewski wrote:
>> > On Mon, Dec 29, 2025 at 1:47 PM Yixun Lan <dlan@gentoo.org> wrote:
>> > >
>> > > SpacemiT K3 SoC has changed gpio register layout while comparing
>> > > with previous generation, the register offset and bank offset
>> > > need to be adjusted, introduce a compatible data to extend the
>> > > driver to support this.
>> > >
>> > > Signed-off-by: Yixun Lan <dlan@gentoo.org>
>> > > ---
>> > >  drivers/gpio/gpio-spacemit-k1.c | 150 ++++++++++++++++++++++++++++------------
>> > >  1 file changed, 106 insertions(+), 44 deletions(-)
>> > >
>> > > diff --git a/drivers/gpio/gpio-spacemit-k1.c b/drivers/gpio/gpio-spacemit-k1.c
>> > > index eb66a15c002f..02cc5c11b617 100644
>> > > --- a/drivers/gpio/gpio-spacemit-k1.c
>> > > +++ b/drivers/gpio/gpio-spacemit-k1.c
>> > > @@ -15,28 +15,19 @@
>> > >  #include <linux/platform_device.h>
>> > >  #include <linux/seq_file.h>
>> > >
> [snip]...
>> > >  static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
>> > >  {
>> > >         return (u32)(gb - gb->sg->sgb);
>> > > @@ -60,13 +70,14 @@ static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
>> > >  static irqreturn_t spacemit_gpio_irq_handler(int irq, void *dev_id)
>> > >  {
>> > >         struct spacemit_gpio_bank *gb = dev_id;
>> > > +       struct spacemit_gpio *sg = gb->sg;
>> > >         unsigned long pending;
>> > >         u32 n, gedr;
>> > >
>> > > -       gedr = readl(gb->base + SPACEMIT_GEDR);
>> > > +       gedr = readl(gb->base + to_spacemit_gpio_regs(sg)->gedr);
>> >
>> > Since you're already touching all these register accesses - can you
>> > maybe provide dedicated wrapper functions around readl()/writel() and
>> > avoid any file-wide changes in the future if anything requires further
>> > modification?
>> >
>> can you elaborate a bit further on this?
>> I don't get how a wrapper helper could help to avoid file-wide changes..
>>
> here is my attempt to solve this, define a macro to register address:
>
> #define to_spacemit_gpio_regs(gb) ((gb)->sg->data->reg_offsets)
>
> #define SPACEMIT_GEDR(gb)      ((gb)->base + to_spacemit_gpio_regs(gb)->gedr)
>
> 	gedr = readl(SPACEMIT_GEDR(gb));
>
> please let me know if this follow your suggestion or not
>
> --
> Yixun Lan (dlan)
>

I was thinking more of something like this:

enum spacemit_gpio_registers {
	SPACEMIT_GPLR,
	SPACEMIT_GPDR,
	...
};

static const unsigned int spacemit_gpio_k1_offsets = {
	[SPACEMIT_GPLR] = 0x00,
	[SPACEMIT_GPDR] = 0x0c,
	...
};

static const unsigned int spacemit_gpio_k3_offsets = ...

struct spacemit_gpio_data {
	const unsigned int *offsets;
	u32 bank_offsets[4];
};

static void spacemit_gpio_write(struct spacemit_gpio_bank *gb,
				enum spacemit_gpio_registers reg, u32 val)
{
	writel(val, gb->base + gb->data->offsets[reg]);
}

Bart
Re: [PATCH 2/2] gpio: spacemit: Add GPIO support for K3 SoC
Posted by Yixun Lan 1 month, 1 week ago
Hi Bartosz,

On 08:38 Fri 02 Jan     , Bartosz Golaszewski wrote:
> On Fri, 2 Jan 2026 13:20:45 +0100, Yixun Lan <dlan@gentoo.org> said:
> > Hi bart,
> >
> > On 19:36 Fri 02 Jan     , Yixun Lan wrote:
> >> Hi Bart,
> >>
> >> On 12:10 Fri 02 Jan     , Bartosz Golaszewski wrote:
> >> > On Mon, Dec 29, 2025 at 1:47 PM Yixun Lan <dlan@gentoo.org> wrote:
> >> > >
> >> > > SpacemiT K3 SoC has changed gpio register layout while comparing
> >> > > with previous generation, the register offset and bank offset
> >> > > need to be adjusted, introduce a compatible data to extend the
> >> > > driver to support this.
> >> > >
> >> > > Signed-off-by: Yixun Lan <dlan@gentoo.org>
> >> > > ---
> >> > >  drivers/gpio/gpio-spacemit-k1.c | 150 ++++++++++++++++++++++++++++------------
> >> > >  1 file changed, 106 insertions(+), 44 deletions(-)
> >> > >
> >> > > diff --git a/drivers/gpio/gpio-spacemit-k1.c b/drivers/gpio/gpio-spacemit-k1.c
> >> > > index eb66a15c002f..02cc5c11b617 100644
> >> > > --- a/drivers/gpio/gpio-spacemit-k1.c
> >> > > +++ b/drivers/gpio/gpio-spacemit-k1.c
> >> > > @@ -15,28 +15,19 @@
> >> > >  #include <linux/platform_device.h>
> >> > >  #include <linux/seq_file.h>
> >> > >
> > [snip]...
> >> > >  static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
> >> > >  {
> >> > >         return (u32)(gb - gb->sg->sgb);
> >> > > @@ -60,13 +70,14 @@ static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
> >> > >  static irqreturn_t spacemit_gpio_irq_handler(int irq, void *dev_id)
> >> > >  {
> >> > >         struct spacemit_gpio_bank *gb = dev_id;
> >> > > +       struct spacemit_gpio *sg = gb->sg;
> >> > >         unsigned long pending;
> >> > >         u32 n, gedr;
> >> > >
> >> > > -       gedr = readl(gb->base + SPACEMIT_GEDR);
> >> > > +       gedr = readl(gb->base + to_spacemit_gpio_regs(sg)->gedr);
> >> >
> >> > Since you're already touching all these register accesses - can you
> >> > maybe provide dedicated wrapper functions around readl()/writel() and
> >> > avoid any file-wide changes in the future if anything requires further
> >> > modification?
> >> >
> >> can you elaborate a bit further on this?
> >> I don't get how a wrapper helper could help to avoid file-wide changes..
> >>
> > here is my attempt to solve this, define a macro to register address:
> >
> > #define to_spacemit_gpio_regs(gb) ((gb)->sg->data->reg_offsets)
> >
> > #define SPACEMIT_GEDR(gb)      ((gb)->base + to_spacemit_gpio_regs(gb)->gedr)
> >
> > 	gedr = readl(SPACEMIT_GEDR(gb));
> >
> > please let me know if this follow your suggestion or not
> >
> > --
> > Yixun Lan (dlan)
> >
> 
> I was thinking more of something like this:
> 
> enum spacemit_gpio_registers {
> 	SPACEMIT_GPLR,
> 	SPACEMIT_GPDR,
> 	...
> };
> 
> static const unsigned int spacemit_gpio_k1_offsets = {
> 	[SPACEMIT_GPLR] = 0x00,
> 	[SPACEMIT_GPDR] = 0x0c,
> 	...
> };
> 
> static const unsigned int spacemit_gpio_k3_offsets = ...
> 
> struct spacemit_gpio_data {
> 	const unsigned int *offsets;
> 	u32 bank_offsets[4];
> };
> 
> static void spacemit_gpio_write(struct spacemit_gpio_bank *gb,
> 				enum spacemit_gpio_registers reg, u32 val)
> {
> 	writel(val, gb->base + gb->data->offsets[reg]);
> }
> 
Ok, I will implement this, thanks for the detail prototype

-- 
Yixun Lan (dlan)
Re: [PATCH 2/2] gpio: spacemit: Add GPIO support for K3 SoC
Posted by Bartosz Golaszewski 1 month, 1 week ago
On Fri, 2 Jan 2026 12:36:43 +0100, Yixun Lan <dlan@gentoo.org> said:
>
>> >  static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
>> >  {
>> >         return (u32)(gb - gb->sg->sgb);
>> > @@ -60,13 +70,14 @@ static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
>> >  static irqreturn_t spacemit_gpio_irq_handler(int irq, void *dev_id)
>> >  {
>> >         struct spacemit_gpio_bank *gb = dev_id;
>> > +       struct spacemit_gpio *sg = gb->sg;
>> >         unsigned long pending;
>> >         u32 n, gedr;
>> >
>> > -       gedr = readl(gb->base + SPACEMIT_GEDR);
>> > +       gedr = readl(gb->base + to_spacemit_gpio_regs(sg)->gedr);
>>
>> Since you're already touching all these register accesses - can you
>> maybe provide dedicated wrapper functions around readl()/writel() and
>> avoid any file-wide changes in the future if anything requires further
>> modification?
>>
> can you elaborate a bit further on this?
> I don't get how a wrapper helper could help to avoid file-wide changes..
>

Just create functions called "spacemit_gpio_read/write()" that wrap the
readl()/writel() and its arguments.

Like:

static u32 spacemit_gpio_read(struct spacemit_gpio_bank *gb, unsigned long reg)
{
	return readl(gb->base + func_to_convert_reg_enum_to_offset(reg));
}

Looks cleaner at call sites even if it's a bit more complex. Just create an
array mapping the register enum to offset and assign it to platform data.

Bart