Power abstraction layer: a software interface for your power system
PAL names a proposed software design pattern in this article, separate from the Power Pal hardware module. The pseudocode is illustrative; it does not describe an implemented or supported PN Labs API.
A sensor driver should be able to request power without knowing which GPIO enables its supply. An application should be able to learn that a rail failed without decoding a particular regulator's status register. A power abstraction layer, or PAL, gives these operations a common interface.
The idea is to describe the power system in terms the application needs: which loads need power, which supplies they share, when those supplies are ready, and what should happen after a fault. Board-specific code translates those requests into the controls the hardware actually provides.

Start with existing power interfaces
This builds on established approaches. Linux's regulator framework lets a consumer request a named supply. Shared regulators stay enabled until their enabled reference count reaches zero. Zephyr provides regulator operations for supported voltages, current limits and error flags; its runtime power management tracks device usage to decide when to suspend or resume devices. A PAL should reuse those facilities when the platform has them. Linux regulator consumer interface, Zephyr regulator API, Zephyr runtime power management.
The proposed addition is a product-level contract. Instead of scattering rail names, timing assumptions and restart rules across drivers, keep them together in one description of the system's power behavior.
Separate a request from a measurement
For this design, keep at least three distinct pieces of information:
- Requested state: a client needs the rail, or has released it.
- State and evidence: off, starting, ready, faulted or unknown, with an explicit distinction between a transition inferred from a command and a state confirmed by feedback or a documented driver guarantee.
- Capabilities: the board can switch the rail, report status, measure voltage, or adjust a setpoint. Each capability is explicit.
Driving an enable pin does not by itself prove a rail is ready. A driver API may promise a stable supply when its enable operation succeeds; the PAL should preserve that documented guarantee. A status pin does not necessarily identify every fault, and a configured voltage is not a measurement. If the board has no voltage measurement, the interface should report that limitation. An unsupported operation should return an error instead of appearing to succeed. Zephyr regulator API.
Illustrative pseudocode, step by step:
request = power.request("sensor_rail"). If the request fails, log its error and return.- On success, retain
ticket = request.ticket. Only an acquired ticket must be released. - Inside a
tryblock, callresult = power.wait_ready(ticket, deadline). - If the result is
READY, callsensor.take_sample(). Otherwise, log the power problem. - In the
finallyblock, callpower.release(ticket)exactly once. This also runs after a timeout or application error.
In this proposed contract, a successfully acquired ticket belongs to one client and is released exactly once, including on timeout or an application error. An ordinary release must not request shutdown of a shared rail that another client still needs. Electrical protection can still force the rail off despite outstanding requests. The adapter maps logical states to actual pin polarities and electrical interfaces; the application never assumes that “high” always means enabled or healthy.
Shared rails also need setpoint arbitration. Define which combinations of requested voltages and limit settings are compatible, and reject incompatible requests or resolve them through an explicit policy. The latest caller must not silently overwrite another client's supply requirements.
Put transitions and faults in the contract
Describe startup prerequisites, readiness feedback, timeouts and shutdown order for each load. Define what happens if a fault arrives during startup or communication with a power controller is lost. A late readiness notification may update the rail's observed state, but it must not revive an expired client request. Keep a fault record separate from the current status so a brief event can still be investigated.
Validate the dependency graph for cycles. Check failure and timeout at every prerequisite so a missing upstream supply cannot leave a downstream request waiting indefinitely.
Recovery also needs a policy. For this design, a retry is an explicit, bounded action after the cause has been evaluated. A latched fault remains latched until that policy permits a reset. Avoid hiding repeated power cycles inside a generic “enable” call.
Keep electrical protection in the hardware
The software interface coordinates a system; it does not change the limits of its protection circuitry. For example, Protect+ uses hardware protection without an onboard microcontroller and exposes isolated Sleep and fault interfaces. That is a possible control boundary for an external controller, not evidence of a programmable threshold API. PN Labs Protect+.
Source selection has electrical requirements too. TI's power multiplexer guide distinguishes manual, automatic and combined control, and discusses reverse blocking and transitions between supplies. A software request to select a source still depends on a circuit designed for that transition. TI, Basics of Power MUX.
Also account for the controller's own supply. If switching off a rail removes power from the controller that must restart it, the design needs a hardware recovery path or an independently powered controller. Specify the control pins' behavior during boot, reset and loss of controller power; software cannot enforce a recovery policy while it is not running.
Make the interface testable
Before tying this contract to a board, test a fake adapter with delayed readiness, a fault during startup, a lost status signal and two clients sharing a rail. Then verify the same transitions on hardware, including the controller's own boot and reset states. Record the board revision and measured timing alongside the adapter configuration.
The result is a place where application intent, electrical feedback and recovery policy meet. A board change then has a defined boundary to review, and the rest of the application has a consistent way to request power and respond when it is unavailable.
For the hardware side of this boundary, read What Is a PSOM (Power System On Module)?. That article covers the module architecture; this one defines the software contract around it.