[PATCH] gpio: spacemit: add support for K3 SoC

Yixun Lan <[email protected]>
Newsgroups gmane.comp.boot-loaders.u-boot
Message-ID <20260822-01-gpio-pinctrl-support-v1-1-6be2f4c71c5d__36900.9090981976$1787398258$gmane$org@kernel.org>
Based on upstream Linux:
  da64eb51595b ("gpio: spacemit: Add GPIO support for K3 SoC")

SpacemiT K3 SoC uses different GPIO register and bank layout compared
to old K1 generation. Refactor the driver by moving hard-coded register
offsets into per-SoC tables and locating them via driver data.

Signed-off-by: Yixun Lan <[email protected]>
---
 drivers/gpio/Kconfig         | 11 ++---
 drivers/gpio/spacemit_gpio.c | 97 ++++++++++++++++++++++++++++++--------------
 2 files changed, 72 insertions(+), 36 deletions(-)

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index a11f3043670..78b4b45be87 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -450,12 +450,13 @@ config SANDBOX_GPIO_COUNT
 	  Select a suitable value depending on your needs.
 
 config SPACEMIT_GPIO
-	bool "Spacemit K1 GPIO driver"
-	depends on DM_GPIO && TARGET_SPACEMIT_K1
+	bool "Spacemit K1/K3 GPIO driver"
+	depends on DM_GPIO && (TARGET_SPACEMIT_K1 || TARGET_SPACEMIT_K3)
 	help
-	  Support the GPIO device in Spacemit SoCs. The GPIOs are arranged
-	  into a number of banks (different for each SoC type) each with 32
-	  GPIOs.
+	  Support the GPIO device in Spacemit K1 and K3 SoCs. The GPIOs are
+	  arranged into a number of banks (different for each SoC type) each
+	  with 32 GPIOs.
+
 
 config SUNXI_GPIO
 	bool "Allwinner GPIO driver"
diff --git a/drivers/gpio/spacemit_gpio.c b/drivers/gpio/spacemit_gpio.c
index de71880df15..e0716a84dfc 100644
--- a/drivers/gpio/spacemit_gpio.c
+++ b/drivers/gpio/spacemit_gpio.c
@@ -19,37 +19,28 @@
 #define GPIO_TO_BANK(pin)	((pin) / GPIO_BANK_SIZE)
 #define GPIO_TO_BIT(pin)	((pin) % GPIO_BANK_SIZE)
 
-static inline int gpio_to_reg_offset(unsigned int pin)
-{
-	unsigned int bank = GPIO_TO_BANK(pin);
-
-	if (bank == 0)
-		return 0;
-	else if (bank == 1)
-		return 4;
-	else if (bank == 2)
-		return 8;
-	else if (bank == 3)
-		return 0x100;
-	log_warning("Use default GPIO bank for an invalid GPIO[%d].\n", pin);
-	return 0;
-}
-
-#define REG_PLR(pin)		(0x00 + gpio_to_reg_offset(pin))
-#define REG_PDR(pin)		(0x0c + gpio_to_reg_offset(pin))
-#define REG_PSR(pin)		(0x18 + gpio_to_reg_offset(pin))
-#define REG_PCR(pin)		(0x24 + gpio_to_reg_offset(pin))
-#define REG_SDR(pin)		(0x54 + gpio_to_reg_offset(pin))
-#define REG_CDR(pin)		(0x60 + gpio_to_reg_offset(pin))
+#define to_spacemit_gpio_regs(priv, reg)	((priv)->data->offsets[reg])
+
+enum spacemit_gpio_registers {
+	SPACEMIT_GPLR,
+	SPACEMIT_GPDR,
+	SPACEMIT_GPSR,
+	SPACEMIT_GPCR,
+	SPACEMIT_GSDR,
+	SPACEMIT_GCDR,
+};
 
 struct spacemit_gpio_data {
 	u16	gpio_base;
 	u16	gpio_count;
 	u8	num_banks;
+	const u16	*bank_offsets;
+	const u16	*offsets;
 };
 
 struct spacemit_gpio_priv {
 	void __iomem *regs;
+	const struct spacemit_gpio_data *data;
 };
 
 static int spacemit_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
@@ -85,10 +76,12 @@ static int spacemit_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
 static int spacemit_gpio_get_value(struct udevice *dev, unsigned int offset)
 {
 	struct spacemit_gpio_priv *priv = dev_get_priv(dev);
-	void __iomem *addr;
+	void __iomem *base, *addr;
 	u32 value, mask;
 
-	addr = priv->regs + REG_PLR(offset);
+	base = priv->regs + priv->data->bank_offsets[GPIO_TO_BANK(offset)];
+
+	addr = base + to_spacemit_gpio_regs(priv, SPACEMIT_GPLR);
 	value = readl(addr);
 	mask = 1 << GPIO_TO_BIT(offset);
 	return !!(value & mask);
@@ -97,10 +90,12 @@ static int spacemit_gpio_get_value(struct udevice *dev, unsigned int offset)
 static int spacemit_gpio_get_function(struct udevice *dev, unsigned int offset)
 {
 	struct spacemit_gpio_priv *priv = dev_get_priv(dev);
-	void __iomem *addr;
+	void __iomem *base, *addr;
 	u32 value, mask;
 
-	addr = priv->regs + REG_PDR(offset);
+	base = priv->regs + priv->data->bank_offsets[GPIO_TO_BANK(offset)];
+
+	addr = base + to_spacemit_gpio_regs(priv, SPACEMIT_GPDR);
 	value = readl(addr);
 	mask = 1 << GPIO_TO_BIT(offset);
 	if (value & mask)
@@ -130,23 +125,25 @@ static int spacemit_gpio_set_flags(struct udevice *dev, unsigned int offset,
 				   ulong flags)
 {
 	struct spacemit_gpio_priv *priv = dev_get_priv(dev);
-	void __iomem *addr;
+	void __iomem *base, *addr;
 	int value;
 
+	base = priv->regs + priv->data->bank_offsets[GPIO_TO_BANK(offset)];
+
 	value = (flags & GPIOD_IS_OUT_ACTIVE) ? 1 : 0;
 	if (flags & GPIOD_IS_IN) {
-		addr = priv->regs + REG_CDR(offset);
+		addr = base + to_spacemit_gpio_regs(priv, SPACEMIT_GCDR);
 		writel(1 << GPIO_TO_BIT(offset), addr);
 	}
 	if (flags & GPIOD_IS_OUT) {
 		if (value) {
-			addr = priv->regs + REG_PSR(offset);
+			addr = base + to_spacemit_gpio_regs(priv, SPACEMIT_GPSR);
 			writel(1 << GPIO_TO_BIT(offset), addr);
 		} else {
-			addr = priv->regs + REG_PCR(offset);
+			addr = base + to_spacemit_gpio_regs(priv, SPACEMIT_GPCR);
 			writel(1 << GPIO_TO_BIT(offset), addr);
 		}
-		addr = priv->regs + REG_SDR(offset);
+		addr = base + to_spacemit_gpio_regs(priv, SPACEMIT_GSDR);
 		writel(1 << GPIO_TO_BIT(offset), addr);
 	}
 	return 0;
@@ -207,6 +204,7 @@ static int spacemit_gpio_probe(struct udevice *dev)
 
 	data = (struct spacemit_gpio_data *)dev_get_driver_data(dev);
 	priv = dev_get_priv(dev);
+	priv->data = data;
 	priv->regs = dev_read_addr_ptr(dev);
 	if (!priv->regs) {
 		dev_err(dev, "Fail to get base address\n");
@@ -232,14 +230,51 @@ out:
 	return ret;
 }
 
+static const u16 spacemit_gpio_k1_offsets[] = {
+	[SPACEMIT_GPLR] = 0x00,
+	[SPACEMIT_GPDR] = 0x0c,
+	[SPACEMIT_GPSR] = 0x18,
+	[SPACEMIT_GPCR] = 0x24,
+	[SPACEMIT_GSDR] = 0x54,
+	[SPACEMIT_GCDR] = 0x60,
+};
+
+static const u16 spacemit_gpio_k1_bank_offsets[] = {
+	0x0, 0x4, 0x8, 0x100,
+};
+
+static const u16 spacemit_gpio_k3_offsets[] = {
+	[SPACEMIT_GPLR] = 0x00,
+	[SPACEMIT_GPDR] = 0x04,
+	[SPACEMIT_GPSR] = 0x08,
+	[SPACEMIT_GPCR] = 0x0c,
+	[SPACEMIT_GSDR] = 0x1c,
+	[SPACEMIT_GCDR] = 0x20,
+};
+
+static const u16 spacemit_gpio_k3_bank_offsets[] = {
+	0x0, 0x40, 0x80, 0x100,
+};
+
 static const struct spacemit_gpio_data k1_gpio_data = {
 	.num_banks	= 4,
 	.gpio_count	= 128,
 	.gpio_base	= 0,
+	.bank_offsets	= spacemit_gpio_k1_bank_offsets,
+	.offsets	= spacemit_gpio_k1_offsets,
+};
+
+static const struct spacemit_gpio_data k3_gpio_data = {
+	.num_banks	= 4,
+	.gpio_count	= 128,
+	.gpio_base	= 0,
+	.bank_offsets	= spacemit_gpio_k3_bank_offsets,
+	.offsets	= spacemit_gpio_k3_offsets,
 };
 
 static const struct udevice_id spacemit_gpio_ids[] = {
 	{ .compatible = "spacemit,k1-gpio", .data = (uintptr_t)&k1_gpio_data, },
+	{ .compatible = "spacemit,k3-gpio", .data = (uintptr_t)&k3_gpio_data, },
 	{ /* sentinel */ }
 };
 

---
base-commit: 36c377b9859ffb53eb1e39ea31e8d96d1e0fe1e5
change-id: 20260722-01-gpio-pinctrl-support-87d7b153599b

Best regards,
--  
Yixun Lan <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.