@@ -91,6 +91,7 @@ static int manual_current; /* Manual current override (-1 = no override) */
9191static unsigned int user_current_limit = -1U ;
9292test_export_static timestamp_t shutdown_target_time ;
9393static timestamp_t precharge_start_time ;
94+ static struct sustain_soc sustain_soc ;
9495
9596/*
9697 * The timestamp when the battery charging current becomes stable.
@@ -1155,6 +1156,8 @@ static void dump_charge_state(void)
11551156 battery_seems_to_be_disconnected );
11561157 ccprintf ("battery_was_removed = %d\n" , battery_was_removed );
11571158 ccprintf ("debug output = %s\n" , debugging ? "on" : "off" );
1159+ ccprintf ("sustain charge = %d%% ~ %d%%\n" ,
1160+ sustain_soc .lower , sustain_soc .upper );
11581161#undef DUMP
11591162}
11601163
@@ -1630,6 +1633,43 @@ static int battery_outside_charging_temperature(void)
16301633}
16311634#endif
16321635
1636+ static void sustain_soc_disable (void )
1637+ {
1638+ sustain_soc .lower = -1 ;
1639+ sustain_soc .upper = -1 ;
1640+ }
1641+
1642+ static int sustain_soc_set (int16_t lower , int16_t upper )
1643+ {
1644+ if (sustain_soc .lower < sustain_soc .upper
1645+ && 0 <= sustain_soc .lower && sustain_soc .upper <= 100 ) {
1646+ sustain_soc .lower = lower ;
1647+ sustain_soc .upper = upper ;
1648+ return EC_SUCCESS ;
1649+ }
1650+
1651+ CPRINTS ("Invalid param: %s(%d, %d)" , __func__ , lower , upper );
1652+ return EC_ERROR_INVAL ;
1653+ }
1654+
1655+ static bool sustain_soc_enabled (void )
1656+ {
1657+ return sustain_soc .lower != -1 && sustain_soc .upper != -1 ;
1658+ }
1659+
1660+ static void sustain_battery_soc (void )
1661+ {
1662+ /* If both of AC and battery aren't present, nothing to do. */
1663+ if (!curr .ac || curr .batt .is_present != BP_YES
1664+ || !sustain_soc_enabled ())
1665+ return ;
1666+
1667+ if (curr .batt .state_of_charge < sustain_soc .lower )
1668+ set_chg_ctrl_mode (CHARGE_CONTROL_NORMAL );
1669+ else if (sustain_soc .upper < curr .batt .state_of_charge )
1670+ set_chg_ctrl_mode (CHARGE_CONTROL_DISCHARGE );
1671+ }
1672+
16331673/*****************************************************************************/
16341674/* Hooks */
16351675void charger_init (void )
@@ -1645,6 +1685,8 @@ void charger_init(void)
16451685 * their tasks. Make them ready first.
16461686 */
16471687 battery_get_params (& curr .batt );
1688+
1689+ sustain_soc_disable ();
16481690}
16491691DECLARE_HOOK (HOOK_INIT , charger_init , HOOK_PRIO_DEFAULT );
16501692
@@ -2061,6 +2103,7 @@ void charger_task(void *u)
20612103 (is_full != prev_full ) ||
20622104 (curr .state != prev_state ) ||
20632105 (curr .batt .display_charge != prev_disp_charge )) {
2106+ sustain_battery_soc ();
20642107 show_charging_progress ();
20652108 prev_charge = curr .batt .state_of_charge ;
20662109 prev_disp_charge = curr .batt .display_charge ;
@@ -2621,6 +2664,22 @@ charge_command_charge_control(struct host_cmd_handler_args *args)
26212664 if (rv != EC_SUCCESS )
26222665 return EC_RES_ERROR ;
26232666
2667+ if (args -> version >= 2 ) {
2668+ /*
2669+ * If charge mode is explicitly set (e.g. DISCHARGE), make sure
2670+ * sustain charge is disabled. To go back to normal mode (and
2671+ * disable sustain charge), set mode=NORMAL, lower=-1, upper=-1.
2672+ */
2673+ if (chg_ctl_mode == CHARGE_CONTROL_NORMAL ) {
2674+ rv = sustain_soc_set (p -> sustain_charge .lower ,
2675+ p -> sustain_charge .upper );
2676+ if (rv )
2677+ return EC_RES_INVALID_PARAM ;
2678+ } else {
2679+ sustain_soc_disable ();
2680+ }
2681+ }
2682+
26242683#ifdef CONFIG_CHARGER_DISCHARGE_ON_AC
26252684#ifdef CONFIG_CHARGER_DISCHARGE_ON_AC_CUSTOM
26262685 rv = board_discharge_on_ac (p -> mode == CHARGE_CONTROL_DISCHARGE );
@@ -2824,6 +2883,7 @@ static int command_chgstate(int argc, char **argv)
28242883{
28252884 int rv ;
28262885 int val ;
2886+ char * e ;
28272887
28282888 if (argc > 1 ) {
28292889 if (!strcasecmp (argv [1 ], "idle" )) {
@@ -2858,6 +2918,20 @@ static int command_chgstate(int argc, char **argv)
28582918 return EC_ERROR_PARAM_COUNT ;
28592919 if (!parse_bool (argv [2 ], & debugging ))
28602920 return EC_ERROR_PARAM2 ;
2921+ } else if (!strcasecmp (argv [1 ], "sustain" )) {
2922+ int lower , upper ;
2923+
2924+ if (argc <= 3 )
2925+ return EC_ERROR_PARAM_COUNT ;
2926+ lower = strtoi (argv [2 ], & e , 0 );
2927+ if (* e )
2928+ return EC_ERROR_PARAM2 ;
2929+ upper = strtoi (argv [3 ], & e , 0 );
2930+ if (* e )
2931+ return EC_ERROR_PARAM3 ;
2932+ rv = sustain_soc_set (lower , upper );
2933+ if (rv )
2934+ return EC_ERROR_INVAL ;
28612935 } else {
28622936 return EC_ERROR_PARAM1 ;
28632937 }
@@ -2867,7 +2941,8 @@ static int command_chgstate(int argc, char **argv)
28672941 return EC_SUCCESS ;
28682942}
28692943DECLARE_CONSOLE_COMMAND (chgstate , command_chgstate ,
2870- "[idle|discharge|debug on|off]" ,
2944+ "[idle|discharge|debug on|off]"
2945+ "\n[sustain lower upper]" ,
28712946 "Get/set charge state machine status" );
28722947
28732948#ifdef CONFIG_EC_EC_COMM_BATTERY_MASTER
0 commit comments