aboutsummaryrefslogtreecommitdiff
path: root/nuttx/drivers/power
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/drivers/power')
-rw-r--r--nuttx/drivers/power/Kconfig23
-rw-r--r--nuttx/drivers/power/Make.defs84
-rw-r--r--nuttx/drivers/power/battery.c254
-rw-r--r--nuttx/drivers/power/max1704x.c564
-rw-r--r--nuttx/drivers/power/pm_activity.c166
-rw-r--r--nuttx/drivers/power/pm_changestate.c227
-rw-r--r--nuttx/drivers/power/pm_checkstate.c161
-rw-r--r--nuttx/drivers/power/pm_initialize.c112
-rw-r--r--nuttx/drivers/power/pm_internal.h210
-rw-r--r--nuttx/drivers/power/pm_register.c112
-rw-r--r--nuttx/drivers/power/pm_update.c334
11 files changed, 2247 insertions, 0 deletions
diff --git a/nuttx/drivers/power/Kconfig b/nuttx/drivers/power/Kconfig
new file mode 100644
index 000000000..ac76331b6
--- /dev/null
+++ b/nuttx/drivers/power/Kconfig
@@ -0,0 +1,23 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+config BATTERY
+ bool "Battery support"
+ default n
+
+config MAX1704X
+ bool "MAX1704X Battery charger support"
+ default n
+ select I2C
+ select I2C_MAX1704X
+ depends on BATTERY
+ ---help---
+ The MAX17040/MAX17041 are ultra-compact, low-cost, host-side fuel-gauge
+ systems for lithium-ion (Li+) batteries in handheld and portable equipment.
+ The MAX17040 is configured to operate with a single lithium cell and the
+ MAX17041 is configured for a dual-cell 2S pack.
+
+config I2C_MAX1704X
+ bool
+ default y if MAX1704X
diff --git a/nuttx/drivers/power/Make.defs b/nuttx/drivers/power/Make.defs
new file mode 100644
index 000000000..45c6aebc3
--- /dev/null
+++ b/nuttx/drivers/power/Make.defs
@@ -0,0 +1,84 @@
+############################################################################
+# drivers/power/Make.defs
+#
+# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
+# Author: Gregory Nutt <gnutt@nuttx.org>
+#
+# 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.
+#
+############################################################################
+
+POWER_DEPPATH =
+POWER_VPATH =
+POWER_CFLAGS =
+
+# Include power management sources
+
+ifeq ($(CONFIG_PM),y)
+
+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
+
+POWER_DEPPATH := --dep-path power
+POWER_VPATH := :power
+POWER_CFLAGS := ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" $(TOPDIR)/drivers/power}
+
+endif
+
+# Add battery drivers
+
+ifeq ($(CONFIG_BATTERY),y)
+
+CSRCS += battery.c
+
+# Add I2C-based battery drivers
+
+ifeq ($(CONFIG_I2C),y)
+
+# Add the MAX1704x I2C-based battery driver
+
+ifeq ($(CONFIG_I2C_MAX1704X),y)
+CSRCS += max1704x.c
+endif
+
+endif
+
+# Include battery suport in the build
+
+POWER_DEPPATH := --dep-path power
+POWER_VPATH := :power
+POWER_CFLAGS := ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" $(TOPDIR)/drivers/power}
+
+endif
+
+# Include power management in the build
+
+DEPPATH += $(POWER_DEPPATH)
+VPATH += $(POWER_VPATH)
+CFLAGS += $(POWER_CFLAGS)
diff --git a/nuttx/drivers/power/battery.c b/nuttx/drivers/power/battery.c
new file mode 100644
index 000000000..698e5571b
--- /dev/null
+++ b/nuttx/drivers/power/battery.c
@@ -0,0 +1,254 @@
+/****************************************************************************
+ * drivers/power/battery.c
+ * Upper-half, character driver for batteries.
+ *
+ * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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 <stdbool.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/fs/fs.h>
+#include <nuttx/power/battery.h>
+
+/* This driver requires:
+ *
+ * CONFIG_BATTERY - Upper half battery driver support
+ */
+
+#if defined(CONFIG_BATTERY)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+static int bat_open(FAR struct file *filep);
+static int bat_close(FAR struct file *filep);
+static ssize_t bat_read(FAR struct file *, FAR char *, size_t nbytes);
+static ssize_t bat_write(FAR struct file *filep, FAR const char *buffer, size_t buflen);
+static int bat_ioctl(FAR struct file *filep,int cmd,unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct file_operations g_batteryops =
+{
+ bat_open,
+ bat_close,
+ bat_read,
+ bat_write,
+ 0,
+ bat_ioctl
+#ifndef CONFIG_DISABLE_POLL
+ , 0
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+/****************************************************************************
+ * Name: bat_open
+ *
+ * Description:
+ * This function is called whenever the battery device is opened.
+ *
+ ****************************************************************************/
+
+static int bat_open(FAR struct file *filep)
+{
+ return OK;
+}
+
+/****************************************************************************
+ * Name: bat_close
+ *
+ * Description:
+ * This routine is called when the battery device is closed.
+ *
+ ****************************************************************************/
+
+static int bat_close(FAR struct file *filep)
+{
+ return OK;
+}
+
+/****************************************************************************
+ * Name: bat_read
+ ****************************************************************************/
+
+static ssize_t bat_read(FAR struct file *filep, FAR char *buffer, size_t buflen)
+{
+ /* Return nothing read */
+
+ return 0;
+}
+
+/****************************************************************************
+ * Name: bat_write
+ ****************************************************************************/
+
+static ssize_t bat_write(FAR struct file *filep, FAR const char *buffer,
+ size_t buflen)
+{
+ /* Return nothing written */
+
+ return 0;
+}
+
+/****************************************************************************
+ * Name: bat_ioctl
+ ****************************************************************************/
+
+static int bat_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct battery_dev_s *dev = inode->i_private;
+ int ret = -EINVAL;
+
+ /* Inforce mutually exclusive access to the battery driver */
+
+ ret = sem_wait(&dev->batsem);
+ if (ret < 0)
+ {
+ return -errno; /* Probably EINTR */
+ }
+
+ /* Procss the IOCTL command */
+
+ ret = -EINVAL; /* Assume a bad argument */
+ switch (cmd)
+ {
+ case BATIOC_STATE:
+ {
+ FAR int *ptr = (FAR int *)((uintptr_t)arg);
+ if (ptr)
+ {
+ ret = dev->ops->state(dev, ptr);
+ }
+ }
+ break;
+
+ case BATIOC_ONLINE:
+ {
+ FAR bool *ptr = (FAR bool *)((uintptr_t)arg);
+ if (ptr)
+ {
+ ret = dev->ops->online(dev, ptr);
+ }
+ }
+ break;
+
+ case BATIOC_VOLTAGE:
+ {
+ FAR b16_t *ptr = (FAR b16_t *)((uintptr_t)arg);
+ if (ptr)
+ {
+ ret = dev->ops->voltage(dev, ptr);
+ }
+ }
+ break;
+
+ case BATIOC_CAPACITY:
+ {
+ FAR b16_t *ptr = (FAR b16_t *)((uintptr_t)arg);
+ if (ptr)
+ {
+ ret = dev->ops->capacity(dev, ptr);
+ }
+ }
+ break;
+
+ default:
+ dbg("Unrecognized cmd: %d\n", cmd);
+ ret = -ENOTTY;
+ break;
+ }
+
+ sem_post(&dev->batsem);
+ return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: battery_register
+ *
+ * Description:
+ * Register a lower half battery driver with the common, upper-half
+ * battery driver.
+ *
+ * Input parameters:
+ * devpath - The location in the pseudo-filesystem to create the driver.
+ * Recommended standard is "/dev/bat0", "/dev/bat1", etc.
+ * dev - An instance of the battery state structure .
+ *
+ * Returned value:
+ * Zero on success or a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int battery_register(FAR const char *devpath, FAR struct battery_dev_s *dev)
+{
+ int ret;
+
+ /* Register the character driver */
+
+ ret = register_driver(devpath, &g_batteryops, 0555, dev);
+ if (ret < 0)
+ {
+ dbg("Failed to register driver: %d\n", ret);
+ }
+ return ret;
+}
+#endif /* CONFIG_BATTERY */
diff --git a/nuttx/drivers/power/max1704x.c b/nuttx/drivers/power/max1704x.c
new file mode 100644
index 000000000..ec50515e6
--- /dev/null
+++ b/nuttx/drivers/power/max1704x.c
@@ -0,0 +1,564 @@
+/****************************************************************************
+ * drivers/power/max1704x.c
+ * Lower half driver for MAX1704x battery charger
+ *
+ * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/* "The MAX17040/MAX17041 are ultra-compact, low-cost, host-side fuel-gauge
+ * systems for lithium-ion (Li+) batteries in handheld and portable equipment.
+ * The MAX17040 is configured to operate with a single lithium cell and the
+ * MAX17041 is configured for a dual-cell 2S pack.
+ */
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c.h>
+#include <nuttx/power/battery.h>
+
+/* This driver requires:
+ *
+ * CONFIG_BATTERY - Upper half battery driver support
+ * CONFIG_I2C - I2C support
+ * CONFIG_I2C_MAX1704X - And the driver must be explictly selected.
+ */
+
+#if defined(CONFIG_BATTERY) && defined(CONFIG_I2C) && defined(CONFIG_I2C_MAX1704X)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+/* CONFIG_I2C_MAX17040 or CONFIG_I2C_MAX17041 - The driver must know which
+ * chip is on the board in order to scale the voltage correctly.
+ */
+
+#if !defined(CONFIG_I2C_MAX17040) && !defined(CONFIG_I2C_MAX17041)
+# warning "Assuming CONFIG_I2C_MAX17040"
+# define CONFIG_I2C_MAX17040 1
+#endif
+
+/* MAX1704x Register Definitions ********************************************/
+/* "All host interaction with the MAX17040/MAX17041 is handled by writing to
+ * and reading from register locations. The MAX17040/MAX17041 have six 16-bit
+ * registers: SOC, VCELL, MODE, VERSION, RCOMP, and COMMAND. Register reads
+ * and writes are only valid if all 16 bits are transferred..."
+ */
+
+/* "VCELL Register. Battery voltage is measured at the CELL pin input with
+ * respect to GND over a 0 to 5.00V range for the MAX17040 and 0 to 10.00V
+ * for the MAX17041 with resolutions of 1.25mV and 2.50mV, respectively..."
+ */
+
+#define MAX1407X_VCELL_ADDR 0x02 /* Bits 4-15: Bits 0-11 of the battery voltage */
+
+/* VCELL conversion macros */
+
+#define MAX14700_VCELL_CONV 82 /* 0.00125 v * 65536 */
+#define MAX14070_VCELL(v) ((b16_t)(v) * MAX14700_VCELL_CONV)
+
+#define MAX14701_VCELL_CONV 163 /* 0.0025 v * 65536 */
+#define MAX14071_VCELL(v) ((b16_t)(v) * MAX14701_VCELL_CONV)
+
+#ifdef CONFIG_I2C_MAX17040
+# define MAX1407X_VCELL(v) MAX14070_VCELL(v)
+#else
+# define MAX1407X_VCELL(v) MAX14071_VCELL(v)
+#endif
+
+/* "SOC Register. The SOC register is a read-only register that displays the
+ * state of charge of the cell as calculated by the ModelGauge algorithm. The
+ * result is displayed as a percentage of the cell’s full capacity...
+ *
+ * "...Units of % can be directly determined by observing only the high byte
+ * of the SOC register. The low byte provides additional resolution in units
+ * 1/256%.
+ */
+
+#define MAX1407X_SOC_ADDR 0x04 /* Bits 0-15: Full SOC */
+
+/* SoC conversion macros */
+
+#define MAX1407X_SOC(s) ((b16_t)(s) << 8)
+#define MAX17040_SOC_FULL itob16(95) /* We say full if Soc >= 95% */
+
+/* "MODE Register.The MODE register allows the host processor to send special
+ * commands to the IC."
+ */
+
+#define MAX1407X_MODE_ADDR 0x06 /* Bits 0-15: 16-bit MODE */
+
+/* Supported modes */
+
+#define MAX1407X_MODE_QUICKSTART 0x4000
+
+/* "The VERSION register is a read-only register that contains a value
+ * indicating the production version of the MAX17040/MAX17041."
+ */
+
+#define MAX1407X_VERSION_ADDR 0x08 /* Bits 0-15: 16-bit VERSION */
+
+/* "RCOMP Register. RCOMP is a 16-bit value used to compensate the ModelGauge
+ * algorithm. RCOMP can be adjusted to optimize performance for different
+ * lithium chemistries or different operating temperatures... The factory-
+ * default value for RCOMP is 9700h."
+ */
+
+#define MAX1407X_RCOMP_ADDR 0x0c /* Bits 0-15: 16-bit RCOMP */
+
+/* "COMMAND Register. The COMMAND register allows the host processor to send
+ * special commands to the IC..."
+ */
+
+#define MAX1407X_COMMAND_ADDR 0xfe /* Bits 0-7: 16-bit COMMAND */
+
+/* Supported copmmands */
+
+#define MAX1407X_COMMAND_POR 0x5400
+
+/* Debug ********************************************************************/
+
+#ifdef CONFIG_DEBUG_MAX1704X
+# define batdbg dbg
+#else
+# ifdef CONFIG_CPP_HAVE_VARARGS
+# define batdbg(x...)
+# else
+# define batdbg (void)
+# endif
+#endif
+
+/****************************************************************************
+ * Private
+ ****************************************************************************/
+
+struct max1704x_dev_s
+{
+ /* The common part of the battery driver visible to the upper-half driver */
+
+ FAR const struct battery_operations_s *ops; /* Battery operations */
+ sem_t batsem; /* Enforce mutually exclusive access */
+
+ /* Data fields specific to the lower half MAX1704x driver follow */
+
+ FAR struct i2c_dev_s *i2c; /* I2C interface */
+ uint8_t addr; /* I2C address */
+ uint32_t frequency; /* I2C frequency */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+/* I2C support */
+
+static int max1704x_getreg16(FAR struct max1704x_dev_s *priv, uint8_t regaddr,
+ FAR uint16_t *regval);
+static int max1704x_putreg16(FAR struct max1704x_dev_s *priv, uint8_t regaddr,
+ uint16_t regval);
+
+static inline int max1704x_getvcell(FAR struct max1704x_dev_s *priv,
+ b16_t *vcell);
+static inline int max1704x_getsoc(FAR struct max1704x_dev_s *priv,
+ b16_t *soc);
+static inline int max1704x_setquikstart(FAR struct max1704x_dev_s *priv);
+static inline int max1704x_getversion(FAR struct max1704x_dev_s *priv,
+ uint16_t *version);
+static inline int max1704x_reset(FAR struct max1704x_dev_s *priv);
+
+/* Battery driver lower half methods */
+
+static int max1704x_state(struct battery_dev_s *dev, int *status);
+static int max1704x_online(struct battery_dev_s *dev, bool *status);
+static int max1704x_voltage(struct battery_dev_s *dev, b16_t *value);
+static int max1704x_capacity(struct battery_dev_s *dev, b16_t *value);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct battery_operations_s g_max1704xops =
+{
+ max1704x_state,
+ max1704x_online,
+ max1704x_voltage,
+ max1704x_capacity
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: max1704x_getreg16
+ *
+ * Description:
+ * Read a 16-bit value from a MAX1704x register pair.
+ *
+ * START <I2C write address> ACK <Reg address> ACK
+ * REPEATED-START <I2C read address> ACK Data0 ACK Data1 NO-ACK STOP
+ *
+ ****************************************************************************/
+
+static int max1704x_getreg16(FAR struct max1704x_dev_s *priv, uint8_t regaddr,
+ FAR uint16_t *regval)
+{
+ uint8_t buffer[2];
+ int ret;
+
+ /* Set the I2C address and address size */
+
+ I2C_SETADDRESS(priv->i2c, priv->addr, 7);
+
+ /* Write the register address */
+
+ ret = I2C_WRITE(priv->i2c, &regaddr, 1);
+ if (ret < 0)
+ {
+ batdbg("I2C_WRITE failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Restart and read 16-bits from the register */
+
+ ret = I2C_READ(priv->i2c, buffer, 2);
+ if (ret < 0)
+ {
+ batdbg("I2C_READ failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Return the 16-bit value */
+
+ return (uint16_t)buffer[0] << 8 | (uint16_t)buffer[1];
+ return OK;
+}
+
+/****************************************************************************
+ * Name: max1704x_putreg16
+ *
+ * Description:
+ * Write a 16-bit value to a MAX1704x register pair.
+ *
+ * START <I2C write address> ACK <Reg address> ACK Data0 ACK Data1 ACK STOP
+ *
+ ****************************************************************************/
+
+static int max1704x_putreg16(FAR struct max1704x_dev_s *priv, uint8_t regaddr,
+ uint16_t regval)
+{
+ uint8_t buffer[3];
+
+ batdbg("addr: %02x regval: %08x\n", regaddr, regval);
+
+ /* Set up a 3 byte message to send */
+
+ buffer[0] = regaddr;
+ buffer[1] = (uint8_t)(regval >> 8);
+ buffer[2] = (uint8_t)(regval & 0xff);
+
+ /* Set the I2C address and address size */
+
+ I2C_SETADDRESS(priv->i2c, priv->addr, 7);
+
+ /* Write the register address followed by the data (no RESTART) */
+
+ return I2C_WRITE(priv->i2c, buffer, 3);
+}
+
+/****************************************************************************
+ * Name: max1704x_getvcell
+ *
+ * Description:
+ * Read the VCELL register and scale the returned value
+ *
+ ****************************************************************************/
+
+static inline int max1704x_getvcell(FAR struct max1704x_dev_s *priv,
+ b16_t *vcell)
+{
+ uint16_t regval = 0;
+ int ret;
+
+ ret = max1704x_getreg16(priv, MAX1407X_VCELL_ADDR, &regval);
+ if (ret == OK)
+ {
+ *vcell = MAX1407X_VCELL(regval);
+ }
+ return ret;
+}
+
+/****************************************************************************
+ * Name: max1704x_getsoc
+ *
+ * Description:
+ * Read the SOC register and scale the returned value
+ *
+ ****************************************************************************/
+
+static inline int max1704x_getsoc(FAR struct max1704x_dev_s *priv,
+ b16_t *soc)
+{
+ uint16_t regval = 0;
+ int ret;
+
+ ret = max1704x_getreg16(priv, MAX1407X_VCELL_ADDR, &regval);
+ if (ret == OK)
+ {
+ *soc = MAX1407X_SOC(regval);
+ }
+ return ret;
+}
+
+/****************************************************************************
+ * Name: max1704x_setquikstart
+ *
+ * Description:
+ * Set Quickstart mode
+ *
+ ****************************************************************************/
+
+static inline int max1704x_setquikstart(FAR struct max1704x_dev_s *priv)
+{
+ return max1704x_putreg16(priv, MAX1407X_MODE_ADDR, MAX1407X_MODE_QUICKSTART);
+}
+
+/****************************************************************************
+ * Name: max1704x_getversion
+ *
+ * Description:
+ * Read the SOC register and scale the returned value
+ *
+ ****************************************************************************/
+
+static inline int max1704x_getversion(FAR struct max1704x_dev_s *priv,
+ uint16_t *version)
+{
+ return max1704x_getreg16(priv, MAX1407X_VCELL_ADDR, version);
+}
+
+/****************************************************************************
+ * Name: max1704x_setrcomp
+ *
+ * Description:
+ * Set Quickstart mode
+ *
+ ****************************************************************************/
+
+static inline int max1704x_setrcomp(FAR struct max1704x_dev_s *priv, uint16_t rcomp)
+{
+ return max1704x_putreg16(priv, MAX1407X_RCOMP_ADDR, rcomp);
+}
+
+/****************************************************************************
+ * Name: max1704x_reset
+ *
+ * Description:
+ * Reset the MAX1704x
+ *
+ ****************************************************************************/
+
+static inline int max1704x_reset(FAR struct max1704x_dev_s *priv)
+{
+ return max1704x_putreg16(priv, MAX1407X_COMMAND_ADDR, MAX1407X_COMMAND_POR);
+}
+
+/****************************************************************************
+ * Name: max1704x_state
+ *
+ * Description:
+ * Return the current battery state
+ *
+ ****************************************************************************/
+
+static int max1704x_state(struct battery_dev_s *dev, int *status)
+{
+ FAR struct max1704x_dev_s *priv = (FAR struct max1704x_dev_s *)dev;
+ b16_t soc = 0;
+ int ret;
+
+ /* Only a few of the possible battery states are supported by this driver:
+ *
+ * BATTERY_UNKNOWN - Returned on error conditions
+ * BATTERY_IDLE - This is what will usually be reported
+ * BATTERY_FULL - This will be reported if the SoC is greater than 95%
+ * BATTERY_CHARGING and BATTERY_DISCHARGING - I don't think this hardware
+ * knows anything about current (charging or dischargin).
+ */
+
+ ret = max1704x_getsoc(priv, &soc);
+ if (ret < 0)
+ {
+ *status = BATTERY_UNKNOWN;
+ return ret;
+ }
+
+ /* Is the battery fully charged? */
+
+ if (soc > MAX17040_SOC_FULL)
+ {
+ *status = BATTERY_FULL;
+ }
+ else
+ {
+ *status = BATTERY_IDLE;
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: max1704x_online
+ *
+ * Description:
+ * Return true if the batter is online
+ *
+ ****************************************************************************/
+
+static int max1704x_online(struct battery_dev_s *dev, bool *status)
+{
+ /* There is no concept of online/offline in this driver */
+
+ *status = true;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: max1704x_voltage
+ *
+ * Description:
+ * Current battery voltage
+ *
+ ****************************************************************************/
+
+static int max1704x_voltage(struct battery_dev_s *dev, b16_t *value)
+{
+ FAR struct max1704x_dev_s *priv = (FAR struct max1704x_dev_s *)dev;
+ return max1704x_getvcell(priv, value);
+}
+
+/****************************************************************************
+ * Name: max1704x_capacity
+ *
+ * Description:
+ * Battery capacity
+ *
+ ****************************************************************************/
+
+static int max1704x_capacity(struct battery_dev_s *dev, b16_t *value)
+{
+ FAR struct max1704x_dev_s *priv = (FAR struct max1704x_dev_s *)dev;
+ return max1704x_getsoc(priv, value);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: max1704x_initialize
+ *
+ * Description:
+ * Initialize the MAX1704x battery driver and return an instance of the
+ * lower_half interface that may be used with battery_register();
+ *
+ * This driver requires:
+ *
+ * CONFIG_BATTERY - Upper half battery driver support
+ * CONFIG_I2C - I2C support
+ * CONFIG_I2C_MAX1704X - And the driver must be explictly selected.
+ * CONFIG_I2C_MAX17040 or CONFIG_I2C_MAX17041 - The driver must know which
+ * chip is on the board in order to scale the voltage correctly.
+ *
+ * Input Parameters:
+ * i2c - An instance of the I2C interface to use to communicate with the MAX1704x
+ * addr - The I2C address of the MAX1704x (Better be 0x36).
+ * frequency - The I2C frequency
+ *
+ * Returned Value:
+ * A pointer to the intialized lower-half driver instance. A NULL pointer
+ * is returned on a failure to initialize the MAX1704x lower half.
+ *
+ ****************************************************************************/
+
+FAR struct battery_dev_s *max1704x_initialize(FAR struct i2c_dev_s *i2c,
+ uint8_t addr, uint32_t frequency)
+{
+ FAR struct max1704x_dev_s *priv;
+#if 0
+ int ret;
+#endif
+
+ /* Initialize the MAX1704x device structure */
+
+ priv = (FAR struct max1704x_dev_s *)kzalloc(sizeof(struct max1704x_dev_s));
+ if (priv)
+ {
+ /* Initialize the MAX1704x device structure */
+
+ sem_init(&priv->batsem, 0, 1);
+ priv->ops = &g_max1704xops;
+ priv->i2c = i2c;
+ priv->addr = addr;
+ priv->frequency = frequency;
+
+ /* Set the I2C frequency (ignoring the returned, actual frequency) */
+
+ (void)I2C_SETFREQUENCY(i2c, priv->frequency);
+
+ /* Reset the MAX1704x (mostly just to make sure that we can talk to it) */
+
+#if 0
+ ret = max1704x_reset(priv);
+ if (ret < 0)
+ {
+ batdbg("Failed to reset the MAX1704x: %d\n", ret);
+ kfree(priv);
+ return NULL;
+ }
+#endif
+ }
+ return (FAR struct battery_dev_s *)priv;
+}
+
+#endif /* CONFIG_BATTERY && CONFIG_I2C && CONFIG_I2C_MAX1704X */
diff --git a/nuttx/drivers/power/pm_activity.c b/nuttx/drivers/power/pm_activity.c
new file mode 100644
index 000000000..f52fc93ff
--- /dev/null
+++ b/nuttx/drivers/power/pm_activity.c
@@ -0,0 +1,166 @@
+/****************************************************************************
+ * drivers/power/pm_activity.c
+ *
+ * Copyright (C) 2011-2012 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/power/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 increments an activity
+ * count and/or will restart a idle timer and prevent entering reduced
+ * power states.
+ *
+ * Input Parameters:
+ * priority - Activity priority, range 0-9. Larger values correspond to
+ * higher priorities. Higher priority activity can prevent the system
+ * from entering 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 > INT16_MAX)
+ {
+ accum = INT16_MAX;
+ }
+
+ /* Save the updated count */
+
+ g_pmglobals.accum = (int16_t)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)
+ {
+ int16_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/power/pm_changestate.c b/nuttx/drivers/power/pm_changestate.c
new file mode 100644
index 000000000..f64760f55
--- /dev/null
+++ b/nuttx/drivers/power/pm_changestate.c
@@ -0,0 +1,227 @@
+/****************************************************************************
+ * drivers/power/pm_changestate.c
+ *
+ * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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/power/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 - Identifies 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 - Identifies 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 */
+
+ cb->notify(cb, newstate);
+ }
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pm_changestate
+ *
+ * Description:
+ * This function is used by platform-specific power management 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 - Identifies 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;
+
+ /* Restore the interrupt state */
+
+ irqrestore(flags);
+ return ret;
+}
+
+#endif /* CONFIG_PM */
diff --git a/nuttx/drivers/power/pm_checkstate.c b/nuttx/drivers/power/pm_checkstate.c
new file mode 100644
index 000000000..9b0e1045e
--- /dev/null
+++ b/nuttx/drivers/power/pm_checkstate.c
@@ -0,0 +1,161 @@
+/****************************************************************************
+ * drivers/power/pm_checkstate.c
+ *
+ * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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/power/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
+ * loop could be suspended for a long period of time between calling
+ * pm_checkstate() and pm_changestate(). The IDLE loop may need to 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)
+ {
+ int16_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/power/pm_initialize.c b/nuttx/drivers/power/pm_initialize.c
new file mode 100644
index 000000000..9401fba9e
--- /dev/null
+++ b/nuttx/drivers/power/pm_initialize.c
@@ -0,0 +1,112 @@
+/****************************************************************************
+ * drivers/power/pm_initialize.c
+ *
+ * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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/power/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/power/pm_internal.h b/nuttx/drivers/power/pm_internal.h
new file mode 100644
index 000000000..f98624f15
--- /dev/null
+++ b/nuttx/drivers/power/pm_internal.h
@@ -0,0 +1,210 @@
+/****************************************************************************
+ * drivers/power/pm_internal.h
+ *
+ * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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_POWER_PM_INTERNAL_H
+#define __DRIVERS_POWER_PM_INTERNAL_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <semaphore.h>
+#include <queue.h>
+
+#include <nuttx/power/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[] array 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.
+ */
+
+ int16_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
+ int16_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(int16_t accum);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* CONFIG_PM */
+#endif /* #define __DRIVERS_POWER_PM_INTERNAL_H */
diff --git a/nuttx/drivers/power/pm_register.c b/nuttx/drivers/power/pm_register.c
new file mode 100644
index 000000000..19f94cb02
--- /dev/null
+++ b/nuttx/drivers/power/pm_register.c
@@ -0,0 +1,112 @@
+/****************************************************************************
+ * drivers/power/pm_register.c
+ *
+ * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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/power/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/power/pm_update.c b/nuttx/drivers/power/pm_update.c
new file mode 100644
index 000000000..ae5e1f840
--- /dev/null
+++ b/nuttx/drivers/power/pm_update.c
@@ -0,0 +1,334 @@
+/****************************************************************************
+ * drivers/power/pm_update.c
+ *
+ * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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/power/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 int16_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
+
+/* Threshold activity values to enter into the next lower power consumption
+ * state. Indexing is next state 0:IDLE, 1:STANDBY, 2:SLEEP.
+ */
+
+static const int16_t g_pmenterthresh[3] =
+{
+ CONFIG_PM_IDLEENTER_THRESH,
+ CONFIG_PM_STANDBYENTER_THRESH,
+ CONFIG_PM_SLEEPENTER_THRESH
+};
+
+/* Threshold activity values to leave the current low power consdumption
+ * state. Indexing is current state 0:IDLE, 1: STANDBY, 2: SLEEP.
+ */
+
+static const int16_t g_pmexitthresh[3] =
+{
+ CONFIG_PM_IDLEEXIT_THRESH,
+ CONFIG_PM_STANDBYEXIT_THRESH,
+ CONFIG_PM_SLEEPEXIT_THRESH
+};
+
+/* Threshold time slice count to enter the next low power consdumption
+ * state. Indexing is next state 0:IDLE, 1: STANDBY, 2: SLEEP.
+ */
+
+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)
+{
+ int16_t accum = (int16_t)((intptr_t)arg);
+ int32_t Y;
+ int index;
+
+#if CONFIG_PM_MEMORY > 1
+ int32_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
+
+ /* First check if increased activity should cause us to return to the
+ * normal operating state. This would be unlikely for the lowest power
+ * consumption states because the CPU is probably asleep. However this
+ * probably does apply for the IDLE state.
+ */
+
+ if (g_pmglobals.state > PM_NORMAL)
+ {
+ /* Get the table index for the current state (which will be the
+ * current state minus one)
+ */
+
+ index = g_pmglobals.state - 1;
+
+ /* Has the threshold to return to normal power consumption state been
+ * exceeded?
+ */
+
+ if (Y > g_pmexitthresh[index])
+ {
+ /* Yes... reset the count and recommend the normal state. */
+
+ g_pmglobals.thrcnt = 0;
+ g_pmglobals.recommended = PM_NORMAL;
+ return;
+ }
+ }
+
+ /* Now, compare this new activity level to the thresholds and counts for
+ * the next 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;
+
+ /* 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 to enter the next lower power consumption state
+ * been exceeded?
+ */
+
+ if (Y > g_pmenterthresh[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(int16_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*)((intptr_t)accum), 0);
+}
+
+#endif /* CONFIG_PM */ \ No newline at end of file