power_mgmt: Add device power management support

Added device power management hook infrastructure. Added
DEVICE_INIT_PM and SYS_INIT_PM macros that creates device
structures with the supplied device_ops structure containing
the hooks.

Added example support in gpio_dw driver.  Updated the sample
app and tested using LPS and Device Suspend Only policies.

Change-Id: I2fe347f8d8fd1041d8318e02738990deb8c5d68e
Signed-off-by: Ramesh Thomas <ramesh.thomas@intel.com>
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
diff --git a/drivers/gpio/gpio_atmel_sam3.c b/drivers/gpio/gpio_atmel_sam3.c
index 2ba3bfa..b93748c 100644
--- a/drivers/gpio/gpio_atmel_sam3.c
+++ b/drivers/gpio/gpio_atmel_sam3.c
@@ -284,20 +284,6 @@
 	return 0;
 }
 
-static int gpio_sam3_suspend_port(struct device *dev)
-{
-	ARG_UNUSED(dev);
-
-	return -ENOTSUP;
-}
-
-static int gpio_sam3_resume_port(struct device *dev)
-{
-	ARG_UNUSED(dev);
-
-	return -ENOTSUP;
-}
-
 static struct gpio_driver_api gpio_sam3_drv_api_funcs = {
 	.config = gpio_sam3_config,
 	.write = gpio_sam3_write,
@@ -305,8 +291,6 @@
 	.set_callback = gpio_sam3_set_callback,
 	.enable_callback = gpio_sam3_enable_callback,
 	.disable_callback = gpio_sam3_disable_callback,
-	.suspend = gpio_sam3_suspend_port,
-	.resume = gpio_sam3_resume_port,
 };
 
 /**
diff --git a/drivers/gpio/gpio_dw.c b/drivers/gpio/gpio_dw.c
index e7f9056..29c2974 100644
--- a/drivers/gpio/gpio_dw.c
+++ b/drivers/gpio/gpio_dw.c
@@ -34,6 +34,10 @@
 #include <drivers/ioapic.h>
 #endif
 
+#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
+#include <power.h>
+#endif
+
 /*
  * ARC architecture configure IP through IO auxiliary registers.
  * Other architectures as ARM and x86 configure IP through MMIO registers
@@ -286,19 +290,21 @@
 	return 0;
 }
 
-static inline int gpio_dw_suspend_port(struct device *port)
+#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
+static inline int gpio_dw_suspend_port(struct device *port, int pm_policy)
 {
 	_gpio_dw_clock_off(port);
 
 	return 0;
 }
 
-static inline int gpio_dw_resume_port(struct device *port)
+static inline int gpio_dw_resume_port(struct device *port, int pm_policy)
 {
 	_gpio_dw_clock_on(port);
 
 	return 0;
 }
+#endif
 
 #ifdef CONFIG_SOC_QUARK_SE
 static inline void gpio_dw_unmask_int(uint32_t mask_addr)
@@ -362,8 +368,6 @@
 	.set_callback = gpio_dw_set_callback,
 	.enable_callback = gpio_dw_enable_callback,
 	.disable_callback = gpio_dw_disable_callback,
-	.suspend = gpio_dw_suspend_port,
-	.resume = gpio_dw_resume_port
 };
 
 #ifdef CONFIG_PCI
@@ -456,9 +460,20 @@
 
 struct gpio_dw_runtime gpio_0_runtime;
 
+#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
+struct device_pm_ops gpio_dev_pm_ops = {
+		.suspend = gpio_dw_suspend_port,
+		.resume = gpio_dw_resume_port
+};
+
+DEVICE_INIT_PM(gpio_dw_0, CONFIG_GPIO_DW_0_NAME, gpio_dw_initialize,
+	       &gpio_dev_pm_ops, &gpio_0_runtime, &gpio_config_0,
+	       SECONDARY, CONFIG_GPIO_DW_INIT_PRIORITY);
+#else
 DEVICE_INIT(gpio_dw_0, CONFIG_GPIO_DW_0_NAME, gpio_dw_initialize,
 	    &gpio_0_runtime, &gpio_config_0,
 	    SECONDARY, CONFIG_GPIO_DW_INIT_PRIORITY);
+#endif
 
 #ifdef CONFIG_GPIO_DW_0_IRQ_DIRECT
 #ifdef CONFIG_IOAPIC
@@ -531,9 +546,15 @@
 
 struct gpio_dw_runtime gpio_1_runtime;
 
+#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
+DEVICE_INIT_PM(gpio_dw_1, CONFIG_GPIO_DW_1_NAME, gpio_dw_initialize,
+	       &gpio_dev_pm_ops, &gpio_1_runtime, &gpio_dw_config_1,
+	       SECONDARY, CONFIG_GPIO_DW_INIT_PRIORITY);
+#else
 DEVICE_INIT(gpio_dw_1, CONFIG_GPIO_DW_1_NAME, gpio_dw_initialize,
 	    &gpio_1_runtime, &gpio_dw_config_1,
 	    SECONDARY, CONFIG_GPIO_DW_INIT_PRIORITY);
+#endif
 
 #ifdef CONFIG_GPIO_DW_1_IRQ_DIRECT
 #ifdef CONFIG_IOAPIC
diff --git a/drivers/gpio/gpio_k64.c b/drivers/gpio/gpio_k64.c
index 7c05066..ba7bfcc 100644
--- a/drivers/gpio/gpio_k64.c
+++ b/drivers/gpio/gpio_k64.c
@@ -221,22 +221,6 @@
 }
 
 
-static int gpio_k64_suspend_port(struct device *dev)
-{
-	ARG_UNUSED(dev);
-
-	return -ENOTSUP;
-}
-
-
-static int gpio_k64_resume_port(struct device *dev)
-{
-	ARG_UNUSED(dev);
-
-	return -ENOTSUP;
-}
-
-
 /**
  * @brief Handler for port interrupts
  * @param dev Pointer to device structure for driver instance
@@ -290,8 +274,6 @@
 	.set_callback = gpio_k64_set_callback,
 	.enable_callback = gpio_k64_enable_callback,
 	.disable_callback = gpio_k64_disable_callback,
-	.suspend = gpio_k64_suspend_port,
-	.resume = gpio_k64_resume_port,
 };
 
 
diff --git a/drivers/gpio/gpio_mmio.c b/drivers/gpio/gpio_mmio.c
index 8824ff59..b7a6436 100644
--- a/drivers/gpio/gpio_mmio.c
+++ b/drivers/gpio/gpio_mmio.c
@@ -277,20 +277,6 @@
 	return -ENOTSUP;
 }
 
-static int gpio_mmio_suspend_port(struct device *dev)
-{
-	ARG_UNUSED(dev);
-
-	return -ENOTSUP;
-}
-
-static int gpio_mmio_resume_port(struct device *dev)
-{
-	ARG_UNUSED(dev);
-
-	return -ENOTSUP;
-}
-
 static struct gpio_driver_api gpio_mmio_drv_api_funcs = {
 	.config = gpio_mmio_config,
 	.write = gpio_mmio_write,
@@ -298,8 +284,6 @@
 	.set_callback = gpio_mmio_set_callback,
 	.enable_callback = gpio_mmio_enable_callback,
 	.disable_callback = gpio_mmio_disable_callback,
-	.suspend = gpio_mmio_suspend_port,
-	.resume = gpio_mmio_resume_port,
 };
 
 /**
diff --git a/drivers/gpio/gpio_pcal9535a.c b/drivers/gpio/gpio_pcal9535a.c
index 25bb5b6..8b97be6 100644
--- a/drivers/gpio/gpio_pcal9535a.c
+++ b/drivers/gpio/gpio_pcal9535a.c
@@ -544,24 +544,6 @@
 	return -ENOTSUP;
 }
 
-static int gpio_pcal9535a_suspend_port(struct device *dev)
-{
-	if (!_has_i2c_master(dev)) {
-		return -EINVAL;
-	}
-
-	return -ENOTSUP;
-}
-
-static int gpio_pcal9535a_resume_port(struct device *dev)
-{
-	if (!_has_i2c_master(dev)) {
-		return -EINVAL;
-	}
-
-	return -ENOTSUP;
-}
-
 static struct gpio_driver_api gpio_pcal9535a_drv_api_funcs = {
 	.config = gpio_pcal9535a_config,
 	.write = gpio_pcal9535a_write,
@@ -569,8 +551,6 @@
 	.set_callback = gpio_pcal9535a_set_callback,
 	.enable_callback = gpio_pcal9535a_enable_callback,
 	.disable_callback = gpio_pcal9535a_disable_callback,
-	.suspend = gpio_pcal9535a_suspend_port,
-	.resume = gpio_pcal9535a_resume_port,
 };
 
 /**
diff --git a/drivers/gpio/gpio_qmsi.c b/drivers/gpio/gpio_qmsi.c
index 8467b0b..7d98833 100644
--- a/drivers/gpio/gpio_qmsi.c
+++ b/drivers/gpio/gpio_qmsi.c
@@ -271,16 +271,6 @@
 	return 0;
 }
 
-static inline int gpio_qmsi_suspend_port(struct device *port)
-{
-	return -ENODEV;
-}
-
-static inline int gpio_qmsi_resume_port(struct device *port)
-{
-	return -ENODEV;
-}
-
 static struct gpio_driver_api api_funcs = {
 	.config = gpio_qmsi_config,
 	.write = gpio_qmsi_write,
@@ -288,8 +278,6 @@
 	.set_callback = gpio_qmsi_set_callback,
 	.enable_callback = gpio_qmsi_enable_callback,
 	.disable_callback = gpio_qmsi_disable_callback,
-	.suspend = gpio_qmsi_suspend_port,
-	.resume = gpio_qmsi_resume_port
 };
 
 int gpio_qmsi_init(struct device *port)
diff --git a/drivers/gpio/gpio_sch.c b/drivers/gpio/gpio_sch.c
index 2ca2998..ad1dc91 100644
--- a/drivers/gpio/gpio_sch.c
+++ b/drivers/gpio/gpio_sch.c
@@ -316,16 +316,6 @@
 	return 0;
 }
 
-static int gpio_sch_suspend(struct device *dev)
-{
-	return 0;
-}
-
-static int gpio_sch_resume(struct device *dev)
-{
-	return 0;
-}
-
 static struct gpio_driver_api gpio_sch_api = {
 	.config = gpio_sch_config,
 	.write = gpio_sch_write,
@@ -333,8 +323,6 @@
 	.set_callback = gpio_sch_set_callback,
 	.enable_callback = gpio_sch_enable_callback,
 	.disable_callback = gpio_sch_disable_callback,
-	.suspend = gpio_sch_suspend,
-	.resume = gpio_sch_resume
 };
 
 int gpio_sch_init(struct device *dev)
diff --git a/drivers/gpio/gpio_stm32.c b/drivers/gpio/gpio_stm32.c
index 6c1fb39..07b6a6e 100644
--- a/drivers/gpio/gpio_stm32.c
+++ b/drivers/gpio/gpio_stm32.c
@@ -178,20 +178,6 @@
 	return 0;
 }
 
-static int gpio_stm32_suspend_port(struct device *dev)
-{
-	ARG_UNUSED(dev);
-
-	return -ENOTSUP;
-}
-
-static int gpio_stm32_resume_port(struct device *dev)
-{
-	ARG_UNUSED(dev);
-
-	return -ENOTSUP;
-}
-
 static struct gpio_driver_api gpio_stm32_driver = {
 	.config = gpio_stm32_config,
 	.write = gpio_stm32_write,
@@ -199,8 +185,6 @@
 	.set_callback = gpio_stm32_set_callback,
 	.enable_callback = gpio_stm32_enable_callback,
 	.disable_callback = gpio_stm32_disable_callback,
-	.suspend = gpio_stm32_suspend_port,
-	.resume = gpio_stm32_resume_port,
 
 };
 
diff --git a/include/device.h b/include/device.h
index f9b7cb2..a784c78 100644
--- a/include/device.h
+++ b/include/device.h
@@ -87,6 +87,7 @@
  * (e.g. CONFIG_KERNEL_INIT_PRIORITY_DEFAULT + 5).
  */
 
+#ifndef CONFIG_DEVICE_POWER_MANAGEMENT
 #define DEVICE_INIT(dev_name, drv_name, init_fn, data, cfg_info, level, prio) \
 	\
 	static struct device_config __config_##dev_name __used \
@@ -100,6 +101,88 @@
 		 .config = &(__config_##dev_name), \
 		 .driver_data = data \
 	}
+#else
+/**
+ * @def DEVICE_INIT_PM
+ *
+ * @brief create device object and set it up for boot time initialization
+ *
+ * @details This macro defines a device object that is automatically
+ * configured by the kernel during system initialization.
+ *
+ * @param dev_name Device name.
+ *
+ * @param drv_name The name this instance of the driver exposes to
+ * the system.
+ *
+ * @param init_fn Address to the init function of the driver.
+ *
+ * @param device_pm_ops Address to the device_pm_ops structure of the driver.
+ *
+ * @param data Pointer to the device's configuration data.
+ *
+ * @param cfg_info The address to the structure containing the
+ * configuration information for this instance of the driver.
+ *
+ * @param level The initialization level at which configuration occurs.
+ * Must be one of the following symbols, which are listed in the order
+ * they are performed by the kernel:
+ *
+ * PRIMARY: Used for devices that have no dependencies, such as those
+ * that rely solely on hardware present in the processor/SOC. These devices
+ * cannot use any kernel services during configuration, since they are not
+ * yet available.
+ *
+ * SECONDARY: Used for devices that rely on the initialization of devices
+ * initialized as part of the PRIMARY level. These devices cannot use any
+ * kernel services during configuration, since they are not yet available.
+ *
+ * NANOKERNEL: Used for devices that require nanokernel services during
+ * configuration.
+ *
+ * MICROKERNEL: Used for devices that require microkernel services during
+ * configuration.
+ *
+ * APPLICATION: Used for application components (i.e. non-kernel components)
+ * that need automatic configuration. These devices can use all services
+ * provided by the kernel during configuration.
+ *
+ * @param prio The initialization priority of the device, relative to
+ * other devices of the same initialization level. Specified as an integer
+ * value in the range 0 to 99; lower values indicate earlier initialization.
+ * Must be a decimal integer literal without leading zeroes or sign (e.g. 32),
+ * or an equivalent symbolic name (e.g. \#define MY_INIT_PRIO 32); symbolic
+ * expressions are *not* permitted
+ * (e.g. CONFIG_KERNEL_INIT_PRIORITY_DEFAULT + 5).
+ */
+
+#define DEVICE_INIT_PM(dev_name, drv_name, init_fn, device_pm_ops, \
+			data, cfg_info, level, prio) \
+	\
+	static struct device_config __config_##dev_name __used \
+	__attribute__((__section__(".devconfig.init"))) = { \
+		.name = drv_name, .init = (init_fn), \
+		.dev_pm_ops = (device_pm_ops), \
+		.config_info = (cfg_info) \
+	}; \
+	\
+	static struct device (__device_##dev_name) __used \
+	__attribute__((__section__(".init_" #level STRINGIFY(prio)))) = { \
+		 .config = &(__config_##dev_name), \
+		 .driver_data = data \
+	}
+
+	/*
+	 * Create a default device_pm_ops for devices that do not call the
+	 * DEVICE_INIT_PM macro so that caller of hook functions
+	 * need not check dev_pm_ops != NULL.
+	 */
+extern struct device_pm_ops device_pm_ops_nop;
+#define DEVICE_INIT(dev_name, drv_name, init_fn, data, cfg_info, level, prio) \
+			DEVICE_INIT_PM(dev_name, drv_name, init_fn, \
+					&device_pm_ops_nop, data, cfg_info, \
+					level, prio)
+#endif
 
 /**
  * @def DEVICE_NAME_GET
@@ -165,6 +248,13 @@
 
 struct device;
 
+#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
+struct device_pm_ops {
+	int (*suspend)(struct device *device, int pm_policy);
+	int (*resume)(struct device *device, int pm_policy);
+};
+#endif
+
 /**
  * @brief Static device information (In ROM) Per driver instance
  * @param name name of the device
@@ -174,6 +264,9 @@
 struct device_config {
 	char	*name;
 	int (*init)(struct device *device);
+#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
+	struct device_pm_ops *dev_pm_ops;
+#endif
 	void *config_info;
 };
 
@@ -193,6 +286,74 @@
 void _sys_device_do_config_level(int level);
 struct device* device_get_binding(char *name);
 
+#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
+/**
+ * Device PM functions
+ */
+
+/**
+ * @brief No-op function to initialize unimplemented pm hooks
+ *
+ * This function should be used to initialize device pm hooks
+ * for which a device has no operation.
+ *
+ * @param unused_device
+ * @param unused_policy
+ *
+ * @retval Always returns 0
+ */
+int device_pm_nop(struct device *unused_device, int unused_policy);
+
+/**
+ * @brief Call the suspend function of a device
+ *
+ * Called by the Power Manager application to let the device do
+ * any policy based PM suspend operations.
+ *
+ * @param device Pointer to device structure of the driver instance.
+ * @param pm_policy PM policy for which this call is made.
+ *
+ * @retval 0 If successful.
+ * @retval -EBUSY If device is busy
+ * @retval Other negative errno code if failure.
+ */
+static inline int device_suspend(struct device *device, int pm_policy)
+{
+	return device->config->dev_pm_ops->suspend(device, pm_policy);
+}
+
+/**
+ * @brief Call the resume function of a device
+ *
+ * Called by the Power Manager application to let the device do
+ * any policy based PM resume operations.
+ *
+ * @param device Pointer to device structure of the driver instance.
+ * @param pm_policy PM policy for which this call is made.
+ *
+ * @retval 0 If successful.
+ * @retval Negative errno code if failure.
+ */
+static inline int device_resume(struct device *device, int pm_policy)
+{
+	return device->config->dev_pm_ops->resume(device, pm_policy);
+}
+
+/**
+ * @brief Gets the device structure list array and device count
+ *
+ * Called by the Power Manager application to get the list of
+ * device structures associated with the devices in the system.
+ * The PM app would use this list to create its own sorted list
+ * based on the order it wishes to suspend or resume the devices.
+ *
+ * @param device_list Pointer to receive the device list array
+ * @param device_count Pointer to receive the device count
+ */
+void device_list_get(struct device **device_list, int *device_count);
+
+#endif
+
 /**
  * Synchronous calls API
  */
diff --git a/include/gpio.h b/include/gpio.h
index b79c393..b4407fb 100644
--- a/include/gpio.h
+++ b/include/gpio.h
@@ -150,8 +150,6 @@
 typedef int (*gpio_disable_callback_t)(struct device *port,
 				       int access_op,
 				       uint32_t pin);
-typedef int (*gpio_suspend_port_t)(struct device *port);
-typedef int (*gpio_resume_port_t)(struct device *port);
 
 struct gpio_driver_api {
 	gpio_config_t config;
@@ -160,8 +158,6 @@
 	gpio_set_callback_t set_callback;
 	gpio_enable_callback_t enable_callback;
 	gpio_disable_callback_t disable_callback;
-	gpio_suspend_port_t suspend;
-	gpio_resume_port_t resume;
 };
 /**
  * @endcond
@@ -325,31 +321,6 @@
 	return api->disable_callback(port, GPIO_ACCESS_BY_PORT, 0);
 }
 
-/**
- * @brief Save the state of the device and make it go to the
- * low power state.
- * @param port Pointer to the device structure for the driver instance.
- */
-static inline int gpio_suspend(struct device *port)
-{
-	struct gpio_driver_api *api;
-
-	api = (struct gpio_driver_api *) port->driver_api;
-	return api->suspend(port);
-}
-
-/**
- * @brief Restore the state stored during suspend and resume operation.
- * @param port Pointer to the device structure for the driver instance.
- */
-static inline int gpio_resume(struct device *port)
-{
-	struct gpio_driver_api *api;
-
-	api = (struct gpio_driver_api *) port->driver_api;
-	return api->resume(port);
-}
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/init.h b/include/init.h
index 7adec2f..56d99cb 100644
--- a/include/init.h
+++ b/include/init.h
@@ -41,6 +41,12 @@
 #define SYS_INIT(init_fn, level, prio) \
 	DEVICE_INIT(sys_init_##init_fn, "", init_fn, NULL, NULL, level, prio)
 
+#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
+#define SYS_INIT_PM(drv_name, init_fn, device_pm_ops, level, prio) \
+	DEVICE_INIT_PM(sys_init_##init_fn, drv_name, init_fn, device_pm_ops, \
+		NULL, NULL, level, prio)
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/kernel/nanokernel/device.c b/kernel/nanokernel/device.c
index 0d6856f..e2a597e 100644
--- a/kernel/nanokernel/device.c
+++ b/kernel/nanokernel/device.c
@@ -35,6 +35,10 @@
 	__device_init_end,
 };
 
+#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
+struct device_pm_ops device_pm_ops_nop = {device_pm_nop, device_pm_nop};
+#endif
+
 /**
  * @brief Execute all the device initialization functions at a given level
  *
@@ -81,3 +85,17 @@
 
 	return NULL;
 }
+
+#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
+int device_pm_nop(struct device *unused_device, int unused_policy)
+{
+	return 0;
+}
+
+void device_list_get(struct device **device_list, int *device_count)
+{
+
+	*device_list = __device_init_start;
+	*device_count = __device_init_end - __device_init_start;
+}
+#endif
diff --git a/samples/power/power_hooks/prj.conf b/samples/power/power_hooks/prj.conf
index 129bd7b..d220f4e 100644
--- a/samples/power/power_hooks/prj.conf
+++ b/samples/power/power_hooks/prj.conf
@@ -1,4 +1,4 @@
 CONFIG_STDOUT_CONSOLE=y
 CONFIG_SYS_POWER_MANAGEMENT=y
-CONFIG_SYS_POWER_LOW_POWER_STATE=y
+CONFIG_DEVICE_POWER_MANAGEMENT=y
 CONFIG_TICKLESS_IDLE=y
diff --git a/samples/power/power_mgr/prj.conf b/samples/power/power_mgr/prj.conf
index 89ab8d4..1bdf850 100644
--- a/samples/power/power_mgr/prj.conf
+++ b/samples/power/power_mgr/prj.conf
@@ -1,5 +1,7 @@
 CONFIG_SYS_POWER_MANAGEMENT=y
 CONFIG_SYS_POWER_LOW_POWER_STATE=y
+CONFIG_DEVICE_POWER_MANAGEMENT=y
 CONFIG_TICKLESS_IDLE=y
 CONFIG_RTC=y
+CONFIG_GPIO=y
 CONFIG_STDOUT_CONSOLE=y
diff --git a/samples/power/power_mgr/src/main.c b/samples/power/power_mgr/src/main.c
index 0a8b9fd..f2b2e6c 100644
--- a/samples/power/power_mgr/src/main.c
+++ b/samples/power/power_mgr/src/main.c
@@ -24,6 +24,7 @@
 #include <misc/printk.h>
 #define PRINT           printk
 #endif
+#include <string.h>
 #include <rtc.h>
 
 #define SLEEPTICKS	SECONDS(5)
@@ -33,6 +34,15 @@
 static void quark_low_power(void);
 static struct device *rtc_dev;
 static uint32_t start_time, end_time;
+static void create_device_list(void);
+static void suspend_devices(int pm_policy);
+static void resume_devices(int pm_policy);
+
+#define DEVICE_POLICY_MAX 10
+static struct device *device_list;
+static int device_count;
+static char device_policy_list[DEVICE_POLICY_MAX];
+static char device_retval[DEVICE_POLICY_MAX];
 
 void main(void)
 {
@@ -49,6 +59,8 @@
 	rtc_enable(rtc_dev);
 	rtc_set_config(rtc_dev, &config);
 
+	create_device_list();
+
 	while (1) {
 		task_sleep(SLEEPTICKS);
 	}
@@ -79,6 +91,7 @@
 	PRINT("\n\nLow power state policy entry!\n");
 
 	/* Turn off peripherals/clocks here */
+	suspend_devices(SYS_PM_LOW_POWER_STATE);
 
 	quark_low_power();
 
@@ -90,6 +103,7 @@
 	PRINT("Device suspend only policy entry!\n");
 
 	/* Turn off peripherals/clocks here */
+	suspend_devices(SYS_PM_DEVICE_SUSPEND_ONLY);
 
 	return SYS_PM_DEVICE_SUSPEND_ONLY;
 }
@@ -120,6 +134,8 @@
 
 static void low_power_state_exit(void)
 {
+	resume_devices(SYS_PM_LOW_POWER_STATE);
+
 	end_time = rtc_read(rtc_dev);
 	PRINT("\nLow power state policy exit!\n");
 	PRINT("Total Elapsed From Suspend To Resume = %d RTC Cycles\n",
@@ -128,6 +144,8 @@
 
 static void device_suspend_only_exit(void)
 {
+	resume_devices(SYS_PM_DEVICE_SUSPEND_ONLY);
+
 	end_time = rtc_read(rtc_dev);
 	PRINT("\nDevice suspend only policy exit!\n");
 	PRINT("Total Elapsed From Suspend To Resume = %d RTC Cycles\n",
@@ -164,3 +182,48 @@
 			::"a"(P_LVL2));
 
 }
+
+static void suspend_devices(int pm_policy)
+{
+	int i;
+
+	for (i = 0; i < device_count; i++) {
+		int idx = device_policy_list[i];
+
+		device_retval[i] = device_suspend(&device_list[idx], pm_policy);
+	}
+}
+
+static void resume_devices(int pm_policy)
+{
+	int i;
+
+	for (i = device_count - 1; i >= 0; i--) {
+		if (!device_retval[i]) {
+			int idx = device_policy_list[i];
+
+			device_resume(&device_list[idx], pm_policy);
+		}
+	}
+}
+
+static void create_device_list(void)
+{
+	int count;
+	int i;
+
+	/*
+	 * Create a list of devices that will be suspended.
+	 * For the demo we will create a simple list containing
+	 * gpio devices.
+	 */
+	device_list_get(&device_list, &count);
+
+	for (i = 0; (i < count) && (device_count < DEVICE_POLICY_MAX); i++) {
+		if (!strcmp(device_list[i].config->name, CONFIG_GPIO_DW_0_NAME) ||
+				!strcmp(device_list[i].config->name,
+					CONFIG_GPIO_DW_1_NAME)) {
+			device_policy_list[device_count++] = i;
+		}
+	}
+}