From: Billy Tsai <billy_tsai@aspeedtech.com>
To: Tony Lindgren <tony@atomide.com>,
Haojian Zhuang <haojian.zhuang@linaro.org>,
Linus Walleij <linusw@kernel.org>
Cc: <linux-arm-kernel@lists.infradead.org>,
<linux-omap@vger.kernel.org>, <linux-gpio@vger.kernel.org>,
<linux-kernel@vger.kernel.org>, <andrew@codeconstruct.com.au>,
<BMC-SW@aspeedtech.com>, Billy Tsai <billy_tsai@aspeedtech.com>
Subject: [PATCH v2 1/3] pinctrl: single: add per-pin binding support for bit-per-mux
Date: Fri, 23 Jan 2026 11:41:23 +0800 [thread overview]
Message-ID: <20260123-upstream_pinctrl_single-v2-1-40f8063cc5a2@aspeedtech.com> (raw)
In-Reply-To: <20260123-upstream_pinctrl_single-v2-0-40f8063cc5a2@aspeedtech.com>
Add support for binding where bit-per-mux users specify pins as
<pin_index func_sel> pairs. Prefer explicit bits binding when present,
but fall back to the new per-pin binding for improved flexibility.
This approach is intended to adapt to hardware with a regular register
layout, where pin functions are arranged with a fixed stride. For example,
the function of pin 0 is controlled by bits [3:0] at offset 0, the
function of pin 1 by bits [7:4] at the same offset, and so on.
Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
drivers/pinctrl/pinctrl-single.c | 132 +++++++++++++++++++++++++++++----------
1 file changed, 100 insertions(+), 32 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 998f23d6c317..757c22cc09f3 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -1041,29 +1041,81 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
break;
}
- offset = pinctrl_spec.args[0];
- vals[found].reg = pcs->base + offset;
+ /*
+ * For legacy (non bit-per-mux) users the first cell is the
+ * register offset and the second (and optional third) cell is
+ * the value to be written.
+ *
+ * For bit-per-mux users we want a simpler binding where the
+ * first cell is the pin index and the second cell is the
+ * function selector. Translate that into register offset,
+ * value and mask here so the rest of the driver can stay
+ * Register based.
+ */
+ if (!pcs->bits_per_mux) {
+ offset = pinctrl_spec.args[0];
+ vals[found].reg = pcs->base + offset;
- switch (pinctrl_spec.args_count) {
- case 2:
- vals[found].val = pinctrl_spec.args[1];
- break;
- case 3:
- vals[found].val = (pinctrl_spec.args[1] | pinctrl_spec.args[2]);
- break;
- }
+ switch (pinctrl_spec.args_count) {
+ case 2:
+ vals[found].val = pinctrl_spec.args[1];
+ break;
+ case 3:
+ vals[found].val = (pinctrl_spec.args[1] |
+ pinctrl_spec.args[2]);
+ break;
+ }
- dev_dbg(pcs->dev, "%pOFn index: 0x%x value: 0x%x\n",
- pinctrl_spec.np, offset, vals[found].val);
+ dev_dbg(pcs->dev, "%pOFn offset: 0x%x value: 0x%x\n",
+ pinctrl_spec.np, offset, vals[found].val);
- pin = pcs_get_pin_by_offset(pcs, offset);
- if (pin < 0) {
- dev_err(pcs->dev,
- "could not add functions for %pOFn %ux\n",
- np, offset);
- break;
+ pin = pcs_get_pin_by_offset(pcs, offset);
+ if (pin < 0) {
+ dev_err(pcs->dev,
+ "could not add functions for %pOFn %ux\n",
+ np, offset);
+ break;
+ }
+ pins[found++] = pin;
+ } else {
+ unsigned int pin_index, func_sel;
+ unsigned int shift, mask, val;
+
+ /* Expect <pin_index func_sel> for bit-per-mux users. */
+ if (pinctrl_spec.args_count < 2) {
+ dev_err(pcs->dev,
+ "invalid args_count for bit-per-mux spec: %i\n",
+ pinctrl_spec.args_count);
+ break;
+ }
+
+ pin_index = pinctrl_spec.args[0];
+ func_sel = pinctrl_spec.args[1];
+
+ if (pin_index >= pcs->desc.npins) {
+ dev_err(pcs->dev,
+ "pin index out of range for %pOFn: %u (npins %u)\n",
+ np, pin_index, pcs->desc.npins);
+ break;
+ }
+
+ offset = pcs_pin_reg_offset_get(pcs, pin_index);
+ shift = pcs_pin_shift_reg_get(pcs, pin_index);
+
+ mask = pcs->fmask << shift;
+ val = (func_sel << shift) & mask;
+
+ vals[found].reg = pcs->base + offset;
+ vals[found].val = val;
+ vals[found].mask = mask;
+
+ dev_dbg(pcs->dev,
+ "%pOFn pin: %u offset: 0x%x func: 0x%x val: 0x%x mask: 0x%x\n",
+ pinctrl_spec.np, pin_index, offset,
+ func_sel, val, mask);
+
+ pins[found++] = pin_index;
}
- pins[found++] = pin;
}
pgnames[0] = np->name;
@@ -1280,21 +1332,37 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
}
if (pcs->bits_per_mux) {
- ret = pcs_parse_bits_in_pinctrl_entry(pcs, np_config, map,
- num_maps, pgnames);
- if (ret < 0) {
- dev_err(pcs->dev, "no pins entries for %pOFn\n",
- np_config);
- goto free_pgnames;
+ /*
+ * For bit-per-mux users there are two possible bindings:
+ * - pinctrl-single,bits: offset/value/mask triples
+ * - pinctrl-single,pins: <pin_index func_sel> pairs
+ *
+ * Prefer the explicit bits binding when present so existing
+ * users keep their current behaviour, otherwise fall back
+ * to the per-pin binding.
+ */
+ if (of_find_property(np_config, "pinctrl-single,bits", NULL)) {
+ ret = pcs_parse_bits_in_pinctrl_entry(pcs, np_config,
+ map, num_maps,
+ pgnames);
+ } else if (of_find_property(np_config,
+ "pinctrl-single,pins", NULL)) {
+ ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map,
+ num_maps, pgnames);
+ } else {
+ ret = -EINVAL;
}
} else {
- ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map,
- num_maps, pgnames);
- if (ret < 0) {
- dev_err(pcs->dev, "no pins entries for %pOFn\n",
- np_config);
- goto free_pgnames;
- }
+ if (of_find_property(np_config, "pinctrl-single,pins", NULL))
+ ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map,
+ num_maps, pgnames);
+ else
+ ret = -EINVAL;
+ }
+
+ if (ret < 0) {
+ dev_err(pcs->dev, "no pins entries for %pOFn\n", np_config);
+ goto free_pgnames;
}
return 0;
--
2.34.1
next prev parent reply other threads:[~2026-01-23 3:46 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-23 3:41 [PATCH v2 0/3] pinctrl: single: bit-per-mux DT flexibility, probe robustness, and consistent pinconf offsets Billy Tsai
2026-01-23 3:41 ` Billy Tsai [this message]
2026-01-23 3:41 ` [PATCH v2 2/3] pinctrl: single: Allow probe to continue if mem region busy Billy Tsai
2026-01-23 3:41 ` [PATCH v2 3/3] pinctrl: single: unify pinconf offset mapping with pinmux Billy Tsai
2026-02-03 0:13 ` [PATCH v2 0/3] pinctrl: single: bit-per-mux DT flexibility, probe robustness, and consistent pinconf offsets Linus Walleij
2026-02-04 6:54 ` Billy Tsai
2026-02-06 4:22 ` Tony Lindgren
2026-02-06 7:24 ` Billy Tsai
2026-02-06 11:04 ` Linus Walleij
2026-02-06 11:34 ` Billy Tsai
2026-02-06 12:50 ` Linus Walleij
2026-02-09 2:25 ` Billy Tsai
2026-02-09 9:50 ` Linus Walleij
2026-02-09 14:42 ` Tony Lindgren
2026-02-10 6:28 ` Billy Tsai
2026-02-11 1:48 ` Andrew Jeffery
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=20260123-upstream_pinctrl_single-v2-1-40f8063cc5a2@aspeedtech.com \
--to=billy_tsai@aspeedtech.com \
--cc=BMC-SW@aspeedtech.com \
--cc=andrew@codeconstruct.com.au \
--cc=haojian.zhuang@linaro.org \
--cc=linusw@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-omap@vger.kernel.org \
--cc=tony@atomide.com \
/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