@@ -39,8 +39,13 @@ struct macsmc_power {
3939 char model_name [MAX_STRING_LENGTH ];
4040 char serial_number [MAX_STRING_LENGTH ];
4141 char mfg_date [MAX_STRING_LENGTH ];
42+
4243 bool has_chwa ;
4344 bool has_chls ;
45+ bool has_ch0i ;
46+ bool has_ch0c ;
47+ bool has_chte ;
48+
4449 u8 num_cells ;
4550 int nominal_voltage_mv ;
4651
@@ -57,8 +62,8 @@ struct macsmc_power {
5762static int macsmc_log_power_set (const char * val , const struct kernel_param * kp );
5863
5964static const struct kernel_param_ops macsmc_log_power_ops = {
60- .set = macsmc_log_power_set ,
61- .get = param_get_bool ,
65+ .set = macsmc_log_power_set ,
66+ .get = param_get_bool ,
6267};
6368
6469static bool log_power = false;
@@ -242,6 +247,7 @@ static int macsmc_battery_get_status(struct macsmc_power *power)
242247 */
243248 if (power -> has_chls ) {
244249 u16 vu16 ;
250+
245251 ret = apple_smc_read_u16 (power -> smc , SMC_KEY (CHLS ), & vu16 );
246252 if (ret == sizeof (vu16 ) && (vu16 & 0xff ) >= CHLS_MIN_END_THRESHOLD )
247253 charge_limit = (vu16 & 0xff ) - CHWA_CHLS_FIXED_START_OFFSET ;
@@ -253,6 +259,7 @@ static int macsmc_battery_get_status(struct macsmc_power *power)
253259
254260 if (charge_limit > 0 ) {
255261 u8 buic = 0 ;
262+
256263 if (apple_smc_read_u8 (power -> smc , SMC_KEY (BUIC ), & buic ) >= 0 &&
257264 buic >= charge_limit )
258265 limited = true;
@@ -291,55 +298,112 @@ static int macsmc_battery_get_status(struct macsmc_power *power)
291298static int macsmc_battery_get_charge_behaviour (struct macsmc_power * power )
292299{
293300 int ret ;
294- u8 val ;
301+ u8 val8 ;
302+ u8 chte_buf [4 ];
303+
304+ if (power -> has_ch0i ) {
305+ /* CH0I returns a bitmask like the low byte of CH0R */
306+ ret = apple_smc_read_u8 (power -> smc , SMC_KEY (CH0I ), & val8 );
307+ if (ret )
308+ return ret ;
309+ if (val8 & CH0R_NOAC_CH0I )
310+ return POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE ;
311+ }
295312
296- /* CH0I returns a bitmask like the low byte of CH0R */
297- ret = apple_smc_read_u8 (power -> smc , SMC_KEY (CH0I ), & val );
298- if (ret )
299- return ret ;
300- if (val & CH0R_NOAC_CH0I )
301- return POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE ;
313+ /* Prefer CHTE available in newer firmwares */
314+ if (power -> has_chte ) {
315+ ret = apple_smc_read (power -> smc , SMC_KEY (CHTE ), chte_buf , 4 );
316+ if (ret < 0 )
317+ return ret ;
318+
319+ if (chte_buf [0 ] == 0x01 )
320+ return POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE ;
321+
322+ } else if (power -> has_ch0c ) {
323+ /* CH0C returns a bitmask containing CH0B/CH0C flags */
324+ ret = apple_smc_read_u8 (power -> smc , SMC_KEY (CH0C ), & val8 );
325+ if (ret )
326+ return ret ;
327+ if (val8 & CH0X_CH0C )
328+ return POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE ;
329+ }
302330
303- /* CH0C returns a bitmask containing CH0B/CH0C flags */
304- ret = apple_smc_read_u8 (power -> smc , SMC_KEY (CH0C ), & val );
305- if (ret )
306- return ret ;
307- if (val & CH0X_CH0C )
308- return POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE ;
309- else
310- return POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO ;
331+ return POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO ;
311332}
312333
313334static int macsmc_battery_set_charge_behaviour (struct macsmc_power * power , int val )
314335{
315- u8 ch0i , ch0c ;
316336 int ret ;
317337
318338 /*
319- * CH0I/CH0C are "hard" controls that will allow the battery to run down to 0.
320- * CH0K/CH0B are "soft" controls that are reset to 0 when SOC drops below 50%;
321- * we don't expose these yet.
339+ * apple_smc_write_u32 does weird things with endianess,
340+ * so we write raw bytes to ensure correctness of CHTE
322341 */
342+ u8 chte_inhibit [4 ] = {0x01 , 0x00 , 0x00 , 0x00 };
343+ u8 chte_auto [4 ] = {0x00 , 0x00 , 0x00 , 0x00 };
323344
324345 switch (val ) {
325346 case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO :
326- ch0i = ch0c = 0 ;
347+ /*
348+ * CH0I/CH0C/CHTE are "hard" controls that will allow the battery to run down to 0.
349+ * CH0K/CH0B are "soft" controls that are reset to 0 when SOC drops below 50%;
350+ * we don't expose these yet.
351+ */
352+ if (power -> has_ch0i ) {
353+ ret = apple_smc_write_u8 (power -> smc , SMC_KEY (CH0I ), 0 );
354+ if (ret )
355+ return ret ;
356+ }
357+
358+ if (power -> has_chte ) {
359+ ret = apple_smc_write (power -> smc , SMC_KEY (CHTE ), chte_auto , 4 );
360+ if (ret )
361+ return ret ;
362+ } else if (power -> has_ch0c ) {
363+ ret = apple_smc_write_u8 (power -> smc , SMC_KEY (CH0C ), 0 );
364+ if (ret )
365+ return ret ;
366+ }
327367 break ;
368+
328369 case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE :
329- ch0i = 0 ;
330- ch0c = 1 ;
370+ if (power -> has_ch0i ) {
371+ ret = apple_smc_write_u8 (power -> smc , SMC_KEY (CH0I ), 0 );
372+ if (ret )
373+ return ret ;
374+ }
375+
376+ /* Prefer CHTE available in newer firmwares */
377+ if (power -> has_chte )
378+ return apple_smc_write (power -> smc , SMC_KEY (CHTE ), chte_inhibit , 4 );
379+ else if (power -> has_ch0c )
380+ return apple_smc_write_u8 (power -> smc , SMC_KEY (CH0C ), 1 );
381+ else
382+ return - EINVAL ;
331383 break ;
384+
332385 case POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE :
333- ch0i = 1 ;
334- ch0c = 0 ;
335- break ;
386+ if (!power -> has_ch0i )
387+ return - EINVAL ;
388+
389+ /* Prefer CHTE available in newer firmwares */
390+ if (power -> has_chte ) {
391+ ret = apple_smc_write (power -> smc , SMC_KEY (CHTE ), chte_auto , 4 );
392+ if (ret )
393+ return ret ;
394+ } else if (power -> has_ch0c ) {
395+ ret = apple_smc_write_u8 (power -> smc , SMC_KEY (CH0C ), 0 );
396+ if (ret )
397+ return ret ;
398+ }
399+
400+ return apple_smc_write_u8 (power -> smc , SMC_KEY (CH0I ), 1 );
401+
336402 default :
337403 return - EINVAL ;
338404 }
339- ret = apple_smc_write_u8 (power -> smc , SMC_KEY (CH0I ), ch0i );
340- if (ret )
341- return ret ;
342- return apple_smc_write_u8 (power -> smc , SMC_KEY (CH0C ), ch0c );
405+
406+ return 0 ;
343407}
344408
345409static int macsmc_battery_get_date (const char * s , int * out )
@@ -539,8 +603,7 @@ static int macsmc_battery_get_property(struct power_supply *psy,
539603 val -> intval = vu16 & 0xff ;
540604 if (val -> intval < CHLS_MIN_END_THRESHOLD || val -> intval >= 100 )
541605 val -> intval = 100 ;
542- }
543- else if (power -> has_chwa ) {
606+ } else if (power -> has_chwa ) {
544607 flag = false;
545608 ret = apple_smc_read_flag (power -> smc , SMC_KEY (CHWA ), & flag );
546609 val -> intval = flag ? CHWA_FIXED_END_THRESHOLD : 100 ;
@@ -838,8 +901,9 @@ static int macsmc_power_probe(struct platform_device *pdev)
838901 struct power_supply_config psy_cfg = {};
839902 struct macsmc_power * power ;
840903 bool flag ;
841- u32 val ;
904+ u8 val8 ;
842905 u16 vu16 ;
906+ u32 val32 ;
843907 int ret ;
844908
845909 power = devm_kzalloc (& pdev -> dev , sizeof (* power ), GFP_KERNEL );
@@ -861,10 +925,37 @@ static int macsmc_power_probe(struct platform_device *pdev)
861925 apple_smc_read (smc , SMC_KEY (BMSN ), power -> serial_number , sizeof (power -> serial_number ) - 1 );
862926 apple_smc_read (smc , SMC_KEY (BMDT ), power -> mfg_date , sizeof (power -> mfg_date ) - 1 );
863927
928+ if (apple_smc_read_u32 (power -> smc , SMC_KEY (CHTE ), & val32 ) >= 0 )
929+ power -> has_chte = true;
930+
931+ if (apple_smc_read_u8 (power -> smc , SMC_KEY (CH0C ), & val8 ) >= 0 )
932+ power -> has_ch0c = true;
933+
934+ if (apple_smc_read_u8 (power -> smc , SMC_KEY (CH0I ), & val8 ) >= 0 )
935+ power -> has_ch0i = true;
936+
864937 /* Turn off the "optimized battery charging" flags, in case macOS left them on */
938+ if (power -> has_chte )
939+ apple_smc_write_u32 (power -> smc , SMC_KEY (CHTE ), 0 );
940+ else if (power -> has_ch0c )
941+ apple_smc_write_u8 (power -> smc , SMC_KEY (CH0C ), 0 );
942+
943+ if (power -> has_ch0i )
944+ apple_smc_write_u8 (power -> smc , SMC_KEY (CH0I ), 0 );
945+
865946 apple_smc_write_u8 (power -> smc , SMC_KEY (CH0K ), 0 );
866947 apple_smc_write_u8 (power -> smc , SMC_KEY (CH0B ), 0 );
867948
949+ power -> batt_desc .charge_behaviours = BIT (POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO );
950+
951+ /* Newer firmwares do not have force discharge, so check if it's supported */
952+ if (power -> has_ch0i )
953+ power -> batt_desc .charge_behaviours |= BIT (POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE );
954+
955+ /* Older firmware uses CH0C, and newer firmware uses CHTE, so check if at least one is present*/
956+ if (power -> has_chte || power -> has_ch0c )
957+ power -> batt_desc .charge_behaviours |= BIT (POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE );
958+
868959 /*
869960 * Prefer CHWA as the SMC firmware from iBoot-10151.1.1 is not compatible with
870961 * this CHLS usage.
@@ -882,7 +973,7 @@ static int macsmc_power_probe(struct platform_device *pdev)
882973 power -> nominal_voltage_mv = MACSMC_NOMINAL_CELL_VOLTAGE_MV * power -> num_cells ;
883974
884975 /* Doing one read of this flag enables critical shutdown notifications */
885- apple_smc_read_u32 (power -> smc , SMC_KEY (BCF0 ), & val );
976+ apple_smc_read_u32 (power -> smc , SMC_KEY (BCF0 ), & val32 );
886977
887978 psy_cfg .drv_data = power ;
888979 power -> batt = devm_power_supply_register (& pdev -> dev , & power -> batt_desc , & psy_cfg );
0 commit comments