Make macsmc-power work on Intel Macs, as a replacement for
acpi-sbs. It exposes a lot more sensors than acpi-sbs, such
as voltage, current, power, temperature, charge and health
info, and also the adapter state.

It also adds a charge limit, which acpi-sbs doesn't offer.

And now we have power stats on non-mobile macs as well (iMacs,
MacPros,etc), using macsmc-ac.

Signed-off-by: Atharva Tiwari <[email protected]>
---
 drivers/power/supply/macsmc-power.c | 751 ++++++++++++++++++++++------
 1 file changed, 606 insertions(+), 145 deletions(-)

diff --git a/drivers/power/supply/macsmc-power.c 
b/drivers/power/supply/macsmc-power.c
index ced37a701..1d64d8185 100644
--- a/drivers/power/supply/macsmc-power.c
+++ b/drivers/power/supply/macsmc-power.c
@@ -7,8 +7,11 @@
  * on Apple Silicon systems.
  *
  * Copyright The Asahi Linux Contributors
+ *
+ * Copyright (C) 2026 Atharva Tiwari <[email protected]>
  */
 
+#include <linux/acpi.h>
 #include <linux/ctype.h>
 #include <linux/delay.h>
 #include <linux/devm-helpers.h>
@@ -80,12 +83,16 @@ struct macsmc_power {
        char serial_number[MAX_STRING_LENGTH];
        char mfg_date[MAX_STRING_LENGTH];
 
+       bool has_battery;
+
        /* Supported feature flags based on SMC key presence */
        bool has_chwa; /* Charge limit (Modern firmware) */
-       bool has_chls; /* Charge limit (Older firmware) */
+       bool has_chls; /* Charge limit (Older firmware And New firmware on 
Intel macs) */
        bool has_ch0i; /* Force discharge (Older firmware) */
        bool has_ch0c; /* Inhibit charge (Older firmware) */
        bool has_chte; /* Inhibit charge (Modern firmware) */
+       bool has_pd0r; /* AC Adapter current power in watts (Old Intel macs) */
+
        /*
         * Battery critical key is 1 byte and charge key is little endian
         * (Modern firmware)
@@ -94,7 +101,9 @@ struct macsmc_power {
 
        u8 num_cells;
        int nominal_voltage_mv;
+       unsigned long long adapter_status;
 
+       struct acpi_device *adapter;
        struct notifier_block nb;
        struct work_struct critical_work;
        bool emergency_shutdown_triggered;
@@ -195,6 +204,37 @@ static int macsmc_battery_get_status(struct macsmc_power 
*power)
        return POWER_SUPPLY_STATUS_CHARGING;
 }
 
+static int macsmc_battery_acpi_get_status(struct macsmc_power *power)
+{
+       int ret;
+       s16 vs16;
+       u16 vu16;
+
+       ret = apple_smc_read_s16(power->smc, SMC_KEY(B0AC), &vs16);
+       if (ret < 0)
+               return ret;
+
+       ret = apple_smc_read_u16(power->smc, SMC_KEY(BRSC), &vu16);
+       if (ret < 0)
+               return ret;
+
+       vu16 = swab16(vu16);
+       vs16 = (s16)swab16(vs16);
+
+       if (power->adapter_status) {
+               if (vu16 == 100 && vs16 <= 0)
+                       return POWER_SUPPLY_STATUS_FULL;
+
+               if (vs16 > 0)
+                       return POWER_SUPPLY_STATUS_CHARGING;
+
+               return POWER_SUPPLY_STATUS_NOT_CHARGING;
+       }
+
+       return POWER_SUPPLY_STATUS_DISCHARGING;
+}
+
+
 static int macsmc_battery_get_charge_behaviour(struct macsmc_power *power)
 {
        int ret;
@@ -322,6 +362,198 @@ static int macsmc_battery_get_capacity_level(struct 
macsmc_power *power)
                return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
 }
 
+static int macsmc_battery_acpi_get_capacity_level(struct macsmc_power *power)
+{
+       int ret;
+       u16 vu16;
+
+       ret = apple_smc_read_u16(power->smc, SMC_KEY(BRSC), &vu16);
+       if (ret < 0)
+               return ret;
+
+       vu16 = swab16(vu16);
+
+       if (vu16 <= 5)
+               return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+       if (vu16 <= 20)
+               return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+       if (vu16 <= 80)
+               return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+       if (vu16 < 100)
+               return POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
+
+       return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+}
+
+static int macsmc_battery_acpi_read_f32_scaled(struct apple_smc *smc, smc_key 
key,
+       int *p, int scale)
+{
+       u32 fval;
+       u64 val;
+       int ret, exp;
+
+       ret = apple_smc_read_u32(smc, key, &fval);
+       if (ret < 0)
+               return ret;
+
+       val = (u64)((fval & GENMASK(22, 0)) | BIT(23));
+       exp = ((fval >> 23) & 0xff) - 127 - 23;
+
+       val *= (u64)scale;
+
+       if (exp > 63)
+               val = U64_MAX;
+       else if (exp < -63)
+               val = 0;
+       else if (exp < 0)
+               val >>= -exp;
+       else if (exp != 0 &&
+                (val & ~((1ULL << (64 - exp)) - 1)))
+               val = U64_MAX;
+       else
+               val <<= exp;
+
+       if (fval & BIT(31)) {
+               if (val > (u64)INT_MAX + 1)
+                       *p = INT_MIN;
+               else
+                       *p = -(int)val;
+       } else {
+               if (val > INT_MAX)
+                       *p = INT_MAX;
+               else
+                       *p = (int)val;
+       }
+
+       return 0;
+}
+
+static int macsmc_battery_acpi_read(struct apple_smc *smc, smc_key key, int 
*val,
+       int scale)
+{
+       int ret;
+       struct apple_smc_key_info info;
+
+       ret = apple_smc_get_key_info(smc, key, &info);
+       if (ret)
+               return ret;
+
+       switch (info.type_code) {
+       /* 32-bit IEEE 754 float */
+       case __SMC_KEY('f', 'l', 't', ' '): {
+               int flt_ = 0;
+
+               ret = macsmc_battery_acpi_read_f32_scaled(smc, key, &flt_, 
scale);
+               if (ret)
+                       return ret;
+
+               *val = flt_;
+               break;
+       }
+
+       /* 3.13 fixed point decimal */
+       case __SMC_KEY('f', 'p', '3', 'd'): {
+               u16 fp3d;
+
+               ret = apple_smc_read_u16(smc, key, &fp3d);
+               if (ret)
+                       return ret;
+
+               *val = mult_frac(be16_to_cpu(fp3d), scale, BIT(13));
+               break;
+       }
+
+       /* 5.11 fixed point decimal */
+       case __SMC_KEY('f', 'p', '5', 'b'): {
+               u16 fp5b;
+
+               ret = apple_smc_read_u16(smc, key, &fp5b);
+               if (ret)
+                       return ret;
+
+               *val = mult_frac(be16_to_cpu(fp5b), scale, BIT(11));
+               break;
+       }
+
+       /* 8.8 fixed point decimal */
+       case __SMC_KEY('f', 'p', '8', '8'): {
+               u16 fp88;
+
+               ret = apple_smc_read_u16(smc, key, &fp88);
+               if (ret)
+                       return ret;
+
+               *val = mult_frac(be16_to_cpu(fp88), scale, BIT(8));
+               break;
+       }
+
+       /* 3.12 signed fixed point decimal */
+       case __SMC_KEY('s', 'p', '3', 'c'): {
+               s16 sp3c;
+
+               ret = apple_smc_read_s16(smc, key, &sp3c);
+               if (ret)
+                       return ret;
+
+               *val = mult_frac((s16)be16_to_cpu(sp3c), scale, BIT(12));
+               break;
+       }
+
+       /* 4.11 signed fixed point decimal */
+       case __SMC_KEY('s', 'p', '4', 'b'): {
+               s16 sp4b;
+
+               ret = apple_smc_read_s16(smc, key, &sp4b);
+               if (ret)
+                       return ret;
+
+               *val = mult_frac((s16)be16_to_cpu(sp4b), scale, BIT(11));
+               break;
+       }
+
+       /* 5.10 signed fixed point decimal */
+       case __SMC_KEY('s', 'p', '5', 'a'): {
+               s16 sp5a;
+
+               ret = apple_smc_read_s16(smc, key, &sp5a);
+               if (ret)
+                       return ret;
+
+               *val = mult_frac((s16)be16_to_cpu(sp5a), scale, BIT(10));
+               break;
+       }
+
+       /* 6.9 signed fixed point decimal */
+       case __SMC_KEY('s', 'p', '6', '9'): {
+               s16 sp69;
+
+               ret = apple_smc_read_s16(smc, key, &sp69);
+               if (ret)
+                       return ret;
+
+               *val = mult_frac((s16)be16_to_cpu(sp69), scale, BIT(9));
+               break;
+       }
+
+       /* 7.8 signed fixed point decimal */
+       case __SMC_KEY('s', 'p', '7', '8'): {
+               s16 sp78;
+
+               ret = apple_smc_read_s16(smc, key, &sp78);
+               if (ret)
+                       return ret;
+
+               *val = mult_frac((s16)be16_to_cpu(sp78), scale, BIT(8));
+               break;
+       }
+
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
 static s16 macsmc_swap_b0rm(struct macsmc_power *power, s16 b0rm)
 {
        /* B0RM was Big Endian, likely pass through from TI gas gauge */
@@ -343,7 +575,10 @@ static int macsmc_battery_get_property(struct power_supply 
*psy,
 
        switch (psp) {
        case POWER_SUPPLY_PROP_STATUS:
-               val->intval = macsmc_battery_get_status(power);
+               if (power->smc->is_acpi)
+                       val->intval = macsmc_battery_acpi_get_status(power);
+               else
+                       val->intval = macsmc_battery_get_status(power);
                ret = val->intval < 0 ? val->intval : 0;
                break;
        case POWER_SUPPLY_PROP_PRESENT:
@@ -359,36 +594,71 @@ static int macsmc_battery_get_property(struct 
power_supply *psy,
                break;
        case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
                ret = apple_smc_read_u16(power->smc, SMC_KEY(B0TF), &vu16);
-               val->intval = vu16 == 0xffff ? 0 : vu16 * 60;
+               if (power->smc->is_acpi)
+                       val->intval = vu16 == 0xffff ? 0 : swab16(vu16) * 60;
+               else
+                       val->intval = vu16 == 0xffff ? 0 : vu16 * 60;
                break;
        case POWER_SUPPLY_PROP_CAPACITY:
-               ret = apple_smc_read_u8(power->smc, SMC_KEY(BUIC), &vu8);
-               val->intval = vu8;
+               if (power->smc->is_acpi) {
+                       ret = apple_smc_read_u16(power->smc, SMC_KEY(BRSC), 
&vu16);
+                       val->intval = swab16(vu16);
+               } else {
+                       ret = apple_smc_read_u8(power->smc, SMC_KEY(BUIC), 
&vu8);
+                       val->intval = vu8;
+               }
                break;
        case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
-               val->intval = macsmc_battery_get_capacity_level(power);
+               if (power->smc->is_acpi)
+                       val->intval = 
macsmc_battery_acpi_get_capacity_level(power);
+               else
+                       val->intval = macsmc_battery_get_capacity_level(power);
                ret = val->intval < 0 ? val->intval : 0;
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
                ret = apple_smc_read_u16(power->smc, SMC_KEY(B0AV), &vu16);
-               val->intval = vu16 * 1000;
+               if (power->smc->is_acpi)
+                       val->intval = swab16(vu16) * 1000;
+               else
+                       val->intval = vu16 * 1000;
                break;
        case POWER_SUPPLY_PROP_CURRENT_NOW:
                ret = apple_smc_read_s16(power->smc, SMC_KEY(B0AC), &vs16);
-               val->intval = vs16 * 1000;
+               if (power->smc->is_acpi)
+                       val->intval = (s16)swab16(vs16) * 1000;
+               else
+                       val->intval = vs16 * 1000;
                break;
        case POWER_SUPPLY_PROP_POWER_NOW:
-               ret = apple_smc_read_s32(power->smc, SMC_KEY(B0AP), &vs32);
-               val->intval = vs32 * 1000;
+               if (power->smc->is_acpi) {
+                       ret = macsmc_battery_acpi_read(power->smc, 
SMC_KEY(B0AP),
+                                       &val->intval, 1000000);
+                       if (ret < 0)
+                               return ret;
+
+                       val->intval = -val->intval;
+                       }
+               else {
+                       ret = apple_smc_read_s32(power->smc, SMC_KEY(B0AP), 
&vs32);
+                       val->intval = vs32 * 1000;
+               }
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
                ret = apple_smc_read_u16(power->smc, SMC_KEY(BITV), &vu16);
-               val->intval = vu16 * 1000;
+               if (power->smc->is_acpi)
+                       val->intval = swab16(vu16) * 1000;
+               else
+                       val->intval = vu16 * 1000;
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
                /* Calculate total max design voltage from per-cell maximum 
voltage */
-               ret = apple_smc_read_u16(power->smc, SMC_KEY(BVVN), &vu16);
-               val->intval = vu16 * 1000 * power->num_cells;
+               if (power->smc->is_acpi) {
+                       ret = apple_smc_read_u16(power->smc, SMC_KEY(BCMV), 
&vu16);
+                       val->intval = swab16(vu16) * 1000 * power->num_cells;
+               } else {
+                       ret = apple_smc_read_u16(power->smc, SMC_KEY(BVVN), 
&vu16);
+                       val->intval = vu16 * 1000 * power->num_cells;
+               }
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_MIN:
                /* Lifetime min */
@@ -400,17 +670,36 @@ static int macsmc_battery_get_property(struct 
power_supply *psy,
                ret = apple_smc_read_s16(power->smc, SMC_KEY(BLPX), &vs16);
                val->intval = vs16 * 1000;
                break;
+       case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
+               if (power->has_chls) {
+                       ret = apple_smc_read_u16(power->smc, SMC_KEY(CHLS), 
&vu16);
+                       val->intval = vu16 & 0xFF;
+               } else {
+                       ret = apple_smc_read_u8(power->smc, SMC_KEY(BCLM), 
&vu8);
+                       val->intval = vu8;
+               }
+               break;
        case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
                ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RC), &vu16);
                val->intval = vu16 * 1000;
                break;
        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
-               ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RI), &vu16);
-               val->intval = vu16 * 1000;
+               if (power->smc->is_acpi) {
+                       ret = apple_smc_read_u16(power->smc, SMC_KEY(CHBI), 
&vu16);
+                       val->intval = swab16(vu16) * 1000;
+               } else {
+                       ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RI), 
&vu16);
+                       val->intval = vu16 * 1000;
+               }
                break;
        case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
-               ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RV), &vu16);
-               val->intval = vu16 * 1000;
+               if (power->smc->is_acpi) {
+                       ret = apple_smc_read_u16(power->smc, SMC_KEY(CHBV), 
&vu16);
+                       val->intval = swab16(vu16) * 1000;
+               } else {
+                       ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RV), 
&vu16);
+                       val->intval = vu16 * 1000;
+               }
                break;
        case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
                ret = apple_smc_read_u16(power->smc, SMC_KEY(B0DC), &vu16);
@@ -418,11 +707,17 @@ static int macsmc_battery_get_property(struct 
power_supply *psy,
                break;
        case POWER_SUPPLY_PROP_CHARGE_FULL:
                ret = apple_smc_read_u16(power->smc, SMC_KEY(B0FC), &vu16);
-               val->intval = vu16 * 1000;
+               if (power->smc->is_acpi)
+                       val->intval = swab16(vu16) * 1000;
+               else
+                       val->intval = vu16 * 1000;
                break;
        case POWER_SUPPLY_PROP_CHARGE_NOW:
                ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RM), &vu16);
-               val->intval = macsmc_swap_b0rm(power, vu16) * 1000;
+               if (power->smc->is_acpi)
+                       val->intval = swab16(vu16) * 1000;
+               else
+                       val->intval = macsmc_swap_b0rm(power, vu16) * 1000;
                break;
        case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
                ret = apple_smc_read_u16(power->smc, SMC_KEY(B0DC), &vu16);
@@ -430,15 +725,37 @@ static int macsmc_battery_get_property(struct 
power_supply *psy,
                break;
        case POWER_SUPPLY_PROP_ENERGY_FULL:
                ret = apple_smc_read_u16(power->smc, SMC_KEY(B0FC), &vu16);
-               val->intval = vu16 * power->nominal_voltage_mv;
+               if (power->smc->is_acpi) {
+                       if (ret < 0)
+                               return ret;
+
+                       u16 voltage;
+
+                       ret = apple_smc_read_u16(power->smc, SMC_KEY(B0AV), 
&voltage);
+                       val->intval = swab16(vu16) * swab16(voltage);
+               } else
+                       val->intval = vu16 * power->nominal_voltage_mv;
                break;
        case POWER_SUPPLY_PROP_ENERGY_NOW:
                ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RM), &vu16);
-               val->intval = macsmc_swap_b0rm(power, vu16) * 
power->nominal_voltage_mv;
+               if (power->smc->is_acpi) {
+                       if (ret < 0)
+                               return ret;
+
+                       u16 voltage;
+
+                       ret = apple_smc_read_u16(power->smc, SMC_KEY(B0AV), 
&voltage);
+                       val->intval = swab16(vu16) * swab16(voltage);
+               } else
+                       val->intval = macsmc_swap_b0rm(power, vu16) * 
power->nominal_voltage_mv;
                break;
        case POWER_SUPPLY_PROP_TEMP:
-               ret = apple_smc_read_u16(power->smc, SMC_KEY(B0AT), &vu16);
-               val->intval = vu16 - 2732; /* Kelvin x10 to Celsius x10 */
+               if (power->smc->is_acpi)
+                       ret = macsmc_battery_acpi_read(power->smc, 
SMC_KEY(TB0T), &val->intval, 10);
+               else {
+                       ret = apple_smc_read_u16(power->smc, SMC_KEY(B0AT), 
&vu16);
+                       val->intval = vu16 - 2732; /* Kelvin x10 to Celsius x10 
*/
+               }
                break;
        case POWER_SUPPLY_PROP_CHARGE_COUNTER:
                ret = apple_smc_read_s64(power->smc, SMC_KEY(BAAC), &vs64);
@@ -446,7 +763,10 @@ static int macsmc_battery_get_property(struct power_supply 
*psy,
                break;
        case POWER_SUPPLY_PROP_CYCLE_COUNT:
                ret = apple_smc_read_u16(power->smc, SMC_KEY(B0CT), &vu16);
-               val->intval = vu16;
+               if (power->smc->is_acpi)
+                       val->intval = swab16(vu16);
+               else
+                       val->intval = vu16;
                break;
        case POWER_SUPPLY_PROP_SCOPE:
                val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
@@ -489,6 +809,15 @@ static int macsmc_battery_set_property(struct power_supply 
*psy,
        switch (psp) {
        case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
                return macsmc_battery_set_charge_behaviour(power, val->intval);
+       case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
+               if (val->intval > 100 || val->intval < 1)
+                       return -EINVAL;
+               if (power->has_chls) {
+                       u16 vu16 = val->intval & 0xFF;
+
+                       return apple_smc_write_u16(power->smc, SMC_KEY(CHLS), 
vu16);
+               }
+               return apple_smc_write_u8(power->smc, SMC_KEY(BCLM), (u8) 
val->intval);
        default:
                return -EINVAL;
        }
@@ -500,6 +829,8 @@ static int macsmc_battery_property_is_writeable(struct 
power_supply *psy,
        switch (psp) {
        case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
                return true;
+       case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
+               return true;
        default:
                return false;
        }
@@ -524,12 +855,47 @@ static int macsmc_ac_get_property(struct power_supply 
*psy,
 
        switch (psp) {
        case POWER_SUPPLY_PROP_ONLINE:
-               ret = apple_smc_read_u32(power->smc, SMC_KEY(CHIS), &vu32);
-               val->intval = !!vu32;
+               if (power->smc->is_acpi) {
+                       if (power->has_battery)
+                               val->intval = power->adapter_status;
+                       else
+                               val->intval = 1;
+               } else {
+                       ret = apple_smc_read_u32(power->smc, SMC_KEY(CHIS), 
&vu32);
+                       val->intval = !!vu32;
+               }
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+               if (power->has_battery)
+                       ret = macsmc_battery_acpi_read(power->smc, 
SMC_KEY(ID0R),
+                                       &val->intval, 1000000);
+               else
+                       ret = macsmc_battery_acpi_read(power->smc, 
SMC_KEY(ID2R),
+                                       &val->intval, 1000000);
+               break;
+       case POWER_SUPPLY_PROP_POWER_NOW:
+               if (power->has_pd0r)
+                       ret = macsmc_battery_acpi_read(power->smc, 
SMC_KEY(PD0R),
+                                       &val->intval, 1000000);
+               else if (power->has_battery)
+                       ret = macsmc_battery_acpi_read(power->smc, 
SMC_KEY(PDTR),
+                                       &val->intval, 1000000);
+               else
+                       ret = macsmc_battery_acpi_read(power->smc, 
SMC_KEY(PD2R),
+                                       &val->intval, 1000000);
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-               ret = apple_smc_read_u16(power->smc, SMC_KEY(AC-n), &vu16);
-               val->intval = vu16 * 1000;
+               if (power->smc->is_acpi) {
+                       if (power->has_battery)
+                               ret = macsmc_battery_acpi_read(power->smc, 
SMC_KEY(VD0R),
+                                               &val->intval, 1000000);
+                       else
+                               ret = macsmc_battery_acpi_read(power->smc, 
SMC_KEY(VD2R),
+                                               &val->intval, 1000000);
+               } else {
+                       ret = apple_smc_read_u16(power->smc, SMC_KEY(AC-n), 
&vu16);
+                       val->intval = vu16 * 1000;
+               }
                break;
        case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
                ret = apple_smc_read_u16(power->smc, SMC_KEY(AC-i), &vu16);
@@ -537,7 +903,10 @@ static int macsmc_ac_get_property(struct power_supply *psy,
                break;
        case POWER_SUPPLY_PROP_INPUT_POWER_LIMIT:
                ret = apple_smc_read_u32(power->smc, SMC_KEY(ACPW), &vu32);
-               val->intval = vu32 * 1000;
+               if (power->smc->is_acpi)
+                       val->intval = swab32(vu32) * 1000;
+               else
+                       val->intval = vu32 * 1000;
                break;
        default:
                return -EINVAL;
@@ -634,6 +1003,23 @@ static int macsmc_power_event(struct notifier_block *nb, 
unsigned long event, vo
        return NOTIFY_DONE;
 }
 
+static void macsmc_power_acpi_notify(acpi_handle handle, u32 event, void 
*context)
+{
+       struct macsmc_power *power = context;
+
+       if (event == 0x80) {
+               acpi_status status = 
acpi_evaluate_integer(power->adapter->handle, "_PSR", NULL,
+                                                               
&power->adapter_status);
+               if (ACPI_FAILURE(status))
+                       return;
+
+               power->adapter_status = !!power->adapter_status;
+               power_supply_changed(power->batt);
+               power_supply_changed(power->ac);
+       }
+}
+
+
 static int macsmc_power_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -670,15 +1056,19 @@ static int macsmc_power_probe(struct platform_device 
*pdev)
         * Check for battery presence.
         * B0AV is a fundamental key.
         */
+       if (smc->is_acpi && apple_smc_read_flag(power->smc, SMC_KEY(BBIN), 
&flag) == 0 && flag)
+               has_battery = true;
+
        if (apple_smc_read_u16(power->smc, SMC_KEY(B0AV), &vu16) == 0 &&
            macsmc_battery_get_status(power) > POWER_SUPPLY_STATUS_UNKNOWN)
                has_battery = true;
 
+       power->has_battery = has_battery;
        /*
         * Check for AC adapter presence.
         * CHIS is a fundamental key.
         */
-       if (apple_smc_key_exists(smc, SMC_KEY(CHIS)))
+       if (apple_smc_key_exists(smc, SMC_KEY(CHIS)) || smc->is_acpi)
                has_ac_adapter = true;
 
        if (!has_battery && !has_ac_adapter)
@@ -694,118 +1084,156 @@ static int macsmc_power_probe(struct platform_device 
*pdev)
 
                nprops = 0;
 
-               /* Fundamental properties */
-               props[nprops++] = POWER_SUPPLY_PROP_STATUS;
-               props[nprops++] = POWER_SUPPLY_PROP_PRESENT;
-               props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_NOW;
-               props[nprops++] = POWER_SUPPLY_PROP_CURRENT_NOW;
-               props[nprops++] = POWER_SUPPLY_PROP_POWER_NOW;
-               props[nprops++] = POWER_SUPPLY_PROP_CAPACITY;
-               props[nprops++] = POWER_SUPPLY_PROP_CAPACITY_LEVEL;
-               props[nprops++] = POWER_SUPPLY_PROP_TEMP;
-               props[nprops++] = POWER_SUPPLY_PROP_CYCLE_COUNT;
-               props[nprops++] = POWER_SUPPLY_PROP_HEALTH;
-               props[nprops++] = POWER_SUPPLY_PROP_SCOPE;
-               props[nprops++] = POWER_SUPPLY_PROP_MODEL_NAME;
-               props[nprops++] = POWER_SUPPLY_PROP_SERIAL_NUMBER;
-               props[nprops++] = POWER_SUPPLY_PROP_MANUFACTURE_YEAR;
-               props[nprops++] = POWER_SUPPLY_PROP_MANUFACTURE_MONTH;
-               props[nprops++] = POWER_SUPPLY_PROP_MANUFACTURE_DAY;
-
-               /* Extended properties usually present */
-               props[nprops++] = POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW;
-               props[nprops++] = POWER_SUPPLY_PROP_TIME_TO_FULL_NOW;
-               props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
-               props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
-               props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_MIN;
-               props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_MAX;
-               props[nprops++] = POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT;
-               props[nprops++] = POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
-               props[nprops++] = POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE;
-               props[nprops++] = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
-               props[nprops++] = POWER_SUPPLY_PROP_CHARGE_FULL;
-               props[nprops++] = POWER_SUPPLY_PROP_CHARGE_NOW;
-               props[nprops++] = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
-               props[nprops++] = POWER_SUPPLY_PROP_ENERGY_FULL;
-               props[nprops++] = POWER_SUPPLY_PROP_ENERGY_NOW;
-               props[nprops++] = POWER_SUPPLY_PROP_CHARGE_COUNTER;
-
-               /* Detect features based on key availability */
-               if (apple_smc_key_exists(smc, SMC_KEY(CHTE)))
-                       power->has_chte = true;
-               if (apple_smc_key_exists(smc, SMC_KEY(CH0C)))
-                       power->has_ch0c = true;
-               if (apple_smc_key_exists(smc, SMC_KEY(CH0I)))
-                       power->has_ch0i = true;
-
-               ret = apple_smc_get_key_info(power->smc, SMC_KEY(BCF0), &info);
-               if (ret) {
-                       dev_err(&pdev->dev, "Failed to determine BCF0 key 
size\n");
-                       return ret;
-               }
-               if (info.size == 1)
-                       power->fw_ge_27 = true;
-               else if (info.size == 4)
-                       power->fw_ge_27 = false;
-               else {
-                       dev_err(&pdev->dev, "Unexpected BCF0 key size %d\n", 
info.size);
-                       return -EIO;
-               }
-
-               /* Reset "Optimised Battery Charging" flags to default state */
-               if (power->has_chte)
-                       apple_smc_write_u32(smc, SMC_KEY(CHTE), 0);
-               else if (power->has_ch0c)
-                       apple_smc_write_u8(smc, SMC_KEY(CH0C), 0);
-
-               if (power->has_ch0i)
-                       apple_smc_write_u8(smc, SMC_KEY(CH0I), 0);
-
-               apple_smc_write_u8(smc, SMC_KEY(CH0K), 0);
-               apple_smc_write_u8(smc, SMC_KEY(CH0B), 0);
-
-               /* Configure charge behaviour if supported */
-               if (power->has_ch0i || power->has_ch0c || power->has_chte) {
-                       props[nprops++] = POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR;
-
-                       power->batt_desc.charge_behaviours =
-                               BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO);
+               if (smc->is_acpi) {
+                       props[nprops++] = POWER_SUPPLY_PROP_STATUS;
+                       props[nprops++] = POWER_SUPPLY_PROP_PRESENT;
+                       props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_NOW;
+                       props[nprops++] = POWER_SUPPLY_PROP_CURRENT_NOW;
+                       props[nprops++] = POWER_SUPPLY_PROP_CAPACITY;
+                       props[nprops++] = POWER_SUPPLY_PROP_CAPACITY_LEVEL;
+                       props[nprops++] = POWER_SUPPLY_PROP_TEMP;
+                       props[nprops++] = POWER_SUPPLY_PROP_CYCLE_COUNT;
+                       props[nprops++] = POWER_SUPPLY_PROP_HEALTH;
+                       props[nprops++] = POWER_SUPPLY_PROP_SCOPE;
+                       props[nprops++] = 
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
+                       props[nprops++] = 
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE;
+                       props[nprops++] = POWER_SUPPLY_PROP_TIME_TO_FULL_NOW;
+                       props[nprops++] = POWER_SUPPLY_PROP_CHARGE_FULL;
+                       props[nprops++] = POWER_SUPPLY_PROP_CHARGE_NOW;
+                       props[nprops++] = POWER_SUPPLY_PROP_ENERGY_FULL;
+                       props[nprops++] = POWER_SUPPLY_PROP_ENERGY_NOW;
+
+                       if (apple_smc_key_exists(smc, SMC_KEY(CHLS)))
+                               power->has_chls = true;
+                       if (power->has_chls || apple_smc_key_exists(smc, 
SMC_KEY(BCLM)))
+                               props[nprops++] = 
POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD;
+                       if (apple_smc_key_exists(smc, SMC_KEY(B0AP)))
+                               props[nprops++] = POWER_SUPPLY_PROP_POWER_NOW;
+                       if (apple_smc_key_exists(smc, SMC_KEY(B0TE)))
+                               props[nprops++] = 
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW;
+                       if (apple_smc_key_exists(smc, SMC_KEY(BITV)))
+                               props[nprops++] = 
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
+                       if (apple_smc_key_exists(smc, SMC_KEY(BCMV)))
+                               props[nprops++] = 
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
+
+                       if (apple_smc_key_exists(smc, SMC_KEY(BC3V)))
+                               power->num_cells = 3;
+                       else
+                               power->num_cells = 2;
+               } else {
+                       /* Fundamental properties */
+                       props[nprops++] = POWER_SUPPLY_PROP_STATUS;
+                       props[nprops++] = POWER_SUPPLY_PROP_PRESENT;
+                       props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_NOW;
+                       props[nprops++] = POWER_SUPPLY_PROP_CURRENT_NOW;
+                       props[nprops++] = POWER_SUPPLY_PROP_POWER_NOW;
+                       props[nprops++] = POWER_SUPPLY_PROP_CAPACITY;
+                       props[nprops++] = POWER_SUPPLY_PROP_CAPACITY_LEVEL;
+                       props[nprops++] = POWER_SUPPLY_PROP_TEMP;
+                       props[nprops++] = POWER_SUPPLY_PROP_CYCLE_COUNT;
+                       props[nprops++] = POWER_SUPPLY_PROP_HEALTH;
+                       props[nprops++] = POWER_SUPPLY_PROP_SCOPE;
+                       props[nprops++] = POWER_SUPPLY_PROP_MODEL_NAME;
+                       props[nprops++] = POWER_SUPPLY_PROP_SERIAL_NUMBER;
+                       props[nprops++] = POWER_SUPPLY_PROP_MANUFACTURE_YEAR;
+                       props[nprops++] = POWER_SUPPLY_PROP_MANUFACTURE_MONTH;
+                       props[nprops++] = POWER_SUPPLY_PROP_MANUFACTURE_DAY;
+
+                       /* Extended properties usually present */
+                       props[nprops++] = POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW;
+                       props[nprops++] = POWER_SUPPLY_PROP_TIME_TO_FULL_NOW;
+                       props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
+                       props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
+                       props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_MIN;
+                       props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_MAX;
+                       props[nprops++] = POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT;
+                       props[nprops++] = 
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
+                       props[nprops++] = 
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE;
+                       props[nprops++] = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
+                       props[nprops++] = POWER_SUPPLY_PROP_CHARGE_FULL;
+                       props[nprops++] = POWER_SUPPLY_PROP_CHARGE_NOW;
+                       props[nprops++] = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
+                       props[nprops++] = POWER_SUPPLY_PROP_ENERGY_FULL;
+                       props[nprops++] = POWER_SUPPLY_PROP_ENERGY_NOW;
+                       props[nprops++] = POWER_SUPPLY_PROP_CHARGE_COUNTER;
+
+                       /* Detect features based on key availability */
+                       if (apple_smc_key_exists(smc, SMC_KEY(CHTE)))
+                               power->has_chte = true;
+                       if (apple_smc_key_exists(smc, SMC_KEY(CH0C)))
+                               power->has_ch0c = true;
+                       if (apple_smc_key_exists(smc, SMC_KEY(CH0I)))
+                               power->has_ch0i = true;
+
+                       ret = apple_smc_get_key_info(power->smc, SMC_KEY(BCF0), 
&info);
+                       if (ret) {
+                               dev_err(&pdev->dev, "Failed to determine BCF0 
key size\n");
+                               return ret;
+                       }
+                       if (info.size == 1)
+                               power->fw_ge_27 = true;
+                       else if (info.size == 4)
+                               power->fw_ge_27 = false;
+                       else {
+                               dev_err(&pdev->dev, "Unexpected BCF0 key size 
%d\n", info.size);
+                               return -EIO;
+                       }
+
+                       /* Reset "Optimised Battery Charging" flags to default 
state */
+                       if (power->has_chte)
+                               apple_smc_write_u32(smc, SMC_KEY(CHTE), 0);
+                       else if (power->has_ch0c)
+                               apple_smc_write_u8(smc, SMC_KEY(CH0C), 0);
 
                        if (power->has_ch0i)
-                               power->batt_desc.charge_behaviours |=
-                                       
BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE);
-
-                       if (power->has_chte || power->has_ch0c)
-                               power->batt_desc.charge_behaviours |=
-                                       
BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE);
+                               apple_smc_write_u8(smc, SMC_KEY(CH0I), 0);
+
+                       apple_smc_write_u8(smc, SMC_KEY(CH0K), 0);
+                       apple_smc_write_u8(smc, SMC_KEY(CH0B), 0);
+
+                       /* Configure charge behaviour if supported */
+                       if (power->has_ch0i || power->has_ch0c || 
power->has_chte) {
+                               props[nprops++] = 
POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR;
+
+                               power->batt_desc.charge_behaviours =
+                                       BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO);
+
+                               if (power->has_ch0i)
+                                       power->batt_desc.charge_behaviours |=
+                                               
BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE);
+
+                               if (power->has_chte || power->has_ch0c)
+                                       power->batt_desc.charge_behaviours |=
+                                               
BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE);
+                       }
+
+                       /* Detect charge limit method (CHWA vs CHLS) */
+                       if (apple_smc_read_flag(power->smc, SMC_KEY(CHWA), 
&flag) == 0)
+                               power->has_chwa = true;
+                       else if (apple_smc_read_u16(power->smc, SMC_KEY(CHLS), 
&vu16) >= 0)
+                               power->has_chls = true;
+
+                       /* Fetch identity strings */
+                       apple_smc_read(smc, SMC_KEY(BMDN), power->model_name,
+                                      sizeof(power->model_name) - 1);
+                       apple_smc_read(smc, SMC_KEY(BMSN), power->serial_number,
+                                      sizeof(power->serial_number) - 1);
+                       apple_smc_read(smc, SMC_KEY(BMDT), power->mfg_date,
+                                      sizeof(power->mfg_date) - 1);
+
+                       apple_smc_read_u8(power->smc, SMC_KEY(BNCB), 
&power->num_cells);
+                       power->nominal_voltage_mv = 
MACSMC_NOMINAL_CELL_VOLTAGE_MV *
+                                                       power->num_cells;
+
+                       /* Enable critical shutdown notifications by reading 
status once */
+                       macsmc_battery_read_bcf0(power, &val32);
                }
-
-               /* Detect charge limit method (CHWA vs CHLS) */
-               if (apple_smc_read_flag(power->smc, SMC_KEY(CHWA), &flag) == 0)
-                       power->has_chwa = true;
-               else if (apple_smc_read_u16(power->smc, SMC_KEY(CHLS), &vu16) 
>= 0)
-                       power->has_chls = true;
-
                if (nprops > MACSMC_MAX_BATT_PROPS)
                        return -ENOMEM;
 
                power->batt_desc.properties = props;
                power->batt_desc.num_properties = nprops;
 
-               /* Fetch identity strings */
-               apple_smc_read(smc, SMC_KEY(BMDN), power->model_name,
-                              sizeof(power->model_name) - 1);
-               apple_smc_read(smc, SMC_KEY(BMSN), power->serial_number,
-                              sizeof(power->serial_number) - 1);
-               apple_smc_read(smc, SMC_KEY(BMDT), power->mfg_date,
-                              sizeof(power->mfg_date) - 1);
-
-               apple_smc_read_u8(power->smc, SMC_KEY(BNCB), &power->num_cells);
-               power->nominal_voltage_mv = MACSMC_NOMINAL_CELL_VOLTAGE_MV * 
power->num_cells;
-
-               /* Enable critical shutdown notifications by reading status 
once */
-               macsmc_battery_read_bcf0(power, &val32);
-
                psy_cfg.drv_data = power;
                power->batt = devm_power_supply_register(dev, 
&power->batt_desc, &psy_cfg);
                if (IS_ERR(power->batt)) {
@@ -829,16 +1257,27 @@ static int macsmc_power_probe(struct platform_device 
*pdev)
                /* Online status is fundamental */
                props[nprops++] = POWER_SUPPLY_PROP_ONLINE;
 
-               /* Input power limits are usually available */
-               if (apple_smc_key_exists(power->smc, SMC_KEY(ACPW)))
-                       props[nprops++] = POWER_SUPPLY_PROP_INPUT_POWER_LIMIT;
-
-               /* macOS 15.4+ firmware dropped legacy AC keys (AC-n, AC-i) */
-               if (apple_smc_read_u16(power->smc, SMC_KEY(AC-n), &vu16) >= 0) {
-                       props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_NOW;
-                       props[nprops++] = POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT;
+               if (smc->is_acpi) {
+                       props[nprops++] = POWER_SUPPLY_PROP_CURRENT_NOW;
+                       props[nprops++] = POWER_SUPPLY_PROP_POWER_NOW;
+                       if (apple_smc_key_exists(power->smc, SMC_KEY(PD0R)))
+                               power->has_pd0r = true;
+                       /* MacBookPro5,x and 7,x dosent have VD0R key or any 
equivalent */
+                       if (!power->has_battery || 
apple_smc_key_exists(power->smc, SMC_KEY(VD0R)))
+                               props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_NOW;
+                       if (apple_smc_key_exists(power->smc, SMC_KEY(ACPW)))
+                               props[nprops++] = 
POWER_SUPPLY_PROP_INPUT_POWER_LIMIT;
+               } else {
+                       /* Input power limits are usually available */
+                       if (apple_smc_key_exists(power->smc, SMC_KEY(ACPW)))
+                               props[nprops++] = 
POWER_SUPPLY_PROP_INPUT_POWER_LIMIT;
+
+                       /* macOS 15.4+ firmware dropped legacy AC keys (AC-n, 
AC-i) */
+                       if (apple_smc_read_u16(power->smc, SMC_KEY(AC-n), 
&vu16) >= 0) {
+                               props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_NOW;
+                               props[nprops++] = 
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT;
+                       }
                }
-
                if (nprops > MACSMC_MAX_AC_PROPS)
                        return -ENOMEM;
 
@@ -858,9 +1297,26 @@ static int macsmc_power_probe(struct platform_device 
*pdev)
        if (!power->batt && !power->ac)
                return -ENODEV;
 
-       power->nb.notifier_call = macsmc_power_event;
-       blocking_notifier_chain_register(smc->event_handlers, &power->nb);
+       if (!smc->is_acpi) {
+               power->nb.notifier_call = macsmc_power_event;
+               blocking_notifier_chain_register(smc->event_handlers, 
&power->nb);
+       } else if (power->has_battery) {
+               power->adapter = acpi_dev_get_first_match_dev("ACPI0003", NULL, 
-1);
+               if (!power->adapter)
+                       return -ENODEV;
 
+               ret = acpi_dev_install_notify_handler(power->adapter, 
ACPI_DEVICE_NOTIFY,
+                                       macsmc_power_acpi_notify, power);
+               if (ret)
+                       return ret;
+
+               acpi_status status = 
acpi_evaluate_integer(power->adapter->handle, "_PSR", NULL,
+                                       &power->adapter_status);
+               if (ACPI_FAILURE(status))
+                       return -EIO;
+
+               power->adapter_status = !!power->adapter_status;
+       }
        return 0;
 }
 
@@ -868,7 +1324,11 @@ static void macsmc_power_remove(struct platform_device 
*pdev)
 {
        struct macsmc_power *power = dev_get_drvdata(&pdev->dev);
 
-       blocking_notifier_chain_unregister(power->smc->event_handlers, 
&power->nb);
+       if (!power->smc->is_acpi)
+               blocking_notifier_chain_unregister(power->smc->event_handlers, 
&power->nb);
+       else
+               acpi_dev_remove_notify_handler(power->adapter, 
ACPI_DEVICE_NOTIFY,
+                               macsmc_power_acpi_notify);
 }
 
 static const struct platform_device_id macsmc_power_id[] = {
@@ -891,3 +1351,4 @@ MODULE_LICENSE("Dual MIT/GPL");
 MODULE_DESCRIPTION("Apple SMC battery and power management driver");
 MODULE_AUTHOR("Hector Martin <[email protected]>");
 MODULE_AUTHOR("Michael Reeves <[email protected]>");
+MODULE_ALIAS("platform:macsmc-power");
-- 
2.55.0


Reply via email to