![]() |
RT-Thread RTOS
An open source embedded real-time operating system
|
Pinctrl applies device-tree pin configurations (mux, pull, drive strength, and related pad settings) before or during driver **probe**.
components/drivers/pinctrl/pinctrl.c**PIN_CONFIG_***: **components/drivers/include/drivers/dev_pin.h**Kconfig: **RT_USING_PINCTRL** (requires **RT_USING_DM** and **RT_USING_PIN**). BSP may add more providers via **SOC_DM_PINCTRL_DIR**.
The consumer node (UART, I2C, SPI, …) references config subnodes under a pinctrl controller:
| Property | Role |
|---|---|
**pinctrl-0**, **pinctrl-1**, … | Phandles to config subnodes (one state per index) |
**pinctrl-names** | Names for each index: "default", "sleep", "active", … |
**pinctrl-0** may contain several phandles (e.g. separate SCL/SDA nodes). They are applied in order; the first error stops the rest.
Phandles must target a config child of the controller, not the controller root nor the consumer itself (see comment in **ofw_pin_ctrl_confs_apply()**).
For **rt_pin_ctrl_confs_apply(dev, index)** (or after name lookup):
The provider is a platform driver for the pinctrl controller. At **probe** it typically:
reg**, enables clock/reset.struct rt_pin_ops.pin_ctrl_confs_apply** to parse **fw_conf_np** and program hardware.rt_ofw_data(controller_ofw_node) = &struct rt_device_pin.parent**.Optional: **pin_ctrl_gpio_request** — pad setup when the GPIO layer claims a line (**pin_gpio_request** in **dev_pin_dm.c**).
**platform_probe()** runs before the driver **probe**:
So most drivers only need correct DT; they do not need to call pinctrl in **probe** unless switching states at runtime.
Full platform order: Platform bus.
Boot-time mux — no code; define **pinctrl-names** + **pinctrl-0** (and extra states if needed).
Runtime state change (sleep, high-speed, etc.):
**name == NULL** in **rt_pin_ctrl_confs_apply_by_name** means **"default"**.
Some drivers (**regulator-fixed**, **led-gpio**, …) call apply again before using GPIO-related pads so DT and hardware stay aligned.
| API | Role |
|---|---|
**rt_pin_ctrl_confs_lookup(dev, name)** | Index in **pinctrl-names**; **-RT_EEMPTY** if missing |
**rt_pin_ctrl_confs_apply(dev, index)** | Apply all phandles in **pinctrl-<index>** |
**rt_pin_ctrl_confs_apply_by_name(dev, name)** | Lookup + apply |
Without **RT_USING_OFW**: **-RT_ENOSYS**.
| Return | Meaning |
|---|---|
**RT_EOK** | State applied |
**-RT_EEMPTY** | No property / no name |
**-RT_ERROR** | Provider missing or no **pin_ctrl_confs_apply** |
**-RT_EIO** | Bad phandle |
struct rt_device_pin** (usually first member of private struct).pin_ctrl_confs_apply(device, fw_conf_np)** — read provider-specific properties on **fw_conf_np** and write pad registers (or firmware, etc.).rt_ofw_data(dev->ofw_node) = &pin_dev->parent** at end of probe.**PIN_CONFIG_*** in **dev_pin.h** are generic semantic types; providers map DT properties to hardware as needed.
From **pinctrl.c** comments — one consumer, two phandles, two config nodes:
| Issue | Mitigation |
|---|---|
| Provider not probed | Register platform driver; core calls **rt_platform_ofw_request** |
| Wrong phandle | Must point to config subnode under controller |
| Name / index mismatch | **rt_pin_ctrl_confs_lookup** string must match **pinctrl-names** |
| Partial apply | First failing phandle aborts the list |
No **rt_ofw_data** | Provider **probe** must set it on controller node |
| Runtime PM | Add **pinctrl-1** + **"sleep"**; **apply_by_name** on suspend/resume |
components/drivers/pinctrl/pinctrl.ccomponents/drivers/core/platform.c