/* * Copyright (C) 2019 Allwinner. * weidonghui * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #include /* * 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 \n" "sunxi_axp \n");