@@ -82,6 +82,8 @@ static unsigned int user_current_limit = -1U;
8282test_export_static timestamp_t shutdown_target_time ;
8383static timestamp_t precharge_start_time ;
8484static struct sustain_soc sustain_soc ;
85+ static struct sustain_soc3 sustain_soc3 [4 ];
86+ int sustain3_slot = 0 ;
8587static struct current_limit {
8688 uint32_t value ; /* Charge limit to apply, in mA */
8789 int soc ; /* Minimum battery SoC at which the limit will be applied. */
@@ -224,6 +226,9 @@ int battery_sustainer_set(int8_t lower, int8_t upper)
224226 sustain_soc .lower = lower ;
225227 sustain_soc .upper = upper ;
226228 CPRINTS ("Sustainer set: %d%% ~ %d%%" , lower , upper );
229+ sustain_soc3 [0 ].lower = lower ;
230+ sustain_soc3 [0 ].upper = upper ;
231+ sustain_soc3 [0 ].discharge = -1 ;
227232 return EC_SUCCESS ;
228233 }
229234
@@ -334,6 +339,14 @@ static void dump_charge_state(void)
334339 ccprintf ("Battery sustainer = %s (%d%% ~ %d%%)\n" ,
335340 battery_sustainer_enabled () ? "on" : "off" , sustain_soc .lower ,
336341 sustain_soc .upper );
342+ ccprintf ("Sustainer slot = %d\n" , sustain3_slot );
343+ for (int n = 0 ; n < 4 ; n ++ ) {
344+ ccprintf ("Sustainer slot[%d] (%d%% ~ %d%% - %d%%)\n" ,
345+ n ,
346+ sustain_soc3 [n ].lower ,
347+ sustain_soc3 [n ].upper ,
348+ sustain_soc3 [n ].discharge );
349+ }
337350#undef DUMP
338351}
339352
@@ -917,11 +930,26 @@ int battery_outside_charging_temperature(void)
917930 return 0 ;
918931}
919932
933+ int sustain3_is_slot_valid (int slot ) {
934+ if (slot < 0 || slot >= 4 ) {
935+ return 0 ;
936+ }
937+ if ((sustain_soc3 [slot ].lower == -1 ) ||
938+ (sustain_soc3 [slot ].upper == -1 )) {
939+ return 0 ;
940+ }
941+ if ((sustain_soc3 [slot ].lower == 0 ) ||
942+ (sustain_soc3 [slot ].upper == 0 )) {
943+ return 0 ;
944+ }
945+ return 1 ;
946+ }
947+
920948static enum ec_charge_control_mode
921949sustain_switch_mode (enum ec_charge_control_mode mode )
922950{
923951 enum ec_charge_control_mode new_mode = mode ;
924- int soc = charge_get_display_charge () / 10 ;
952+ int soc = ( charge_get_display_charge () + 5 ) / 10 ;
925953
926954 /*
927955 * The sustain range is defined by 'lower' and 'upper' where the equal
@@ -946,54 +974,68 @@ sustain_switch_mode(enum ec_charge_control_mode mode)
946974 * makes the sustainer use DISCHARGE instead of IDLE. This is done by
947975 * setting lower != upper in V2, which doesn't support the flag.
948976 */
977+
978+ /*
979+ * Slot 0 is the parameters set by the BIOS
980+ * Slot 1 is the parameters set by the user. e.g. with ectool
981+ * Slot 2 is the battery_extender stage 1
982+ * Slot 3 is the battery_extender stage 2
983+ */
984+ int slot = sustain3_slot ;
985+ if (slot < 0 || slot >= 4 ) {
986+ slot = 0 ;
987+ }
988+ // If the current slot is invalid, switch back to slot 0
989+ // If slot == 0, and slot 1 is valid, switch to slot 1
990+ if (!sustain3_is_slot_valid (slot )) {
991+ slot = 0 ;
992+ }
993+ if (slot == 0 ) {
994+ if (sustain3_is_slot_valid (1 )) {
995+ slot = 1 ;
996+ } else {
997+ slot = 0 ;
998+ }
999+ }
1000+ sustain3_slot = slot ;
1001+ int discharge = sustain_soc3 [slot ].discharge ;
1002+ if (discharge <= sustain_soc3 [slot ].upper ) discharge = 126 ;
1003+ // By default, don't change mode
1004+ new_mode = mode ;
9491005 switch (mode ) {
9501006 case CHARGE_CONTROL_NORMAL :
9511007 /* Currently charging */
952- if (sustain_soc .upper < soc ) {
1008+ if (soc >= discharge ) {
1009+ new_mode = CHARGE_CONTROL_DISCHARGE ;
1010+ } else if (soc >= sustain_soc3 [slot ].upper ) {
9531011 /*
9541012 * We come here only if the soc is already above the
9551013 * upper limit at the time the sustainer started.
9561014 */
957- //new_mode = CHARGE_CONTROL_DISCHARGE;
9581015 new_mode = CHARGE_CONTROL_IDLE ;
959- } else if (sustain_soc .upper == soc ) {
960- /*
961- * We've been charging and finally reached the upper.
962- * Let's switch to IDLE to stay.
963- */
964- //if (sustain_soc.flags & EC_CHARGE_CONTROL_FLAG_NO_IDLE)
965- // new_mode = CHARGE_CONTROL_DISCHARGE;
966- //else
967- new_mode = CHARGE_CONTROL_IDLE ;
9681016 }
9691017 break ;
9701018 case CHARGE_CONTROL_IDLE :
971- /* Discharging naturally */
972- if (soc < sustain_soc .lower )
1019+ if (soc >= discharge ) {
1020+ new_mode = CHARGE_CONTROL_DISCHARGE ;
1021+ if (soc <= sustain_soc3 [slot ].lower )
9731022 /*
9741023 * Presumably, we stayed in the sustain range for a
9751024 * while but finally fell off the range. Let's charge to
9761025 * the upper.
9771026 */
9781027 new_mode = CHARGE_CONTROL_NORMAL ;
979- else if (sustain_soc .upper < soc )
980- /*
981- * This can happen only if sustainer is restarted with
982- * decreased upper limit. Let's discharge to the upper.
983- */
984- //new_mode = CHARGE_CONTROL_DISCHARGE;
985- new_mode = CHARGE_CONTROL_IDLE ;
1028+ }
9861029 break ;
9871030 case CHARGE_CONTROL_DISCHARGE :
9881031 /* Discharging actively. */
989- if (soc <= sustain_soc .upper &&
990- !(sustain_soc .flags & EC_CHARGE_CONTROL_FLAG_NO_IDLE ))
1032+ if (soc <= sustain_soc3 [slot ].upper )
9911033 /*
9921034 * Normal case. We've been discharging and finally
9931035 * reached the upper. Let's switch to IDLE to stay.
9941036 */
9951037 new_mode = CHARGE_CONTROL_IDLE ;
996- else if (soc < sustain_soc .lower )
1038+ else if (soc <= sustain_soc3 [ slot ] .lower )
9971039 /*
9981040 * This can happen only if sustainer is restarted with
9991041 * increase lower limit. Let's charge to the upper (then
@@ -2206,6 +2248,36 @@ charge_command_charge_control(struct host_cmd_handler_args *args)
22062248DECLARE_HOST_COMMAND (EC_CMD_CHARGE_CONTROL , charge_command_charge_control ,
22072249 EC_VER_MASK (2 ) | EC_VER_MASK (3 ));
22082250
2251+
2252+ static enum ec_status
2253+ charge_command_charge_control3 (struct host_cmd_handler_args * args )
2254+ {
2255+ const struct ec_params_charge_control3 * p = args -> params ;
2256+ struct ec_response_charge_control3 * r = args -> response ;
2257+
2258+ if (p -> cmd == EC_CHARGE_CONTROL_CMD_SET ) {
2259+ int slot = p -> slot ;
2260+ sustain_soc3 [slot ].lower = p -> sustain_soc3 .lower ;
2261+ sustain_soc3 [slot ].upper = p -> sustain_soc3 .upper ;
2262+ sustain_soc3 [slot ].discharge = p -> sustain_soc3 .discharge ;
2263+ } else if (p -> cmd == EC_CHARGE_CONTROL_CMD_GET ) {
2264+ for (int n = 0 ; n < 4 ; n ++ ) {
2265+ r -> slot = sustain3_slot ;
2266+ r -> sustain_soc3 [n ].lower = sustain_soc3 [n ].lower ;
2267+ r -> sustain_soc3 [n ].upper = sustain_soc3 [n ].upper ;
2268+ r -> sustain_soc3 [n ].discharge = sustain_soc3 [n ].discharge ;
2269+ }
2270+ args -> response_size = sizeof (* r );
2271+ return EC_RES_SUCCESS ;
2272+ } else {
2273+ return EC_RES_INVALID_PARAM ;
2274+ }
2275+
2276+ return EC_RES_SUCCESS ;
2277+ }
2278+ DECLARE_HOST_COMMAND (EC_CMD_CHARGE_CONTROL3 , charge_command_charge_control3 ,
2279+ EC_VER_MASK (3 ));
2280+
22092281static enum ec_status
22102282charge_command_current_limit (struct host_cmd_handler_args * args )
22112283{
0 commit comments