samples: power: Add test for device Idle PM

Added test for Device Idle Power Management to invoke
device_pm_get/put API's.

Signed-off-by: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
diff --git a/CODEOWNERS b/CODEOWNERS
index 61c0fea..c54b250 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -228,6 +228,7 @@
 /samples/net/sockets/                     @jukkar @tbursztyka @pfalcon
 /samples/sensor/                          @bogdan-davidoaia
 /samples/subsys/usb/                      @jfischer-phytec-iot @finikorg
+/samples/subsys/power/                    @ramakrishnapallala @pizi-nordic
 /scripts/coccicheck                       @himanshujha199640 @JuliaLawall
 /scripts/coccinelle/                      @himanshujha199640 @JuliaLawall
 /scripts/elf_helper.py                    @andrewboie
diff --git a/samples/subsys/power/device_pm/CMakeLists.txt b/samples/subsys/power/device_pm/CMakeLists.txt
new file mode 100644
index 0000000..9c27f92
--- /dev/null
+++ b/samples/subsys/power/device_pm/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.13.1)
+include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
+project(device)
+
+FILE(GLOB app_sources src/*.c)
+target_sources(app PRIVATE ${app_sources})
diff --git a/samples/subsys/power/device_pm/prj.conf b/samples/subsys/power/device_pm/prj.conf
new file mode 100644
index 0000000..98088b4
--- /dev/null
+++ b/samples/subsys/power/device_pm/prj.conf
@@ -0,0 +1,3 @@
+CONFIG_SYS_POWER_MANAGEMENT=y
+CONFIG_DEVICE_POWER_MANAGEMENT=y
+CONFIG_DEVICE_IDLE_PM=y
diff --git a/samples/subsys/power/device_pm/sample.yaml b/samples/subsys/power/device_pm/sample.yaml
new file mode 100644
index 0000000..506ed98
--- /dev/null
+++ b/samples/subsys/power/device_pm/sample.yaml
@@ -0,0 +1,6 @@
+sample:
+  name: Device Idle Power Management
+tests:
+  ospm.dev_idle_pm:
+    platform_whitelist: nrf52840_pca10056 nrf52_pca10040
+    tags: power
diff --git a/samples/subsys/power/device_pm/src/dummy_driver.c b/samples/subsys/power/device_pm/src/dummy_driver.c
new file mode 100644
index 0000000..6d64829
--- /dev/null
+++ b/samples/subsys/power/device_pm/src/dummy_driver.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <misc/printk.h>
+#include "dummy_parent.h"
+#include "dummy_driver.h"
+
+static struct k_poll_event async_evt;
+u32_t device_power_state;
+static struct device *parent;
+
+static int dummy_open(struct device *dev)
+{
+	int ret;
+	int signaled = 0, result;
+
+	printk("open()\n");
+
+	/* Make sure parent is resumed */
+	ret = device_pm_get_sync(parent);
+	if (ret < 0) {
+		return ret;
+	}
+
+	ret = device_pm_get(dev);
+	if (ret < 0) {
+		return ret;
+	}
+
+	printk("Async wakeup request queued\n");
+
+	do {
+		(void)k_poll(&async_evt, 1, K_FOREVER);
+		k_poll_signal_check(&dev->config->pm->signal,
+						&signaled, &result);
+	} while (!signaled);
+
+	async_evt.state = K_POLL_STATE_NOT_READY;
+	k_poll_signal_reset(&dev->config->pm->signal);
+
+	if (result == DEVICE_PM_ACTIVE_STATE) {
+		printk("Dummy device resumed\n");
+		ret = 0;
+	} else {
+		printk("Dummy device Not resumed\n");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+static int dummy_read(struct device *dev, u32_t *val)
+{
+	struct dummy_parent_api *api;
+	int ret;
+
+	printk("read()\n");
+
+	api = (struct dummy_parent_api *)parent->driver_api;
+	ret = api->transfer(parent, DUMMY_PARENT_RD, val);
+	return ret;
+}
+
+static int dummy_write(struct device *dev, u32_t val)
+{
+	struct dummy_parent_api *api;
+	int ret;
+
+	printk("write()\n");
+	api = (struct dummy_parent_api *)parent->driver_api;
+	ret = api->transfer(parent, DUMMY_PARENT_WR, &val);
+	return ret;
+}
+
+static int dummy_close(struct device *dev)
+{
+	int ret;
+
+	printk("close()\n");
+	ret = device_pm_put_sync(dev);
+	if (ret == 1) {
+		printk("Async suspend request ququed\n");
+	}
+
+	/* Parent can be suspended */
+	if (parent) {
+		device_pm_put(parent);
+	}
+
+	return ret;
+}
+
+static u32_t dummy_get_power_state(struct device *dev)
+{
+	return device_power_state;
+}
+
+static int dummy_suspend(struct device *dev)
+{
+	printk("child suspending..\n");
+	device_power_state = DEVICE_PM_SUSPEND_STATE;
+
+	return 0;
+}
+
+static int dummy_resume_from_suspend(struct device *dev)
+{
+	printk("child resuming..\n");
+	device_power_state = DEVICE_PM_ACTIVE_STATE;
+
+	return 0;
+}
+
+static int dummy_device_pm_ctrl(struct device *dev, u32_t ctrl_command,
+				void *context, device_pm_cb cb, void *arg)
+{
+	int ret = 0;
+
+	switch (ctrl_command) {
+	case DEVICE_PM_SET_POWER_STATE:
+		if (*((u32_t *)context) == DEVICE_PM_ACTIVE_STATE) {
+			ret = dummy_resume_from_suspend(dev);
+		} else {
+			ret = dummy_suspend(dev);
+		}
+		break;
+	case DEVICE_PM_GET_POWER_STATE:
+		*((u32_t *)context) = dummy_get_power_state(dev);
+		break;
+	default:
+		ret = -EINVAL;
+
+	}
+
+	cb(dev, ret, context, arg);
+
+	return ret;
+}
+
+static const struct dummy_driver_api funcs = {
+	.open = dummy_open,
+	.read = dummy_read,
+	.write = dummy_write,
+	.close = dummy_close,
+};
+
+int dummy_init(struct device *dev)
+{
+	parent = device_get_binding(DUMMY_PARENT_NAME);
+	if (!parent) {
+		printk("parent not found\n");
+	}
+
+	device_pm_enable(dev);
+	device_power_state = DEVICE_PM_ACTIVE_STATE;
+
+	k_poll_event_init(&async_evt, K_POLL_TYPE_SIGNAL,
+			K_POLL_MODE_NOTIFY_ONLY, &dev->config->pm->signal);
+	return 0;
+}
+
+DEVICE_DEFINE(dummy_driver, DUMMY_DRIVER_NAME, &dummy_init,
+		    dummy_device_pm_ctrl, NULL, NULL, APPLICATION,
+		    CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &funcs);
diff --git a/samples/subsys/power/device_pm/src/dummy_driver.h b/samples/subsys/power/device_pm/src/dummy_driver.h
new file mode 100644
index 0000000..0fc5994
--- /dev/null
+++ b/samples/subsys/power/device_pm/src/dummy_driver.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018 Intel Corporation.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr.h>
+#include <device.h>
+#define DUMMY_DRIVER_NAME	"dummy_driver"
+
+typedef int (*dummy_api_open_t)(struct device *dev);
+
+typedef int (*dummy_api_read_t)(struct device *dev,
+				     u32_t *val);
+typedef int (*dummy_api_write_t)(struct device *dev,
+				     u32_t val);
+typedef int (*dummy_api_close_t)(struct device *dev);
+
+struct dummy_driver_api {
+	dummy_api_open_t open;
+	dummy_api_read_t read;
+	dummy_api_write_t write;
+	dummy_api_close_t close;
+};
diff --git a/samples/subsys/power/device_pm/src/dummy_parent.c b/samples/subsys/power/device_pm/src/dummy_parent.c
new file mode 100644
index 0000000..a47fdce
--- /dev/null
+++ b/samples/subsys/power/device_pm/src/dummy_parent.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <misc/printk.h>
+#include "dummy_parent.h"
+
+static u32_t store_value;
+u32_t parent_power_state;
+
+static int dummy_transfer(struct device *dev, u32_t cmd, u32_t *val)
+{
+	printk("transfer()\n");
+
+	if (cmd == DUMMY_PARENT_WR) {
+		store_value = *val;
+	} else {
+		*val = store_value;
+	}
+
+	return 0;
+}
+
+static u32_t dummy_get_power_state(struct device *dev)
+{
+	return parent_power_state;
+}
+
+static int dummy_suspend(struct device *dev)
+{
+	printk("parent suspending..\n");
+	parent_power_state = DEVICE_PM_SUSPEND_STATE;
+
+	return 0;
+}
+
+static int dummy_resume_from_suspend(struct device *dev)
+{
+	printk("parent resuming..\n");
+	parent_power_state = DEVICE_PM_ACTIVE_STATE;
+
+	return 0;
+}
+
+static int dummy_parent_pm_ctrl(struct device *dev, u32_t ctrl_command,
+				void *context, device_pm_cb cb, void *arg)
+{
+	int ret = 0;
+
+	switch (ctrl_command) {
+	case DEVICE_PM_SET_POWER_STATE:
+		if (*((u32_t *)context) == DEVICE_PM_ACTIVE_STATE) {
+			ret = dummy_resume_from_suspend(dev);
+		} else {
+			ret = dummy_suspend(dev);
+		}
+		break;
+	case DEVICE_PM_GET_POWER_STATE:
+		*((u32_t *)context) = dummy_get_power_state(dev);
+		break;
+	default:
+		ret = -EINVAL;
+
+	}
+
+	cb(dev, ret, context, arg);
+	return ret;
+}
+
+static const struct dummy_parent_api funcs = {
+	.transfer = dummy_transfer,
+};
+
+int dummy_parent_init(struct device *dev)
+{
+	device_pm_enable(dev);
+	parent_power_state = DEVICE_PM_ACTIVE_STATE;
+	return 0;
+}
+
+DEVICE_DEFINE(dummy_parent, DUMMY_PARENT_NAME, &dummy_parent_init,
+		    dummy_parent_pm_ctrl, NULL, NULL, POST_KERNEL,
+		    CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &funcs);
diff --git a/samples/subsys/power/device_pm/src/dummy_parent.h b/samples/subsys/power/device_pm/src/dummy_parent.h
new file mode 100644
index 0000000..77195b5
--- /dev/null
+++ b/samples/subsys/power/device_pm/src/dummy_parent.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2018 Intel Corporation.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr.h>
+#include <device.h>
+#define DUMMY_PARENT_NAME	"dummy_parent"
+
+#define DUMMY_PARENT_RD		0
+#define DUMMY_PARENT_WR		1
+
+typedef int (*dummy_api_transfer_t)(struct device *dev, u32_t cmd, u32_t *val);
+
+struct dummy_parent_api {
+	dummy_api_transfer_t transfer;
+};
diff --git a/samples/subsys/power/device_pm/src/main.c b/samples/subsys/power/device_pm/src/main.c
new file mode 100644
index 0000000..c30057b
--- /dev/null
+++ b/samples/subsys/power/device_pm/src/main.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018 Intel Corporation.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <misc/printk.h>
+#include "dummy_driver.h"
+
+/* Application main Thread */
+void main(void)
+{
+	struct device *dev;
+	struct dummy_driver_api *api;
+	int ret, val;
+
+	printk("Device PM sample app start\n");
+	dev = device_get_binding(DUMMY_DRIVER_NAME);
+	api = (struct dummy_driver_api *)dev->driver_api;
+	ret = api->open(dev);
+	val = 10;
+	ret = api->write(dev, val);
+	ret = api->read(dev, &val);
+	ret = api->close(dev);
+	printk("Device PM sample app complete\n");
+}