| /* |
| * Copyright (c) 2018 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <sys/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); |