1111#include <linux/mfd/core.h>
1212#include <linux/mfd/macsmc.h>
1313#include <linux/power_supply.h>
14+ #include <linux/reboot.h>
15+ #include <linux/delay.h>
16+ #include <linux/workqueue.h>
1417
1518#define MAX_STRING_LENGTH 256
1619
@@ -26,6 +29,9 @@ struct macsmc_power {
2629 struct power_supply * ac ;
2730
2831 struct notifier_block nb ;
32+
33+ struct work_struct critical_work ;
34+ bool shutdown_started ;
2935};
3036
3137#define CHNC_BATTERY_FULL BIT(0)
@@ -46,6 +52,9 @@ struct macsmc_power {
4652#define CH0X_CH0C BIT(0)
4753#define CH0X_CH0B BIT(1)
4854
55+ #define ACSt_CAN_BOOT_AP BIT(2)
56+ #define ACSt_CAN_BOOT_IBOOT BIT(1)
57+
4958static int macsmc_battery_get_status (struct macsmc_power * power )
5059{
5160 u64 nocharge_flags ;
@@ -188,6 +197,34 @@ static int macsmc_battery_get_date(const char *s, int *out)
188197 return 0 ;
189198}
190199
200+ static int macsmc_battery_get_capacity_level (struct macsmc_power * power )
201+ {
202+ u32 val ;
203+ int ret ;
204+
205+ /* Check for emergency shutdown condition */
206+ if (apple_smc_read_u32 (power -> smc , SMC_KEY (BCF0 ), & val ) >= 0 && val )
207+ return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL ;
208+
209+ /* Check AC status for whether we could boot in this state */
210+ if (apple_smc_read_u32 (power -> smc , SMC_KEY (ACSt ), & val ) >= 0 ) {
211+ if (!(val & ACSt_CAN_BOOT_IBOOT ))
212+ return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL ;
213+
214+ if (!(val & ACSt_CAN_BOOT_AP ))
215+ return POWER_SUPPLY_CAPACITY_LEVEL_LOW ;
216+ }
217+
218+ /* Check battery full flag */
219+ ret = apple_smc_read_flag (power -> smc , SMC_KEY (BSFC ));
220+ if (ret > 0 )
221+ return POWER_SUPPLY_CAPACITY_LEVEL_FULL ;
222+ else if (ret == 0 )
223+ return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL ;
224+ else
225+ return POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN ;
226+ }
227+
191228static int macsmc_battery_get_property (struct power_supply * psy ,
192229 enum power_supply_property psp ,
193230 union power_supply_propval * val )
@@ -225,6 +262,10 @@ static int macsmc_battery_get_property(struct power_supply *psy,
225262 ret = apple_smc_read_u8 (power -> smc , SMC_KEY (BUIC ), & vu8 );
226263 val -> intval = vu8 ;
227264 break ;
265+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL :
266+ val -> intval = macsmc_battery_get_capacity_level (power );
267+ ret = val -> intval < 0 ? val -> intval : 0 ;
268+ break ;
228269 case POWER_SUPPLY_PROP_VOLTAGE_NOW :
229270 ret = apple_smc_read_u16 (power -> smc , SMC_KEY (B0AV ), & vu16 );
230271 val -> intval = vu16 * 1000 ;
@@ -344,6 +385,7 @@ static enum power_supply_property macsmc_battery_props[] = {
344385 POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW ,
345386 POWER_SUPPLY_PROP_TIME_TO_FULL_NOW ,
346387 POWER_SUPPLY_PROP_CAPACITY ,
388+ POWER_SUPPLY_PROP_CAPACITY_LEVEL ,
347389 POWER_SUPPLY_PROP_VOLTAGE_NOW ,
348390 POWER_SUPPLY_PROP_CURRENT_NOW ,
349391 POWER_SUPPLY_PROP_POWER_NOW ,
@@ -425,6 +467,59 @@ static const struct power_supply_desc macsmc_ac_desc = {
425467 .num_properties = ARRAY_SIZE (macsmc_ac_props ),
426468};
427469
470+ static void macsmc_power_critical_work (struct work_struct * wrk ) {
471+ struct macsmc_power * power = container_of (wrk , struct macsmc_power , critical_work );
472+ int ret ;
473+ u32 bcf0 ;
474+ u16 bitv , b0av ;
475+
476+ /*
477+ * Check if the battery voltage is below the design voltage. If it is,
478+ * we have a few seconds until the machine dies. Explicitly shut down,
479+ * which at least gets the NVMe controller to flush its cache.
480+ */
481+ if (apple_smc_read_u16 (power -> smc , SMC_KEY (BITV ), & bitv ) >= 0 &&
482+ apple_smc_read_u16 (power -> smc , SMC_KEY (B0AV ), & b0av ) >= 0 &&
483+ b0av < bitv ) {
484+ dev_crit (power -> dev , "Emergency notification: Battery is critical\n" );
485+ if (kernel_can_power_off ())
486+ kernel_power_off ();
487+ else /* Missing macsmc-reboot driver? In this state, this will not boot anyway. */
488+ kernel_restart ("Battery is critical" );
489+ }
490+
491+ /* This spams once per second, so make sure we only trigger shutdown once. */
492+ if (power -> shutdown_started )
493+ return ;
494+
495+ /* Check for battery empty condition */
496+ ret = apple_smc_read_u32 (power -> smc , SMC_KEY (BCF0 ), & bcf0 );
497+ if (ret < 0 ) {
498+ dev_err (power -> dev ,
499+ "Emergency notification: Failed to read battery status\n" );
500+ } else if (bcf0 == 0 ) {
501+ dev_warn (power -> dev , "Emergency notification: Battery status is OK?\n" );
502+ return ;
503+ } else {
504+ dev_warn (power -> dev , "Emergency notification: Battery is empty\n" );
505+ }
506+
507+ power -> shutdown_started = true;
508+
509+ /*
510+ * Attempt to trigger an orderly shutdown. At this point, we should have a few
511+ * minutes of reserve capacity left, enough to do a clean shutdown.
512+ */
513+ dev_warn (power -> dev , "Shutting down in 10 seconds\n" );
514+ ssleep (10 );
515+
516+ /*
517+ * Don't force it; if this stalls or fails, the last-resort check above will
518+ * trigger a hard shutdown when shutdown is truly imminent.
519+ */
520+ orderly_poweroff (false);
521+ }
522+
428523static int macsmc_power_event (struct notifier_block * nb , unsigned long event , void * data )
429524{
430525 struct macsmc_power * power = container_of (nb , struct macsmc_power , nb );
@@ -436,6 +531,28 @@ static int macsmc_power_event(struct notifier_block *nb, unsigned long event, vo
436531 power_supply_changed (power -> batt );
437532 power_supply_changed (power -> ac );
438533
534+ return NOTIFY_OK ;
535+ } else if (event == 0x71020000 ) {
536+ schedule_work (& power -> critical_work );
537+
538+ return NOTIFY_OK ;
539+ } else if ((event & 0xffff0000 ) == 0x71060000 ) {
540+ u8 changed_port = event >> 8 ;
541+ u8 cur_port ;
542+
543+ /* Port charging state change? */
544+ if (apple_smc_read_u8 (power -> smc , SMC_KEY (AC - W ), & cur_port ) >= 0 ) {
545+ dev_info (power -> dev , "Port %d state change (charge port: %d)\n" ,
546+ changed_port + 1 , cur_port );
547+ }
548+
549+ power_supply_changed (power -> batt );
550+ power_supply_changed (power -> ac );
551+
552+ return NOTIFY_OK ;
553+ } else if ((event & 0xff000000 ) == 0x71000000 ) {
554+ dev_info (power -> dev , "Unknown charger event 0x%lx\n" , event );
555+
439556 return NOTIFY_OK ;
440557 }
441558
@@ -447,6 +564,7 @@ static int macsmc_power_probe(struct platform_device *pdev)
447564 struct apple_smc * smc = dev_get_drvdata (pdev -> dev .parent );
448565 struct power_supply_config psy_cfg = {};
449566 struct macsmc_power * power ;
567+ u32 val ;
450568 int ret ;
451569
452570 power = devm_kzalloc (& pdev -> dev , sizeof (* power ), GFP_KERNEL );
@@ -470,6 +588,9 @@ static int macsmc_power_probe(struct platform_device *pdev)
470588 apple_smc_write_u8 (power -> smc , SMC_KEY (CH0K ), 0 );
471589 apple_smc_write_u8 (power -> smc , SMC_KEY (CH0B ), 0 );
472590
591+ /* Doing one read of this flag enables critical shutdown notifications */
592+ apple_smc_read_u32 (power -> smc , SMC_KEY (BCF0 ), & val );
593+
473594 psy_cfg .drv_data = power ;
474595 power -> batt = devm_power_supply_register (& pdev -> dev , & macsmc_battery_desc , & psy_cfg );
475596 if (IS_ERR (power -> batt )) {
@@ -488,6 +609,8 @@ static int macsmc_power_probe(struct platform_device *pdev)
488609 power -> nb .notifier_call = macsmc_power_event ;
489610 apple_smc_register_notifier (power -> smc , & power -> nb );
490611
612+ INIT_WORK (& power -> critical_work , macsmc_power_critical_work );
613+
491614 return 0 ;
492615}
493616
0 commit comments