718 lines
20 KiB
C
718 lines
20 KiB
C
/*
|
|
* Copyright (C) 2019 Allwinner.
|
|
* weidonghui <weidonghui@allwinnertech.com>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
#include <sunxi_power/power_manage.h>
|
|
#include <sys_config.h>
|
|
#include <sunxi_board.h>
|
|
#include <spare_head.h>
|
|
#include <sunxi_display2.h>
|
|
#include <console.h>
|
|
|
|
/*
|
|
* Global data (for the gd->bd)
|
|
*/
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
int set_gpio_bias(void)
|
|
{
|
|
char bias_name[32];
|
|
int bias_vol;
|
|
int val;
|
|
int nodeoffset = -1, offset;
|
|
const struct fdt_property *prop;
|
|
const char *pname;
|
|
const int *pdata;
|
|
nodeoffset = fdt_path_offset(working_fdt, FDT_PATH_GPIO_BIAS);
|
|
for (offset = fdt_first_property_offset(working_fdt, nodeoffset);
|
|
offset > 0; offset = fdt_next_property_offset(working_fdt, offset)) {
|
|
prop = fdt_get_property_by_offset(working_fdt, offset, NULL);
|
|
pname = fdt_string(working_fdt, fdt32_to_cpu(prop->nameoff));
|
|
pdata = (const int *)prop->data;
|
|
bias_vol = fdt32_to_cpu(pdata[0]);
|
|
memset(bias_name, 0, sizeof(bias_name));
|
|
strcpy(bias_name, pname);
|
|
if (strstr((const char *)bias_name, "bias") == NULL) {
|
|
continue;
|
|
}
|
|
printf("bias_name:%s\t bias_vol:%d\n", bias_name, bias_vol);
|
|
if (bias_name[1] == 'l') {
|
|
val = readl(SUNXI_R_PIO_BASE + 0x340);
|
|
if (bias_vol <= 1800) {
|
|
val |= (1 << 0);
|
|
} else {
|
|
val &= ~(1 << 0);
|
|
}
|
|
writel(val, SUNXI_R_PIO_BASE + 0x340);
|
|
} else if ((bias_name[1] <= 'j') && (bias_name[1] >= 'a')) {
|
|
val = readl(SUNXI_PIO_BASE + 0x340);
|
|
if (bias_vol <= 1800) {
|
|
val |= (1 << (bias_name[1] - 'a'));
|
|
} else {
|
|
val &= ~(1 << (bias_name[1] - 'a'));
|
|
}
|
|
writel(val, SUNXI_PIO_BASE + 0x340);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int axp_set_power_supply_output(void)
|
|
{
|
|
int onoff, val = 0, ret = 0;
|
|
int power_delay = 0;
|
|
char delay_name[32];
|
|
char power_name[32];
|
|
int power_vol;
|
|
int power_vol_d;
|
|
int nodeoffset = -1, nodeoffset2 = -1, offset;
|
|
int twi_nodeoffset = -1;
|
|
int pmu_nodeoffset = -1;
|
|
const struct fdt_property *prop;
|
|
const char *pname;
|
|
const int *pdata;
|
|
const char *twi_regu_name;
|
|
char pmu_node_str[8] = {0};
|
|
char twi_path[128] = {0};
|
|
int work_mode = get_boot_work_mode();
|
|
|
|
#ifdef CONFIG_SUNXI_TRY_POWER_SPLY
|
|
char axp_name[16] = {0}, chipid;
|
|
char axp_sply_path[64] = {0};
|
|
pmu_get_info(axp_name, (unsigned char *)&chipid);
|
|
sprintf(axp_sply_path, "/soc/%s_power_sply", axp_name);
|
|
nodeoffset = fdt_path_offset(working_fdt, axp_sply_path);
|
|
#endif
|
|
if (nodeoffset < 0) {
|
|
nodeoffset = fdt_path_offset(working_fdt, FDT_PATH_POWER_SPLY);
|
|
}
|
|
|
|
nodeoffset2 = fdt_path_offset(working_fdt, FDT_PATH_GPIO_BIAS);
|
|
if (nodeoffset2 < 0) {
|
|
pr_msg("%s get gpio bias information fail!\n", __func__);
|
|
}
|
|
|
|
char sply_node[32], bias_node[32];
|
|
int reg_base, pin_base;
|
|
int i = 0, ret1, ret2;
|
|
|
|
struct pin_bias_t {
|
|
const char *pin_name;
|
|
char *supply_name;
|
|
int gpio_bias;
|
|
} pin_bias[] = {
|
|
{"pc"},
|
|
{"pl"},
|
|
};
|
|
|
|
/* Get pmu node and its parent twi node*/
|
|
sprintf(pmu_node_str, "pmu0");
|
|
pmu_nodeoffset = fdt_path_offset(working_fdt, pmu_node_str);
|
|
twi_nodeoffset = fdt_parent_offset(working_fdt, pmu_nodeoffset);
|
|
fdt_get_path(working_fdt, twi_nodeoffset, twi_path, sizeof(twi_path));
|
|
|
|
/* Get the regulator for pmu's twi, for changing pinctrl when change voltage*/
|
|
twi_regu_name = fdt_get_regulator_name(twi_nodeoffset, "twi");
|
|
|
|
/* For change GPIO[x] bias when gpio voltage is changed */
|
|
for (i = 0; i < sizeof(pin_bias)/sizeof(pin_bias[0]); i++) {
|
|
sprintf(sply_node, "%s_supply", pin_bias[i].pin_name);
|
|
sprintf(bias_node, "%s_bias", pin_bias[i].pin_name);
|
|
ret1 = fdt_getprop_string(working_fdt, nodeoffset2, sply_node, (char **)(&(pin_bias[i].supply_name)));
|
|
ret2 = script_parser_fetch(FDT_PATH_GPIO_BIAS, bias_node, &(pin_bias[i].gpio_bias), 0);
|
|
pr_msg("gpio_bias, %s: %4d, %s: %-9s\n",
|
|
bias_node, ret2 < 0 ? -1 : pin_bias[i].gpio_bias,
|
|
sply_node, ret1 < 0 ? "not set" : pin_bias[i].supply_name);
|
|
};
|
|
|
|
for (offset = fdt_first_property_offset(working_fdt, nodeoffset);
|
|
offset > 0; offset = fdt_next_property_offset(working_fdt, offset)) {
|
|
prop = fdt_get_property_by_offset(working_fdt, offset, NULL);
|
|
pname = fdt_string(working_fdt, fdt32_to_cpu(prop->nameoff));
|
|
pdata = (const int *)prop->data;
|
|
power_vol = fdt32_to_cpu(pdata[0]);
|
|
memset(power_name, 0, sizeof(power_name));
|
|
strcpy(power_name, pname);
|
|
if (strstr((const char *)power_name, "vol") == NULL) {
|
|
continue;
|
|
}
|
|
|
|
onoff = -1;
|
|
power_vol_d = 0;
|
|
|
|
if (power_vol > 1100000) {
|
|
if (work_mode != WORK_MODE_BOOT) {
|
|
onoff = 0;
|
|
} else {
|
|
onoff = 1;
|
|
}
|
|
power_vol_d = power_vol % 10000;
|
|
} else if (power_vol > 10000) {
|
|
onoff = 1;
|
|
power_vol_d = power_vol % 10000;
|
|
|
|
} else if (power_vol >= 0) {
|
|
onoff = 0;
|
|
power_vol_d = power_vol;
|
|
}
|
|
|
|
debug("%s = %d, onoff=%d\n", power_name, power_vol_d, onoff);
|
|
|
|
if (pmu_set_voltage(power_name, power_vol_d, onoff)) {
|
|
debug("axp set %s to %d failed\n", power_name,
|
|
power_vol_d);
|
|
}
|
|
|
|
/*set delay for each output*/
|
|
sprintf(delay_name, "%s_delay", power_name);
|
|
ret = script_parser_fetch(FDT_PATH_POWER_DELAY, delay_name, &power_delay, 0);
|
|
if (ret < 0)
|
|
power_delay = 0;
|
|
if (power_delay != 0) {
|
|
pr_msg("%s need to wait stable!\n", power_name);
|
|
|
|
/* change twi pinctrl to shorten delay time */
|
|
if (!strncmp(twi_regu_name, power_name, strlen(twi_regu_name))) {
|
|
fdt_set_all_pin(twi_path, "pinctrl-1");
|
|
pr_msg("%s has set pinctrl-1\n", twi_path);
|
|
}
|
|
|
|
mdelay(power_delay / 1000);
|
|
|
|
if (!strncmp(twi_regu_name, power_name, strlen(twi_regu_name))) {
|
|
fdt_set_all_pin(twi_path, "pinctrl-0");
|
|
pr_msg("%s has set pinctrl-0\n", twi_path);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < sizeof(pin_bias)/sizeof(pin_bias[0]); i++) {
|
|
if (!strncmp(pin_bias[i].supply_name, power_name, sizeof(power_name))) {
|
|
if (pin_bias[i].gpio_bias == 0)
|
|
pin_bias[i].gpio_bias = power_vol_d;
|
|
|
|
if (pin_bias[i].pin_name[1] >= 'l') {
|
|
reg_base = SUNXI_R_PIO_BASE;
|
|
pin_base = 'l';
|
|
} else {
|
|
reg_base = SUNXI_PIO_BASE;
|
|
pin_base = 'a';
|
|
}
|
|
|
|
val = readl(reg_base + 0x340);
|
|
if (pin_bias[i].gpio_bias <= 1800)
|
|
val |= (1 << (pin_bias[i].pin_name[1] - pin_base));
|
|
else
|
|
val &= ~(1 << (pin_bias[i].pin_name[1] - pin_base));
|
|
|
|
writel(val, reg_base + 0x340);
|
|
pr_msg("GPIO%c change bias done!\n", pin_bias[i].pin_name[1] - 'a' + 'A');
|
|
}
|
|
}
|
|
|
|
pr_msg("%s = %d, onoff=%d\n", power_name, pmu_get_voltage(power_name), onoff);
|
|
}
|
|
|
|
#ifndef CONFIG_GPIO_BIAS_SKIP
|
|
set_gpio_bias();
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
int axp_set_charge_vol_limit(char *dev)
|
|
{
|
|
int limit_vol = 0;
|
|
if (strstr(dev, "vol") == NULL) {
|
|
debug("Illegal string");
|
|
return -1;
|
|
}
|
|
if (script_parser_fetch(FDT_PATH_CHARGER0, dev, &limit_vol, 1)) {
|
|
return -1;
|
|
}
|
|
pmu_set_bus_vol_limit(limit_vol);
|
|
return 0;
|
|
}
|
|
|
|
int axp_set_current_limit(char *dev)
|
|
{
|
|
int limit_cur = 0;
|
|
if (strstr(dev, "cur") == NULL) {
|
|
debug("Illegal string");
|
|
return -1;
|
|
}
|
|
if (script_parser_fetch(FDT_PATH_CHARGER0, dev, &limit_cur, 1)) {
|
|
return -1;
|
|
}
|
|
if (!strncmp(dev, "pmu_runtime_chgcur", sizeof("pmu_runtime_chgcur")) ||
|
|
!strncmp(dev, "pmu_suspend_chgcur", sizeof("pmu_suspend_chgcur"))) {
|
|
bmu_set_charge_current_limit(limit_cur);
|
|
} else {
|
|
bmu_set_vbus_current_limit(limit_cur);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int axp_get_battery_status(void)
|
|
{
|
|
int dcin_exist, bat_vol;
|
|
int ratio;
|
|
int safe_vol = 0, safe_ratio = 1;
|
|
int ntc_status = -1, ntc_cur = 0;
|
|
dcin_exist = bmu_get_axp_bus_exist();
|
|
bat_vol = bmu_get_battery_vol();
|
|
script_parser_fetch(FDT_PATH_CHARGER0, "pmu_safe_vol", &safe_vol, -1);
|
|
script_parser_fetch(FDT_PATH_CHARGER0, "pmu_safe_ratio", &safe_ratio, 1);
|
|
script_parser_fetch(FDT_PATH_POWER_SPLY, "ntc_status", &ntc_status, 0);
|
|
script_parser_fetch(FDT_PATH_CHARGER0, "ntc_cur", &ntc_cur, 0);
|
|
|
|
ratio = bmu_get_battery_capacity();
|
|
pr_msg("bat_vol=%d, ratio=%d\n", bat_vol, ratio);
|
|
pr_msg("safe_vol=%d, safe_ratio=%d\n", safe_vol, safe_ratio);
|
|
if (ratio < safe_ratio) {
|
|
if (dcin_exist) {
|
|
return BATTERY_RATIO_TOO_LOW_WITH_DCIN;
|
|
}
|
|
return BATTERY_RATIO_TOO_LOW_WITHOUT_DCIN;
|
|
}
|
|
if (bat_vol < safe_vol) {
|
|
return BATTERY_VOL_TOO_LOW;
|
|
}
|
|
pr_msg("ntc_status=%d, ntc_cur=%dmA\n", ntc_status, ntc_cur);
|
|
bmu_set_ntc_onoff(ntc_status, ntc_cur);
|
|
|
|
return BATTERY_RATIO_ENOUGH;
|
|
}
|
|
|
|
int sunxi_bat_low_vol_handle(void)
|
|
{
|
|
int i = 0, safe_vol = 0, safe_ratio = 1, bmp_type = 0;
|
|
int onoff = DISP_LCD_BACKLIGHT_DISABLE;
|
|
__maybe_unused unsigned long arg[3] = {0};
|
|
int bat_vol = bmu_get_battery_vol();
|
|
int dcin_exist = bmu_get_axp_bus_exist();
|
|
int bat_ratio = bmu_get_battery_capacity();
|
|
script_parser_fetch(FDT_PATH_CHARGER0, "pmu_safe_vol", &safe_vol, -1);
|
|
script_parser_fetch(FDT_PATH_CHARGER0, "pmu_safe_ratio", &safe_ratio, 1);
|
|
script_parser_fetch(FDT_PATH_CHARGER0, "bat_bmp_type", &bmp_type, 0);
|
|
|
|
if (bmp_type)
|
|
onoff = DISP_LCD_BACKLIGHT_ENABLE;
|
|
|
|
pr_force("bat_ratio:%d\tsafe_ratio:%d\tbat_vol:%dmV\tsafe_vol:%dmV\n",
|
|
bat_ratio, safe_ratio, bat_vol, safe_vol);
|
|
while (bat_vol < safe_vol || bat_ratio < safe_ratio) {
|
|
bat_vol = bmu_get_battery_vol();
|
|
bat_ratio = bmu_get_battery_capacity();
|
|
dcin_exist = bmu_get_axp_bus_exist();
|
|
if (onoff == DISP_LCD_BACKLIGHT_ENABLE) {
|
|
if (i++ >= 500) {
|
|
i = 0;
|
|
onoff = DISP_LCD_BACKLIGHT_DISABLE;
|
|
pr_notice("onoff:DISP_LCD_BACKLIGHT_DISABLE\n");
|
|
pr_force("bat_ratio:%d\tsafe_ratio:%d\tbat_vol:%dmV\tsafe_vol:%dmV\n",
|
|
bat_ratio, safe_ratio, bat_vol, safe_vol);
|
|
#ifdef CONFIG_DISP2_SUNXI
|
|
disp_ioctl(NULL, onoff, (void *)arg);
|
|
#endif
|
|
}
|
|
} else {
|
|
if (pmu_get_key_irq() > 0) {
|
|
i = 0;
|
|
onoff = DISP_LCD_BACKLIGHT_ENABLE;
|
|
pr_notice("onoff:DISP_LCD_BACKLIGHT_ENABLE\n");
|
|
pr_force("bat_ratio:%d%\tbat_vol:%dmV\tsafe_vol:%dmV\n", bat_ratio, bat_vol, safe_vol);
|
|
#if defined(CONFIG_EINK200_SUNXI) || defined(CONFIG_CMD_SUNXI_BMP)
|
|
sunxi_bmp_display("bat\\bat0.bmp");
|
|
#endif
|
|
#ifdef CONFIG_DISP2_SUNXI
|
|
disp_ioctl(NULL, onoff, (void *)arg);
|
|
#endif
|
|
}
|
|
}
|
|
if (!dcin_exist) {
|
|
onoff = DISP_LCD_BACKLIGHT_ENABLE;
|
|
#if defined(CONFIG_EINK200_SUNXI) || defined(CONFIG_CMD_SUNXI_BMP)
|
|
sunxi_bmp_display("bat\\bat0.bmp");
|
|
#endif
|
|
#ifdef CONFIG_DISP2_SUNXI
|
|
disp_ioctl(NULL, onoff, (void *)arg);
|
|
#endif
|
|
pr_force("bat_ratio:%d%\tbat_vol:%dmV\tsafe_vol:%dmV\n", bat_ratio, bat_vol, safe_vol);
|
|
tick_printf("battery ratio is low without dcin,to be shutdown\n");
|
|
mdelay(3000);
|
|
sunxi_board_shutdown_charge();
|
|
}
|
|
if (ctrlc())
|
|
break;
|
|
mdelay(10);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int sunxi_bat_key_handle(void)
|
|
{
|
|
int dcin_exist = bmu_get_axp_bus_exist();
|
|
__maybe_unused unsigned long arg[3] = {0};
|
|
while (pmu_get_key_irq() <= 0) {
|
|
dcin_exist = bmu_get_axp_bus_exist();
|
|
if (!dcin_exist) {
|
|
tick_printf("dcin is out,to be shutdown\n");
|
|
mdelay(3000);
|
|
sunxi_board_shutdown_charge();
|
|
}
|
|
if (ctrlc())
|
|
break;
|
|
mdelay(10);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int sunxi_bat_temp_handle(void)
|
|
{
|
|
__maybe_unused int ret, temp = 300, i, j;
|
|
int safe_temp[2], para[16];
|
|
char para_name[32];
|
|
int onoff = DISP_LCD_BACKLIGHT_ENABLE;
|
|
__maybe_unused unsigned long arg[3] = {0};
|
|
int dcin_exist = bmu_get_axp_bus_exist();
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
j = i + 1;
|
|
sprintf(para_name, "pmu_bat_temp_para%d", j);
|
|
ret = script_parser_fetch(FDT_PATH_CHARGER0, para_name, ¶[i], -1);
|
|
}
|
|
temp = bmu_get_ntc_temp((int *)para);
|
|
ret = script_parser_fetch(FDT_PATH_CHARGER0, "safe_temp_H", &safe_temp[0], 600);
|
|
ret = script_parser_fetch(FDT_PATH_CHARGER0, "safe_temp_L", &safe_temp[1], 0);
|
|
pr_force("safe_temp_H:%d\tsafe_temp_L:%d\ttemp:%d\n", safe_temp[0], safe_temp[1], temp);
|
|
while (temp < safe_temp[1] || safe_temp[0] < temp) {
|
|
dcin_exist = bmu_get_axp_bus_exist();
|
|
temp = bmu_get_ntc_temp((int *)para);
|
|
if (onoff == DISP_LCD_BACKLIGHT_ENABLE) {
|
|
if (i++ >= 200) {
|
|
i = 0;
|
|
onoff = DISP_LCD_BACKLIGHT_DISABLE;
|
|
pr_notice("onoff:DISP_LCD_BACKLIGHT_DISABLE\n");
|
|
pr_force("safe_temp_H:%d\tsafe_temp_L:%d\ttemp:%d\n", safe_temp[0], safe_temp[1], temp);
|
|
#ifdef CONFIG_DISP2_SUNXI
|
|
disp_ioctl(NULL, onoff, (void *)arg);
|
|
#endif
|
|
}
|
|
} else {
|
|
if (pmu_get_key_irq() > 0) {
|
|
i = 0;
|
|
onoff = DISP_LCD_BACKLIGHT_ENABLE;
|
|
pr_notice("onoff:DISP_LCD_BACKLIGHT_ENABLE\n");
|
|
pr_force("safe_temp_H:%d\tsafe_temp_L:%d\temp:%d\n", safe_temp[0], safe_temp[1], temp);
|
|
#ifdef CONFIG_DISP2_SUNXI
|
|
disp_ioctl(NULL, onoff, (void *)arg);
|
|
#endif
|
|
}
|
|
}
|
|
if (!dcin_exist) {
|
|
onoff = DISP_LCD_BACKLIGHT_ENABLE;
|
|
pr_notice("onoff:DISP_LCD_BACKLIGHT_ENABLE\n");
|
|
pr_force("safe_temp_H:%d\tsafe_temp_L:%d\temp:%d\n", safe_temp[0], safe_temp[1], temp);
|
|
tick_printf("battery without dcin,to be shutdown\n");
|
|
#ifdef CONFIG_DISP2_SUNXI
|
|
disp_ioctl(NULL, onoff, (void *)arg);
|
|
#endif
|
|
mdelay(3000);
|
|
sunxi_board_shutdown_charge();
|
|
}
|
|
|
|
if (ctrlc())
|
|
break;
|
|
mdelay(10);
|
|
}
|
|
#if defined(CONFIG_EINK200_SUNXI) || defined(CONFIG_CMD_SUNXI_BMP)
|
|
sunxi_bmp_display("bat\\bat_blank.bmp");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/* reset bat capacity when system is writing firmware*/
|
|
int axp_reset_capacity(void)
|
|
{
|
|
return bmu_reset_capacity();
|
|
}
|
|
|
|
/* set dcdc pwm mode */
|
|
int axp_set_dcdc_mode(void)
|
|
{
|
|
const struct fdt_property *prop;
|
|
int nodeoffset = -1, offset, mode;
|
|
const char *pname;
|
|
const int *pdata;
|
|
|
|
if (nodeoffset < 0) {
|
|
nodeoffset = fdt_path_offset(working_fdt, FDT_PATH_POWER_SPLY);
|
|
}
|
|
|
|
for (offset = fdt_first_property_offset(working_fdt, nodeoffset);
|
|
offset > 0; offset = fdt_next_property_offset(working_fdt, offset)) {
|
|
prop = fdt_get_property_by_offset(working_fdt, offset, NULL);
|
|
pname = fdt_string(working_fdt, fdt32_to_cpu(prop->nameoff));
|
|
pdata = (const int *)prop->data;
|
|
mode = fdt32_to_cpu(pdata[0]);
|
|
if (strstr(pname, "mode") == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if (pmu_set_dcdc_mode(pname, mode) < 0) {
|
|
debug("set %s fail!\n", pname);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_SUNXI_PMU_EXT
|
|
int pmu_ext_set_dcdc_mode(void)
|
|
{
|
|
const struct fdt_property *prop;
|
|
int nodeoffset = -1, offset, mode;
|
|
const char *pname;
|
|
const int *pdata;
|
|
|
|
if (nodeoffset < 0) {
|
|
nodeoffset = fdt_path_offset(working_fdt, FDT_PATH_POWER_SPLY);
|
|
}
|
|
|
|
for (offset = fdt_first_property_offset(working_fdt, nodeoffset);
|
|
offset > 0; offset = fdt_next_property_offset(working_fdt, offset)) {
|
|
prop = fdt_get_property_by_offset(working_fdt, offset, NULL);
|
|
pname = fdt_string(working_fdt, fdt32_to_cpu(prop->nameoff));
|
|
pdata = (const int *)prop->data;
|
|
mode = fdt32_to_cpu(pdata[0]);
|
|
if (strstr(pname, "mode") == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if (strstr(pname, "ext") == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if (pmu_set_dcdc_mode_ext(pname, mode) < 0) {
|
|
debug("set %s fail!\n", pname);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int axp_battery_status_handle(void)
|
|
{
|
|
int battery_status;
|
|
int ret = 0, bat_exist = 0, ntc_status = -1, bmp_type, charge_mode;
|
|
int temp = 300, safe_temp[2], i, j;
|
|
int para[16];
|
|
char para_name[32];
|
|
|
|
ret = script_parser_fetch(FDT_PATH_POWER_SPLY, "battery_exist", &bat_exist, 1);
|
|
if (ret < 0)
|
|
bat_exist = 1;
|
|
|
|
ret = bmu_get_battery_probe();
|
|
if ((ret < 1) || (!bat_exist)) {
|
|
gd->chargemode = 0;
|
|
return 0;
|
|
}
|
|
|
|
ret = script_parser_fetch(FDT_PATH_POWER_SPLY, "ntc_status", &ntc_status, 0);
|
|
if (ret < 0)
|
|
ntc_status = 0;
|
|
|
|
ret = script_parser_fetch(FDT_PATH_CHARGER0, "bat_bmp_type", &bmp_type, 0);
|
|
if (ret < 0)
|
|
bmp_type = 0;
|
|
|
|
if (ntc_status > 0) {
|
|
for (i = 0; i < 16; i++) {
|
|
j = i + 1;
|
|
sprintf(para_name, "pmu_bat_temp_para%d", j);
|
|
ret = script_parser_fetch(FDT_PATH_CHARGER0, para_name, ¶[i], -1);
|
|
}
|
|
temp = bmu_get_ntc_temp((int *)para);
|
|
ret = script_parser_fetch(FDT_PATH_CHARGER0, "safe_temp_H", &safe_temp[0], 600);
|
|
ret = script_parser_fetch(FDT_PATH_CHARGER0, "safe_temp_L", &safe_temp[1], 0);
|
|
tick_printf("battery temp is %d\n", temp);
|
|
if (temp >= safe_temp[0]) {
|
|
#if defined(CONFIG_EINK200_SUNXI) || defined(CONFIG_CMD_SUNXI_BMP)
|
|
sunxi_bmp_display("bat\\bat_htmp.bmp");
|
|
#endif
|
|
tick_printf("battery temp (%d) is too high", temp);
|
|
if (ntc_status == 1) {
|
|
tick_printf(" , to be shutdown\n");
|
|
mdelay(3000);
|
|
sunxi_board_shutdown();
|
|
} else {
|
|
tick_printf(" , waitting for lower temp\n");
|
|
sunxi_bat_temp_handle();
|
|
}
|
|
} else if (temp <= safe_temp[1]) {
|
|
#if defined(CONFIG_EINK200_SUNXI) || defined(CONFIG_CMD_SUNXI_BMP)
|
|
sunxi_bmp_display("bat\\bat_ltmp.bmp");
|
|
#endif
|
|
tick_printf("battery temp (%d) is too low", temp);
|
|
if (ntc_status == 1) {
|
|
tick_printf(" , to be shutdown\n");
|
|
mdelay(3000);
|
|
sunxi_board_shutdown();
|
|
} else {
|
|
tick_printf(" , waitting for higher temp\n");
|
|
sunxi_bat_temp_handle();
|
|
}
|
|
}
|
|
}
|
|
|
|
ret = script_parser_fetch(FDT_PATH_POWER_SPLY, "charge_mode", &charge_mode, 1);
|
|
if (ret < 0)
|
|
charge_mode = 1;
|
|
|
|
#ifdef CONFIG_AXP_LATE_INFO
|
|
battery_status = axp_get_battery_status();
|
|
#else
|
|
battery_status = gd->pmu_runtime_chgcur;
|
|
#endif
|
|
if (gd->chargemode == 1) {
|
|
if ((battery_status == BATTERY_RATIO_TOO_LOW_WITH_DCIN)
|
|
|| (battery_status == BATTERY_RATIO_TOO_LOW_WITHOUT_DCIN)
|
|
|| (battery_status == BATTERY_VOL_TOO_LOW)) {
|
|
|
|
#if defined(CONFIG_EINK200_SUNXI) || defined(CONFIG_CMD_SUNXI_BMP)
|
|
if (bmp_type)
|
|
sunxi_bmp_display("bat\\bat0.bmp");
|
|
#endif
|
|
#if 0
|
|
tick_printf("battery ratio is low with dcin,to be shutdown\n");
|
|
mdelay(3000);
|
|
sunxi_board_shutdown();
|
|
#else
|
|
sunxi_bat_low_vol_handle();
|
|
#endif
|
|
} else if (charge_mode == 2) {
|
|
tick_printf("press power_on to start up\n");
|
|
sunxi_bat_key_handle();
|
|
} else {
|
|
#if defined(CONFIG_EINK200_SUNXI) || defined(CONFIG_CMD_SUNXI_BMP)
|
|
sunxi_bmp_display("bat\\battery_charge.bmp");
|
|
#endif
|
|
}
|
|
} else if ((battery_status == BATTERY_RATIO_TOO_LOW_WITHOUT_DCIN) || (battery_status == BATTERY_VOL_TOO_LOW)) {
|
|
#if defined(CONFIG_EINK200_SUNXI) || defined(CONFIG_CMD_SUNXI_BMP)
|
|
sunxi_bmp_display("bat\\bat0.bmp");
|
|
#endif
|
|
tick_printf("battery ratio or vol is low ,to be shutdown\n");
|
|
mdelay(3000);
|
|
sunxi_board_shutdown_charge();
|
|
}
|
|
|
|
if (charge_mode == 2 || charge_mode == 0)
|
|
gd->chargemode = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int axp_set_vol(char *name, uint onoff)
|
|
{
|
|
return pmu_set_voltage(name, 0, onoff);
|
|
}
|
|
|
|
|
|
int sunxi_update_axp_info(void)
|
|
{
|
|
int val = -1;
|
|
char bootreason[16] = {0};
|
|
int ret = 0, bat_exist = 0;
|
|
|
|
ret = script_parser_fetch(FDT_PATH_POWER_SPLY, "battery_exist", &bat_exist, 1);
|
|
if (ret < 0)
|
|
bat_exist = 1;
|
|
|
|
#ifdef CONFIG_SUNXI_BMU
|
|
#ifdef CONFIG_AXP_LATE_INFO
|
|
val = bmu_get_poweron_source();
|
|
#else
|
|
val = gd->pmu_saved_status;
|
|
#endif
|
|
#endif
|
|
if ((val == -1) && (pmu_get_sys_mode() == SUNXI_CHARGING_FLAG)) {
|
|
val = AXP_BOOT_SOURCE_CHARGER;
|
|
pmu_set_sys_mode(0);
|
|
}
|
|
switch (val) {
|
|
case AXP_BOOT_SOURCE_BUTTON:
|
|
strncpy(bootreason, "button", sizeof("button"));
|
|
break;
|
|
case AXP_BOOT_SOURCE_IRQ_LOW:
|
|
strncpy(bootreason, "irq", sizeof("irq"));
|
|
break;
|
|
case AXP_BOOT_SOURCE_VBUS_USB:
|
|
strncpy(bootreason, "usb", sizeof("usb"));
|
|
break;
|
|
case AXP_BOOT_SOURCE_CHARGER:
|
|
strncpy(bootreason, "charger", sizeof("charger"));
|
|
if (bat_exist)
|
|
gd->chargemode = 1;
|
|
break;
|
|
case AXP_BOOT_SOURCE_BATTERY:
|
|
strncpy(bootreason, "battery", sizeof("battery"));
|
|
break;
|
|
default:
|
|
strncpy(bootreason, "unknow", sizeof("unknow"));
|
|
break;
|
|
}
|
|
env_set("bootreason", bootreason);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int do_sunxi_axp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
|
{
|
|
u8 reg_addr;
|
|
u8 reg_value;
|
|
if (argc < 4)
|
|
return -1;
|
|
reg_addr = (u8)simple_strtoul(argv[3], NULL, 16);
|
|
if (!strncmp(argv[1], "pmu", 3)) {
|
|
#ifdef CONFIG_SUNXI_PMU
|
|
if (!strncmp(argv[2], "read", 4)) {
|
|
printf("pmu_value:0x%x\n", pmu_get_reg_value(reg_addr));
|
|
} else if (!strncmp(argv[2], "write", 5)) {
|
|
reg_value = (u8)simple_strtoul(argv[4], NULL, 16);
|
|
printf("pmu_value:0x%x\n", pmu_set_reg_value(reg_addr, reg_value));
|
|
} else {
|
|
printf("input error\n");
|
|
return -1;
|
|
}
|
|
#endif
|
|
} else if (!strncmp(argv[1], "bmu", 3)) {
|
|
#ifdef CONFIG_SUNXI_BMU
|
|
if (!strncmp(argv[2], "read", 4)) {
|
|
printf("bmu_value:0x%x\n", bmu_get_reg_value(reg_addr));
|
|
} else if (!strncmp(argv[2], "write", 5)) {
|
|
reg_value = (u8)simple_strtoul(argv[4], NULL, 16);
|
|
printf("bmu_value:0x%x\n", bmu_set_reg_value(reg_addr, reg_value));
|
|
} else {
|
|
printf("input error\n");
|
|
return -1;
|
|
}
|
|
#endif
|
|
} else {
|
|
printf("input error\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
U_BOOT_CMD(sunxi_axp, 6, 1, do_sunxi_axp, "sunxi_axp sub-system",
|
|
"sunxi_axp <pmu/bmu> <read> <reg_addr>\n"
|
|
"sunxi_axp <pmu/bmu> <write> <reg_addr> <reg_value>\n");
|
|
|
|
|