Fishwaldo opened a new pull request, #19871:
URL: https://github.com/apache/nuttx/pull/19871
## Summary
The pinctrl interface is write only: every operation sets a property, and
nothing reports what a pin currently holds. During board bring up the useful
question is the opposite one, and the interface meant to describe pins cannot
answer it.
This adds an optional `get_pad` method that fills a `struct
pinctrl_padinfo_s`
describing one pad, and two callers for it:
* `/proc/pinctrl`, under the new `CONFIG_PINCTRL_PROCFS`, printing one
`key:value` line per pad. Every line carries the same tokens in the same
order, with `-` for a field the pad does not have, so the file can be
parsed.
The framework owns the format; controllers only supply data.
* a `PINCTRLC_GETPAD` ioctl, giving userspace the programmatic read-back that
text cannot serve, e.g. reading a pad back after setting it. The structure
embeds its strings rather than pointing at them, so one shape serves both
callers across the user/kernel boundary.
**Everything here is optional.** A controller that does not implement
`get_pad`
is still listed, and the ioctl returns `-ENOTSUP`. A pad need not have every
field: fill what it has and set the matching `PINCTRL_HAVE_*` bit, and
anything
the structure has no member for goes in `extra` as further `key:value` text.
**Pad and function names are entirely optional too** — leave them empty and
pads
are reported by number alone. `PINCTRL_PADNAME()` and two lookup helpers are
provided for controllers that do want names, so each one need not invent its
own
table.
A minimal controller is about this much:
```c
/* Optional: one entry per pad, its name then the name of each function
* select in select order. NULL marks a select the manual does not name.
*/
static const struct pinctrl_padname_s g_mychip_padnames[] =
{
[MYCHIP_PAD_I2C0_SCL] = PINCTRL_PADNAME("I2C0_SCL", "I2C0_SCL",
NULL, "GPIO44"),
[MYCHIP_PAD_SPI0_CLK] = PINCTRL_PADNAME("SPI0_CLK", "SPI0_CLK"),
[MYCHIP_PAD_XIN] = PINCTRL_PADNAME("XIN", NULL),
};
static int mychip_getpad(struct pinctrl_dev_s *dev, uint32_t pin,
struct pinctrl_padinfo_s *info)
{
uint32_t val = getreg32(MYCHIP_PAD(pin));
FAR const char *name;
info->have = PINCTRL_HAVE_FUNCTION | PINCTRL_HAVE_PULL;
info->function = (val & PAD_FUNC_MASK) >> PAD_FUNC_SHIFT;
info->pullup = (val & PAD_PU) != 0;
info->pulldown = (val & PAD_PD) != 0;
/* Names are optional; both helpers return NULL when a name is absent,
* which leaves the strings empty.
*/
name = pinctrl_padname(g_mychip_padnames, nitems(g_mychip_padnames),
pin);
if (name != NULL)
{
strlcpy(info->name, name, sizeof(info->name));
}
name = pinctrl_funcname(g_mychip_padnames, nitems(g_mychip_padnames),
pin, info->function);
if (name != NULL)
{
strlcpy(info->funcname, name, sizeof(info->funcname));
}
/* Anything the structure has no member for */
snprintf(info->extra, sizeof(info->extra), "ms:%u", (val >> 8) & 3);
return OK;
}
static const struct pinctrl_ops_s g_mychip_ops =
{
...
.get_pad = mychip_getpad,
};
```
The documentation is updated with the method, the validity bits, the optional
naming and the procfs entry.
## Impact
New feature, off by default. `CONFIG_PINCTRL_PROCFS` depends on
`FS_PROCFS_REGISTER`; with it unset nothing here is compiled.
`struct pinctrl_ops_s` gains one optional member and `struct pinctrl_dev_s`
gains `npins`. There are currently **no pinctrl providers in master**, so no
existing driver needs updating. The first consumer will be the ESWIN EIC7700X
pad multiplexer, in a pull request following shortly; it drives 166 pads
through
four different field layouts, which is what the `have` bits and `extra` exist
for.
No change to the existing five operations, their ioctls or their behaviour.
Worth flagging to reviewers: **no in-tree configuration enables
`CONFIG_PINCTRL`
at all**, so CI will not compile this code. A green run says nothing about
it,
and the testing below is the only evidence.
## Testing
Host: macOS 15.5 (arm64), `riscv-none-elf-gcc` 13.2, Sphinx 6.2.1.
**Build**, since CI cannot: `sim:nsh` with `PINCTRL`, `FS_PROCFS`,
`FS_PROCFS_REGISTER` and `PINCTRL_PROCFS` forced on compiles
`drivers/pinctrl/pinctrl.c` clean; also built with `PINCTRL_PROCFS` off to
check
the disabled path. Documentation builds with no new warnings.
**Hardware**: ESWIN EIC7700 EVB (EIC7700X, 4 x RV64GC), booted over TFTP
with an
out-of-tree pinctrl driver implementing `get_pad` for all 166 pads.
Board start up:
```
[CPU0] clk: registered 264 clocks, 0 failed
[CPU0] pinctrl: 166 pads, 3 configured
```
```
nsh> cat /proc/pinctrl
pinctrl0: 166 pads
0 CHIP_MODE func:0 sel:CHIP_MODE ds:0 pu:0 pd:1 ie:1
smt:1 slew:-
5 XIN func:- sel:- ds:12 pu:- pd:- ie:-
smt:- slew:- frs:2 rd:0
91 I2C0_SCL func:0 sel:I2C0_SCL ds:1 pu:0 pd:0 ie:1
smt:0 slew:-
141 S_MODE func:2 sel:GPIO94 ds:1 pu:0 pd:0 ie:1
smt:0 slew:-
163 LPDDR_REF_CLK func:- sel:- ds:0 pu:0 pd:0 ie:1
smt:0 slew:- ms:3
164 ADDR_RGMII0_SEL_MODE func:- sel:- ds:- pu:- pd:- ie:-
smt:- slew:- ms1:1 ms2:1
```
That exercises all four of the chip's pad layouts: pad 0 a general pad, 5 an
oscillator pad with no function select and its own `frs`/`rd` fields, 163 an
RGMII pad carrying `ms`, and 164 a mode-select pad that has almost nothing
and
renders as `-` throughout. `sel:GPIO94` on pad 141 is a named function
select.
Checked on that output:
* all 166 pads present, strictly sequential, **no gap or repeat at any read
boundary** — the file is far larger than one read buffer, so this
exercises the
`pos` accounting across many `read()` calls
* every line carries the identical token set; an `awk` pass splitting on the
fields finds no line that deviates
* no trailing whitespace, and no truncated record
A controller without `get_pad` was checked by removing the method: the
controller is still listed with a note, and the ioctl returns `-ENOTSUP`.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]