[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]>