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 ;
@@ -187,6 +196,34 @@ static int macsmc_battery_get_date(const char *s, int *out)
187196 return 0 ;
188197}
189198
199+ static int macsmc_battery_get_capacity_level (struct macsmc_power * power )
200+ {
201+ u32 val ;
202+ int ret ;
203+
204+ /* Check for emergency shutdown condition */
205+ if (apple_smc_read_u32 (power -> smc , SMC_KEY (BCF0 ), & val ) >= 0 && val )
206+ return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL ;
207+
208+ /* Check AC status for whether we could boot in this state */
209+ if (apple_smc_read_u32 (power -> smc , SMC_KEY (ACSt ), & val ) >= 0 ) {
210+ if (!(val & ACSt_CAN_BOOT_IBOOT ))
211+ return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL ;
212+
213+ if (!(val & ACSt_CAN_BOOT_AP ))
214+ return POWER_SUPPLY_CAPACITY_LEVEL_LOW ;
215+ }
216+
217+ /* Check battery full flag */
218+ ret = apple_smc_read_flag (power -> smc , SMC_KEY (BSFC ));
219+ if (ret > 0 )
220+ return POWER_SUPPLY_CAPACITY_LEVEL_FULL ;
221+ else if (ret == 0 )
222+ return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL ;
223+ else
224+ return POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN ;
225+ }
226+
190227static int macsmc_battery_get_property (struct power_supply * psy ,
191228 enum power_supply_property psp ,
192229 union power_supply_propval * val )
@@ -224,6 +261,10 @@ static int macsmc_battery_get_property(struct power_supply *psy,
224261 ret = apple_smc_read_u8 (power -> smc , SMC_KEY (BUIC ), & vu8 );
225262 val -> intval = vu8 ;
226263 break ;
264+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL :
265+ val -> intval = macsmc_battery_get_capacity_level (power );
266+ ret = val -> intval < 0 ? val -> intval : 0 ;
267+ break ;
227268 case POWER_SUPPLY_PROP_VOLTAGE_NOW :
228269 ret = apple_smc_read_u16 (power -> smc , SMC_KEY (B0AV ), & vu16 );
229270 val -> intval = vu16 * 1000 ;
@@ -343,6 +384,7 @@ static enum power_supply_property macsmc_battery_props[] = {
343384 POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW ,
344385 POWER_SUPPLY_PROP_TIME_TO_FULL_NOW ,
345386 POWER_SUPPLY_PROP_CAPACITY ,
387+ POWER_SUPPLY_PROP_CAPACITY_LEVEL ,
346388 POWER_SUPPLY_PROP_VOLTAGE_NOW ,
347389 POWER_SUPPLY_PROP_CURRENT_NOW ,
348390 POWER_SUPPLY_PROP_POWER_NOW ,
@@ -424,6 +466,59 @@ static const struct power_supply_desc macsmc_ac_desc = {
424466 .num_properties = ARRAY_SIZE (macsmc_ac_props ),
425467};
426468
469+ static void macsmc_power_critical_work (struct work_struct * wrk ) {
470+ struct macsmc_power * power = container_of (wrk , struct macsmc_power , critical_work );
471+ int ret ;
472+ u32 bcf0 ;
473+ u16 bitv , b0av ;
474+
475+ /*
476+ * Check if the battery voltage is below the design voltage. If it is,
477+ * we have a few seconds until the machine dies. Explicitly shut down,
478+ * which at least gets the NVMe controller to flush its cache.
479+ */
480+ if (apple_smc_read_u16 (power -> smc , SMC_KEY (BITV ), & bitv ) >= 0 &&
481+ apple_smc_read_u16 (power -> smc , SMC_KEY (B0AV ), & b0av ) >= 0 &&
482+ b0av < bitv ) {
483+ dev_crit (power -> dev , "Emergency notification: Battery is critical\n" );
484+ if (kernel_can_power_off ())
485+ kernel_power_off ();
486+ else /* Missing macsmc-reboot driver? In this state, this will not boot anyway. */
487+ kernel_restart ("Battery is critical" );
488+ }
489+
490+ /* This spams once per second, so make sure we only trigger shutdown once. */
491+ if (power -> shutdown_started )
492+ return ;
493+
494+ /* Check for battery empty condition */
495+ ret = apple_smc_read_u32 (power -> smc , SMC_KEY (BCF0 ), & bcf0 );
496+ if (ret < 0 ) {
497+ dev_err (power -> dev ,
498+ "Emergency notification: Failed to read battery status\n" );
499+ } else if (bcf0 == 0 ) {
500+ dev_warn (power -> dev , "Emergency notification: Battery status is OK?\n" );
501+ return ;
502+ } else {
503+ dev_warn (power -> dev , "Emergency notification: Battery is empty\n" );
504+ }
505+
506+ power -> shutdown_started = true;
507+
508+ /*
509+ * Attempt to trigger an orderly shutdown. At this point, we should have a few
510+ * minutes of reserve capacity left, enough to do a clean shutdown.
511+ */
512+ dev_warn (power -> dev , "Shutting down in 10 seconds\n" );
513+ ssleep (10 );
514+
515+ /*
516+ * Don't force it; if this stalls or fails, the last-resort check above will
517+ * trigger a hard shutdown when shutdown is truly imminent.
518+ */
519+ orderly_poweroff (false);
520+ }
521+
427522static int macsmc_power_event (struct notifier_block * nb , unsigned long event , void * data )
428523{
429524 struct macsmc_power * power = container_of (nb , struct macsmc_power , nb );
@@ -435,6 +530,28 @@ static int macsmc_power_event(struct notifier_block *nb, unsigned long event, vo
435530 power_supply_changed (power -> batt );
436531 power_supply_changed (power -> ac );
437532
533+ return NOTIFY_OK ;
534+ } else if (event == 0x71020000 ) {
535+ schedule_work (& power -> critical_work );
536+
537+ return NOTIFY_OK ;
538+ } else if ((event & 0xffff0000 ) == 0x71060000 ) {
539+ u8 changed_port = event >> 8 ;
540+ u8 cur_port ;
541+
542+ /* Port charging state change? */
543+ if (apple_smc_read_u8 (power -> smc , SMC_KEY (AC - W ), & cur_port ) >= 0 ) {
544+ dev_info (power -> dev , "Port %d state change (charge port: %d)\n" ,
545+ changed_port + 1 , cur_port );
546+ }
547+
548+ power_supply_changed (power -> batt );
549+ power_supply_changed (power -> ac );
550+
551+ return NOTIFY_OK ;
552+ } else if ((event & 0xff000000 ) == 0x71000000 ) {
553+ dev_info (power -> dev , "Unknown charger event 0x%lx\n" , event );
554+
438555 return NOTIFY_OK ;
439556 }
440557
@@ -446,6 +563,7 @@ static int macsmc_power_probe(struct platform_device *pdev)
446563 struct apple_smc * smc = dev_get_drvdata (pdev -> dev .parent );
447564 struct power_supply_config psy_cfg = {};
448565 struct macsmc_power * power ;
566+ u32 val ;
449567 int ret ;
450568
451569 power = devm_kzalloc (& pdev -> dev , sizeof (* power ), GFP_KERNEL );
@@ -469,6 +587,9 @@ static int macsmc_power_probe(struct platform_device *pdev)
469587 apple_smc_write_u8 (power -> smc , SMC_KEY (CH0K ), 0 );
470588 apple_smc_write_u8 (power -> smc , SMC_KEY (CH0B ), 0 );
471589
590+ /* Doing one read of this flag enables critical shutdown notifications */
591+ apple_smc_read_u32 (power -> smc , SMC_KEY (BCF0 ), & val );
592+
472593 psy_cfg .drv_data = power ;
473594 power -> batt = devm_power_supply_register (& pdev -> dev , & macsmc_battery_desc , & psy_cfg );
474595 if (IS_ERR (power -> batt )) {
@@ -487,6 +608,8 @@ static int macsmc_power_probe(struct platform_device *pdev)
487608 power -> nb .notifier_call = macsmc_power_event ;
488609 apple_smc_register_notifier (power -> smc , & power -> nb );
489610
611+ INIT_WORK (& power -> critical_work , macsmc_power_critical_work );
612+
490613 return 0 ;
491614}
492615
0 commit comments