153 lines
3.3 KiB
C
153 lines
3.3 KiB
C
/*
|
|
* Copyright (c) 2018 Intel Corporation.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr.h>
|
|
#include <kernel.h>
|
|
#include <string.h>
|
|
#include <soc.h>
|
|
#include <device.h>
|
|
#include "policy/pm_policy.h"
|
|
|
|
#if defined(CONFIG_SYS_POWER_MANAGEMENT)
|
|
#define LOG_LEVEL CONFIG_SYS_PM_LOG_LEVEL /* From power module Kconfig */
|
|
#include <logging/log.h>
|
|
LOG_MODULE_DECLARE(power);
|
|
|
|
/*
|
|
* FIXME: Remove the conditional inclusion of
|
|
* core_devices array once we enble the capability
|
|
* to build the device list based on devices power
|
|
* and clock domain dependencies.
|
|
*/
|
|
#if defined(CONFIG_SOC_FAMILY_NRF)
|
|
#define MAX_PM_DEVICES 15
|
|
#define MAX_DEV_NAME_LEN 16
|
|
static const char core_devices[][MAX_DEV_NAME_LEN] = {
|
|
"CLOCK_32K",
|
|
"CLOCK_16M",
|
|
"sys_clock",
|
|
"UART_0",
|
|
};
|
|
#else
|
|
#error "Add SoC's core devices list for PM"
|
|
#endif
|
|
|
|
/*
|
|
* Ordered list to store devices on which
|
|
* device power policies would be executed.
|
|
*/
|
|
static int device_ordered_list[MAX_PM_DEVICES];
|
|
static int device_retval[MAX_PM_DEVICES];
|
|
static struct device *pm_device_list;
|
|
static int device_count;
|
|
|
|
const char *device_pm_state_str(u32_t state)
|
|
{
|
|
switch (state) {
|
|
case DEVICE_PM_ACTIVE_STATE:
|
|
return "active";
|
|
case DEVICE_PM_LOW_POWER_STATE:
|
|
return "low power";
|
|
case DEVICE_PM_SUSPEND_STATE:
|
|
return "suspend";
|
|
case DEVICE_PM_FORCE_SUSPEND_STATE:
|
|
return "force suspend";
|
|
case DEVICE_PM_OFF_STATE:
|
|
return "off";
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
static int _sys_pm_devices(u32_t state)
|
|
{
|
|
for (int i = device_count - 1; i >= 0; i--) {
|
|
int idx = device_ordered_list[i];
|
|
|
|
/* TODO: Improve the logic by checking device status
|
|
* and set the device states accordingly.
|
|
*/
|
|
device_retval[i] = device_set_power_state(&pm_device_list[idx],
|
|
state,
|
|
NULL, NULL);
|
|
if (device_retval[i]) {
|
|
LOG_DBG("%s did not enter %s state",
|
|
pm_device_list[idx].config->name,
|
|
device_pm_state_str(state));
|
|
return device_retval[i];
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int sys_pm_suspend_devices(void)
|
|
{
|
|
return _sys_pm_devices(DEVICE_PM_SUSPEND_STATE);
|
|
}
|
|
|
|
int sys_pm_low_power_devices(void)
|
|
{
|
|
return _sys_pm_devices(DEVICE_PM_LOW_POWER_STATE);
|
|
}
|
|
|
|
int sys_pm_force_suspend_devices(void)
|
|
{
|
|
return _sys_pm_devices(DEVICE_PM_FORCE_SUSPEND_STATE);
|
|
}
|
|
|
|
void sys_pm_resume_devices(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < device_count; i++) {
|
|
if (!device_retval[i]) {
|
|
int idx = device_ordered_list[i];
|
|
|
|
device_set_power_state(&pm_device_list[idx],
|
|
DEVICE_PM_ACTIVE_STATE, NULL, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
void sys_pm_create_device_list(void)
|
|
{
|
|
int count;
|
|
int i, j;
|
|
bool is_core_dev;
|
|
|
|
/*
|
|
* Create an ordered list of devices that will be suspended.
|
|
* Ordering should be done based on dependencies. Devices
|
|
* in the beginning of the list will be resumed first.
|
|
*/
|
|
device_list_get(&pm_device_list, &count);
|
|
|
|
/* Reserve for 32KHz, 16MHz, system clock, etc... */
|
|
device_count = ARRAY_SIZE(core_devices);
|
|
|
|
for (i = 0; (i < count) && (device_count < MAX_PM_DEVICES); i++) {
|
|
|
|
/* Check if the device is core device */
|
|
for (j = 0, is_core_dev = false;
|
|
j < ARRAY_SIZE(core_devices);
|
|
j++) {
|
|
if (!strcmp(pm_device_list[i].config->name,
|
|
&core_devices[j][0])) {
|
|
is_core_dev = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (is_core_dev) {
|
|
device_ordered_list[j] = i;
|
|
} else {
|
|
device_ordered_list[device_count++] = i;
|
|
}
|
|
}
|
|
}
|
|
#endif /* defined(CONFIG_SYS_POWER_MANAGEMENT) */
|