411 lines
13 KiB
C
411 lines
13 KiB
C
/*----------------------------------------------------------------------------
|
||
* Copyright (c) TJD Technologies Co., Ltd. 2025. All rights reserved.
|
||
*
|
||
* Description: common_pm.c
|
||
*
|
||
* Author: luziquan@ss-tjd.com
|
||
*
|
||
* Create: 2024-05-29
|
||
*--------------------------------------------------------------------------*/
|
||
|
||
#include "common_pm.h"
|
||
#include "common_pm_port.h"
|
||
#include "gpio.h"
|
||
#include "i2c_porting.h"
|
||
#include "osal_list.h"
|
||
#include "pinctrl.h"
|
||
#include "sys_config.h"
|
||
#include "uart.h"
|
||
#include <stddef.h>
|
||
#include <stdio.h>
|
||
|
||
// clang-format off
|
||
#define ENABLE_PRINT_INFO 1
|
||
#define DEBUG_ENABLE 0
|
||
#if ENABLE_PRINT_INFO
|
||
#define static_print_info(...) sys_pm_log_i(__VA_ARGS__) // 一般信息打印宏控制
|
||
#define static_print_warn(...) sys_pm_log_w(__VA_ARGS__) // 警告信息打印一般常开
|
||
#define static_print_error(...) sys_pm_log_e(__VA_ARGS__) // 错误信息打印一般常开
|
||
#if DEBUG_ENABLE
|
||
#define static_print_debug(...) sys_pm_log_d(__VA_ARGS__)
|
||
#else
|
||
#define static_print_debug(...)
|
||
#endif
|
||
#else
|
||
#define static_print_info(...)
|
||
#define static_print_warn(...)
|
||
#define static_print_error(...)
|
||
#endif
|
||
// clang-format on
|
||
|
||
#ifndef ARRAY_SIZE
|
||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||
#endif
|
||
|
||
typedef struct
|
||
{
|
||
struct osal_list_head node;
|
||
screen_event_callback callback;
|
||
} screen_event_node_t;
|
||
|
||
typedef struct
|
||
{
|
||
struct osal_list_head node;
|
||
shutdown_event_callback callback;
|
||
} shutdown_event_node_t;
|
||
typedef struct
|
||
{
|
||
struct osal_list_head node;
|
||
recover_event_callback callback;
|
||
} recover_event_node_t;
|
||
|
||
/* 相同的gpio放在一起,避免重复设置 */
|
||
// clang-format off
|
||
static power_manager_device_t g_model_device[POWER_MODEL_MAX_ID] = {
|
||
// [POWER_MODEL_SCREEN_ID] = {NORMAL_LDO_GPIO_PIN, NULL, PM_POWER_STATUS_OFF},
|
||
// [POWER_MODEL_ENCODER_ID] = {NORMAL_LDO_GPIO_PIN, NULL, PM_POWER_STATUS_OFF},
|
||
[POWER_MODEL_GPS_ID] = {GPS_POWER_GPIO_PIN, NULL, PM_POWER_STATUS_OFF},
|
||
[POWER_MODEL_HRSENSOR_ID] = {HR_LDO_GPIO_PIN, NULL, PM_POWER_STATUS_OFF},
|
||
[POWER_MODEL_ALIPAY_ID] = {ALIPAY_LDO_GPIO_PIN, NULL, PM_POWER_STATUS_OFF},
|
||
};
|
||
// clang-format on
|
||
|
||
static bool g_power_manager_inited = false;
|
||
static OSAL_LIST_HEAD(g_screen_event_list);
|
||
static OSAL_LIST_HEAD(g_shutdown_event_list);
|
||
static OSAL_LIST_HEAD(g_recover_event_list);
|
||
|
||
static void open(void)
|
||
{
|
||
if (g_power_manager_inited == true) {
|
||
static_print_error("power_manager has been opened");
|
||
return;
|
||
}
|
||
power_manager_gpio_init();
|
||
|
||
power_manager_gpio_set_dir(NORMAL_LDO_GPIO_PIN, GPIO_OUTPUT);
|
||
power_manager_gpio_set(NORMAL_LDO_GPIO_PIN, PM_POWER_STATUS_OFF);
|
||
power_manager_gpio_set(NORMAL_LDO_GPIO_PIN, PM_POWER_STATUS_ON);
|
||
|
||
for (uint8_t i = 0; i < ARRAY_SIZE(g_model_device); i++) {
|
||
if (i != 0 && g_model_device[i].ldo_gpio == g_model_device[i - 1].ldo_gpio) {
|
||
continue;
|
||
}
|
||
power_manager_gpio_set_dir(g_model_device[i].ldo_gpio, GPIO_OUTPUT);
|
||
power_manager_gpio_set(g_model_device[i].ldo_gpio, g_model_device[i].status);
|
||
}
|
||
|
||
g_power_manager_inited = true;
|
||
static_print_info("power_manager open suceess");
|
||
}
|
||
|
||
static void close(void)
|
||
{
|
||
g_power_manager_inited = false;
|
||
static_print_info("power_manager close suceess");
|
||
}
|
||
|
||
static uint32_t set_model_power_on(const power_model_id_t model_id)
|
||
{
|
||
// 有一个Model需要开启,就开启
|
||
g_model_device[model_id].status = power_manager_gpio_set(g_model_device[model_id].ldo_gpio, PM_POWER_STATUS_ON);
|
||
|
||
return POWER_MANAGER_SUCC;
|
||
}
|
||
|
||
static uint32_t set_model_power_off(const power_model_id_t model_id)
|
||
{
|
||
// 全部Model都需要关闭,才关闭
|
||
for (int i = 0; i < POWER_MODEL_MAX_ID; i++) {
|
||
if (i == model_id) {
|
||
continue;
|
||
}
|
||
|
||
/* 对相同发的gpio做判断 */
|
||
if (g_model_device[i].ldo_gpio == g_model_device[model_id].ldo_gpio &&
|
||
g_model_device[i].status == PM_POWER_STATUS_ON) {
|
||
g_model_device[model_id].status = PM_POWER_STATUS_OFF;
|
||
return POWER_MANAGER_ARBITRA_FAIL;
|
||
}
|
||
}
|
||
|
||
static_print_debug("Arbitration Succ Close");
|
||
g_model_device[model_id].status = power_manager_gpio_set(g_model_device[model_id].ldo_gpio, PM_POWER_STATUS_OFF);
|
||
|
||
return POWER_MANAGER_SUCC;
|
||
}
|
||
|
||
static uint32_t set_model_power_status(const power_model_id_t model_id, const power_status_t status)
|
||
{
|
||
static_print_debug("power_manager set model_id = %d, status = %d", model_id, status);
|
||
if (g_power_manager_inited == false || model_id >= POWER_MODEL_MAX_ID) {
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
if (g_model_device[model_id].status == status) {
|
||
return status;
|
||
}
|
||
|
||
if (g_model_device[model_id].ldo_gpio == 0) {
|
||
static_print_error("model %d gpio is invalid", model_id);
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
switch (status) {
|
||
case PM_POWER_STATUS_ON:
|
||
return set_model_power_on(model_id);
|
||
case PM_POWER_STATUS_OFF:
|
||
return set_model_power_off(model_id);
|
||
default:
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
}
|
||
|
||
static uint32_t get_model_power_status(const power_model_id_t model_id)
|
||
{
|
||
if (g_power_manager_inited == false || model_id >= POWER_MODEL_MAX_ID) {
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
return g_model_device[model_id].status;
|
||
}
|
||
|
||
static void master_power_off(void) { power_manager_gpio_set(MASTER_DCDC_GPIO_PIN, PM_POWER_STATUS_OFF); }
|
||
|
||
static uint32_t register_lp_event(const power_model_id_t model_id, lp_event_callback callback)
|
||
{
|
||
if (g_power_manager_inited == false || model_id >= POWER_MODEL_MAX_ID) {
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
if (g_model_device[model_id].lp_callback != NULL) {
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
g_model_device[model_id].lp_callback = callback;
|
||
|
||
static_print_debug("register lp event model_id = %d", model_id);
|
||
|
||
return POWER_MANAGER_SUCC;
|
||
}
|
||
|
||
static uint32_t unregister_lp_event(const power_model_id_t model_id)
|
||
{
|
||
if (g_power_manager_inited == false || model_id >= POWER_MODEL_MAX_ID) {
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
if (g_model_device[model_id].lp_callback == NULL) {
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
g_model_device[model_id].lp_callback = NULL;
|
||
|
||
return POWER_MANAGER_SUCC;
|
||
}
|
||
|
||
static uint32_t register_screen_event(screen_event_callback callback)
|
||
{
|
||
screen_event_node_t *new_node = (screen_event_node_t *)malloc(sizeof(screen_event_node_t));
|
||
if (new_node == NULL) {
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
new_node->callback = callback;
|
||
osal_list_add_tail(&new_node->node, &g_screen_event_list);
|
||
return POWER_MANAGER_SUCC;
|
||
}
|
||
|
||
static uint32_t unregister_screen_event(screen_event_callback callback)
|
||
{
|
||
struct osal_list_head *cur = NULL;
|
||
struct osal_list_head *next = NULL;
|
||
|
||
if (callback == NULL) {
|
||
static_print_error("parameter invalid!");
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
if (osal_list_empty(&g_screen_event_list) != 0) {
|
||
static_print_error("g_screen_event_list is empty!");
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
osal_list_for_each_safe(cur, next, &g_screen_event_list)
|
||
{
|
||
screen_event_node_t *node = osal_list_entry(cur, screen_event_node_t, node);
|
||
if (node->callback == callback) {
|
||
osal_list_del(cur);
|
||
free(node);
|
||
return POWER_MANAGER_SUCC;
|
||
}
|
||
}
|
||
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
static uint32_t register_shutdown_callback(shutdown_event_callback callback)
|
||
{
|
||
shutdown_event_node_t *new_node = (shutdown_event_node_t *)malloc(sizeof(shutdown_event_node_t));
|
||
if (new_node == NULL) {
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
new_node->callback = callback;
|
||
osal_list_add_tail(&new_node->node, &g_shutdown_event_list);
|
||
return POWER_MANAGER_SUCC;
|
||
}
|
||
|
||
static uint32_t unregister_shutdown_callback(shutdown_event_callback callback)
|
||
{
|
||
struct osal_list_head *cur = NULL;
|
||
struct osal_list_head *next = NULL;
|
||
|
||
if (callback == NULL) {
|
||
static_print_error("parameter invalid!");
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
if (osal_list_empty(&g_shutdown_event_list) != 0) {
|
||
static_print_error("g_shutdown_event_list is empty!");
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
osal_list_for_each_safe(cur, next, &g_shutdown_event_list)
|
||
{
|
||
shutdown_event_node_t *node = osal_list_entry(cur, shutdown_event_node_t, node);
|
||
if (node->callback == callback) {
|
||
osal_list_del(cur);
|
||
free(node);
|
||
return POWER_MANAGER_SUCC;
|
||
}
|
||
}
|
||
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
static uint32_t register_recover_callback(recover_event_callback callback)
|
||
{
|
||
recover_event_node_t *new_node = (recover_event_node_t *)malloc(sizeof(recover_event_node_t));
|
||
if (new_node == NULL) {
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
new_node->callback = callback;
|
||
osal_list_add_tail(&new_node->node, &g_recover_event_list);
|
||
return POWER_MANAGER_SUCC;
|
||
}
|
||
|
||
static uint32_t unregister_recover_callback(recover_event_callback callback)
|
||
{
|
||
struct osal_list_head *cur = NULL;
|
||
struct osal_list_head *next = NULL;
|
||
|
||
if (callback == NULL) {
|
||
static_print_error("parameter invalid!");
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
if (osal_list_empty(&g_recover_event_list) != 0) {
|
||
static_print_error("g_recover_event_list is empty!");
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
osal_list_for_each_safe(cur, next, &g_recover_event_list)
|
||
{
|
||
recover_event_node_t *node = osal_list_entry(cur, recover_event_node_t, node);
|
||
if (node->callback == callback) {
|
||
osal_list_del(cur);
|
||
free(node);
|
||
return POWER_MANAGER_SUCC;
|
||
}
|
||
}
|
||
|
||
return POWER_MANAGER_FAIL;
|
||
}
|
||
|
||
static struct power_manager_class_ops g_power_manager_ops = {
|
||
.open = open,
|
||
.close = close,
|
||
.get_model_power_status = get_model_power_status,
|
||
.set_model_power_status = set_model_power_status,
|
||
.register_lp_on_event = register_lp_event,
|
||
.unregister_lp_on_event = unregister_lp_event,
|
||
.register_screen_on_event = register_screen_event,
|
||
.unregister_screen_on_event = unregister_screen_event,
|
||
.register_shutdown_event = register_shutdown_callback,
|
||
.unregister_shutdown_event = unregister_shutdown_callback,
|
||
.register_recover_event = register_recover_callback,
|
||
.unregister_recover_event = unregister_recover_callback,
|
||
};
|
||
|
||
const struct power_manager_class_ops *tjd_driver_common_pm_get_ops(void) { return &g_power_manager_ops; }
|
||
|
||
void tjd_driver_pm_lp_enter(pm_event_t event)
|
||
{
|
||
if (event == PM_EVENT_SUSPEND) {
|
||
/* 心率,马达,加速计外设的I2C通道寄存器保存,关中断 */
|
||
/* 进入低功耗模式 */
|
||
for (uint8_t i = 0; i < ARRAY_SIZE(g_model_device); i++) {
|
||
if (g_model_device[i].lp_callback != NULL) {
|
||
g_model_device[i].lp_callback(PM_EVENT_SUSPEND);
|
||
}
|
||
}
|
||
|
||
// gsensor 加密se i2c0
|
||
i2c_save_reg(I2C_BUS_0);
|
||
|
||
// encoder hr i2c2 msensor
|
||
i2c_save_reg(I2C_BUS_2);
|
||
} else {
|
||
/* 心率,马达,加速计外设的I2C通道寄存器的恢复,关中断,重新配置pinmux,重新初始化。 */
|
||
/* 退出低功耗模式 */
|
||
i2c_recovery_reg(I2C_BUS_0);
|
||
i2c_recovery_reg(I2C_BUS_2);
|
||
for (uint8_t i = 0; i < ARRAY_SIZE(g_model_device); i++) {
|
||
if (g_model_device[i].lp_callback != NULL) {
|
||
g_model_device[i].lp_callback(PM_EVENT_RESUME);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void tjd_driver_pm_screen_event(screen_status_t status)
|
||
{
|
||
screen_event_node_t *inst = NULL;
|
||
osal_list_for_each_entry(inst, &g_screen_event_list, node)
|
||
{
|
||
if (inst != NULL) {
|
||
inst->callback(status);
|
||
}
|
||
}
|
||
}
|
||
|
||
void tjd_driver_pm_power_down_event(void)
|
||
{
|
||
static_print_debug("power_manager shutdown process");
|
||
for (uint8_t i = 0; i < ARRAY_SIZE(g_model_device); i++) {
|
||
power_manager_gpio_set(g_model_device[i].ldo_gpio, PM_POWER_STATUS_OFF);
|
||
}
|
||
master_power_off();
|
||
}
|
||
|
||
void tjd_driver_pm_shutdown_event(void)
|
||
{
|
||
shutdown_event_node_t *inst = NULL;
|
||
osal_list_for_each_entry(inst, &g_shutdown_event_list, node)
|
||
{
|
||
if (inst != NULL) {
|
||
inst->callback();
|
||
}
|
||
}
|
||
}
|
||
|
||
void tjd_driver_pm_recover_event(void)
|
||
{
|
||
recover_event_node_t *inst = NULL;
|
||
osal_list_for_each_entry(inst, &g_recover_event_list, node)
|
||
{
|
||
if (inst != NULL) {
|
||
inst->callback();
|
||
}
|
||
}
|
||
}
|