mcu_hi3321_watch/tjd/driver/common/common_pm.c
2025-05-26 20:15:20 +08:00

411 lines
13 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*----------------------------------------------------------------------------
* 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();
}
}
}