Skip to main content Why GPIO, pinctrl, clock, regulator, and reset Are Driver Lifecycle Resources | IoT Worker

Why GPIO, pinctrl, clock, regulator, and reset Are Driver Lifecycle Resources

Many embedded Linux device bugs look like register-access bugs: probe runs, register mapping succeeds, but reads return invalid values; interrupts never arrive; an I2C device randomly NACKs; the first access after resume fails.

The problem is not always in register access.

Whether hardware works often depends on more basic resources first: pins must be muxed correctly, clocks must be enabled, power must be stable, reset must be released, and GPIO polarity must be correct.

The safest first model is this: GPIO, pinctrl, clock, regulator, and reset are not side configuration fields. They are prerequisites that turn a device from “present on the board” into “accessible by the driver.” The driver must manage their lifecycle across probe, remove, suspend/resume, and runtime PM.

Device Tree describes resources
-> probe obtains resources
-> pinctrl selects state
-> regulator powers device
-> clock is enabled
-> reset is deasserted
-> registers / transfers can be used
-> suspend/remove unwinds state

The exact order varies by hardware, but the dependencies must be explicit.

Device Tree Describes; It Does Not Automatically Enable

Device Tree often contains:

pinctrl-names = "default", "sleep";
pinctrl-0 = <&uart0_pins>;
pinctrl-1 = <&uart0_sleep_pins>;
clocks = <&clk 3>;
vdd-supply = <&vdd_3v3>;
reset-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;

These properties describe wiring, providers, and possible states.

But “written in Device Tree” does not mean the resource has been enabled. The driver still has to obtain, enable, switch, and release resources through kernel frameworks.

Device Tree describes hardware facts. The driver uses those resources according to hardware timing.

If the driver misses one resource, the device may still be created and probe may still run, while the hardware is not actually accessible.

pinctrl Decides Whether Signals Reach Pins

SoC pins are usually multiplexed. One pin can be GPIO, UART TX, I2C SDA, SPI MISO, or another function.

pinctrl selects pin muxing and electrical attributes:

  • mux function
  • pull-up or pull-down
  • drive strength
  • input enable
  • sleep-state pin configuration

If pinctrl is wrong, register configuration can be perfect while the external signal never reaches the pin.

Typical symptoms:

  • UART has no output
  • I2C bus keeps NACKing
  • GPIO interrupt works while running but cannot wake from sleep
  • SPI waveform appears on no pin
  • sleep state puts pins in high impedance and device state is lost

Drivers often select the default state in probe or runtime resume, and the sleep state in suspend or low power.

clock Decides Whether Logic Runs

Many peripherals require clocks before register access works.

The Linux clock framework lets drivers obtain clocks:

clk = devm_clk_get(dev, NULL);
clk_prepare_enable(clk);

Some devices have several clocks: bus clock, core clock, reference clock, sample clock. Enabling only one may not be enough.

Clock bugs often look like:

  • register access timeout
  • status bit never changes
  • wrong baud rate, sample rate, or SPI frequency
  • first access after resume fails
  • runtime PM resumes without re-enabling clocks

clk_prepare_enable() and clk_disable_unprepare() must be paired. Drivers must handle error paths, remove, suspend/resume, and runtime PM.

Clocks are not “enable once and forget.” Low-power paths may turn them off, and resume paths must restore them.

regulator Decides Whether the Device Has Power

The regulator framework manages power rails.

Device Tree often uses properties like vdd-supply, vcc-supply, or iovcc-supply. Drivers request power:

vdd = devm_regulator_get(dev, "vdd");
regulator_enable(vdd);

Devices may have multiple supplies:

  • core supply
  • IO supply
  • analog supply
  • sensor bias
  • peripheral module power

Power order, ramp delay, and voltage range can all matter.

Typical issues:

  • registers read all 0 or all 1
  • I2C device address does not respond
  • driver accesses too soon after power-on
  • sleep turns power off and resume does not reinitialize
  • shared regulator is disabled incorrectly and affects another device

Regulator enable/disable has reference-count semantics. A driver must not disable power it does not own, and must not assume the bootloader keeps power enabled forever.

reset Is Not Just a GPIO Toggle

Many devices need reset control.

Reset may come from:

  • reset controller
  • GPIO reset
  • PMIC
  • external MCU

Linux may use reset framework:

rst = devm_reset_control_get_optional(dev, NULL);
reset_control_deassert(rst);

or GPIO descriptors:

reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
gpiod_set_value_cansleep(reset, 0);

The hard part is polarity and timing.

Datasheets may require:

  • hold reset after power stabilizes
  • enable clock before releasing reset
  • wait after reset release for calibration
  • assert reset before suspend and reinitialize after resume

If polarity is wrong, the device may stay in reset.
If release happens too early, boot may fail intermittently.
If resume skips reinitialization, the device may only partially recover.

GPIO Descriptors Are Safer Than Global Numbers

Old code often used global GPIO numbers. New drivers should prefer GPIO descriptor APIs:

irq_gpio = devm_gpiod_get(dev, "irq", GPIOD_IN);
reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);

Descriptor APIs help because they:

  • obtain GPIOs by Device Tree property name
  • handle active-low semantics
  • work better with multiple GPIO controllers
  • tie lifetime more clearly to the device

GPIO is not only high or low. It may involve pinctrl, direction, open-drain, pull-up, edge interrupt, and wake capability.

If both pinctrl and gpiolib affect the same pin, keep the boundary clear: pinctrl manages mux and electrical state; GPIO APIs manage direction, value, or interrupt.

devm Manages Release, Not Hardware Timing

Many resource acquisitions use devm_:

clk = devm_clk_get(dev, NULL);
vdd = devm_regulator_get(dev, "vdd");
reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);

devm_ automatically releases resources on probe failure or remove, reducing error-path cleanup.

But it does not automatically:

  • enable clocks
  • enable regulators
  • select pinctrl states
  • release reset
  • wait according to datasheet timing
  • restore state in suspend/resume

devm_ manages resource-object lifetime, not hardware-running-state lifetime.

The driver still must explicitly order enable/disable, assert/deassert, default/sleep, and prepare/unprepare operations.

probe, remove, and PM Paths Should Be Symmetric

These resources are not only used once in probe.

Drivers usually need to consider:

probe: get resources, power on, enable clocks, release reset, initialize hardware
remove: stop I/O, disable IRQs, reset or power down, release resources
suspend: stop transfers, save state, switch sleep pinctrl, disable clocks/regulators
resume: restore power and clocks, release reset, reinitialize hardware
runtime suspend: locally reduce power while idle
runtime resume: restore device before the next access

If only probe is correct, the device may work on first boot but fail after low power, module unload, reboot, or error recovery.

The hard part is often not “how to get the resource,” but “when to enable it, when to disable it, and where to unwind on failure.”

EPROBE_DEFER Often Means a Provider Is Not Ready

These resources are provided by other drivers:

  • clock provider
  • regulator provider
  • pinctrl provider
  • GPIO controller
  • reset controller

If the current driver probes before its provider is ready, resource acquisition may return -EPROBE_DEFER.

This usually means “try again later,” not permanent failure.

When debugging deferred probe, check:

  • whether the provider has a Device Tree node
  • whether the provider driver is enabled
  • whether the provider itself failed to probe
  • whether supply, clock, reset, and GPIO names match
  • whether dependencies form a cycle

Do not fix this only by retrying or adding delays in the consumer driver. The real issue often lives in provider readiness or Device Tree references.

What to Check First for Resource Bugs

When probe runs but hardware does not work, check these layers:

First, do runtime Device Tree resources exist? Check clocks, *-supply, pinctrl-*, reset-*, and *-gpios in the actual dtb.

Second, are providers ready? Did clock, regulator, pinctrl, GPIO, and reset-controller providers probe successfully?

Third, do names match? devm_regulator_get(dev, "vdd") expects vdd-supply; GPIO names follow similar conventions.

Fourth, does enable order match the datasheet? Power, clock, reset, delay, and register access order should not be guessed.

Fifth, do error paths unwind? If probe fails halfway, already-enabled clocks, supplies, and GPIO states need cleanup.

Sixth, does suspend/resume restore state? pinctrl, clocks, regulators, and reset may need setup again.

Seventh, does runtime PM change state? Resources may be off while idle and must be restored before the next access.

Eighth, do GPIO polarity and pinctrl conflict? Active-low, direction, pull, mux, and wake source need to be checked together.

What to Remember in Practice

GPIO, pinctrl, clock, regulator, and reset are not decorative Device Tree properties.

Together they decide whether hardware is actually accessible:

  • pinctrl decides whether signals reach the right pins
  • clock decides whether peripheral logic runs
  • regulator decides whether the device has power
  • reset decides whether the device is out of reset
  • GPIO controls board-level lines and interrupt pins

A driver manages more than registers. It manages these resources across probe to remove, suspend to resume, and idle to runtime resume.

Many “driver is written but device does not move” bugs come from these prerequisites not actually being true.