mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-06 06:21:56 +00:00
Add support for OS managed Power Management framework for Zephyr under 'subsys/power'. This framework takes care of implementing the _sys_soc_suspend/_sys_soc_resume API's, a PM policy based on SoC Low Power residencies and also provides necessary API's to do devices suspend and resume. Also add necessary changes to support the existing Application managed Power Management framework. Signed-off-by: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
116 lines
2.6 KiB
C
116 lines
2.6 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 "pm_policy.h"
|
|
|
|
#define LOG_MODULE_NAME power
|
|
#define LOG_LEVEL CONFIG_PM_LOG_LEVEL /* From power module Kconfig */
|
|
#include <logging/log.h>
|
|
LOG_MODULE_DECLARE();
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
#ifdef CONFIG_SOC_SERIES_NRF52X
|
|
#define MAX_PM_DEVICES 15
|
|
#define NUM_CORE_DEVICES 4
|
|
#define MAX_DEV_NAME_LEN 16
|
|
static const char core_devices[NUM_CORE_DEVICES][MAX_DEV_NAME_LEN] = {
|
|
"clk_k32src",
|
|
"clk_m16src",
|
|
"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;
|
|
|
|
int sys_pm_suspend_devices(void)
|
|
{
|
|
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],
|
|
DEVICE_PM_SUSPEND_STATE);
|
|
if (device_retval[i]) {
|
|
LOG_ERR("%s suspend operation failed\n",
|
|
pm_device_list[idx].config->name);
|
|
return device_retval[i];
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
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 = NUM_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 < NUM_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;
|
|
}
|
|
}
|
|
}
|