The primary functionality supported by the power management package is
to change the system's global power mode. This is achieved by calling
the function power_set_mode
with a single
argument, which should be one of PowerMode_Active,
PowerMode_Idle, PowerMode_Sleep
or PowerMode_Off. Typically this function will only
be invoked in certain scenarios:
A typical system will contain a policy module which is primarily
responsible for initiating power mode changes, and a thread inside the
power management package. The policy module will call
power_set_mode
, which has the effect of
manipulating some internal state in the power management package and
waking up its thread. When this thread gets scheduled to run (its
priority is controlled by a configuration option), it will iterate
over the power controllers and invoke each controller to change its
power mode. There is support for a callback function, and for
detached power controllers.
After a call to power_set_mode
but before the
power management thread has had a chance to iterate over all the
controllers, or even before the thread has been rescheduled at all,
the policy module may decide that a different power mode would be more
appropriate for the current situation and calls
power_set_mode
again. This has the effect of
aborting the previous mode change, followed by the power management
thread iterating over the power controllers again for the new mode.
If there is no single policy module responsible for power mode
changes, any code can call power_set_mode
. If
there are multiple calls in quick succession, earlier calls will
be aborted and the system should end up in the power mode
corresponding to the last call
As a special case, it is possible for a power controller to call
power_set_mode
when invoked by the power
management thread. For example a power controller could decide that it
is inappropriate for the system to go to sleep because the device it
is associated with is still busy. The effect is as if the policy
module had called power_set_mode
again before
the mode change had completed.
If the power management package has been configured not to use a
separate thread then obviously the behaviour is somewhat different.
The call to power_set_mode
will now iterate over
the various power controllers immediately, rather than leaving this to
a separate thread, and the whole mode change completes before
power_set_mode
returns. If some other thread or a
DSR calls power_set_mode
concurrently the
behaviour of the system is undefined. However, it is still legal for a
power controller to call power_set_mode
:
effectively this is a recursive call; it is detected by the system,
and internal state is updated; the recursive
power_set_mode
call now returns, and when the
power controller returns back to the original
power_set_mode
call it detects what has happened,
aborts the previous mode change, and starts a new mode change as
requested by the controller.
power_set_mode
is normally invoked from thread
context. If a separate power management thread is used it can be
invoked safely from DSR context. If the system is configured not to
use such a thread, it may or may not be safe to invoke this function
from DSR context: essentially the function just iterates through
the various power controllers, and the documentation or source code of
each controller present in the current system will have to be examined
to determine whether or not this can happen safely in DSR context.
power_set_mode
should never be invoked from
ISR context.
In some cases it is desirable to set the power mode of an individual
controller separately from the mode for the system as a whole. For
example if a device is not currently being used then the associated
power controller could be set to PowerMode_Off,
even while the system as a whole is still active. This can be achieved
by calling the function
power_set_controller_mode
. It takes two
arguments: the first identifies a particular controller; the second
specifies the desired new power mode for that controller. The function
operates in much the same way as power_set_mode
,
for example if a separate power management thread is being used then
power_set_controller_mode
operates by
manipulating some internal state and waking up that thread. The
limitations are also much the same as for
power_set_mode
, so for example
power_set_controller_mode
should not be invoked
from inside ISRs.
Manipulating individual controllers is often used in conjunction with
the function power_set_controller_attached
,
allowing the policy module to specify which controllers are affected
by global mode changes.
In exceptional circumstances it may be necessary to invoke a power
controller directly, bypassing the power management thread and
higher-level functionality such as callback functions. The
function power_set_controller_mode_now
allows
this. It takes two arguments, a controller and a mode, just like
power_set_controller_mode
.
Use of power_set_controller_mode_now
is
dangerous. For example no attempt is made to synchronise with any
other power mode changes that might be happening concurrently. A
possible use is when the system gets woken up out of
sleep mode: depending on the hardware, on which power
controllers are present, and on the application code it may be
necessary to wake up some power controllers immediately before the
system as a whole is ready to run again.