From d910aa6029e78d485f773f00c5be0ee544fe12eb Mon Sep 17 00:00:00 2001 From: Ramakrishna Pallala Date: Wed, 13 Mar 2019 16:08:57 +0530 Subject: [PATCH] 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 --- CODEOWNERS | 1 + samples/subsys/power/device_pm/CMakeLists.txt | 6 + samples/subsys/power/device_pm/prj.conf | 3 + samples/subsys/power/device_pm/sample.yaml | 6 + .../subsys/power/device_pm/src/dummy_driver.c | 167 ++++++++++++++++++ .../subsys/power/device_pm/src/dummy_driver.h | 24 +++ .../subsys/power/device_pm/src/dummy_parent.c | 85 +++++++++ .../subsys/power/device_pm/src/dummy_parent.h | 18 ++ samples/subsys/power/device_pm/src/main.c | 26 +++ 9 files changed, 336 insertions(+) create mode 100644 samples/subsys/power/device_pm/CMakeLists.txt create mode 100644 samples/subsys/power/device_pm/prj.conf create mode 100644 samples/subsys/power/device_pm/sample.yaml create mode 100644 samples/subsys/power/device_pm/src/dummy_driver.c create mode 100644 samples/subsys/power/device_pm/src/dummy_driver.h create mode 100644 samples/subsys/power/device_pm/src/dummy_parent.c create mode 100644 samples/subsys/power/device_pm/src/dummy_parent.h create mode 100644 samples/subsys/power/device_pm/src/main.c diff --git a/CODEOWNERS b/CODEOWNERS index 61c0fea4760..c54b2509ad1 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 00000000000..9c27f925754 --- /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 00000000000..98088b4d50d --- /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 00000000000..506ed981de1 --- /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 00000000000..6d648295288 --- /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 +#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 00000000000..0fc5994e5cc --- /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 +#include +#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 00000000000..a47fdcef39c --- /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 +#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 00000000000..77195b5559a --- /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 +#include +#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 00000000000..c30057bf3ff --- /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 +#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"); +}