mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-02-06 09:02:20 +08:00
[dm][power] add new drivers for power framework
Some checks failed
ToolsCI / Tools (push) Has been cancelled
RT-Thread BSP Static Build Check / 🔍 Summary of Git Diff Changes (push) Has been cancelled
doc_doxygen / doxygen_doc generate (push) Has been cancelled
pkgs_test / change (push) Has been cancelled
utest_auto_run / A9 :components/dfs.cfg (push) Has been cancelled
utest_auto_run / A9 :components/lwip.cfg (push) Has been cancelled
utest_auto_run / A9 :components/netdev.cfg (push) Has been cancelled
utest_auto_run / A9 :components/sal.cfg (push) Has been cancelled
utest_auto_run / A9 :cpp11/cpp11.cfg (push) Has been cancelled
utest_auto_run / AARCH64-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / A9-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / XUANTIE-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64 :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :default.cfg (push) Has been cancelled
utest_auto_run / A9-smp :default.cfg (push) Has been cancelled
utest_auto_run / RISCV :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / RISCV :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/ipc.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/kernel_basic.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/mem.cfg (push) Has been cancelled
RT-Thread BSP Static Build Check / ${{ matrix.legs.RTT_BSP }} (push) Has been cancelled
RT-Thread BSP Static Build Check / collect-artifacts (push) Has been cancelled
doc_doxygen / deploy (push) Has been cancelled
Weekly CI Scheduler / Trigger and Monitor CIs (push) Has been cancelled
Weekly CI Scheduler / Create Discussion Report (push) Has been cancelled
Some checks failed
ToolsCI / Tools (push) Has been cancelled
RT-Thread BSP Static Build Check / 🔍 Summary of Git Diff Changes (push) Has been cancelled
doc_doxygen / doxygen_doc generate (push) Has been cancelled
pkgs_test / change (push) Has been cancelled
utest_auto_run / A9 :components/dfs.cfg (push) Has been cancelled
utest_auto_run / A9 :components/lwip.cfg (push) Has been cancelled
utest_auto_run / A9 :components/netdev.cfg (push) Has been cancelled
utest_auto_run / A9 :components/sal.cfg (push) Has been cancelled
utest_auto_run / A9 :cpp11/cpp11.cfg (push) Has been cancelled
utest_auto_run / AARCH64-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / A9-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / XUANTIE-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64 :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :default.cfg (push) Has been cancelled
utest_auto_run / A9-smp :default.cfg (push) Has been cancelled
utest_auto_run / RISCV :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / RISCV :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/ipc.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/kernel_basic.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/mem.cfg (push) Has been cancelled
RT-Thread BSP Static Build Check / ${{ matrix.legs.RTT_BSP }} (push) Has been cancelled
RT-Thread BSP Static Build Check / collect-artifacts (push) Has been cancelled
doc_doxygen / deploy (push) Has been cancelled
Weekly CI Scheduler / Trigger and Monitor CIs (push) Has been cancelled
Weekly CI Scheduler / Create Discussion Report (push) Has been cancelled
1. GPIO poweroff/restart 2. Generic SYSCON regmap poweroff/reboot mode/reboot 3. Emulator battery(thermal)/charger 4. GPIO charger Signed-off-by: GuEe-GUI <2991707448@qq.com>
This commit is contained in:
2
components/drivers/power/Kconfig
Normal file
2
components/drivers/power/Kconfig
Normal file
@@ -0,0 +1,2 @@
|
||||
rsource "reset/Kconfig"
|
||||
rsource "supply/Kconfig"
|
||||
11
components/drivers/power/SConscript
Normal file
11
components/drivers/power/SConscript
Normal file
@@ -0,0 +1,11 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
objs = []
|
||||
list = os.listdir(cwd)
|
||||
|
||||
for d in list:
|
||||
path = os.path.join(cwd, d)
|
||||
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||
objs = objs + SConscript(os.path.join(d, 'SConscript'))
|
||||
Return('objs')
|
||||
@@ -2,6 +2,38 @@ menuconfig RT_USING_POWER_RESET
|
||||
bool "Using Board level reset or poweroff"
|
||||
depends on RT_USING_DM
|
||||
|
||||
config RT_POWER_RESET_GPIO_POWEROFF
|
||||
bool "GPIO poweroff"
|
||||
depends on RT_USING_POWER_RESET
|
||||
depends on RT_USING_PIN
|
||||
depends on RT_USING_PINCTRL
|
||||
|
||||
config RT_POWER_RESET_GPIO_RESTART
|
||||
bool "GPIO restart"
|
||||
depends on RT_USING_POWER_RESET
|
||||
depends on RT_USING_PIN
|
||||
depends on RT_USING_PINCTRL
|
||||
|
||||
config RT_POWER_RESET_SYSCON_POWEROFF
|
||||
bool "Generic SYSCON regmap poweroff driver"
|
||||
depends on RT_USING_POWER_RESET
|
||||
depends on RT_MFD_SYSCON
|
||||
|
||||
config RT_POWER_RESET_SYSCON_REBOOT_MODE
|
||||
bool "Generic SYSCON regmap reboot mode driver"
|
||||
depends on RT_USING_POWER_RESET
|
||||
depends on RT_MFD_SYSCON
|
||||
select RT_POWER_RESET_REBOOT_MODE
|
||||
|
||||
config RT_POWER_RESET_SYSCON_REBOOT
|
||||
bool "Generic SYSCON regmap reboot driver"
|
||||
depends on RT_USING_POWER_RESET
|
||||
depends on RT_MFD_SYSCON
|
||||
|
||||
if RT_USING_POWER_RESET
|
||||
osource "$(SOC_DM_POWER_RESET_DIR)/Kconfig"
|
||||
endif
|
||||
|
||||
config RT_POWER_RESET_REBOOT_MODE
|
||||
bool
|
||||
depends on RT_USING_OFW
|
||||
|
||||
@@ -10,6 +10,24 @@ CPPPATH = [cwd + '/../../include']
|
||||
|
||||
src = []
|
||||
|
||||
if GetDepend(['RT_POWER_RESET_GPIO_POWEROFF']):
|
||||
src += ['gpio-poweroff.c']
|
||||
|
||||
if GetDepend(['RT_POWER_RESET_GPIO_RESTART']):
|
||||
src += ['gpio-restart.c']
|
||||
|
||||
if GetDepend(['RT_POWER_RESET_REBOOT_MODE']):
|
||||
src += ['reboot-mode.c']
|
||||
|
||||
if GetDepend(['RT_POWER_RESET_SYSCON_POWEROFF']):
|
||||
src += ['syscon-poweroff.c']
|
||||
|
||||
if GetDepend(['RT_POWER_RESET_SYSCON_REBOOT_MODE']):
|
||||
src += ['syscon-reboot-mode.c']
|
||||
|
||||
if GetDepend(['RT_POWER_RESET_SYSCON_REBOOT']):
|
||||
src += ['syscon-reboot.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
|
||||
100
components/drivers/power/reset/gpio-poweroff.c
Normal file
100
components/drivers/power/reset/gpio-poweroff.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define DBG_TAG "reset.gpio.poweroff"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
struct gpio_poweroff
|
||||
{
|
||||
rt_ubase_t pin;
|
||||
rt_uint8_t active_value;
|
||||
|
||||
rt_uint32_t timeout_ms;
|
||||
rt_uint32_t active_delay_ms;
|
||||
rt_uint32_t inactive_delay_ms;
|
||||
};
|
||||
|
||||
static rt_err_t gpio_poweroff_do_poweroff(struct rt_device *dev)
|
||||
{
|
||||
struct gpio_poweroff *gp = dev->user_data;
|
||||
|
||||
rt_pin_mode(gp->pin, PIN_MODE_OUTPUT);
|
||||
rt_thread_mdelay(gp->active_delay_ms);
|
||||
|
||||
rt_pin_write(gp->pin, !gp->active_value);
|
||||
rt_thread_mdelay(gp->inactive_delay_ms);
|
||||
rt_pin_write(gp->pin, gp->active_value);
|
||||
|
||||
rt_thread_mdelay(gp->timeout_ms);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t gpio_poweroff_probe(struct rt_platform_device *pdev)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_device *dev = &pdev->parent;
|
||||
struct gpio_poweroff *gp = rt_calloc(1, sizeof(*gp));
|
||||
|
||||
if (!gp)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
gp->pin = rt_pin_get_named_pin(dev, RT_NULL, 0, RT_NULL, &gp->active_value);
|
||||
|
||||
if (gp->pin < 0)
|
||||
{
|
||||
err = gp->pin;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
gp->active_delay_ms = 100;
|
||||
gp->inactive_delay_ms = 100;
|
||||
gp->timeout_ms = 3000;
|
||||
|
||||
rt_dm_dev_prop_read_u32(dev, "active-delay-ms", &gp->active_delay_ms);
|
||||
rt_dm_dev_prop_read_u32(dev, "inactive-delay-ms", &gp->inactive_delay_ms);
|
||||
rt_dm_dev_prop_read_u32(dev, "timeout-ms", &gp->timeout_ms);
|
||||
|
||||
dev->user_data = gp;
|
||||
|
||||
if ((err = rt_dm_power_off_handler(dev, RT_DM_POWER_OFF_MODE_SHUTDOWN,
|
||||
RT_DM_POWER_OFF_PRIO_DEFAULT, gpio_poweroff_do_poweroff)))
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
_fail:
|
||||
rt_free(gp);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct rt_ofw_node_id gpio_poweroff_ofw_ids[] =
|
||||
{
|
||||
{ .compatible = "gpio-poweroff" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct rt_platform_driver gpio_poweroff_driver =
|
||||
{
|
||||
.name = "reset-gpio-poweroff",
|
||||
.ids = gpio_poweroff_ofw_ids,
|
||||
|
||||
.probe = gpio_poweroff_probe,
|
||||
};
|
||||
RT_PLATFORM_DRIVER_EXPORT(gpio_poweroff_driver);
|
||||
100
components/drivers/power/reset/gpio-restart.c
Normal file
100
components/drivers/power/reset/gpio-restart.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define DBG_TAG "reset.gpio.restart"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
struct gpio_restart
|
||||
{
|
||||
rt_ubase_t pin;
|
||||
rt_uint8_t active_value;
|
||||
|
||||
rt_uint32_t wait_delay_ms;
|
||||
rt_uint32_t active_delay_ms;
|
||||
rt_uint32_t inactive_delay_ms;
|
||||
};
|
||||
|
||||
static rt_err_t gpio_restart_do_restart(struct rt_device *dev)
|
||||
{
|
||||
struct gpio_restart *gr = dev->user_data;
|
||||
|
||||
rt_pin_mode(gr->pin, PIN_MODE_OUTPUT);
|
||||
rt_thread_mdelay(gr->active_delay_ms);
|
||||
|
||||
rt_pin_write(gr->pin, !gr->active_value);
|
||||
rt_thread_mdelay(gr->inactive_delay_ms);
|
||||
rt_pin_write(gr->pin, gr->active_value);
|
||||
|
||||
rt_thread_mdelay(gr->wait_delay_ms);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t gpio_restart_probe(struct rt_platform_device *pdev)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_device *dev = &pdev->parent;
|
||||
struct gpio_restart *gr = rt_calloc(1, sizeof(*gr));
|
||||
|
||||
if (!gr)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
gr->pin = rt_pin_get_named_pin(dev, RT_NULL, 0, RT_NULL, &gr->active_value);
|
||||
|
||||
if (gr->pin < 0)
|
||||
{
|
||||
err = gr->pin;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
gr->active_delay_ms = 100;
|
||||
gr->inactive_delay_ms = 100;
|
||||
gr->wait_delay_ms = 3000;
|
||||
|
||||
rt_dm_dev_prop_read_u32(dev, "active-delay", &gr->active_delay_ms);
|
||||
rt_dm_dev_prop_read_u32(dev, "inactive-delay", &gr->inactive_delay_ms);
|
||||
rt_dm_dev_prop_read_u32(dev, "wait-delay", &gr->wait_delay_ms);
|
||||
|
||||
dev->user_data = gr;
|
||||
|
||||
if ((err = rt_dm_power_off_handler(dev, RT_DM_POWER_OFF_MODE_RESET,
|
||||
RT_DM_POWER_OFF_PRIO_DEFAULT, gpio_restart_do_restart)))
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
_fail:
|
||||
rt_free(gr);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct rt_ofw_node_id gpio_restart_ofw_ids[] =
|
||||
{
|
||||
{ .compatible = "gpio-restart" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct rt_platform_driver gpio_restart_driver =
|
||||
{
|
||||
.name = "reset-gpio-restart",
|
||||
.ids = gpio_restart_ofw_ids,
|
||||
|
||||
.probe = gpio_restart_probe,
|
||||
};
|
||||
RT_PLATFORM_DRIVER_EXPORT(gpio_restart_driver);
|
||||
105
components/drivers/power/reset/reboot-mode.c
Normal file
105
components/drivers/power/reset/reboot-mode.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include "reboot-mode.h"
|
||||
|
||||
#define MODE_SUFFIXE "mode-"
|
||||
|
||||
struct mode_info
|
||||
{
|
||||
rt_slist_t list;
|
||||
|
||||
const char *mode;
|
||||
rt_uint32_t magic;
|
||||
};
|
||||
|
||||
static rt_err_t reboot_mode_work(struct rt_device *dev, char *cmd)
|
||||
{
|
||||
struct mode_info *info;
|
||||
struct reboot_mode *reboot = (void *)dev;
|
||||
|
||||
cmd = cmd ? : "normal";
|
||||
|
||||
rt_slist_for_each_entry(info, &reboot->mode_nodes, list)
|
||||
{
|
||||
if (!rt_strcmp(info->mode, cmd))
|
||||
{
|
||||
reboot->write(reboot, info->magic);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t reboot_mode_register(struct reboot_mode *reboot)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct mode_info *info;
|
||||
struct rt_ofw_prop *prop;
|
||||
struct rt_ofw_node *np = reboot->dev->ofw_node;
|
||||
const int mode_suffixe_len = sizeof(MODE_SUFFIXE) - 1;
|
||||
|
||||
if (!reboot || !reboot->dev)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
rt_slist_init(&reboot->mode_nodes);
|
||||
|
||||
rt_ofw_foreach_prop(np, prop)
|
||||
{
|
||||
if (rt_strncmp(prop->name, MODE_SUFFIXE, mode_suffixe_len))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
info = rt_malloc(sizeof(*info));
|
||||
|
||||
if (!info)
|
||||
{
|
||||
err = -RT_ENOMEM;
|
||||
|
||||
goto _end;
|
||||
}
|
||||
|
||||
info->mode = prop->name + mode_suffixe_len;
|
||||
info->magic = fdt32_to_cpu(*(const fdt32_t *)prop->value);
|
||||
|
||||
rt_slist_init(&info->list);
|
||||
|
||||
rt_slist_insert(&reboot->mode_nodes, &info->list);
|
||||
}
|
||||
|
||||
err = rt_dm_reboot_mode_register((void *)reboot, &reboot_mode_work);
|
||||
|
||||
_end:
|
||||
if (err)
|
||||
{
|
||||
struct mode_info *prev_info = RT_NULL;
|
||||
|
||||
rt_slist_for_each_entry(info, &reboot->mode_nodes, list)
|
||||
{
|
||||
if (prev_info)
|
||||
{
|
||||
rt_free(prev_info);
|
||||
}
|
||||
|
||||
prev_info = info;
|
||||
}
|
||||
|
||||
if (prev_info)
|
||||
{
|
||||
rt_free(prev_info);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
27
components/drivers/power/reset/reboot-mode.h
Normal file
27
components/drivers/power/reset/reboot-mode.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __RESET_REBOOT_MODE_H__
|
||||
#define __RESET_REBOOT_MODE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
struct reboot_mode
|
||||
{
|
||||
rt_slist_t mode_nodes;
|
||||
|
||||
struct rt_device *dev;
|
||||
rt_err_t (*write)(struct reboot_mode *reboot, rt_uint32_t magic);
|
||||
};
|
||||
|
||||
rt_err_t reboot_mode_register(struct reboot_mode *reboot);
|
||||
|
||||
#endif /* __RESET_REBOOT_MODE_H__ */
|
||||
104
components/drivers/power/reset/syscon-poweroff.c
Normal file
104
components/drivers/power/reset/syscon-poweroff.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define DBG_TAG "reset.syscon.poweroff"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
static struct rt_syscon *syscon;
|
||||
static rt_uint32_t offset, value, mask;
|
||||
|
||||
static void syscon_poweroff(void)
|
||||
{
|
||||
/* Issue the poweroff */
|
||||
rt_syscon_update_bits(syscon, offset, mask, value);
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
LOG_E("Unable to poweroff system");
|
||||
}
|
||||
|
||||
static rt_err_t syscon_poweroff_probe(struct rt_platform_device *pdev)
|
||||
{
|
||||
rt_err_t mask_err, value_err;
|
||||
struct rt_ofw_node *np = pdev->parent.ofw_node;
|
||||
|
||||
syscon = rt_syscon_find_by_ofw_phandle(np, "regmap");
|
||||
|
||||
if (!syscon)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
if (rt_ofw_prop_read_u32(np, "offset", &offset))
|
||||
{
|
||||
LOG_E("read '%s' fail", "offset");
|
||||
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
value_err = rt_ofw_prop_read_u32(np, "value", &value);
|
||||
mask_err = rt_ofw_prop_read_u32(np, "mask", &mask);
|
||||
|
||||
if (value_err && mask_err)
|
||||
{
|
||||
LOG_E("read '%s' and '%s' fail", "value", "mask");
|
||||
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
if (value_err)
|
||||
{
|
||||
/* support old binding */
|
||||
value = mask;
|
||||
mask = 0xffffffff;
|
||||
}
|
||||
else if (mask_err)
|
||||
{
|
||||
/* support value without mask */
|
||||
mask = 0xffffffff;
|
||||
}
|
||||
|
||||
if (rt_dm_machine_shutdown)
|
||||
{
|
||||
LOG_E("rt_dm_machine_shutdown have hook %p", rt_dm_machine_shutdown);
|
||||
|
||||
return -RT_EBUSY;
|
||||
}
|
||||
|
||||
rt_dm_machine_shutdown = syscon_poweroff;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_ofw_node_id syscon_poweroff_ofw_ids[] =
|
||||
{
|
||||
{ .compatible = "syscon-poweroff" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct rt_platform_driver syscon_poweroff_driver =
|
||||
{
|
||||
.name = "reset-syscon-poweroff",
|
||||
.ids = syscon_poweroff_ofw_ids,
|
||||
|
||||
.probe = syscon_poweroff_probe,
|
||||
};
|
||||
|
||||
static int syscon_poweroff_driver_register(void)
|
||||
{
|
||||
rt_platform_driver_register(&syscon_poweroff_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_SUBSYS_EXPORT(syscon_poweroff_driver_register);
|
||||
115
components/drivers/power/reset/syscon-reboot-mode.c
Normal file
115
components/drivers/power/reset/syscon-reboot-mode.c
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define DBG_TAG "reset.syscon.reboot-mode"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "reboot-mode.h"
|
||||
|
||||
struct syscon_reboot_mode
|
||||
{
|
||||
struct rt_syscon *map;
|
||||
|
||||
struct reboot_mode reboot;
|
||||
|
||||
rt_uint32_t offset;
|
||||
rt_uint32_t mask;
|
||||
};
|
||||
|
||||
static rt_err_t syscon_reboot_mode_write(struct reboot_mode *reboot,
|
||||
rt_uint32_t magic)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct syscon_reboot_mode *srbm;
|
||||
|
||||
srbm = rt_container_of(reboot, struct syscon_reboot_mode, reboot);
|
||||
|
||||
err = rt_syscon_update_bits(srbm->map, srbm->offset, srbm->mask, magic);
|
||||
|
||||
if (err)
|
||||
{
|
||||
LOG_E("Update reboot mode bits failed");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static rt_err_t syscon_reboot_mode_probe(struct rt_platform_device *pdev)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_ofw_node *np;
|
||||
struct rt_device *dev = &pdev->parent;
|
||||
struct syscon_reboot_mode *srbm = rt_calloc(1, sizeof(*srbm));
|
||||
|
||||
if (!srbm)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
np = rt_ofw_get_parent(dev->ofw_node);
|
||||
srbm->map = rt_syscon_find_by_ofw_node(np);
|
||||
rt_ofw_node_put(np);
|
||||
|
||||
if (!srbm->map)
|
||||
{
|
||||
err = -RT_EIO;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
srbm->reboot.dev = dev;
|
||||
srbm->reboot.write = syscon_reboot_mode_write;
|
||||
srbm->mask = 0xffffffff;
|
||||
|
||||
if (rt_dm_dev_prop_read_u32(dev, "offset", &srbm->offset))
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
rt_dm_dev_prop_read_u32(dev, "mask", &srbm->mask);
|
||||
|
||||
if ((err = reboot_mode_register(&srbm->reboot)))
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
_fail:
|
||||
rt_free(srbm);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct rt_ofw_node_id syscon_reboot_mode_ofw_ids[] =
|
||||
{
|
||||
{ .compatible = "syscon-reboot-mode" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct rt_platform_driver syscon_reboot_mode_driver =
|
||||
{
|
||||
.name = "reset-syscon-reboot-mode",
|
||||
.ids = syscon_reboot_mode_ofw_ids,
|
||||
|
||||
.probe = syscon_reboot_mode_probe,
|
||||
};
|
||||
|
||||
static int syscon_reboot_mode_driver_register(void)
|
||||
{
|
||||
rt_platform_driver_register(&syscon_reboot_mode_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_SUBSYS_EXPORT(syscon_reboot_mode_driver_register);
|
||||
104
components/drivers/power/reset/syscon-reboot.c
Normal file
104
components/drivers/power/reset/syscon-reboot.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define DBG_TAG "reset.syscon.reboot"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
static struct rt_syscon *syscon;
|
||||
static rt_uint32_t offset, value, mask;
|
||||
|
||||
static void syscon_reboot(void)
|
||||
{
|
||||
/* Issue the reboot */
|
||||
rt_syscon_update_bits(syscon, offset, mask, value);
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
LOG_E("Unable to restart system");
|
||||
}
|
||||
|
||||
static rt_err_t syscon_reboot_probe(struct rt_platform_device *pdev)
|
||||
{
|
||||
rt_err_t mask_err, value_err;
|
||||
struct rt_ofw_node *np = pdev->parent.ofw_node;
|
||||
|
||||
syscon = rt_syscon_find_by_ofw_phandle(np, "regmap");
|
||||
|
||||
if (!syscon)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
if (rt_ofw_prop_read_u32(np, "offset", &offset))
|
||||
{
|
||||
LOG_E("read '%s' fail", "offset");
|
||||
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
value_err = rt_ofw_prop_read_u32(np, "value", &value);
|
||||
mask_err = rt_ofw_prop_read_u32(np, "mask", &mask);
|
||||
|
||||
if (value_err && mask_err)
|
||||
{
|
||||
LOG_E("read '%s' and '%s' fail", "value", "mask");
|
||||
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
if (value_err)
|
||||
{
|
||||
/* support old binding */
|
||||
value = mask;
|
||||
mask = 0xffffffff;
|
||||
}
|
||||
else if (mask_err)
|
||||
{
|
||||
/* support value without mask */
|
||||
mask = 0xffffffff;
|
||||
}
|
||||
|
||||
if (rt_dm_machine_reset)
|
||||
{
|
||||
LOG_E("rt_dm_machine_reset have hook %p", rt_dm_machine_reset);
|
||||
|
||||
return -RT_EBUSY;
|
||||
}
|
||||
|
||||
rt_dm_machine_reset = syscon_reboot;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_ofw_node_id syscon_reboot_ofw_ids[] =
|
||||
{
|
||||
{ .compatible = "syscon-reboot" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct rt_platform_driver syscon_reboot_driver =
|
||||
{
|
||||
.name = "reset-syscon-reboot",
|
||||
.ids = syscon_reboot_ofw_ids,
|
||||
|
||||
.probe = syscon_reboot_probe,
|
||||
};
|
||||
|
||||
static int syscon_reboot_driver_register(void)
|
||||
{
|
||||
rt_platform_driver_register(&syscon_reboot_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_SUBSYS_EXPORT(syscon_reboot_driver_register);
|
||||
@@ -15,6 +15,21 @@ if RT_USING_POWER_SUPPLY
|
||||
comment "Power Supply Device Drivers"
|
||||
endif
|
||||
|
||||
config RT_POWER_SUPPLY_EMU
|
||||
bool "Emulator battery(thermal)/charger"
|
||||
depends on RT_USING_POWER_SUPPLY
|
||||
depends on RT_USING_PM
|
||||
depends on RT_USING_CONSOLE
|
||||
depends on RT_USING_MSH
|
||||
depends on RT_USING_CPU_USAGE_TRACER
|
||||
default n
|
||||
|
||||
config RT_POWER_SUPPLY_CHARGER_GPIO
|
||||
bool "GPIO charger"
|
||||
depends on RT_USING_POWER_SUPPLY
|
||||
depends on RT_USING_PIN
|
||||
default y
|
||||
|
||||
if RT_USING_POWER_SUPPLY
|
||||
osource "$(SOC_DM_POWER_SUPPLY_DIR)/Kconfig"
|
||||
endif
|
||||
|
||||
@@ -13,6 +13,12 @@ src = ['supply.c']
|
||||
if GetDepend(['RT_POWER_SUPPLY_DAEMON']):
|
||||
src += ['supply-daemon.c']
|
||||
|
||||
if GetDepend(['RT_POWER_SUPPLY_EMU']):
|
||||
src += ['emu-power.c']
|
||||
|
||||
if GetDepend(['RT_POWER_SUPPLY_CHARGER_GPIO']):
|
||||
src += ['gpio-charger.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
|
||||
379
components/drivers/power/supply/emu-power.c
Normal file
379
components/drivers/power/supply/emu-power.c
Normal file
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <drivers/misc.h>
|
||||
|
||||
#define POLL_INTERVAL_MS 3000
|
||||
#define CHARGE_STEP_FAST 4
|
||||
#define CHARGE_STEP_NORMAL 2
|
||||
#define CHARGE_STEP_TRICKLE 1
|
||||
#define DISCHARGE_BASE_RATE 1
|
||||
#define TEMP_SENSITIVITY 30
|
||||
|
||||
struct emu_power
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
struct rt_power_supply battery;
|
||||
struct rt_power_supply charger;
|
||||
|
||||
struct rt_timer poller;
|
||||
|
||||
rt_uint32_t status;
|
||||
rt_uint32_t health;
|
||||
rt_uint32_t present;
|
||||
rt_uint32_t capacity;
|
||||
rt_uint32_t voltage;
|
||||
rt_uint32_t temp;
|
||||
rt_uint32_t charge_counter;
|
||||
rt_uint32_t current_now;
|
||||
rt_uint32_t current_avg;
|
||||
rt_uint32_t charge_full_uah;
|
||||
rt_uint32_t cycle_count;
|
||||
rt_uint32_t ac_online;
|
||||
rt_uint32_t voltage_max;
|
||||
rt_uint32_t current_max;
|
||||
|
||||
rt_tick_t last_poll_tick;
|
||||
|
||||
rt_uint8_t load_index;
|
||||
rt_ubase_t cpu_load;
|
||||
rt_ubase_t load_history[5];
|
||||
rt_ubase_t last_idle;
|
||||
rt_ubase_t last_total;
|
||||
};
|
||||
static struct emu_power _emu_power;
|
||||
|
||||
static enum rt_power_supply_property emu_battery_properties[] =
|
||||
{
|
||||
RT_POWER_SUPPLY_PROP_STATUS,
|
||||
RT_POWER_SUPPLY_PROP_HEALTH,
|
||||
RT_POWER_SUPPLY_PROP_PRESENT,
|
||||
RT_POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
RT_POWER_SUPPLY_PROP_CAPACITY,
|
||||
RT_POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
RT_POWER_SUPPLY_PROP_TEMP,
|
||||
RT_POWER_SUPPLY_PROP_CHARGE_COUNTER,
|
||||
RT_POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
RT_POWER_SUPPLY_PROP_CURRENT_AVG,
|
||||
RT_POWER_SUPPLY_PROP_CHARGE_FULL,
|
||||
RT_POWER_SUPPLY_PROP_CYCLE_COUNT,
|
||||
RT_POWER_SUPPLY_PROP_SCOPE,
|
||||
};
|
||||
|
||||
static struct rt_power_supply_battery_info emu_battery_info =
|
||||
{
|
||||
.technology = RT_POWER_SUPPLY_TECHNOLOGY_LION,
|
||||
.energy_full_design_uwh = 3000000000, /* 3000mWh */
|
||||
.charge_full_design_uah = 3000000, /* 3000mAh */
|
||||
.voltage_min_design_uv = 3000000, /* 3.0V */
|
||||
.voltage_max_design_uv = 4200000, /* 4.2V */
|
||||
.precharge_current_ua = 500000, /* 500mA */
|
||||
.charge_term_current_ua = 1000000, /* 1000mA */
|
||||
.charge_restart_voltage_uv = 3500000, /* 3.5V */
|
||||
.constant_charge_current_max_ua = 2000000, /* 2000mA */
|
||||
.constant_charge_voltage_max_uv = 4200000, /* 4.2V */
|
||||
.temp_ambient_alert_min = -10000, /* -10C */
|
||||
.temp_ambient_alert_max = 40000, /* 40C */
|
||||
.temp_alert_min = 20000, /* 20C */
|
||||
.temp_alert_max = 25000, /* 25C */
|
||||
.temp_min = 0, /* 0C */
|
||||
.temp_max = 35000, /* 35C */
|
||||
};
|
||||
|
||||
static rt_err_t emu_battery_get_property(struct rt_power_supply *psy,
|
||||
enum rt_power_supply_property prop, union rt_power_supply_property_val *val)
|
||||
{
|
||||
struct emu_power *ep = rt_container_of(psy, struct emu_power, battery);
|
||||
|
||||
switch (prop)
|
||||
{
|
||||
case RT_POWER_SUPPLY_PROP_STATUS:
|
||||
val->intval = ep->status;
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_HEALTH:
|
||||
val->intval = ep->health;
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_PRESENT:
|
||||
val->intval = ep->present;
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_TECHNOLOGY:
|
||||
val->intval = RT_POWER_SUPPLY_TECHNOLOGY_LION;
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_CAPACITY:
|
||||
val->intval = ep->capacity;
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
val->intval = ep->voltage;
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_TEMP:
|
||||
val->intval = ep->temp;
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_CHARGE_COUNTER:
|
||||
val->intval = ep->charge_counter;
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
val->intval = ep->current_now;
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_CURRENT_AVG:
|
||||
val->intval = ep->current_avg;
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_CHARGE_FULL:
|
||||
val->intval = ep->charge_full_uah;
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_CYCLE_COUNT:
|
||||
val->intval = ep->cycle_count;
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_SCOPE:
|
||||
val->intval = RT_POWER_SUPPLY_SCOPE_SYSTEM;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_power_supply_ops emu_battery_ops =
|
||||
{
|
||||
.get_property = emu_battery_get_property,
|
||||
};
|
||||
|
||||
static enum rt_power_supply_property emu_charger_properties[] =
|
||||
{
|
||||
RT_POWER_SUPPLY_PROP_ONLINE,
|
||||
RT_POWER_SUPPLY_PROP_VOLTAGE_MAX,
|
||||
RT_POWER_SUPPLY_PROP_CURRENT_MAX,
|
||||
};
|
||||
|
||||
static rt_err_t emu_charger_get_property(struct rt_power_supply *psy,
|
||||
enum rt_power_supply_property prop, union rt_power_supply_property_val *val)
|
||||
{
|
||||
struct emu_power *ep = rt_container_of(psy, struct emu_power, charger);
|
||||
|
||||
switch (prop)
|
||||
{
|
||||
case RT_POWER_SUPPLY_PROP_ONLINE:
|
||||
val->intval = ep->ac_online;
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_VOLTAGE_MAX:
|
||||
val->intval = ep->voltage_max;
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_CURRENT_MAX:
|
||||
val->intval = ep->current_max;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_power_supply_ops emu_charger_ops =
|
||||
{
|
||||
.get_property = emu_charger_get_property,
|
||||
};
|
||||
|
||||
static void emu_power_poll(void *param)
|
||||
{
|
||||
rt_tick_t current_tick;
|
||||
rt_uint32_t elapsed_ms, avg_load = 0;
|
||||
rt_ubase_t current_idle, current_total, idle_diff, total_diff;
|
||||
struct rt_cpu_usage_stats *stats = &rt_cpu_self()->cpu_stat;
|
||||
struct emu_power *ep = param;
|
||||
|
||||
current_tick = rt_tick_get();
|
||||
elapsed_ms = (current_tick - ep->last_poll_tick) * (1000 / RT_TICK_PER_SECOND);
|
||||
ep->last_poll_tick = current_tick;
|
||||
|
||||
current_idle = stats->idle;
|
||||
current_total = stats->user + stats->system + stats->irq + current_idle;
|
||||
|
||||
idle_diff = current_idle - ep->last_idle;
|
||||
total_diff = current_total - ep->last_total;
|
||||
|
||||
ep->last_idle = current_idle;
|
||||
ep->last_total = current_total;
|
||||
|
||||
if (total_diff > 0)
|
||||
{
|
||||
ep->cpu_load = 100 - (idle_diff * 100) / total_diff;
|
||||
}
|
||||
else
|
||||
{
|
||||
ep->cpu_load = 0;
|
||||
}
|
||||
ep->cpu_load = rt_clamp((rt_ubase_t)ep->cpu_load, 0UL, 100UL);
|
||||
|
||||
ep->load_history[ep->load_index++ % RT_ARRAY_SIZE(ep->load_history)] = ep->cpu_load;
|
||||
|
||||
for (int i = 0; i < RT_ARRAY_SIZE(ep->load_history); i++)
|
||||
{
|
||||
avg_load += ep->load_history[i];
|
||||
}
|
||||
avg_load /= RT_ARRAY_SIZE(ep->load_history);
|
||||
|
||||
if (ep->ac_online)
|
||||
{
|
||||
int step;
|
||||
|
||||
if (ep->capacity < 80)
|
||||
{
|
||||
step = CHARGE_STEP_FAST;
|
||||
ep->current_now = 2000000;
|
||||
}
|
||||
else if (ep->capacity < 95)
|
||||
{
|
||||
step = CHARGE_STEP_NORMAL;
|
||||
ep->current_now = 1000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
step = CHARGE_STEP_TRICKLE;
|
||||
ep->current_now = 500000;
|
||||
}
|
||||
|
||||
ep->capacity = rt_min_t(rt_uint32_t,
|
||||
ep->capacity + (step * elapsed_ms) / POLL_INTERVAL_MS, 100);
|
||||
|
||||
ep->voltage = emu_battery_info.voltage_max_design_uv - (100 - ep->capacity) * 30;
|
||||
|
||||
if (ep->capacity >= 100)
|
||||
{
|
||||
ep->status = RT_POWER_SUPPLY_STATUS_FULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ep->status = RT_POWER_SUPPLY_STATUS_CHARGING;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int drain = (avg_load * DISCHARGE_BASE_RATE * elapsed_ms) / 1000;
|
||||
|
||||
ep->capacity = rt_max_t(rt_uint32_t, ep->capacity - drain, 0);
|
||||
ep->current_now = -(500000 + (avg_load * 5000));
|
||||
ep->voltage = emu_battery_info.voltage_min_design_uv + ep->capacity * 1200;
|
||||
|
||||
ep->status = (ep->capacity > 0) ?
|
||||
RT_POWER_SUPPLY_STATUS_DISCHARGING : RT_POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
}
|
||||
|
||||
ep->temp = 25000 + (ep->current_now / 1000) * TEMP_SENSITIVITY;
|
||||
ep->temp = rt_clamp((rt_uint32_t)ep->temp,
|
||||
(rt_uint32_t)emu_battery_info.temp_min, (rt_uint32_t)emu_battery_info.temp_max);
|
||||
|
||||
rt_power_supply_changed(&ep->charger);
|
||||
rt_power_supply_changed(&ep->battery);
|
||||
}
|
||||
|
||||
static int emu_power_init(void)
|
||||
{
|
||||
struct rt_cpu_usage_stats *stats = &rt_cpu_self()->cpu_stat;
|
||||
struct emu_power *ep = &_emu_power;
|
||||
|
||||
rt_memset(ep, 0, sizeof(*ep));
|
||||
|
||||
rt_dm_dev_set_name(&ep->parent, "emu-power");
|
||||
|
||||
ep->battery.dev = &ep->parent,
|
||||
ep->battery.type = RT_POWER_SUPPLY_TYPE_BATTERY,
|
||||
ep->battery.properties_nr = RT_ARRAY_SIZE(emu_battery_properties),
|
||||
ep->battery.properties = emu_battery_properties,
|
||||
ep->battery.battery_info = &emu_battery_info,
|
||||
ep->battery.ops = &emu_battery_ops,
|
||||
|
||||
ep->charger.dev = &ep->parent,
|
||||
ep->charger.type = RT_POWER_SUPPLY_TYPE_USB_SDP,
|
||||
ep->charger.properties_nr = RT_ARRAY_SIZE(emu_charger_properties),
|
||||
ep->charger.properties = emu_charger_properties,
|
||||
ep->charger.ops = &emu_charger_ops,
|
||||
|
||||
ep->status = RT_POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
ep->health = RT_POWER_SUPPLY_HEALTH_GOOD;
|
||||
ep->present = 1;
|
||||
ep->capacity = 100;
|
||||
ep->voltage = 3800000;
|
||||
ep->voltage_max = emu_battery_info.voltage_max_design_uv;
|
||||
ep->current_max = emu_battery_info.constant_charge_current_max_ua;
|
||||
ep->temp = 25000;
|
||||
ep->last_poll_tick = rt_tick_get();
|
||||
ep->last_idle = stats->idle;
|
||||
ep->last_total = stats->user + stats->system + stats->irq + stats->idle;
|
||||
|
||||
rt_power_supply_register(&ep->battery);
|
||||
rt_power_supply_register(&ep->charger);
|
||||
|
||||
rt_timer_init(&ep->poller, ep->parent.parent.name, &emu_power_poll, ep,
|
||||
rt_tick_from_millisecond(POLL_INTERVAL_MS), RT_TIMER_FLAG_PERIODIC);
|
||||
rt_timer_start(&ep->poller);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_DEVICE_EXPORT(emu_power_init);
|
||||
|
||||
static int emu_charger(int argc, char**argv)
|
||||
{
|
||||
rt_base_t level;
|
||||
struct emu_power *ep = &_emu_power;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
goto _help;
|
||||
}
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
if (!rt_strcmp(argv[1], "on"))
|
||||
{
|
||||
ep->status = RT_POWER_SUPPLY_STATUS_CHARGING;
|
||||
ep->ac_online = 1;
|
||||
ep->current_max = emu_battery_info.constant_charge_current_max_ua;
|
||||
}
|
||||
else if (!rt_strcmp(argv[1], "off"))
|
||||
{
|
||||
ep->status = RT_POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
ep->ac_online = 0;
|
||||
ep->current_max = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
goto _help;
|
||||
}
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return 0;
|
||||
|
||||
_help:
|
||||
rt_kprintf("Usage: %s [on|off]\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
MSH_CMD_EXPORT(emu_charger, emu charger switch);
|
||||
346
components/drivers/power/supply/gpio-charger.c
Normal file
346
components/drivers/power/supply/gpio-charger.c
Normal file
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
struct gpio_desc
|
||||
{
|
||||
rt_base_t pin;
|
||||
rt_uint8_t flags;
|
||||
};
|
||||
|
||||
rt_packed(struct gpio_mapping
|
||||
{
|
||||
rt_uint32_t limit_ua;
|
||||
rt_uint32_t gpiodata;
|
||||
});
|
||||
|
||||
struct gpio_charger
|
||||
{
|
||||
struct rt_power_supply parent;
|
||||
|
||||
struct gpio_desc gpiod;
|
||||
struct gpio_desc charge_status;
|
||||
|
||||
rt_ssize_t current_limit_gpios_nr;
|
||||
struct gpio_desc *current_limit_gpios;
|
||||
struct gpio_mapping *current_limit_map;
|
||||
|
||||
rt_uint32_t current_limit_map_size;
|
||||
rt_uint32_t charge_current_limit;
|
||||
|
||||
/* To be fill */
|
||||
enum rt_power_supply_property gpio_charger_properties[3];
|
||||
};
|
||||
|
||||
static rt_err_t set_charge_current_limit(struct gpio_charger *gpioc, int val)
|
||||
{
|
||||
int i;
|
||||
struct gpio_mapping mapping;
|
||||
struct gpio_desc *gpios = gpioc->current_limit_gpios;
|
||||
|
||||
if (!gpioc->current_limit_map_size)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < gpioc->current_limit_map_size; i++)
|
||||
{
|
||||
if (gpioc->current_limit_map[i].limit_ua <= val)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
mapping = gpioc->current_limit_map[i];
|
||||
|
||||
for (i = 0; i < gpioc->current_limit_gpios_nr; i++)
|
||||
{
|
||||
rt_bool_t val = (mapping.gpiodata >> i) & 1;
|
||||
struct gpio_desc *gpio = &gpios[gpioc->current_limit_gpios_nr - i - 1];
|
||||
|
||||
rt_pin_mode(gpio->pin, PIN_MODE_OUTPUT);
|
||||
rt_pin_write(gpio->pin, val ? gpio->flags : !gpio->flags);
|
||||
}
|
||||
|
||||
gpioc->charge_current_limit = mapping.limit_ua;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t gpio_charger_get_property(struct rt_power_supply *psy,
|
||||
enum rt_power_supply_property prop, union rt_power_supply_property_val *val)
|
||||
{
|
||||
struct gpio_charger *gpioc = rt_container_of(psy, struct gpio_charger, parent);
|
||||
|
||||
switch (prop)
|
||||
{
|
||||
case RT_POWER_SUPPLY_PROP_ONLINE:
|
||||
rt_pin_mode(gpioc->gpiod.pin, PIN_MODE_INPUT);
|
||||
val->intval = rt_pin_read(gpioc->gpiod.pin) == gpioc->gpiod.flags;
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_STATUS:
|
||||
rt_pin_mode(gpioc->charge_status.pin, PIN_MODE_INPUT);
|
||||
if (rt_pin_read(gpioc->charge_status.pin) == gpioc->charge_status.flags)
|
||||
{
|
||||
val->intval = RT_POWER_SUPPLY_STATUS_CHARGING;
|
||||
}
|
||||
else
|
||||
{
|
||||
val->intval = RT_POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
|
||||
val->intval = gpioc->charge_current_limit;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t gpio_charger_set_property(struct rt_power_supply *psy,
|
||||
enum rt_power_supply_property prop, const union rt_power_supply_property_val *val)
|
||||
{
|
||||
struct gpio_charger *gpioc = rt_container_of(psy, struct gpio_charger, parent);
|
||||
|
||||
switch (prop)
|
||||
{
|
||||
case RT_POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
|
||||
return set_charge_current_limit(gpioc, val->intval);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_power_supply_ops gpio_charger_ops =
|
||||
{
|
||||
.get_property = gpio_charger_get_property,
|
||||
.set_property = gpio_charger_set_property,
|
||||
};
|
||||
|
||||
static void gpio_charger_isr(void *args)
|
||||
{
|
||||
struct gpio_charger *gpioc = args;
|
||||
|
||||
rt_power_supply_changed(&gpioc->parent);
|
||||
}
|
||||
|
||||
static rt_err_t init_charge_current_limit(struct rt_device *dev,
|
||||
struct gpio_charger *gpioc)
|
||||
{
|
||||
rt_ssize_t len;
|
||||
rt_uint32_t cur_limit = RT_UINT32_MAX;
|
||||
|
||||
gpioc->current_limit_gpios_nr = rt_pin_get_named_pin_count(dev, "charge-current-limit");
|
||||
if (gpioc->current_limit_gpios_nr <= 0)
|
||||
{
|
||||
return gpioc->current_limit_gpios_nr;
|
||||
}
|
||||
|
||||
gpioc->current_limit_gpios = rt_malloc(gpioc->current_limit_gpios_nr *
|
||||
sizeof(*gpioc->current_limit_gpios));
|
||||
if (!gpioc->current_limit_gpios)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
len = rt_dm_dev_prop_count_of_u32(dev, "charge-current-limit-mapping");
|
||||
if (len < 0)
|
||||
{
|
||||
return len;
|
||||
}
|
||||
|
||||
if (len == 0 || len % 2)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
gpioc->current_limit_map_size = len / 2;
|
||||
|
||||
gpioc->current_limit_map = rt_malloc(gpioc->current_limit_map_size *
|
||||
sizeof(*gpioc->current_limit_map));
|
||||
if (!gpioc->current_limit_map)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
len = rt_dm_dev_prop_read_u32_array_index(dev, "charge-current-limit-mapping",
|
||||
0, (int)len, (rt_uint32_t *)(void *)gpioc->current_limit_map);
|
||||
if (len < 0)
|
||||
{
|
||||
return len;
|
||||
}
|
||||
|
||||
for (int i = 0; i < gpioc->current_limit_map_size; ++i)
|
||||
{
|
||||
if (gpioc->current_limit_map[i].limit_ua > cur_limit)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
cur_limit = gpioc->current_limit_map[i].limit_ua;
|
||||
}
|
||||
|
||||
/* Default to smallest current limitation for safety reasons */
|
||||
len = gpioc->current_limit_map_size - 1;
|
||||
set_charge_current_limit(gpioc, gpioc->current_limit_map[len].limit_ua);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t gpio_charger_probe(struct rt_platform_device *pdev)
|
||||
{
|
||||
rt_err_t err;
|
||||
int num_props = 0;
|
||||
const char *chargetype;
|
||||
struct gpio_charger *gpioc;
|
||||
struct rt_device *dev = &pdev->parent;
|
||||
|
||||
gpioc = rt_calloc(1, sizeof(*gpioc));
|
||||
|
||||
if (!gpioc)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
gpioc->gpiod.pin = rt_pin_get_named_pin(dev, RT_NULL, 0, RT_NULL, &gpioc->gpiod.flags);
|
||||
|
||||
if (gpioc->gpiod.pin < 0 && gpioc->gpiod.pin != -RT_EEMPTY)
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
if (gpioc->gpiod.pin >= 0)
|
||||
{
|
||||
gpioc->gpio_charger_properties[num_props] = RT_POWER_SUPPLY_PROP_ONLINE;
|
||||
++num_props;
|
||||
}
|
||||
|
||||
gpioc->charge_status.pin = rt_pin_get_named_pin(dev, "charge-status", 0,
|
||||
RT_NULL, &gpioc->charge_status.flags);
|
||||
|
||||
if (gpioc->charge_status.pin < 0 && gpioc->charge_status.pin != -RT_EEMPTY)
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
if (gpioc->charge_status.pin >= 0)
|
||||
{
|
||||
gpioc->gpio_charger_properties[num_props] = RT_POWER_SUPPLY_PROP_STATUS;
|
||||
++num_props;
|
||||
}
|
||||
|
||||
if ((err = init_charge_current_limit(dev, gpioc)))
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
if (gpioc->current_limit_map)
|
||||
{
|
||||
gpioc->gpio_charger_properties[num_props] = RT_POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
|
||||
++num_props;
|
||||
}
|
||||
|
||||
if (!rt_dm_dev_prop_read_string(dev, "charger-type", &chargetype))
|
||||
{
|
||||
if (!rt_strcmp("unknown", chargetype))
|
||||
{
|
||||
gpioc->parent.type = RT_POWER_SUPPLY_TYPE_UNKNOWN;
|
||||
}
|
||||
else if (!rt_strcmp("battery", chargetype))
|
||||
{
|
||||
gpioc->parent.type = RT_POWER_SUPPLY_TYPE_BATTERY;
|
||||
}
|
||||
else if (!rt_strcmp("ups", chargetype))
|
||||
{
|
||||
gpioc->parent.type = RT_POWER_SUPPLY_TYPE_UPS;
|
||||
}
|
||||
else if (!rt_strcmp("mains", chargetype))
|
||||
{
|
||||
gpioc->parent.type = RT_POWER_SUPPLY_TYPE_MAINS;
|
||||
}
|
||||
else if (!rt_strcmp("usb-sdp", chargetype))
|
||||
{
|
||||
gpioc->parent.type = RT_POWER_SUPPLY_TYPE_USB_SDP;
|
||||
}
|
||||
else if (!rt_strcmp("usb-dcp", chargetype))
|
||||
{
|
||||
gpioc->parent.type = RT_POWER_SUPPLY_TYPE_USB_DCP;
|
||||
}
|
||||
else if (!rt_strcmp("usb-cdp", chargetype))
|
||||
{
|
||||
gpioc->parent.type = RT_POWER_SUPPLY_TYPE_USB_CDP;
|
||||
}
|
||||
else if (!rt_strcmp("usb-aca", chargetype))
|
||||
{
|
||||
gpioc->parent.type = RT_POWER_SUPPLY_TYPE_USB_ACA;
|
||||
}
|
||||
else
|
||||
{
|
||||
gpioc->parent.type = RT_POWER_SUPPLY_TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
gpioc->parent.dev = dev,
|
||||
gpioc->parent.properties_nr = num_props,
|
||||
gpioc->parent.properties = gpioc->gpio_charger_properties,
|
||||
gpioc->parent.ops = &gpio_charger_ops;
|
||||
|
||||
if ((err = rt_power_supply_register(&gpioc->parent)))
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
rt_pin_mode(gpioc->gpiod.pin, PIN_MODE_INPUT);
|
||||
rt_pin_attach_irq(gpioc->gpiod.pin, PIN_IRQ_MODE_RISING, gpio_charger_isr, gpioc);
|
||||
rt_pin_irq_enable(gpioc->gpiod.pin, RT_TRUE);
|
||||
|
||||
rt_pin_mode(gpioc->charge_status.pin, PIN_MODE_INPUT);
|
||||
rt_pin_attach_irq(gpioc->charge_status.pin, PIN_IRQ_MODE_RISING, gpio_charger_isr, gpioc);
|
||||
rt_pin_irq_enable(gpioc->charge_status.pin, RT_TRUE);
|
||||
|
||||
return RT_EOK;
|
||||
_fail:
|
||||
if (gpioc->current_limit_map)
|
||||
{
|
||||
rt_free(gpioc->current_limit_map);
|
||||
}
|
||||
if (gpioc->current_limit_gpios)
|
||||
{
|
||||
rt_free(gpioc->current_limit_gpios);
|
||||
}
|
||||
rt_free(gpioc);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct rt_ofw_node_id gpio_charger_ofw_ids[] =
|
||||
{
|
||||
{ .compatible = "gpio-charger" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct rt_platform_driver gpio_charger_driver =
|
||||
{
|
||||
.name = "gpio-charger",
|
||||
.ids = gpio_charger_ofw_ids,
|
||||
|
||||
.probe = gpio_charger_probe,
|
||||
};
|
||||
RT_PLATFORM_DRIVER_EXPORT(gpio_charger_driver);
|
||||
Reference in New Issue
Block a user