* [PATCH v2] power: supply: macsmc: Support macOS 27 SMC firmware
@ 2026-06-12 18:36 Sasha Finkelstein
2026-06-12 19:33 ` Janne Grunau
2026-06-12 19:53 ` Joshua Peisach
0 siblings, 2 replies; 5+ messages in thread
From: Sasha Finkelstein @ 2026-06-12 18:36 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Neal Gompa, Sebastian Reichel
Cc: asahi, linux-arm-kernel, linux-pm, linux-kernel,
Sasha Finkelstein
The SMC firmware included in macOS 27 changed the size of BCF0 key from
4 to 1 bytes. This key is used for indicating that battery state is
critically low.
Reviewed-by: Sven Peter <sven@kernel.org>
Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
---
Changes in v2:
- Addressing review feedback
- Link to v1: https://patch.msgid.link/20260611-gate-power-v1-1-8a62721086c7@chaosmail.tech
---
drivers/power/supply/macsmc-power.c | 35 ++++++++++++++++++++++++++++++++---
1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/drivers/power/supply/macsmc-power.c b/drivers/power/supply/macsmc-power.c
index 33ca07460f3a..747315e372bc 100644
--- a/drivers/power/supply/macsmc-power.c
+++ b/drivers/power/supply/macsmc-power.c
@@ -86,6 +86,7 @@ struct macsmc_power {
bool has_ch0i; /* Force discharge (Older firmware) */
bool has_ch0c; /* Inhibit charge (Older firmware) */
bool has_chte; /* Inhibit charge (Modern firmware) */
+ bool bcf0_1byte; /* Battery critical key is 1 byte (Modern firmware) */
u8 num_cells;
int nominal_voltage_mv;
@@ -273,6 +274,19 @@ static int macsmc_battery_get_date(const char *s, int *out)
return 0;
}
+static int macsmc_battery_read_bcf0(struct macsmc_power *power, u32 *val)
+{
+ u8 tval = 0;
+ int ret;
+
+ if (!power->bcf0_1byte)
+ return apple_smc_read_u32(power->smc, SMC_KEY(BCF0), val);
+
+ ret = apple_smc_read_u8(power->smc, SMC_KEY(BCF0), &tval);
+ *val = tval;
+ return ret;
+}
+
static int macsmc_battery_get_capacity_level(struct macsmc_power *power)
{
bool flag;
@@ -280,7 +294,7 @@ static int macsmc_battery_get_capacity_level(struct macsmc_power *power)
int ret;
/* Check for emergency shutdown condition */
- if (apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &val) >= 0 && val)
+ if (macsmc_battery_read_bcf0(power, &val) >= 0 && val)
return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
/* Check AC status for whether we could boot in this state */
@@ -577,7 +591,7 @@ static void macsmc_power_critical_work(struct work_struct *wrk)
* Check if SMC flagged the battery as empty.
* We trigger a graceful shutdown to let the OS save data.
*/
- if (apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &bcf0) == 0 && bcf0 != 0) {
+ if (macsmc_battery_read_bcf0(power, &bcf0) == 0 && bcf0 != 0) {
power->orderly_shutdown_triggered = true;
dev_crit(power->dev, "Battery critical (empty flag set). Triggering orderly shutdown.\n");
orderly_poweroff(true);
@@ -616,6 +630,7 @@ static int macsmc_power_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent);
struct power_supply_config psy_cfg = {};
+ struct apple_smc_key_info info;
struct macsmc_power *power;
bool has_battery = false;
bool has_ac_adapter = false;
@@ -714,6 +729,20 @@ static int macsmc_power_probe(struct platform_device *pdev)
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->bcf0_1byte = true;
+ else if (info.size == 4)
+ power->bcf0_1byte = 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);
@@ -766,7 +795,7 @@ static int macsmc_power_probe(struct platform_device *pdev)
power->nominal_voltage_mv = MACSMC_NOMINAL_CELL_VOLTAGE_MV * power->num_cells;
/* Enable critical shutdown notifications by reading status once */
- apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &val32);
+ macsmc_battery_read_bcf0(power, &val32);
psy_cfg.drv_data = power;
power->batt = devm_power_supply_register(dev, &power->batt_desc, &psy_cfg);
---
base-commit: 9716c086c8e8b141d35aa61f2e96a2e83de212a7
change-id: 20260611-gate-power-cfd726dc0d7f
Best regards,
--
Sasha Finkelstein <k@chaosmail.tech>
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2] power: supply: macsmc: Support macOS 27 SMC firmware
2026-06-12 18:36 [PATCH v2] power: supply: macsmc: Support macOS 27 SMC firmware Sasha Finkelstein
@ 2026-06-12 19:33 ` Janne Grunau
2026-06-12 19:42 ` Sasha Finkelstein
2026-06-12 19:53 ` Joshua Peisach
1 sibling, 1 reply; 5+ messages in thread
From: Janne Grunau @ 2026-06-12 19:33 UTC (permalink / raw)
To: Sasha Finkelstein
Cc: Sven Peter, Neal Gompa, Sebastian Reichel, asahi,
linux-arm-kernel, linux-pm, linux-kernel
On Fri, Jun 12, 2026 at 08:36:03PM +0200, Sasha Finkelstein wrote:
> The SMC firmware included in macOS 27 changed the size of BCF0 key from
> 4 to 1 bytes. This key is used for indicating that battery state is
> critically low.
>
> Reviewed-by: Sven Peter <sven@kernel.org>
> Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
I think
Fixes: 0ebf821cf6c7 ("power: supply: Add macsmc-power driver for Apple Silicon")
and "Cc: stable" could be justified. Timing is a little unfortunate with
v7.1 expected on sunday.
> ---
> Changes in v2:
> - Addressing review feedback
> - Link to v1: https://patch.msgid.link/20260611-gate-power-v1-1-8a62721086c7@chaosmail.tech
> ---
> drivers/power/supply/macsmc-power.c | 35 ++++++++++++++++++++++++++++++++---
> 1 file changed, 32 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/power/supply/macsmc-power.c b/drivers/power/supply/macsmc-power.c
> index 33ca07460f3a..747315e372bc 100644
> --- a/drivers/power/supply/macsmc-power.c
> +++ b/drivers/power/supply/macsmc-power.c
> @@ -86,6 +86,7 @@ struct macsmc_power {
> bool has_ch0i; /* Force discharge (Older firmware) */
> bool has_ch0c; /* Inhibit charge (Older firmware) */
> bool has_chte; /* Inhibit charge (Modern firmware) */
> + bool bcf0_1byte; /* Battery critical key is 1 byte (Modern firmware) */
>
> u8 num_cells;
> int nominal_voltage_mv;
> @@ -273,6 +274,19 @@ static int macsmc_battery_get_date(const char *s, int *out)
> return 0;
> }
>
> +static int macsmc_battery_read_bcf0(struct macsmc_power *power, u32 *val)
> +{
> + u8 tval = 0;
> + int ret;
> +
> + if (!power->bcf0_1byte)
> + return apple_smc_read_u32(power->smc, SMC_KEY(BCF0), val);
> +
> + ret = apple_smc_read_u8(power->smc, SMC_KEY(BCF0), &tval);
> + *val = tval;
> + return ret;
> +}
I think the following is slightly easier to read
{
if (power->bcf0_1byte) {
u8 tval = 0;
int ret = apple_smc_read_u8(power->smc, SMC_KEY(BCF0), &tval);
*val = tval;
return ret;
}
return apple_smc_read_u32(power->smc, SMC_KEY(BCF0), val);
}
Not worth a respin in itself but worthwhile if there's a v3 for the the
Fixes: tag.
> +
> static int macsmc_battery_get_capacity_level(struct macsmc_power *power)
> {
> bool flag;
> @@ -280,7 +294,7 @@ static int macsmc_battery_get_capacity_level(struct macsmc_power *power)
> int ret;
>
> /* Check for emergency shutdown condition */
> - if (apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &val) >= 0 && val)
> + if (macsmc_battery_read_bcf0(power, &val) >= 0 && val)
> return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
>
> /* Check AC status for whether we could boot in this state */
> @@ -577,7 +591,7 @@ static void macsmc_power_critical_work(struct work_struct *wrk)
> * Check if SMC flagged the battery as empty.
> * We trigger a graceful shutdown to let the OS save data.
> */
> - if (apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &bcf0) == 0 && bcf0 != 0) {
> + if (macsmc_battery_read_bcf0(power, &bcf0) == 0 && bcf0 != 0) {
> power->orderly_shutdown_triggered = true;
> dev_crit(power->dev, "Battery critical (empty flag set). Triggering orderly shutdown.\n");
> orderly_poweroff(true);
> @@ -616,6 +630,7 @@ static int macsmc_power_probe(struct platform_device *pdev)
> struct device *dev = &pdev->dev;
> struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent);
> struct power_supply_config psy_cfg = {};
> + struct apple_smc_key_info info;
> struct macsmc_power *power;
> bool has_battery = false;
> bool has_ac_adapter = false;
> @@ -714,6 +729,20 @@ static int macsmc_power_probe(struct platform_device *pdev)
> 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->bcf0_1byte = true;
> + else if (info.size == 4)
> + power->bcf0_1byte = 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);
> @@ -766,7 +795,7 @@ static int macsmc_power_probe(struct platform_device *pdev)
> power->nominal_voltage_mv = MACSMC_NOMINAL_CELL_VOLTAGE_MV * power->num_cells;
>
> /* Enable critical shutdown notifications by reading status once */
> - apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &val32);
> + macsmc_battery_read_bcf0(power, &val32);
>
> psy_cfg.drv_data = power;
> power->batt = devm_power_supply_register(dev, &power->batt_desc, &psy_cfg);
>
> ---
Reviewed-by: Janne Grunau <j@jannau.net>
thanks
Janne
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] power: supply: macsmc: Support macOS 27 SMC firmware
2026-06-12 19:33 ` Janne Grunau
@ 2026-06-12 19:42 ` Sasha Finkelstein
2026-06-12 19:56 ` Janne Grunau
0 siblings, 1 reply; 5+ messages in thread
From: Sasha Finkelstein @ 2026-06-12 19:42 UTC (permalink / raw)
To: Janne Grunau
Cc: Sven Peter, Neal Gompa, Sebastian Reichel, asahi,
linux-arm-kernel, linux-pm, linux-kernel
> On Jun 12, 2026, at 21:33, Janne Grunau <j@jannau.net> wrote:
>
> I think the following is slightly easier to read
>
> {
> if (power->bcf0_1byte) {
> u8 tval = 0;
> int ret = apple_smc_read_u8(power->smc, SMC_KEY(BCF0), &tval);
> *val = tval;
> return ret;
> }
>
> return apple_smc_read_u32(power->smc, SMC_KEY(BCF0), val);
> }
I personally prefer using early returns as much as possible, as it makes
it easier for me to read in linear order and due to line length reasons.
But no strong opinion either way.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] power: supply: macsmc: Support macOS 27 SMC firmware
2026-06-12 18:36 [PATCH v2] power: supply: macsmc: Support macOS 27 SMC firmware Sasha Finkelstein
2026-06-12 19:33 ` Janne Grunau
@ 2026-06-12 19:53 ` Joshua Peisach
1 sibling, 0 replies; 5+ messages in thread
From: Joshua Peisach @ 2026-06-12 19:53 UTC (permalink / raw)
To: Sasha Finkelstein, Sven Peter, Janne Grunau, Neal Gompa,
Sebastian Reichel
Cc: asahi, linux-arm-kernel, linux-pm, linux-kernel
On Fri Jun 12, 2026 at 2:36 PM EDT, Sasha Finkelstein wrote:
> The SMC firmware included in macOS 27 changed the size of BCF0 key from
> 4 to 1 bytes. This key is used for indicating that battery state is
> critically low.
>
> Reviewed-by: Sven Peter <sven@kernel.org>
> Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
> ---
> Changes in v2:
> - Addressing review feedback
> - Link to v1: https://patch.msgid.link/20260611-gate-power-v1-1-8a62721086c7@chaosmail.tech
> ---
> drivers/power/supply/macsmc-power.c | 35 ++++++++++++++++++++++++++++++++---
> 1 file changed, 32 insertions(+), 3 deletions(-)
>
Reviewed-by: Joshua Peisach <jpeisach@ubuntu.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] power: supply: macsmc: Support macOS 27 SMC firmware
2026-06-12 19:42 ` Sasha Finkelstein
@ 2026-06-12 19:56 ` Janne Grunau
0 siblings, 0 replies; 5+ messages in thread
From: Janne Grunau @ 2026-06-12 19:56 UTC (permalink / raw)
To: Sasha Finkelstein
Cc: Sven Peter, Neal Gompa, Sebastian Reichel, asahi,
linux-arm-kernel, linux-pm, linux-kernel
On Fri, Jun 12, 2026 at 09:42:12PM +0200, Sasha Finkelstein wrote:
>
> > On Jun 12, 2026, at 21:33, Janne Grunau <j@jannau.net> wrote:
> >
> > I think the following is slightly easier to read
> >
> > {
> > if (power->bcf0_1byte) {
> > u8 tval = 0;
> > int ret = apple_smc_read_u8(power->smc, SMC_KEY(BCF0), &tval);
> > *val = tval;
> > return ret;
> > }
> >
> > return apple_smc_read_u32(power->smc, SMC_KEY(BCF0), val);
> > }
>
> I personally prefer using early returns as much as possible, as it makes
> it easier for me to read in linear order and due to line length reasons.
> But no strong opinion either way.
I don't disagree in general but in this case the code inside the 4 lines
inside the if are not much more complex than the early return. It
limits the scope of the local variables and avois a not on the
condition.
I can live with either version and the strength of my opinion will be
depleted by writing this reply.
Janne
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-06-12 19:56 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-12 18:36 [PATCH v2] power: supply: macsmc: Support macOS 27 SMC firmware Sasha Finkelstein
2026-06-12 19:33 ` Janne Grunau
2026-06-12 19:42 ` Sasha Finkelstein
2026-06-12 19:56 ` Janne Grunau
2026-06-12 19:53 ` Joshua Peisach
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox