| /* |
| * Copyright (C) 2014 Marvell International Ltd. |
| * Yi Zhang <yizhang@marvell.com> |
| * |
| * SPDX-License-Identifier: GPL-2.0+ |
| */ |
| |
| #include "charge.h" |
| #include <power/power_chrg.h> |
| |
| DECLARE_GLOBAL_DATA_PTR; |
| static u32 boot_uv = UBOOT_CHGBOOT_UV; |
| static u32 extern_power_flag = 0; |
| static u32 skip_poweroff_chg = 0; |
| extern unsigned int pmic_power_status; |
| static struct pmic *g_p_bat; |
| __weak void oled_show_mrvl_logo(u8 choice) {} |
| __weak void oled_show_no_battery(void) {} |
| __weak void oled_show_bat_soc(u8 percent) {} |
| __weak void oled_show_bat_charging(u16 percent) {} |
| __weak void oled_display_off(void) {} |
| __weak void charger_enable_bat_priority(void) {} |
| __weak void lcd_show_bat_soc(int percent) {} |
| __weak void lcd_show_no_battery(void) {} |
| __weak void lcd_show_mrvl_log(void) {} |
| __weak void lcd_panel_on(int on_off) {} |
| |
| static struct pmic *init_charger_fg(u8 pmic_i2c_bus, |
| u8 chg_i2c_bus, u8 fg_i2c_bus) |
| { |
| int ret; |
| static int charger_fg_inited = 0; |
| struct pmic *p_fg, *p_chrg, *p_bat; |
| |
| if (charger_fg_inited) |
| return g_p_bat; |
| |
| ret = power_chrg_init(chg_i2c_bus); |
| if (ret) { |
| printf("init charger fails.\n"); |
| return NULL; |
| } |
| |
| ret = power_fg_init(fg_i2c_bus); |
| if (ret) { |
| printf("init fuelgauge fails.\n"); |
| return NULL; |
| } |
| |
| ret = power_bat_init(pmic_i2c_bus); |
| if (ret) { |
| printf("init charger/fuelgauge parent fails.\n"); |
| return NULL; |
| } |
| |
| p_chrg = pmic_get(MARVELL_PMIC_CHARGE); |
| if (!p_chrg) { |
| printf("%s: access charger fails\n", MARVELL_PMIC_CHARGE); |
| return NULL; |
| } |
| |
| p_fg = pmic_get(MARVELL_PMIC_FG); |
| if (!p_fg) { |
| printf("%s: access fuelgauge fails\n", MARVELL_PMIC_FG); |
| return NULL; |
| } |
| |
| p_bat = pmic_get(MARVELL_PMIC_BATT); |
| if (!p_bat) { |
| printf("%s: access charger/fuelgauge parent fails\n", |
| MARVELL_PMIC_BATT); |
| return NULL; |
| } |
| |
| p_fg->parent = p_bat; |
| p_chrg->parent = p_bat; |
| |
| p_bat->pbat->battery_init(p_bat, p_fg, p_chrg, NULL); |
| |
| g_p_bat = p_bat; |
| charger_fg_inited = 1; |
| return p_bat; |
| } |
| |
| |
| static bool check_charger_fg(struct pmic *p_bat) |
| { |
| int charger_type; |
| struct pmic *p_chrg; |
| |
| if (!p_bat || !p_bat->pbat || !p_bat->pbat->chrg) { |
| printf("charger is NULL\n"); |
| return false; |
| } |
| p_chrg = p_bat->pbat->chrg; |
| |
| charger_type = p_chrg->chrg->chrg_type(p_chrg); |
| printf("charger type: %d\n", charger_type); |
| |
| if (p_bat->pbat->fg->fg->fg_battery_check(p_bat->pbat->fg, p_bat)) { |
| printf("fg check failed\n"); |
| return false; |
| } |
| return true; |
| } |
| |
| static bool is_bat_present(struct pmic *p_bat) |
| { |
| struct pmic *p_chrg; |
| |
| if (!p_bat || !p_bat->pbat || !p_bat->pbat->chrg) { |
| printf("%s: charger is NULL\n", __FUNCTION__); |
| return false; |
| } |
| |
| p_chrg = p_bat->pbat->chrg; |
| |
| if (!p_chrg->chrg->chrg_bat_present(p_chrg)) { |
| printf("No bat found\n"); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static int do_charging(struct pmic *p_bat, u32 target_uv, u32 boot_min_uv) |
| { |
| int ret; |
| |
| if (!p_bat || !p_bat->pbat) |
| return CHG_STAT_NOT_READY; |
| |
| if (p_bat->pbat->battery_charge) { |
| while (p_bat->pbat->bat->voltage_uV <= target_uv) { |
| ret = p_bat->pbat->battery_charge(p_bat); |
| |
| if (ret == CHG_STAT_ONKEY_BOOT) { |
| #ifdef CONFIG_PWROFFCHG_IN_UBOOT |
| if (p_bat->pbat->bat->voltage_uV > UBOOT_CHGBOOT_UV) { |
| return CHG_STAT_ONKEY_BOOT; |
| } else { |
| /* onkey detected but battery is low */ |
| printf("vbat too low: %d uV, does not boot up", |
| p_bat->pbat->bat->voltage_uV); |
| } |
| #endif |
| } else if (ret == CHG_STAT_BAT_LOST || |
| ret == CHG_STAT_CHGR_LOST) { |
| /* return error stat and power off */ |
| return ret; |
| } |
| |
| /* |
| * other state is normal then we charge until target_uv is met |
| * if it's poweroff charge now, we continue charge untill |
| * charge remove to poweroff or onkey event to bootup |
| */ |
| } |
| } |
| |
| return CHG_STAT_NORMAL; |
| } |
| |
| /* |
| * [0, 0] --> no charge, only show uboot charging logo and set cmdline, |
| * for debug |
| * [0, lo_uv] --> charge only |
| * [lo_uv, hi_uv] --> charge and show uboot charging logo |
| * [hi_uv, )]--> not charge in uboot, set cmdline and boot |
| * |
| * function returns with following cases: |
| * a. charger removed and still doesn't charge to boot_min_uv |
| * b. battery removed and still doesn't charge to boot_min_uv |
| * c. battery charge to boot_min_uv and normal return |
| * d. long onkey detected but desn't meet boot_min_uv will not return |
| * e. battery full but do not detect onkey/charger remove/battery event won't return |
| */ |
| |
| static int loop_charge(struct pmic *p_bat, |
| int lo_uv, u32 hi_uv, u32 boot_min_uv) |
| { |
| int ret = CHG_STAT_NORMAL; |
| |
| if (!p_bat || !p_bat->pbat) { |
| printf("%s: battery information is NULL!\n", __func__); |
| return CHG_STAT_NOT_READY; |
| } |
| |
| if (lo_uv > hi_uv) |
| lo_uv = hi_uv; |
| |
| /* for sequence test */ |
| if ((lo_uv == 0) && (hi_uv == 0)) { |
| /* TODO: show logo here */ |
| return CHG_STAT_NORMAL; |
| } |
| |
| /* clear bat data stored in pmic rtc domain */ |
| pmic_clear_bat_strdata(); |
| |
| printf("\n%s begins...\n\n", __func__); |
| |
| /* show initial soc */ |
| /* oled_show_bat_soc(p_bat->pbat->bat->state_of_chrg); */ |
| |
| if (p_bat->pbat->bat->voltage_uV <= lo_uv) { |
| printf("charging phase #1\n"); |
| ret = do_charging(p_bat, lo_uv, boot_min_uv); |
| if (ret != CHG_STAT_NORMAL) |
| goto out; |
| } |
| |
| if (p_bat->pbat->bat->voltage_uV <= hi_uv) { |
| printf("charging phase #2\n"); |
| ret = do_charging(p_bat, hi_uv, boot_min_uv); |
| if (ret != CHG_STAT_NORMAL) |
| goto out; |
| } |
| |
| out: |
| printf("\n%s finishes..., ret: %d\n\n", __func__, ret); |
| return ret; |
| } |
| |
| static bool add_charger_cmdline(void) |
| { |
| char *cmdline = malloc(COMMAND_LINE_SIZE); |
| if (!cmdline) { |
| printf("%s: alloc for cmdline fails.\n", __func__); |
| return false; |
| } |
| /* |
| * we need to access before the env is relocated, |
| * gd->env_buf is too small, don't use getenv(); |
| */ |
| if (gd->flags & GD_FLG_ENV_READY) { |
| strncpy(cmdline, getenv("bootargs"), COMMAND_LINE_SIZE); |
| printf("%s: getenv()\n", __func__); |
| } else { |
| getenv_f("bootargs", cmdline, COMMAND_LINE_SIZE); |
| printf("%s: getenv_f()\n", __func__); |
| } |
| debug("%s: bootargs = %s\n", __func__, getenv("bootargs")); |
| sprintf(cmdline + strlen(cmdline), " asrbatp"); |
| if (setenv("bootargs", cmdline)) { |
| printf("%s: set bootargs fails\n", __func__); |
| free(cmdline); |
| return false; |
| } |
| debug("%s: bootargs = %s\n", __func__, getenv("bootargs")); |
| |
| free(cmdline); |
| return true; |
| } |
| |
| static char *bootup_reason[] = { |
| "power off", |
| "onkey", |
| "usb charge", |
| "rtc alarm", |
| "fault wakeup", |
| "bat wakeup", |
| "reboot", |
| }; |
| |
| static void enable_pm80x_fg_cmdline(void) |
| { |
| char *cmdline; |
| |
| cmdline = malloc(COMMAND_LINE_SIZE); |
| strncpy(cmdline, getenv("bootargs"), COMMAND_LINE_SIZE); |
| sprintf(cmdline + strlen(cmdline), " force_pm80x_fg"); |
| setenv("bootargs", cmdline); |
| free(cmdline); |
| } |
| |
| #ifndef CONFIG_POWER_88PM830 |
| int detect_mrvl_charger(unsigned char bus) |
| { |
| static const char name[] = "mrvl_charger"; |
| struct pmic *p = pmic_alloc(); |
| |
| if (!p) { |
| printf("%s: POWER allocation error!\n", __func__); |
| return -ENOMEM; |
| } |
| p->name = name; |
| p->interface = PMIC_I2C; |
| p->number_of_regs = 0x40; |
| p->hw.i2c.addr = 0x68; |
| p->hw.i2c.tx_num = 1; |
| p->bus = bus; |
| |
| p->chrg = NULL; |
| |
| if (pmic_probe(p)) { |
| printf("%s: no mrvl charger!\n", __func__); |
| return -ENODEV; |
| } |
| return 0; |
| } |
| #endif |
| |
| /* |
| * this function name is from lagacy design, although we call it poweroff charge, |
| * some other check routine is also done in this function. we don't need to do |
| * any check in *_dkb.c otherwise we just call this function in *_dkb.c which |
| * makes it easy to maintain the code |
| */ |
| void power_off_charge(u32 *emmd_pmic, u8 pmic_i2c, |
| u8 chg_i2c, u8 fg_i2c, u32 lo_uv, u32 hi_uv) |
| { |
| int ret; |
| struct pmic *p_bat; |
| struct pmic_chip_desc *board_pmic_chip; |
| bool chg_fg_status, cmd_status, bat_present = false; |
| enum sys_boot_up_reason reason; |
| bool force_chg = !!((lo_uv == 0) && (hi_uv == 0)); |
| |
| if (skip_poweroff_chg) |
| return; |
| |
| /* set bootargs force_pm80x_fg to choose pm80x_fg */ |
| #ifndef CONFIG_POWER_88PM830 |
| if (detect_mrvl_charger(chg_i2c)) |
| enable_pm80x_fg_cmdline(); |
| #endif |
| debug("lo_uv = %d, hi_uv = %d, force_chg = %d\n", |
| lo_uv, hi_uv, force_chg); |
| |
| board_pmic_chip = get_marvell_pmic(); |
| if (!board_pmic_chip) { |
| printf("--- %s: chip is NULL.\n", __func__); |
| goto out_bootup_nopmic; |
| } |
| |
| reason = get_boot_up_reason(emmd_pmic); |
| if (reason < SYS_BR_MAX && reason >= 0) |
| printf("bootup reason: %s\n", bootup_reason[reason]); |
| |
| p_bat = init_charger_fg(pmic_i2c, chg_i2c, fg_i2c); |
| if (!p_bat) { |
| printf("charger&bat probe fails!\n"); |
| if (!force_chg) |
| goto out_bootup_no_charger; |
| } |
| |
| /* we check if the battery is online again */ |
| bat_present = is_bat_present(p_bat); |
| if (!bat_present) { |
| if (!force_chg) { |
| if (extern_power_flag == 1) |
| goto out_bootup_extern_supply; |
| else |
| goto out_bootup_nobat_noextern; |
| } |
| } |
| |
| /* get battery initial status */ |
| /* p_bat->fg->fg_battery_update(p_bat->pbat->fg, p_bat); */ |
| if ((reason == SYS_BR_CHARGE) || force_chg) { |
| /* check TA type and fuel gauge chip */ |
| chg_fg_status = check_charger_fg(p_bat); |
| if (!chg_fg_status) { |
| printf("charger/fuelgauge status is not right!\n"); |
| if (!force_chg) |
| goto out_bootup_ta_fg_error; |
| } |
| |
| /* TODO: disable backlight and cp-D2*/ |
| /* setop(0); */ |
| |
| //printf("run cp_d2 to put cp/msa into LPM\n"); |
| //run_command("cp_d2", 0); |
| |
| /* charge until the system can boot up */ |
| ret = loop_charge(p_bat, lo_uv, hi_uv, boot_uv); |
| if (ret == CHG_STAT_CHGR_LOST || ret == CHG_STAT_BAT_LOST) { |
| printf("chgr or bat is removed, power down!\n"); |
| goto charger_bat_lost_pd; |
| } |
| |
| /* if charger is removed, shut down the device */ |
| if (!p_bat->chrg->chrg_type(p_bat->pbat->chrg)) { |
| printf("charger is removed, power down!\n"); |
| goto charger_bat_lost_pd; |
| } |
| |
| /* long onekey detected in power off loop */ |
| goto out_bootup_lonkey_from_pchg; |
| } else if (reason == SYS_BR_ONKEY) { |
| /* this is very rare to happen, wakeup by onkey with charger */ |
| if (p_bat->chrg->chrg_type(p_bat->pbat->chrg)) { |
| /* |
| * onkey boot with charger, this case is very rare |
| * battery need charge to UBOOT_CHGBOOT_UV |
| */ |
| if (p_bat->pbat->bat->voltage_uV <= UBOOT_CHGBOOT_UV) { |
| /* detect if charger is online again */ |
| if (p_bat->chrg->chrg_type(p_bat->pbat->chrg)) { |
| /* charge until the system can boot up */ |
| ret = loop_charge(p_bat, lo_uv, UBOOT_CHGBOOT_UV, boot_uv); |
| if (ret == CHG_STAT_CHGR_LOST || ret == CHG_STAT_BAT_LOST) { |
| printf("chgr or bat is removed, power down!\n"); |
| goto charger_bat_lost_pd; |
| } |
| |
| /* |
| * charged to UBOOT_CHGBOOT_UV and returns now |
| * if charger is removed, shut down the device |
| */ |
| if (!p_bat->chrg->chrg_type(p_bat->pbat->chrg)) { |
| printf("charger is removed, power down!\n"); |
| goto charger_bat_lost_pd; |
| } |
| |
| /* onkey and chg to normal voltage */ |
| goto out_bootup_lonkey_chgrdy; |
| } else { |
| /* display batter low and power down */ |
| printf("battery need charge but without charger" |
| ", power down\n"); |
| goto bat_low_pd; |
| } |
| } else |
| goto out_bootup_lonkey_nochg; |
| } else |
| goto out_bootup_lonkey_nochg; |
| } else if (reason == SYS_BR_RTC_ALARM) { |
| /* RTC ALARM wakeup */ |
| goto out_bootup_rtc; |
| } else if (reason == SYS_BR_FAULT_WAKEUP) { |
| /* fault wakeup: such as kernel panic or pmic reset */ |
| goto out_bootup_fault_wakeup; |
| } else { |
| /* |
| * kernel reboot |
| */ |
| printf("%s: do nothing for charge.\n", __func__); |
| |
| /* check if bat is still there again */ |
| chg_fg_status = check_charger_fg(p_bat); |
| if (!chg_fg_status) { |
| printf("ta&fg detection failed!\n"); |
| goto out_bootup_ta_fg_error; |
| } |
| |
| /* |
| * here we choose 3.45V as power down voltage |
| */ |
| if (p_bat->chrg->chrg_type(p_bat->pbat->chrg)) { |
| /* battery need charge to UBOOT_CHGBOOT_UV |
| * reboot with low voltage, this is very rare to happen |
| * ususally system already powers down at this point |
| */ |
| if (p_bat->pbat->bat->voltage_uV <= UBOOT_CHGBOOT_UV) { |
| /* charger is connected */ |
| if (p_bat->chrg->chrg_type(p_bat->pbat->chrg)) { |
| /* charge until the system can boot up */ |
| ret = loop_charge(p_bat, lo_uv, UBOOT_CHGBOOT_UV, boot_uv); |
| if (ret == CHG_STAT_CHGR_LOST || ret == CHG_STAT_BAT_LOST) { |
| printf("chgr or bat is removed, power down!\n"); |
| goto charger_bat_lost_pd; |
| } |
| |
| /* if charger is removed, shut down the device */ |
| if (!p_bat->chrg->chrg_type(p_bat->pbat->chrg)) { |
| printf("charger is removed, power down!\n"); |
| goto charger_bat_lost_pd; |
| } |
| goto out_bootup_reboot_chg_rdy; |
| } else { |
| /* display batter low and power down */ |
| printf("battery need charge but without charger" |
| ", power down\n"); |
| goto bat_low_pd; |
| } |
| } else { |
| /* reboot with charger connected */ |
| goto out_bootup_reboot_with_ta_vrdy; |
| } |
| } else |
| goto out_bootup_reboot_no_ta; |
| } |
| |
| /* boot up and display logo in below cases */ |
| out_bootup_reboot_with_ta_vrdy: |
| out_bootup_reboot_no_ta: |
| out_bootup_reboot_chg_rdy: |
| out_bootup_rtc: |
| out_bootup_lonkey_chgrdy: |
| out_bootup_lonkey_nochg: |
| out_bootup_lonkey_from_pchg: |
| out_bootup_cmdline_error: |
| out_bootup_ta_fg_error: |
| out_bootup_no_charger: |
| out_bootup_nopmic: |
| out_bootup_fault_wakeup: |
| /* |
| * voltage is ok so we can switch to battery priority mode |
| */ |
| charger_enable_bat_priority(); |
| oled_show_mrvl_logo(0); |
| lcd_show_mrvl_log(); |
| #ifdef CONFIG_FG_PM803 |
| if (bat_present && pmic_is_pm803()) { |
| cmd_status = add_charger_cmdline(); |
| if (!cmd_status) |
| printf("add charger cmdline failes"); |
| } |
| #endif |
| return; |
| |
| /* show bat low and power down */ |
| bat_low_pd: |
| oled_show_bat_soc(0); |
| lcd_show_bat_soc(0); |
| mdelay(500); |
| |
| /* charger removed in power off chg loop, turn off display and power down */ |
| charger_bat_lost_pd: |
| oled_display_off(); |
| lcd_panel_on(0); |
| pmic_enter_powerdown(board_pmic_chip); |
| |
| /* no battery case(dkb) and external power supply case */ |
| out_bootup_extern_supply: |
| charger_enable_bat_priority(); |
| |
| out_bootup_nobat_noextern: |
| oled_show_no_battery(); |
| lcd_show_no_battery(); |
| return; |
| } |
| |
| |
| /* |
| * this function is called at very early stage where lcd/led is not inited yet, |
| * we just check whether we should power down or can go further, in the next step |
| * we will check what we should do in power off charge function |
| */ |
| void check_sys_boot_or_pd(u32 *emmd_pmic, u8 pmic_i2c, u8 chg_i2c, u8 fg_i2c) |
| { |
| int i; |
| bool cmd_status; |
| struct pmic *p_bat; |
| struct pmic_chip_desc *board_pmic_chip; |
| enum sys_boot_up_reason reason; |
| |
| board_pmic_chip = get_marvell_pmic(); |
| if (!board_pmic_chip) { |
| printf("--- %s: chip is NULL.\n", __func__); |
| goto out_boot_further; |
| } |
| |
| reason = get_boot_up_reason(emmd_pmic); |
| |
| printf("boot up reason = %d\n", reason); |
| p_bat = init_charger_fg(pmic_i2c, chg_i2c, fg_i2c); |
| if (!p_bat) { |
| printf("battery initializtion fails!\n"); |
| goto out_boot_further; |
| } |
| |
| /* get battery initial status |
| * don't update bat soc for restart case |
| */ |
| if (SYS_BR_REBOOT != reason) { |
| p_bat->fg->fg_battery_update(p_bat->pbat->fg, p_bat, 0); |
| printf("vbat: %d uv\n", p_bat->pbat->bat->voltage_uV); |
| } else { |
| skip_poweroff_chg = 1; |
| goto out_boot_further; |
| } |
| |
| /* if charger is not connected with */ |
| if (!is_bat_present(p_bat)) { |
| /* |
| * bat is not present while the charger ic is alive, |
| * this is probably powered by external power supply |
| */ |
| if (p_bat->pbat->bat->voltage_uV > (3100 * 1000)) { |
| extern_power_flag = 1; |
| printf("!!!external power supply case\n"); |
| } else { |
| extern_power_flag = 0; |
| printf("no external power supply\n"); |
| } |
| |
| goto out_boot_further; |
| } |
| |
| if (reason == SYS_BR_ONKEY) { |
| /* |
| * onkey boot without charger |
| */ |
| if (!p_bat->chrg->chrg_type(p_bat->pbat->chrg)) { |
| /* battery is too low and even don't turn on disp */ |
| if (p_bat->pbat->bat->voltage_uV < BAT_LOW_UV) { |
| printf("batt volt is low (%dmV) and charger is not present, power down\n", |
| p_bat->pbat->bat->voltage_uV / 1000); |
| pmic_enter_powerdown(board_pmic_chip); |
| } else { |
| /* Battery is enough to boot */ |
| i = 10; |
| while (i > 0) { |
| i--; |
| udelay(ONKEY_BOOT_CHECK_USEC/10); |
| if (!marvell88pm_get_onkey()) |
| goto onkey_boot_pd; |
| } |
| printf("%s: long onkey deteced, boot...\n", __func__); |
| goto out_boot_further; |
| } |
| } |
| } else if (reason == SYS_BR_BAT_WAKEUP || reason == SYS_BR_POWER_OFF) { |
| printf("Power down on bat wakeup\n"); |
| pmic_enter_powerdown(board_pmic_chip); |
| } else if (reason == SYS_BR_RTC_ALARM) { |
| /* RTC ALARM wakeup */ |
| goto out_boot_further; |
| } else if (reason == SYS_BR_FAULT_WAKEUP) { |
| /* fault wakeup: such as kernel panic or pmic reset */ |
| goto out_boot_further; |
| } else { |
| /* |
| * here we choose 3.45V as power down voltage |
| */ |
| if (!p_bat->chrg->chrg_type(p_bat->pbat->chrg)) { |
| /* no charger and battery is too low */ |
| if (p_bat->pbat->bat->voltage_uV < BAT_LOW_UV) { |
| printf("batt volt is low (%dmV) and charger is not present, power down\n", |
| p_bat->pbat->bat->voltage_uV / 1000); |
| pmic_enter_powerdown(board_pmic_chip); |
| } else |
| goto out_boot_further; |
| } |
| } |
| |
| out_boot_further: |
| #ifdef CONFIG_FG_PM803 |
| if (skip_poweroff_chg && pmic_is_pm803() && is_bat_present(p_bat)) { |
| cmd_status = add_charger_cmdline(); |
| if (!cmd_status) |
| printf("add charger cmdline failes"); |
| } |
| #endif |
| return; |
| |
| onkey_boot_pd: |
| printf("onkey boot: long onkey not detected\n"); |
| printf("power off now ...\n"); |
| pmic_enter_powerdown(board_pmic_chip); |
| } |
| |
| int do_poff_chg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
| { |
| u8 pmic_i2c, chg_i2c, fg_i2c; |
| u32 *emmd_pmic; |
| u32 lo_uv, hi_uv; |
| |
| if (argc != 7) |
| return -1; |
| |
| emmd_pmic = (void *)simple_strtoul(argv[1], NULL, 16); |
| pmic_i2c = simple_strtoul(argv[2], NULL, 16); |
| chg_i2c = simple_strtoul(argv[3], NULL, 16); |
| fg_i2c = simple_strtoul(argv[4], NULL, 16); |
| lo_uv = simple_strtoul(argv[5], NULL, 10); |
| hi_uv = simple_strtoul(argv[6], NULL, 10); |
| |
| debug("emmd_pmic = 0x%x\n", *emmd_pmic); |
| power_off_charge((u32 *)&pmic_power_status, pmic_i2c, chg_i2c, fg_i2c, |
| lo_uv, hi_uv); |
| |
| return 0; |
| } |
| |
| static char help_text[] = |
| "Usage:\n" |
| "pwroffchg emmd_pmic_addr pmic_i2c_number chg_i2c_number fg_i2c_number" |
| " low_volt high_volt\n" |
| "if you choose low_volt and high_volt as 0, it enters into test mode:\n" |
| "only show uboot charging logo and set cmmdline\n" |
| "for example:\n" |
| "pwroffchg 0x8140040 2 2 2 0 0" |
| ""; |
| |
| U_BOOT_CMD( |
| pwroffchg, 7, 1, do_poff_chg, |
| "Test power off charging", help_text |
| ); |