| .. _pm-power-domain: | 
 |  | 
 | Power Domain | 
 | ############ | 
 |  | 
 | Introduction | 
 | ************ | 
 |  | 
 | The Zephyr power domain abstraction is designed to support groupings of devices | 
 | powered by a common source to be notified of power source state changes in a | 
 | generic fashion. Application code that is using device A does not need to know | 
 | that device B is on the same power domain and should also be configured into a | 
 | low power state. | 
 |  | 
 | Power domains are optional on Zephyr, to enable this feature the | 
 | option :kconfig:option:`CONFIG_PM_DEVICE_POWER_DOMAIN` has to be set. | 
 |  | 
 | When a power domain turns itself on or off, it is the responsibility of the | 
 | power domain to notify all devices using it through their power management | 
 | callback called with | 
 | :c:enumerator:`PM_DEVICE_ACTION_TURN_ON` or | 
 | :c:enumerator:`PM_DEVICE_ACTION_TURN_OFF` respectively. This | 
 | work flow is illustrated in the diagram below. | 
 |  | 
 | .. _pm-domain-work-flow: | 
 |  | 
 | .. graphviz:: | 
 |    :caption: Power domain work flow | 
 |  | 
 |    digraph { | 
 |        rankdir="TB"; | 
 |  | 
 |        action [style=invis] | 
 |        { | 
 |            rank = same; | 
 |            rankdir="LR" | 
 |            devA [label="gpio0"] | 
 |            devB [label="gpio1"] | 
 |        } | 
 |        domain [label="gpio_domain"] | 
 |  | 
 |       action -> devA [label="pm_device_get()"] | 
 |       devA:se -> domain:n [label="pm_device_get()"] | 
 |  | 
 |       domain -> devB [label="action_cb(PM_DEVICE_ACTION_TURN_ON)"] | 
 |       domain:sw -> devA:sw [label="action_cb(PM_DEVICE_ACTION_TURN_ON)"] | 
 |    } | 
 |  | 
 | Internal Power Domains | 
 | ---------------------- | 
 |  | 
 | Most of the devices in an SoC have independent power control that can | 
 | be turned on or off to reduce power consumption. But there is a | 
 | significant amount of static current leakage that can't be controlled | 
 | only using device power management. To solve this problem, SoCs | 
 | normally are divided into several regions grouping devices that | 
 | are generally used together, so that an unused region can be | 
 | completely powered off to eliminate this leakage. These regions are | 
 | called "power domains", can be present in a hierarchy and can be | 
 | nested. | 
 |  | 
 | External Power Domains | 
 | ---------------------- | 
 |  | 
 | Devices external to a SoC can be powered from sources other than the main power | 
 | source of the SoC. These external sources are typically a switch, a regulator, | 
 | or a dedicated power IC. Multiple devices can be powered from the same source, | 
 | and this grouping of devices is typically called a "power domain". | 
 |  | 
 | Placing devices on power domains can be done for a variety of reasons, | 
 | including to enable devices with high power consumption in low power mode to be | 
 | completely turned off when not in use. | 
 |  | 
 | Implementation guidelines | 
 | ************************* | 
 |  | 
 | In a first place, a device that acts as a power domain needs to | 
 | declare compatible with ``power-domain``. Taking | 
 | :ref:`pm-domain-work-flow` as example, the following code defines a | 
 | domain called ``gpio_domain``. | 
 |  | 
 | .. code-block:: devicetree | 
 |  | 
 | 	gpio_domain: gpio_domain@4 { | 
 | 		compatible = "power-domain"; | 
 | 		... | 
 | 	}; | 
 |  | 
 | A power domain needs to implement the PM action callback used by the | 
 | PM subsystem to turn devices on and off. | 
 |  | 
 | .. code-block:: c | 
 |  | 
 |     static int mydomain_pm_action(const struct device *dev, | 
 |                                enum pm_device_action *action) | 
 |     { | 
 |         switch (action) { | 
 |         case PM_DEVICE_ACTION_RESUME: | 
 |             /* resume the domain */ | 
 |             ... | 
 |             /* notify children domain is now powered */ | 
 |             pm_device_children_action_run(dev, PM_DEVICE_ACTION_TURN_ON, NULL); | 
 |             break; | 
 |         case PM_DEVICE_ACTION_SUSPEND: | 
 |             /* notify children domain is going down */ | 
 |             pm_device_children_action_run(dev, PM_DEVICE_ACTION_TURN_OFF, NULL); | 
 |             /* suspend the domain */ | 
 |             ... | 
 |             break; | 
 |         case PM_DEVICE_ACTION_TURN_ON: | 
 |             /* turn on the domain (e.g. setup control pins to disabled) */ | 
 |             ... | 
 |             break; | 
 |         case PM_DEVICE_ACTION_TURN_OFF: | 
 |             /* turn off the domain (e.g. reset control pins to default state) */ | 
 |             ... | 
 |             break; | 
 |         default: | 
 |             return -ENOTSUP; | 
 |         } | 
 |  | 
 |         return 0; | 
 |     } | 
 |  | 
 | Devices belonging to this device can be declared referring it in the | 
 | ``power-domain`` node's property. The example below declares devices | 
 | ``gpio0`` and ``gpio1`` belonging to domain ``gpio_domain```. | 
 |  | 
 | .. code-block:: devicetree | 
 |  | 
 |         &gpio0 { | 
 |                 compatible = "zephyr,gpio-emul"; | 
 |                 gpio-controller; | 
 |                 power-domains = <&gpio_domain>; | 
 |         }; | 
 |  | 
 |         &gpio1 { | 
 |                 compatible = "zephyr,gpio-emul"; | 
 |                 gpio-controller; | 
 |                 power-domains = <&gpio_domain>; | 
 |         }; | 
 |  | 
 | All devices under a domain will be notified when the domain changes | 
 | state. These notifications are sent as actions in the device PM action | 
 | callback and can be used by them to do any additional work required. | 
 | They can safely be ignored though. | 
 |  | 
 | .. code-block:: c | 
 |  | 
 |     static int mydev_pm_action(const struct device *dev, | 
 |                                enum pm_device_action *action) | 
 |     { | 
 |         switch (action) { | 
 |         case PM_DEVICE_ACTION_SUSPEND: | 
 |             /* suspend the device */ | 
 |             ... | 
 |             break; | 
 |         case PM_DEVICE_ACTION_RESUME: | 
 |             /* resume the device */ | 
 |             ... | 
 |             break; | 
 |         case PM_DEVICE_ACTION_TURN_ON: | 
 |             /* configure the device into low power mode */ | 
 |             ... | 
 |             break; | 
 |         case PM_DEVICE_ACTION_TURN_OFF: | 
 |             /* prepare the device for power down */ | 
 |             ... | 
 |             break; | 
 |         default: | 
 |             return -ENOTSUP; | 
 |         } | 
 |  | 
 |         return 0; | 
 |     } | 
 |  | 
 | .. note:: | 
 |  | 
 |    It is responsibility of driver or the application to set the domain as | 
 |    "wakeup" source if a device depending on it is used as "wakeup" source. | 
 |  | 
 | Examples | 
 | ******** | 
 |  | 
 | Some helpful examples showing power domain features: | 
 |  | 
 | * :zephyr_file:`tests/subsys/pm/device_power_domains/` | 
 | * :zephyr_file:`tests/subsys/pm/power_domain/` |