U-Boot Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Yixun Lan <dlan@kernel.org>
To: u-boot-spacemit@groups.io, u-boot@lists.u-boot-project.org
Cc: Eric Chung <eric.chung@riscstar.com>,
	 Raymond Mao <raymond.mao@riscstar.com>,
	 Junhui Liu <junhui.liu@pigmoral.tech>,
	Tom Rini <trini@konsulko.com>,  Yixun Lan <dlan@kernel.org>
Subject: [PATCH v2 1/2] pinctrl: spacemit: configure drive strength based on power source
Date: Wed, 23 Sep 2026 13:06:52 +0000	[thread overview]
Message-ID: <20260923-01-k3-pinctrl-support-v2-1-e76a917ee252@kernel.org> (raw)
In-Reply-To: <20260923-01-k3-pinctrl-support-v2-0-e76a917ee252@kernel.org>

SpacemiT external-voltage pins use different drive strength tables for
1.8V and 3.3V. The selected power source therefore needs to be known
before programming the drive strength. But pinctrl_generic_set_state()
applies pin configuration properties according device tree order, which
lead to configure drive-strength before power-source.

Add a vendor specific set_state() callback that applies the supported
properties in a fixed order, ensuring that power-source is configured
before setting drive strength.

Signed-off-by: Yixun Lan <dlan@kernel.org>
---
 drivers/pinctrl/spacemit/pinctrl-k1.c | 166 +++++++++++++++++++++++++++-------
 1 file changed, 131 insertions(+), 35 deletions(-)

diff --git a/drivers/pinctrl/spacemit/pinctrl-k1.c b/drivers/pinctrl/spacemit/pinctrl-k1.c
index 7d801f08d20..ff0fa3a4b18 100644
--- a/drivers/pinctrl/spacemit/pinctrl-k1.c
+++ b/drivers/pinctrl/spacemit/pinctrl-k1.c
@@ -441,8 +441,8 @@ static const struct pinconf_param spacemit_pinconf_params[] = {
 	{ "bias-disable",	PIN_CONFIG_BIAS_DISABLE,	0 },
 	{ "bias-pull-down",	PIN_CONFIG_BIAS_PULL_DOWN,	1 },
 	{ "bias-pull-up",	PIN_CONFIG_BIAS_PULL_UP,	1 },
-	{ "drive-strength",	PIN_CONFIG_DRIVE_STRENGTH,	U32_MAX },
 	{ "power-source",	PIN_CONFIG_POWER_SOURCE,	U32_MAX },
+	{ "drive-strength",	PIN_CONFIG_DRIVE_STRENGTH,	U32_MAX },
 };
 
 static void spacemit_set_io_power_domain(struct udevice *dev,
@@ -474,17 +474,60 @@ static void spacemit_set_io_power_domain(struct udevice *dev,
 	writel(val, priv->regs + IO_PWR_DOMAIN_OFFSET + offset);
 }
 
+static enum spacemit_pin_io_type spacemit_get_pin_io_type(struct spacemit_pinctrl_priv *priv,
+							  unsigned int pin)
+{
+	int i;
+
+	for (i = 0; i < priv->nr_io_pins; i++)
+		if (priv->io_pins[i].pin == pin &&
+		    priv->io_pins[i].io_type != IO_TYPE_EXTERNAL)
+			return priv->io_pins[i].io_type;
+
+	return IO_TYPE_1V8;
+}
+
+static int spacemit_set_pin_power_source(struct udevice *dev, unsigned int pin,
+					 unsigned int power_source)
+{
+	struct spacemit_pinctrl_priv *priv = dev_get_priv(dev);
+	enum spacemit_pin_io_type io_type;
+	int i;
+
+	switch (power_source) {
+	case PIN_POWER_STATE_1V8:
+		io_type = IO_TYPE_1V8;
+		break;
+	case PIN_POWER_STATE_3V3:
+		io_type = IO_TYPE_3V3;
+		break;
+	default:
+		dev_err(dev, "Invalid power source (%d)\n", power_source);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < priv->nr_io_pins; i++) {
+		if (priv->io_pins[i].pin != pin)
+			continue;
+
+		priv->io_pins[i].io_type = io_type;
+		spacemit_set_io_power_domain(dev, pin, io_type);
+
+		return 0;
+	}
+
+	return 0;
+}
+
 static int spacemit_pinconf_set(struct udevice *dev, unsigned int pin_selector,
 				unsigned int param, unsigned int argument)
 {
-	struct spacemit_pinctrl_data *data;
 	struct spacemit_pinctrl_priv *priv = dev_get_priv(dev);
+	struct spacemit_pinctrl_data *data;
+	enum spacemit_pin_io_type io_type;
 	void __iomem *addr;
 	u32 mask;
-	unsigned int io_type;
 	u8 ds;
-	bool found;
-	int i;
 
 	data = (struct spacemit_pinctrl_data *)dev_get_driver_data(dev);
 	if (!data || !data->pin_to_reg)
@@ -504,14 +547,7 @@ static int spacemit_pinconf_set(struct udevice *dev, unsigned int pin_selector,
 		clrsetbits_le32(addr, mask, PAD_PULLUP | PAD_PULL_EN);
 		break;
 	case PIN_CONFIG_DRIVE_STRENGTH:
-		io_type = IO_TYPE_1V8;
-		for (i = 0; i < priv->nr_io_pins; i++) {
-			if (priv->io_pins[i].pin != pin_selector)
-				continue;
-			if (priv->io_pins[i].io_type != IO_TYPE_EXTERNAL)
-				io_type = priv->io_pins[i].io_type;
-			break;
-		}
+		io_type = spacemit_get_pin_io_type(priv, pin_selector);
 		if (io_type != IO_TYPE_3V3 && io_type != IO_TYPE_1V8) {
 			dev_err(dev, "Invalid IO type (%d)\n", io_type);
 			return -EINVAL;
@@ -520,30 +556,90 @@ static int spacemit_pinconf_set(struct udevice *dev, unsigned int pin_selector,
 		clrsetbits_le32(addr, PAD_DRIVE, FIELD_PREP(PAD_DRIVE, ds));
 		break;
 	case PIN_CONFIG_POWER_SOURCE:
-		for (i = 0, found = false; i < priv->nr_io_pins; i++) {
-			if (priv->io_pins[i].pin != pin_selector)
-				continue;
-			if (argument == PIN_POWER_STATE_3V3) {
-				priv->io_pins[i].io_type = IO_TYPE_3V3;
-				found = true;
-			} else if (argument == PIN_POWER_STATE_1V8) {
-				priv->io_pins[i].io_type = IO_TYPE_1V8;
-				found = true;
-			}
-			break;
-		}
-		if (!found && argument != PIN_POWER_STATE_1V8 &&
-		    argument != PIN_POWER_STATE_3V3) {
-			dev_err(dev, "Invalid power source (%d)\n", argument);
-			return -EINVAL;
-		}
-		if (found)
-			spacemit_set_io_power_domain(dev, pin_selector,
-						     priv->io_pins[i].io_type);
-		break;
+		return spacemit_set_pin_power_source(dev, pin_selector, argument);
 	default:
 		return -EOPNOTSUPP;
 	}
+
+	return 0;
+}
+
+static int spacemit_pinctrl_apply_group(struct udevice *dev,
+					struct udevice *config)
+{
+	const struct pinconf_param *param;
+	const void *value;
+	u32 argument;
+	u32 pinmux;
+	int npins;
+	int len;
+	int ret;
+	int i, j;
+
+	ret = dev_read_size(config, "pinmux");
+	if (ret == -EINVAL)
+		return 0;
+	if (ret < 0 || ret % sizeof(pinmux))
+		return -EINVAL;
+	npins = ret / sizeof(pinmux);
+
+	for (i = 0; i < npins; i++) {
+		ret = dev_read_u32_index(config, "pinmux", i, &pinmux);
+		if (ret)
+			return ret;
+
+		ret = spacemit_pinmux_set(dev, spacemit_dt_get_pin(pinmux),
+					  spacemit_dt_get_pin_mux(pinmux));
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(spacemit_pinconf_params); i++) {
+		param = &spacemit_pinconf_params[i];
+		value = dev_read_prop(config, param->property, &len);
+		if (!value)
+			continue;
+
+		if (len >= sizeof(fdt32_t))
+			argument = fdt32_to_cpu(*(const fdt32_t *)value);
+		else
+			argument = param->default_value;
+
+		for (j = 0; j < npins; j++) {
+			ret = dev_read_u32_index(config, "pinmux", j,
+						 &pinmux);
+			if (ret)
+				return ret;
+
+			ret = spacemit_pinconf_set(dev,
+						   spacemit_dt_get_pin(pinmux),
+						   param->param, argument);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int spacemit_pinctrl_set_state(struct udevice *dev,
+				      struct udevice *config)
+{
+	struct udevice *child;
+	int ret;
+
+	ret = spacemit_pinctrl_apply_group(dev, config);
+	if (ret)
+		return ret;
+
+	for (device_find_first_child(config, &child);
+	     child;
+	     device_find_next_child(&child)) {
+		ret = spacemit_pinctrl_apply_group(dev, child);
+		if (ret)
+			return ret;
+	}
+
 	return 0;
 }
 
@@ -625,7 +721,7 @@ static const struct pinctrl_ops spacemit_pinctrl_ops = {
 	.get_pin_name		= spacemit_get_pin_name,
 	.get_functions_count	= spacemit_get_functions_count,
 	.get_pin_muxing		= spacemit_get_pin_muxing,
-	.set_state		= pinctrl_generic_set_state,
+	.set_state		= spacemit_pinctrl_set_state,
 	.gpio_request_enable	= spacemit_pinctrl_request_gpio,
 	.gpio_disable_free	= spacemit_pinctrl_free_gpio,
 	.pinmux_set		= spacemit_pinmux_set,

-- 
2.55.0


  reply	other threads:[~2026-09-23 13:07 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-23 13:06 [PATCH v2 0/2] riscv: spacemit: add pinctrl support for K3 SoC Yixun Lan
2026-09-23 13:06 ` Yixun Lan [this message]
2026-09-23 13:06 ` [PATCH v2 2/2] pinctrl: spacemit: k3: add K3 pin support Yixun Lan
2026-10-07  9:12   ` E Shattow
2026-09-29 10:12 ` (subset) [PATCH v2 0/2] riscv: spacemit: add pinctrl support for K3 SoC Yixun Lan
2026-10-09  7:24 ` Yixun Lan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260923-01-k3-pinctrl-support-v2-1-e76a917ee252@kernel.org \
    --to=dlan@kernel.org \
    --cc=eric.chung@riscstar.com \
    --cc=junhui.liu@pigmoral.tech \
    --cc=raymond.mao@riscstar.com \
    --cc=trini@konsulko.com \
    --cc=u-boot-spacemit@groups.io \
    --cc=u-boot@lists.u-boot-project.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox