summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nuttx/ChangeLog1
-rw-r--r--nuttx/arch/sim/src/up_head.c11
-rw-r--r--nuttx/arch/sim/src/up_idle.c21
-rw-r--r--nuttx/drivers/Makefile1
-rwxr-xr-xnuttx/drivers/pm/Make.defs50
-rw-r--r--nuttx/drivers/pm/pm_activity.c166
-rw-r--r--nuttx/drivers/pm/pm_changestate.c223
-rw-r--r--nuttx/drivers/pm/pm_checkstate.c161
-rw-r--r--nuttx/drivers/pm/pm_initialize.c112
-rw-r--r--nuttx/drivers/pm/pm_internal.h210
-rw-r--r--nuttx/drivers/pm/pm_register.c112
-rw-r--r--nuttx/drivers/pm/pm_update.c287
-rw-r--r--nuttx/include/nuttx/pm.h278
13 files changed, 1571 insertions, 62 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 661ba99d9..a5743d55e 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -2051,3 +2051,4 @@
-print-libgcc-file-name.
* lib/time/lib_gmtimer.c: Correct several calculations that could lead
to errors in dates.
+ * drivers/pm: Add the beginnings of a NuttX power management sub-system.
diff --git a/nuttx/arch/sim/src/up_head.c b/nuttx/arch/sim/src/up_head.c
index e1d8c943b..431d417de 100644
--- a/nuttx/arch/sim/src/up_head.c
+++ b/nuttx/arch/sim/src/up_head.c
@@ -47,6 +47,7 @@
#include <nuttx/init.h>
#include <nuttx/arch.h>
+#include <nuttx/pm.h>
/****************************************************************************
* Private Data
@@ -60,6 +61,16 @@ static jmp_buf sim_abort;
int main(int argc, char **argv, char **envp)
{
+ /* Power management should be initialized early in the (simulated) boot
+ * sequence.
+ */
+
+#ifdef CONFIG_PM
+ pm_initialize();
+#endif
+
+ /* Then start NuttX */
+
if (setjmp(sim_abort) == 0)
{
os_start();
diff --git a/nuttx/arch/sim/src/up_idle.c b/nuttx/arch/sim/src/up_idle.c
index 32efaa11b..f1d9974d2 100644
--- a/nuttx/arch/sim/src/up_idle.c
+++ b/nuttx/arch/sim/src/up_idle.c
@@ -40,7 +40,10 @@
#include <nuttx/config.h>
#include <time.h>
+
#include <nuttx/arch.h>
+#include <nuttx/pm.h>
+
#include "up_internal.h"
/****************************************************************************
@@ -103,6 +106,24 @@ void up_idle(void)
uipdriver_loop();
#endif
+ /* Fake some power management stuff for testing purposes */
+
+#ifdef CONFIG_PM
+ {
+ static enum pm_state_e state = PM_NORMAL;
+ enum pm_state_e newstate;
+
+ newstate = pm_checkstate();
+ if (newstate != state)
+ {
+ if (pm_changestate(newstate) == OK)
+ {
+ state = newstate;
+ }
+ }
+ }
+#endif
+
/* Wait a bit so that the sched_process_timer() is called close to the
* correct rate.
*/
diff --git a/nuttx/drivers/Makefile b/nuttx/drivers/Makefile
index d1361e3b5..8c86feff6 100644
--- a/nuttx/drivers/Makefile
+++ b/nuttx/drivers/Makefile
@@ -56,6 +56,7 @@ include mmcsd/Make.defs
include mtd/Make.defs
include net/Make.defs
include pipes/Make.defs
+include pm/Make.defs
include sensors/Make.defs
include serial/Make.defs
include usbdev/Make.defs
diff --git a/nuttx/drivers/pm/Make.defs b/nuttx/drivers/pm/Make.defs
new file mode 100755
index 000000000..6204973f5
--- /dev/null
+++ b/nuttx/drivers/pm/Make.defs
@@ -0,0 +1,50 @@
+############################################################################
+# drivers/pm/Make.defs
+#
+# Copyright (C) 2011 Gregory Nutt. All rights reserved.
+# Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# 3. Neither the name NuttX nor the names of its contributors may be
+# used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+############################################################################
+
+# Has power management support been initialized?
+
+ifeq ($(CONFIG_PM),y)
+
+# Include power management sources
+
+CSRCS += pm_activity.c pm_changestate.c pm_checkstate.c pm_initialize.c pm_register.c pm_update.c
+
+# Include power management in the build
+
+DEPPATH += --dep-path pm
+VPATH += :pm
+CFLAGS += ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" $(TOPDIR)/drivers/pm}
+endif
+
diff --git a/nuttx/drivers/pm/pm_activity.c b/nuttx/drivers/pm/pm_activity.c
new file mode 100644
index 000000000..f1518520b
--- /dev/null
+++ b/nuttx/drivers/pm/pm_activity.c
@@ -0,0 +1,166 @@
+/****************************************************************************
+ * drivers/pm/pm_activity.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/pm.h>
+#include <nuttx/clock.h>
+#include <arch/irq.h>
+
+#include "pm_internal.h"
+
+#ifdef CONFIG_PM
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pm_activity
+ *
+ * Description:
+ * This function is called by a device driver to indicate that it is
+ * performing meaningful activities (non-idle). This increment an activty
+ * cound and/or will restart a idle timer and prevent entering IDLE
+ * power states.
+ *
+ * Input Parameters:
+ * priority - activity priority, range 0-9. Larger values correspond to
+ * higher priorities. Higher priority activity can prevent the system
+ * fromentering reduced power states for a longer period of time.
+ *
+ * As an example, a button press might be higher priority activity because
+ * it means that the user is actively interacting with the device.
+ *
+ * Returned Value:
+ * None.
+ *
+ * Assumptions:
+ * This function may be called from an interrupt handler (this is the ONLY
+ * PM function that may be called from an interrupt handler!).
+ *
+ ****************************************************************************/
+
+void pm_activity(int priority)
+{
+ uint32_t now;
+ uint32_t accum;
+ irqstate_t flags;
+
+ /* Just increment the activity count in the current time slice. The priority
+ * is simply the number of counts that are added.
+ */
+
+ if (priority > 0)
+ {
+ /* Add the priority to the accumulated counts in a critical section. */
+
+ flags = irqsave();
+ accum = (uint32_t)g_pmglobals.accum + priority;
+
+ /* Make sure that we do not overflow the underlying uint16_t representation */
+
+ if (accum > UINT16_MAX)
+ {
+ accum = UINT16_MAX;
+ }
+
+ /* Save the updated count */
+
+ g_pmglobals.accum = accum;
+
+ /* Check the elapsed time. In periods of low activity, time slicing is
+ * controlled by IDLE loop polling; in periods of higher activity, time
+ * slicing is controlled by driver activity. In either case, the duration
+ * of the time slice is only approximate; during times of heavy activity,
+ * time slices may be become longer and the activity level may be over-
+ * estimated.
+ */
+
+ now = clock_systimer();
+ if (now - g_pmglobals.stime >= TIME_SLICE_TICKS)
+ {
+ uint16_t tmp;
+
+ /* Sample the count, reset the time and count, and assess the PM
+ * state. This is an atomic operation because interrupts are
+ * still disabled.
+ */
+
+ tmp = g_pmglobals.accum;
+ g_pmglobals.stime = now;
+ g_pmglobals.accum = 0;
+
+ /* Reassessing the PM state may require some computation. However,
+ * the work will actually be performed on a worker thread at a user-
+ * controlled priority.
+ */
+
+ (void)pm_update(accum);
+ }
+
+ irqrestore(flags);
+ }
+}
+
+#endif /* CONFIG_PM */ \ No newline at end of file
diff --git a/nuttx/drivers/pm/pm_changestate.c b/nuttx/drivers/pm/pm_changestate.c
new file mode 100644
index 000000000..e98e46236
--- /dev/null
+++ b/nuttx/drivers/pm/pm_changestate.c
@@ -0,0 +1,223 @@
+/****************************************************************************
+ * drivers/pm/pm_changestate.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/pm.h>
+#include <arch/irq.h>
+
+#include "pm_internal.h"
+
+#ifdef CONFIG_PM
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pm_prepall
+ *
+ * Description:
+ * Prepare every driver for the state change.
+ *
+ * Input Parameters:
+ * newstate - Idenfifies the new PM state
+ *
+ * Returned Value:
+ * 0 (OK) means that the callback function for all registered drivers
+ * returned OK (meaning that they accept the state change). Non-zero
+ * means that one of the drivers refused the state change. In this case,
+ * the system will revert to the preceding state.
+ *
+ * Assumptions:
+ * Interrupts are disabled.
+ *
+ ****************************************************************************/
+
+static int pm_prepall(enum pm_state_e newstate)
+{
+ FAR sq_entry_t *entry;
+ int ret = OK;
+
+ /* Visit each registered callback structure. */
+
+ for (entry = sq_peek(&g_pmglobals.registry);
+ entry && ret == OK;
+ entry = sq_next(entry))
+ {
+ /* Is the prepare callback supported? */
+
+ FAR struct pm_callback_s *cb = (FAR struct pm_callback_s *)entry;
+ if (cb->prepare)
+ {
+ /* Yes.. prepare the driver */
+
+ ret = cb->prepare(cb, newstate);
+ }
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: pm_changeall
+ *
+ * Description:
+ * Inform all drivers of the state change.
+ *
+ * Input Parameters:
+ * newstate - Idenfifies the new PM state
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Interrupts are disabled.
+ *
+ ****************************************************************************/
+
+static inline void pm_changeall(enum pm_state_e newstate)
+{
+ FAR sq_entry_t *entry;
+
+ /* Visit each registered callback structure. */
+
+ for (entry = sq_peek(&g_pmglobals.registry); entry; entry = sq_next(entry))
+ {
+ /* Is the notification callback supported? */
+
+ FAR struct pm_callback_s *cb = (FAR struct pm_callback_s *)entry;
+ if (cb->notify)
+ {
+ /* Yes.. notify the driver */
+
+ (void)cb->notify(cb, newstate);
+ }
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pm_changestate
+ *
+ * Description:
+ * This function is used to platform-specific power managmeent logic. It
+ * will announce the power management power management state change to all
+ * drivers that have registered for power management event callbacks.
+ *
+ * Input Parameters:
+ * newstate - Idenfifies the new PM state
+ *
+ * Returned Value:
+ * 0 (OK) means that the callback function for all registered drivers
+ * returned OK (meaning that they accept the state change). Non-zero
+ * means that one of the drivers refused the state change. In this case,
+ * the system will revert to the preceding state.
+ *
+ * Assumptions:
+ * It is assumed that interrupts are disabled when this function is
+ * called. This function is probably called from the IDLE loop... the
+ * lowest priority task in the system. Changing driver power management
+ * states may result in renewed system activity and, as a result, can
+ * suspend the IDLE thread before it completes the entire state change
+ * unless interrupts are disabled throughout the state change.
+ *
+ ****************************************************************************/
+
+int pm_changestate(enum pm_state_e newstate)
+{
+ irqstate_t flags;
+ int ret;
+
+ /* Disable interrupts throught this operation... changing driver states
+ * could cause additional driver activity that might interfere with the
+ * state change. When the state change is complete, interrupts will be
+ * re-enabled.
+ */
+
+ flags = irqsave();
+
+ /* First, prepare the drivers for the state change. In this phase,
+ * drivers may refuse the state state change.
+ */
+
+ ret = pm_prepall(newstate);
+ if (ret != OK)
+ {
+ /* One or more drivers is not ready for this state change. Revert to
+ * the preceding state.
+ */
+
+ newstate = g_pmglobals.state;
+ (void)pm_prepall(newstate);
+ }
+
+ /* All drivers have agreed to the state change (or, one or more have
+ * disagreed and the state has been reverted). Set the new state.
+ */
+
+ pm_changeall(newstate);
+ g_pmglobals.state = newstate;
+ return ret;
+}
+
+#endif /* CONFIG_PM */
diff --git a/nuttx/drivers/pm/pm_checkstate.c b/nuttx/drivers/pm/pm_checkstate.c
new file mode 100644
index 000000000..6b23ad05c
--- /dev/null
+++ b/nuttx/drivers/pm/pm_checkstate.c
@@ -0,0 +1,161 @@
+/****************************************************************************
+ * drivers/pm/pm_checkstate.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/pm.h>
+#include <nuttx/clock.h>
+#include <arch/irq.h>
+
+#include "pm_internal.h"
+
+#ifdef CONFIG_PM
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pm_checkstate
+ *
+ * Description:
+ * This function is called from the MCU-specific IDLE loop to monitor the
+ * the power management conditions. This function returns the "recommended"
+ * power management state based on the PM configuration and activity
+ * reported in the last sampling periods. The power management state is
+ * not automatically changed, however. The IDLE loop must call
+ * pm_changestate() in order to make the state change.
+ *
+ * These two steps are separated because the plaform-specific IDLE loop may
+ * have additional situational information that is not available to the
+ * the PM sub-system. For example, the IDLE loop may know that the
+ * battery charge level is very low and may force lower power states
+ * even if there is activity.
+ *
+ * NOTE: That these two steps are separated in time and, hence, the IDLE
+ * could be suspended for a long period of time between calling
+ * pm_checkstate() and pm_changestate(). There it is recommended that
+ * the IDLE loop make these calls atomic by either disabling interrupts
+ * until the state change is completed.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * The recommended power management state.
+ *
+ ****************************************************************************/
+
+enum pm_state_e pm_checkstate(void)
+{
+ uint32_t now;
+ irqstate_t flags;
+
+ /* Check for the end of the current time slice. This must be performed
+ * with interrupts disabled so that it does not conflict with the similar
+ * logic in pm_activity().
+ */
+
+ flags = irqsave();
+
+ /* Check the elapsed time. In periods of low activity, time slicing is
+ * controlled by IDLE loop polling; in periods of higher activity, time
+ * slicing is controlled by driver activity. In either case, the duration
+ * of the time slice is only approximate; during times of heavy activity,
+ * time slices may be become longer and the activity level may be over-
+ * estimated.
+ */
+
+ now = clock_systimer();
+ if (now - g_pmglobals.stime >= TIME_SLICE_TICKS)
+ {
+ uint16_t accum;
+
+ /* Sample the count, reset the time and count, and assess the PM
+ * state. This is an atomic operation because interrupts are
+ * still disabled.
+ */
+
+ accum = g_pmglobals.accum;
+ g_pmglobals.stime = now;
+ g_pmglobals.accum = 0;
+
+ /* Reassessing the PM state may require some computation. However,
+ * the work will actually be performed on a worker thread at a user-
+ * controlled priority.
+ */
+
+ (void)pm_update(accum);
+ }
+ irqrestore(flags);
+
+ /* Return the recommended state. Assuming that we are called from the
+ * IDLE thread at the lowest priority level, any updates scheduled on the
+ * worker thread above should have already been peformed and the recommended
+ * state should be current:
+ */
+
+ return g_pmglobals.recommended;
+}
+
+#endif /* CONFIG_PM */
diff --git a/nuttx/drivers/pm/pm_initialize.c b/nuttx/drivers/pm/pm_initialize.c
new file mode 100644
index 000000000..70cd8d7e6
--- /dev/null
+++ b/nuttx/drivers/pm/pm_initialize.c
@@ -0,0 +1,112 @@
+/****************************************************************************
+ * drivers/pm/pm_initialize.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <semaphore.h>
+
+#include <nuttx/pm.h>
+
+#include "pm_internal.h"
+
+#ifdef CONFIG_PM
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* All PM global data: */
+
+struct pm_global_s g_pmglobals;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pm_initialize
+ *
+ * Description:
+ * This function is called by MCU-specific one-time at power on reset in
+ * order to initialize the power management capabilities. This function
+ * must be called *very* early in the intialization sequence *before* any
+ * other device drivers are initialize (since they may attempt to register
+ * with the power management subsystem).
+ *
+ * Input parameters:
+ * None.
+ *
+ * Returned value:
+ * None.
+ *
+ ****************************************************************************/
+
+void pm_initialize(void)
+{
+ /* Initialize the registry and the PM global data structures. The PM
+ * global data structure resides in .bss which is zeroed at boot time. So
+ * it is only required to initialize non-zero elements of the PM global
+ * data structure here.
+ */
+
+ sq_init(&g_pmglobals.registry);
+ sem_init(&g_pmglobals.regsem, 0, 1);
+}
+
+#endif /* CONFIG_PM */ \ No newline at end of file
diff --git a/nuttx/drivers/pm/pm_internal.h b/nuttx/drivers/pm/pm_internal.h
new file mode 100644
index 000000000..e0cb3fb1a
--- /dev/null
+++ b/nuttx/drivers/pm/pm_internal.h
@@ -0,0 +1,210 @@
+/****************************************************************************
+ * drivers/pm/pm_internal.h
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __DRIVERS_PM_PM_INTERNAL_H
+#define __DRIVERS_PM_PM_INTERNAL_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <semaphore.h>
+#include <queue.h>
+
+#include <nuttx/pm.h>
+#include <nuttx/wqueue.h>
+
+#ifdef CONFIG_PM
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+
+#ifndef CONFIG_SCHED_WORKQUEUE
+# warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
+#endif
+
+/* Convert the time slice interval into system clock ticks.
+ *
+ * CONFIG_PM_SLICEMS provides the duration of one time slice in milliseconds.
+ * CLOCKS_PER_SEC provides the number of timer ticks in one second.
+ *
+ * slice ticks = (CONFIG_PM_SLICEMS msec / 1000 msec/sec) /
+ * (CLOCKS_PER_SEC ticks/sec)
+ */
+
+#define TIME_SLICE_TICKS ((CONFIG_PM_SLICEMS * CLOCKS_PER_SEC) / 1000)
+
+/* Function-like macros *****************************************************/
+/****************************************************************************
+ * Name: pm_lock
+ *
+ * Descripton:
+ * Lock the power management registry. NOTE: This function may return
+ * an error if a signal is received while what (errno == EINTR).
+ *
+ ****************************************************************************/
+
+#define pm_lock() sem_wait(&g_pmglobals.regsem);
+
+/****************************************************************************
+ * Name: pm_unlock
+ *
+ * Descripton:
+ * Unlock the power management registry.
+ *
+ ****************************************************************************/
+
+#define pm_unlock() sem_post(&g_pmglobals.regsem);
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+/* This structure encapsulates all of the global data used by the PM module */
+
+struct pm_global_s
+{
+ /* state - The current state (as determined by an explicit call to
+ * pm_changestate()
+ * recommended - The recommended state based on the PM algorithm in
+ * function pm_update().
+ * mndex - The index to the next slot in the memory[] arry to use.
+ * mcnt - A tiny counter used only at start up. The actual
+ * algorithm cannot be applied until CONFIG_PM_MEMORY
+ * samples have been collected.
+ */
+
+ uint8_t state;
+ uint8_t recommended;
+ uint8_t mndx;
+ uint8_t mcnt;
+
+ /* accum - The accumulated counts in this time interval
+ * thrcnt - The number of below threshold counts seen.
+ */
+
+ uint16_t accum;
+ uint16_t thrcnt;
+
+ /* This is the averaging "memory." The averaging algorithm is simply:
+ * Y = (An*X + SUM(Ai*Yi))/SUM(Aj), where i = 1..n-1 and j= 1..n, n is the
+ * length of the "memory", Ai is the weight applied to each value, and X is
+ * the current activity.
+ *
+ * CONFIG_PM_MEMORY provides the memory for the algorithm. Default: 2
+ * CONFIG_PM_COEFn provides weight for each sample. Default: 1
+ */
+
+#if CONFIG_PM_MEMORY > 1
+ uint16_t memory[CONFIG_PM_MEMORY-1];
+#endif
+
+ /* stime - The time (in ticks) at the start of the current time slice */
+
+ uint32_t stime;
+
+ /* This semaphore manages mutually exclusive access to the power management
+ * registry. It must be initialized to the value 1.
+ */
+
+ sem_t regsem;
+
+ /* For work that has been deferred to the worker thread */
+
+ struct work_s work;
+
+ /* registry is a singly-linked list of registered power management
+ * callback structures. To ensure mutually exclusive access, this list
+ * must be locked by calling pm_lock() before it is accessed.
+ */
+
+ sq_queue_t registry;
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+# define EXTERN extern "C"
+extern "C"
+{
+#else
+# define EXTERN extern
+#endif
+
+/* All PM global data: */
+
+EXTERN struct pm_global_s g_pmglobals;
+
+/************************************************************************************
+ * Public Function Prototypes
+ ************************************************************************************/
+
+/****************************************************************************
+ * Name: pm_update
+ *
+ * Description:
+ * This internal function is called at the end of a time slice in order to
+ * update driver activity metrics and recommended states.
+ *
+ * Input Parameters:
+ * accum - The value of the activity accumulator at the end of the time
+ * slice.
+ *
+ * Returned Value:
+ * None.
+ *
+ * Assumptions:
+ * This function may be called from a driver, perhaps even at the interrupt
+ * level. It may also be called from the IDLE loop at the lowest possible
+ * priority level. To reconcile these various conditions, all work is
+ * performed on the worker thread at a user-selectable priority.
+ *
+ ****************************************************************************/
+
+EXTERN void pm_update(uint16_t accum);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* CONFIG_PM */
+#endif /* #define __DRIVERS_PM_PM_INTERNAL_H */
diff --git a/nuttx/drivers/pm/pm_register.c b/nuttx/drivers/pm/pm_register.c
new file mode 100644
index 000000000..41d4bb836
--- /dev/null
+++ b/nuttx/drivers/pm/pm_register.c
@@ -0,0 +1,112 @@
+/****************************************************************************
+ * drivers/pm/pm_register.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <queue.h>
+#include <assert.h>
+
+#include <nuttx/pm.h>
+
+#include "pm_internal.h"
+
+#ifdef CONFIG_PM
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pm_register
+ *
+ * Description:
+ * This function is called by a device driver in order to register to
+ * receive power management event callbacks.
+ *
+ * Input parameters:
+ * callbacks - An instance of struct pm_callback_s providing the driver
+ * callback functions.
+ *
+ * Returned value:
+ * Zero (OK) on success; otherwise a negater errno value is returned.
+ *
+ ****************************************************************************/
+
+int pm_register(FAR struct pm_callback_s *callbacks)
+{
+ int ret;
+
+ DEBUGASSERT(callbacks);
+
+ /* Add the new entry to the end of the list of registered callbacks */
+
+ ret = pm_lock();
+ if (ret == OK)
+ {
+ sq_addlast(&callbacks->entry, &g_pmglobals.registry);
+ pm_unlock();
+ }
+ return ret;
+}
+
+#endif /* CONFIG_PM */ \ No newline at end of file
diff --git a/nuttx/drivers/pm/pm_update.c b/nuttx/drivers/pm/pm_update.c
new file mode 100644
index 000000000..d3ff75090
--- /dev/null
+++ b/nuttx/drivers/pm/pm_update.c
@@ -0,0 +1,287 @@
+/****************************************************************************
+ * drivers/pm/pm_update.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+
+#include <nuttx/pm.h>
+#include <nuttx/wqueue.h>
+
+#include "pm_internal.h"
+
+#ifdef CONFIG_PM
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+/* CONFIG_PM_MEMORY is the total number of time slices (including the current
+ * time slice. The histor or previous values is then CONFIG_PM_MEMORY-1.
+ */
+
+#if CONFIG_PM_MEMORY > 1
+static const uint16_t g_pmcoeffs[CONFIG_PM_MEMORY-1] =
+{
+ CONFIG_PM_COEF1
+#if CONFIG_PM_MEMORY > 2
+ , CONFIG_PM_COEF2
+#endif
+#if CONFIG_PM_MEMORY > 3
+ , CONFIG_PM_COEF3
+#endif
+#if CONFIG_PM_MEMORY > 4
+ , CONFIG_PM_COEF4
+#endif
+#if CONFIG_PM_MEMORY > 5
+ , CONFIG_PM_COEF5
+#endif
+#if CONFIG_PM_MEMORY > 6
+# warning "This logic needs to be extended"
+#endif
+};
+#endif
+
+static const uint16_t g_pmthresh[3] =
+{
+ CONFIG_PM_IDLEENTER_THRESH,
+ CONFIG_PM_STANDBYENTER_THRESH,
+ CONFIG_PM_SLEEPENTER_THRESH
+};
+
+static const uint16_t g_pmcount[3] =
+{
+ CONFIG_PM_IDLEENTER_COUNT,
+ CONFIG_PM_STANDBYENTER_COUNT,
+ CONFIG_PM_SLEEPENTER_COUNT
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pm_worker
+ *
+ * Description:
+ * This worker function is queue at the end of a time slice in order to
+ * update driver activity metrics and recommended states.
+ *
+ * Input Parameters:
+ * arg - The value of the activity accumulator at the end of the time
+ * slice.
+ *
+ * Returned Value:
+ * None.
+ *
+ * Assumptions:
+ * This function runs on the worker thread.
+ *
+ ****************************************************************************/
+
+void pm_worker(FAR void *arg)
+{
+ uint16_t accum = (uint16_t)((uintptr_t)arg);
+ uint32_t Y;
+
+#if CONFIG_PM_MEMORY > 1
+ uint32_t denom;
+ int i, j;
+
+ /* We won't bother to do anything until we have accumulated
+ * CONFIG_PM_MEMORY-1 samples.
+ */
+
+ if (g_pmglobals.mcnt < CONFIG_PM_MEMORY-1)
+ {
+ g_pmglobals.memory[g_pmglobals.mcnt] = accum;
+ g_pmglobals.mcnt++;
+ return;
+ }
+
+ /* The averaging algorithm is simply: Y = (An*X + SUM(Ai*Yi))/SUM(Aj), where
+ * i = 1..n-1 and j= 1..n, n is the length of the "memory", Ai is the
+ * weight applied to each value, and X is the current activity.
+ *
+ * CONFIG_PM_MEMORY provides the memory for the algorithm. Default: 2
+ * CONFIG_PM_COEFn provides weight for each sample. Default: 1
+ *
+ * First, calclate Y = An*X
+ */
+
+ Y = CONFIG_PM_COEFN * accum;
+ denom = CONFIG_PM_COEFN;
+
+ /* Then calculate Y += SUM(Ai*Yi), i = 1..n-1. The oldest sample will
+ * reside at g_pmglobals.mndx (and this is the value that we will overwrite
+ * with the new value).
+ */
+
+ for (i = 0, j = g_pmglobals.mndx; i < CONFIG_PM_MEMORY-1; i++, j++)
+ {
+ if (j >= CONFIG_PM_MEMORY-1)
+ {
+ j = 0;
+ }
+
+ Y += g_pmcoeffs[i] * g_pmglobals.memory[j];
+ denom += g_pmcoeffs[i];
+ }
+
+ /* Compute and save the new activity value */
+
+ Y /= denom;
+ g_pmglobals.memory[g_pmglobals.mndx] = Y;
+ g_pmglobals.mndx++;
+ if (g_pmglobals.mndx >= CONFIG_PM_MEMORY-1)
+ {
+ g_pmglobals.mndx = 0;
+ }
+
+#else
+
+ /* No smoothing */
+
+ Y = accum;
+
+#endif
+
+ /* Now, compare this new activity level to the thresholds and counts for
+ * the next state. Determine if it is appropriate to switch to a new,
+ * lower power consumption state.
+ *
+ * If we are already in the SLEEP state, then there is nothing more to be
+ * done (in fact, I would be surprised to be executing!).
+ */
+
+ if (g_pmglobals.state < PM_SLEEP)
+ {
+ unsigned int nextstate;
+ int index;
+
+ /* Get the next state and the table index for the next state (which will
+ * be the current state)
+ */
+
+ index = g_pmglobals.state;
+ nextstate = g_pmglobals.state + 1;
+
+ /* Has the threshold for the next state been exceeded? */
+
+ if (Y > g_pmthresh[index])
+ {
+ /* No... reset the count and recommend the current state */
+
+ g_pmglobals.thrcnt = 0;
+ g_pmglobals.recommended = g_pmglobals.state;
+ }
+
+ /* Yes.. have we already recommended this state? If so, do nothing */
+
+ else if (g_pmglobals.recommended < nextstate)
+ {
+ /* No.. increment the count. Has is passed the the count required
+ * for a state transition?
+ */
+
+ if (++g_pmglobals.thrcnt >= g_pmcount[index])
+ {
+ /* Yes, recommend the new state and set up for the next
+ * transition.
+ */
+
+ g_pmglobals.thrcnt = 0;
+ g_pmglobals.recommended = nextstate;
+ }
+ }
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pm_update
+ *
+ * Description:
+ * This internal function is called at the end of a time slice in order to
+ * update driver activity metrics and recommended states.
+ *
+ * Input Parameters:
+ * accum - The value of the activity accumulator at the end of the time
+ * slice.
+ *
+ * Returned Value:
+ * None.
+ *
+ * Assumptions:
+ * This function may be called from a driver, perhaps even at the interrupt
+ * level. It may also be called from the IDLE loop at the lowest possible
+ * priority level. To reconcile these various conditions, all work is
+ * performed on the worker thread at a user-selectable priority. This will
+ * also serialize all of the updates and eliminate any need for additional
+ * protection.
+ *
+ ****************************************************************************/
+
+void pm_update(uint16_t accum)
+{
+ /* The work will be performed on the worker thread */
+
+ DEBUGASSERT(g_pmglobals.work.worker == NULL);
+ (void)work_queue(&g_pmglobals.work, pm_worker, (FAR void*)((uintptr_t)accum), 0);
+}
+
+#endif /* CONFIG_PM */ \ No newline at end of file
diff --git a/nuttx/include/nuttx/pm.h b/nuttx/include/nuttx/pm.h
index 184f00e9c..36daadcbc 100644
--- a/nuttx/include/nuttx/pm.h
+++ b/nuttx/include/nuttx/pm.h
@@ -37,22 +37,28 @@
* have various names and are sometimes used in conflicting ways. In the
* PM logic, we will use the following terminology:
*
- * NORMAL - The normal, full power operating mode.
- * REDUCED - This is still basically normal operational mode, but with some
- * simple changes to reduce power consumption. Perhaps this just
- * means just dimming the backlight.
- * STANDBY - Standby is a very low power consumption mode. It is the lowest
- * power from which the system can recover quickly.
- * SLEEP - The lowest power consumption mode. It may require some time
- * to get back to normal operation from SLEEP (some parts may
- * even require going through reset).
+ * NORMAL - The normal, full power operating mode.
+ * IDLE - This is still basically normal operational mode, the system is,
+ * however, IDLE and some simple simple steps to reduce power
+ * consumption provided that they do not interfere with normal
+ * Operation. Simply dimming the a backlight might be an example
+ * somethat that would be done when the system is idle.
+ * STANDBY - Standby is a lower power consumption mode that may involve more
+ * extensive power management steps such has disabling clocking or
+ * setting the processor into reduced power consumption modes. In
+ * this state, the system should still be able to resume normal
+ * activity almost immediately.
+ * SLEEP - The lowest power consumption mode. The most drastic power
+ * reduction measures possible should be taken in this state. It
+ * may require some time to get back to normal operation from
+ * SLEEP (some MCUs may even require going through reset).
*
* State changes always proceed from higher to lower power usage:
*
- * NORMAL->REDUCED->STANDBY->SLEEP
- * ^ | | |
- * | V V V
- * +-------+---------+--------+
+ * NORMAL->IDLE->STANDBY->SLEEP
+ * ^ | | |
+ * | V V V
+ * +-------+------+--------+
*/
#ifndef __INCLUDE_NUTTX_PM_H
@@ -64,28 +70,112 @@
#include <nuttx/config.h>
+#include <queue.h>
+
#ifdef CONFIG_PM
/****************************************************************************
* Pre-Processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
-/* Time slices */
+/* Time slices. The power management module collects activity counts in
+ * time slices. At the end of the time slice, the count accumulated during
+ * that interval is applied to an averaging algorithm to determine the
+ * activity level.
+ *
+ * CONFIG_PM_SLICEMS provides the duration of that time slice. Default: 100
+ * Milliseconds
+ */
#ifndef CONFIG_PM_SLICEMS
-# define CONFIG_PM_SLICEMS 100 /* Default is 100 msec */
+# define CONFIG_PM_SLICEMS 100 /* Default is 100 msec */
+#endif
+
+/* The averaging algorithm is simply: Y = (An*X + SUM(Ai*Yi))/SUM(Aj), where
+ * i = 1..n-1 and j= 1..n, n is the length of the "memory", Ai is the
+ * weight applied to each value, and X is the current activity.
+ *
+ * CONFIG_PM_MEMORY provides the memory for the algorithm. Default: 2
+ * CONFIG_PM_COEFn provides weight for each sample. Default: 1
+ *
+ * Setting CONFIG_PM_MEMORY=1 disables all smoothing.
+ */
+
+#ifndef CONFIG_PM_MEMORY
+# define CONFIG_PM_MEMORY 2
+#endif
+
+#ifndef CONFIG_PM_MEMORY < 1
+# error "CONFIG_PM_MEMORY must be >= 1"
+#endif
+
+#ifndef CONFIG_PM_COEFN
+# define CONFIG_PM_COEFN 1
+#endif
+
+#if CONFIG_PM_MEMORY > 1 && !defined(CONFIG_PM_COEF1)
+# define CONFIG_PM_COEF1 1
+#endif
+
+#if CONFIG_PM_MEMORY > 2 && !defined(CONFIG_PM_COEF2)
+# define CONFIG_PM_COEF2 1
+#endif
+
+#if CONFIG_PM_MEMORY > 3 && !defined(CONFIG_PM_COEF3)
+# define CONFIG_PM_COEF3 1
+#endif
+
+#if CONFIG_PM_MEMORY > 4 && !defined(CONFIG_PM_COEF4)
+# define CONFIG_PM_COEF4 1
+#endif
+
+#if CONFIG_PM_MEMORY > 5 && !defined(CONFIG_PM_COEF5)
+# define CONFIG_PM_COEF5 1
+#endif
+
+#if CONFIG_PM_MEMORY > 6
+# warning "This logic needs to be extended"
+#endif
+
+/* State changes then occur when the weight activity account crosses
+ * threshold values for certain periods of time (time slice count).
+ *
+ * CONFIG_PM_xxxENTER_THRESH is the threshold value for entering state xxx.
+ * CONFIG_PM_xxxENTER_COUNT is the count for entering state xxx.
+ *
+ * Resuming to normal state, on the other hand, is usually immediate and
+ * controlled by wakeup conditions established by the platform. The PM
+ * module only recommends reduced power states.
+ */
+
+#ifndef CONFIG_PM_IDLEENTER_THRESH
+# define CONFIG_PM_IDLEENTER_THRESH 1 /* Essentially no activity */
#endif
-#ifndef CONFIG_PM_NREDUCED
-# define CONFIG_PM_NREDUCED 30 /* Thiry IDLE slices to enter reduced mode */
+#ifndef CONFIG_PM_IDLEENTER_COUNT
+# define CONFIG_PM_IDLEENTER_COUNT 30 /* Thirty IDLE slices to enter
+ * IDLE mode from normal
+ */
#endif
-#ifndef CONFIG_PM_NSTANDBY
-# define CONFIG_PM_NSTANDBY 80 /* Eight IDLE slices to enter standby mode */
+#ifndef CONFIG_PM_STANDBYENTER_THRESH
+# define CONFIG_PM_STANDBYENTER_THRESH 1 /* Essentially no activity */
#endif
-#ifndef CONFIG_PM_NSLEEP
-# define CONFIG_PM_NSLEEP 150 /* 150 IDLE slices to enter standby mode */
+#ifndef CONFIG_PM_STANDBYENTER_COUNT
+# define CONFIG_PM_STANDBYENTER_COUNT 50 /* Fifty IDLE slices to enter
+ * STANDBY mode from IDLE
+ */
+#endif
+
+#ifndef CONFIG_PM_SLEEPENTER_THRESH
+# define CONFIG_PM_SLEEPENTER_THRESH 1 /* Essentially no activity */
+#endif
+
+#ifndef CONFIG_PM_SLEEPENTER_COUNT
+# define CONFIG_PM_SLEEPENTER_COUNT 70 /* 70 IDLE slices to enter SLEEP
+ * mode from STANDBY
+ */
#endif
/****************************************************************************
@@ -98,30 +188,38 @@
enum pm_state_e
{
- PM_REDUCED = 0, /* Drivers will receive periodic this indications if it is
- * appropriate to enter a simple reduced power state. This
- * would include simple things such as displaying display back-
- * lighting. The driver should essentially be ready to resume
- * normal activity instantly.
+ PM_NORMAL = 0, /* Normal full power operating mode. If the driver is in
+ * a reduced power usage mode, it should immediately re-
+ * initialize for normal operatin.
*
- * PM_REDUCED may be followed by PM_STANDBY or PM_RESUME.
+ * PM_NORMAL may be followed by PM_IDLE.
*/
- PM_STANDBY, /* The system is entering standby mode. The driver should
- * already be prepared for this mode.
+ PM_IDLE, /* Drivers will receive this state change if it is
+ * appropriate to enter a simple IDLE power state. This
+ * would include simple things such as reducing display back-
+ * lighting. The driver should be ready to resume normal
+ * activity instantly.
*
- * PM_STANDBY may be followed PM_SLEEP or by PM_RESUME
+ * PM_IDLE may be followed by PM_STANDBY or PM_NORMAL.
*/
- PM_SLEEP, /* The system is entering deep sleep mode. The driver should
- * already be prepared for this mode.
+ PM_STANDBY, /* The system is entering standby mode. Standby is a lower
+ * power consumption mode that may involve more extensive
+ * power management steps such has disabling clocking or
+ * setting the processor into reduced power consumption
+ * modes. In this state, the system should still be able
+ * to resume normal activity almost immediately.
*
- * PM_SLEEP may be following by PM_RESUME
+ * PM_STANDBY may be followed PM_SLEEP or by PM_NORMAL
*/
- PM_RESUME, /* The system is resuming normal operation. The driver should
- * reinitialize for normal operation.
+ PM_SLEEP, /* The system is entering deep sleep mode. The most drastic
+ * power reduction measures possible should be taken in this
+ * state. It may require some time to get back to normal
+ * operation from SLEEP (some MCUs may even require going
+ * through reset).
*
- * PM_RESUME may be followed by PM_REDUCED.
+ * PM_SLEEP may be following by PM_NORMAL
*/
-}
+};
/* This structure contain pointers callback functions in the driver. These
* callback functions can be used to provide power management information
@@ -130,7 +228,7 @@ enum pm_state_e
struct pm_callback_s
{
- struct pm_callback_s *flink; /* Supports a singly linked list */
+ struct sq_entry_s entry; /* Supports a singly linked list */
/**************************************************************************
* Name: prepare
@@ -173,12 +271,14 @@ struct pm_callback_s
*
* Returned Value:
* 0 (OK) means the event was successfully processed. Non-zero means
- * means that the driver failed to enter the power mode.
+ * means that the driver failed to enter the lower power consumption
+ * mode. Drivers are not permitted to return non-zero values when
+ * reverting to higher power consumption modes!
*
**************************************************************************/
int (*notify)(FAR struct pm_callback_s *cb, enum pm_state_e pmstate);
-}
+};
/****************************************************************************
* Public Data
@@ -197,6 +297,26 @@ extern "C" {
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
+ * Name: pm_initialize
+ *
+ * Description:
+ * This function is called by MCU-specific one-time at power on reset in
+ * order to initialize the power management capabilities. This function
+ * must be called *very* early in the intialization sequence *before* any
+ * other device drivers are initialize (since they may attempt to register
+ * with the power management subsystem).
+ *
+ * Input parameters:
+ * None.
+ *
+ * Returned value:
+ * None.
+ *
+ ****************************************************************************/
+
+EXTERN void pm_initialize(void);
+
+/****************************************************************************
* Name: pm_register
*
* Description:
@@ -215,60 +335,94 @@ extern "C" {
EXTERN int pm_register(FAR struct pm_callback_s *callbacks);
/****************************************************************************
- * Name: pm_changestate
+ * Name: pm_activity
*
* Description:
- * This function is used to platform-specific power managmeent logic. It
- * will announce the power management power management state change to all
- * drivers that have registered for power management event callbacks.
+ * This function is called by a device driver to indicate that it is
+ * performing meaningful activities (non-idle). This increment an activty
+ * cound and/or will restart a idle timer and prevent entering IDLE
+ * power states.
*
* Input Parameters:
- * pmstate - Idenfifies the new PM state
+ * priority - activity priority, range 0-9. Larger values correspond to
+ * higher priorities. Higher priority activity can prevent the system
+ * fromentering reduced power states for a longer period of time.
+ *
+ * As an example, a button press might be higher priority activity because
+ * it means that the user is actively interacting with the device.
*
* Returned Value:
- * 0 (OK) means that the callback function for all registered drivers
- * returned OK (meaning that they accept the state change).
+ * None.
+ *
+ * Assumptions:
+ * This function may be called from an interrupt handler (this is the ONLY
+ * PM function that may be called from an interrupt handler!).
*
****************************************************************************/
-EXTERN int pm_changestate(enum pm_event_s pmstate);
+EXTERN void pm_activity(int priority);
/****************************************************************************
- * Name: pm_activity
+ * Name: pm_checkstate
*
* Description:
- * This function is called by a device driver to indicate that it is
- * performing meaningful activities (non-idle). This increment an activty
- * cound and/or will restart a idle timer and prevent entering reduced
- * power states.
+ * This function is called from the MCU-specific IDLE loop to monitor the
+ * the power management conditions. This function returns the "recommended"
+ * power management state based on the PM configuration and activity
+ * reported in the last sampling periods. The power management state is
+ * not automatically changed, however. The IDLE loop must call
+ * pm_changestate() in order to make the state change.
+ *
+ * These two steps are separated because the plaform-specific IDLE loop may
+ * have additional situational information that is not available to the
+ * the PM sub-system. For example, the IDLE loop may know that the
+ * battery charge level is very low and may force lower power states
+ * even if there is activity.
+ *
+ * NOTE: That these two steps are separated in time and, hence, the IDLE
+ * could be suspended for a long period of time between calling
+ * pm_checkstate() and pm_changestate(). There it is recommended that
+ * the IDLE loop make these calls atomic by either disabling interrupts
+ * until the state change is completed.
*
* Input Parameters:
* None
*
* Returned Value:
- * The current activity count.
+ * The recommended power management state.
*
****************************************************************************/
-EXTERN int pm_activity(void);
+EXTERN enum pm_state_e pm_checkstate(void);
/****************************************************************************
- * Name: pm_checkactivity
+ * Name: pm_changestate
*
* Description:
- * Return the activity count accumulated since the last time this function
- * was called. A count of zero will indicate that no meaningful activity
- * occurred since the last time this function was called.
+ * This function is used to platform-specific power managmeent logic. It
+ * will announce the power management power management state change to all
+ * drivers that have registered for power management event callbacks.
*
* Input Parameters:
- * None
+ * newstate - Idenfifies the new PM state
*
* Returned Value:
- * The current activity count.
+ * 0 (OK) means that the callback function for all registered drivers
+ * returned OK (meaning that they accept the state change). Non-zero
+ * means that one of the drivers refused the state change. In this case,
+ * the system will revert to the preceding state.
+ *
+ * Assumptions:
+ * It is assumed that interrupts are disabled when this function is
+ * called. This function is probably called from the IDLE loop... the
+ * lowest priority task in the system. Changing driver power management
+ * states may result in renewed system activity and, as a result, can
+ * suspend the IDLE thread before it completes the entire state change
+ * unless interrupts are disabled throughout the state change.
*
****************************************************************************/
-EXTERN int pm_checkactivity(void);
+EXTERN int pm_changestate(enum pm_state_e newstate);
#undef EXTERN
#ifdef __cplusplus