From nobody Sun Feb 8 14:59:43 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BBFBF3431F5; Mon, 5 Jan 2026 12:56:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767617807; cv=none; b=EcHWlRtToxq5bgYpkK9dh4QPFQfgMtHW/gJ1NodH3QQRV3u85O5Ap2HvDGqE8GVprvn6cwzGLyUCLWbJ0FFjMCAb5qvW0iOPi9MrYzv5H/6W+kiXdJy31RupXn+rOG5CQCEfpu4LxtBg+/zw73jz7yMuIGimKQeycAj43E6NUR4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767617807; c=relaxed/simple; bh=ISxie3OV52JevMKlRh2xw6FFKWCvl8p3z0hNgCDjeVc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Hq5/ZcUtRVBk7BfRCfCyJ8nLVRIUFcds6oyBuqSv8h5kRtybzR8uLXW3nE3ZZRu2fSUg34T2CmE6p9e56GccwI7Y5jX18vNmznTmkE6f9+SRykn40h7XfG6eBH5ynonBAznvH1OFxEQtnjGIDdAMzkjq5ZX6VR2PNIuEhkk/kg8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=qptgPEsp; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="qptgPEsp" Received: by smtp.kernel.org (Postfix) with ESMTPS id 5BC13C16AAE; Mon, 5 Jan 2026 12:56:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1767617807; bh=ISxie3OV52JevMKlRh2xw6FFKWCvl8p3z0hNgCDjeVc=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=qptgPEsppprFLs3YxxwuOswZiXHGrQ4Mf+nxK8HT/MPJ+PWEjsnzHPqbaiuNuvYGg lm2zZfuIRuBp2Qh6OMyu+hjjTm3QhqM7dUCCZtjV8U2XkSePowslgC9STaSmHnzur3 gI5/LBfST9ApmOPKPbVgfAraU0nqQAc6ZvtJUyGi1CgZxQyhG7JFQb6RhD/JFQOt6+ Vr48gOb+g67dfZ5+clW+JsdvGSkghHTePGD4dt1uyewY/oU+RSOpN47KTD0fN34q1g Mvv9+n3ZO9DVtoVXOJeo/XLylvnsl7Vsfd/TjcjPx4ezKJtQ5l4ISrbIX2dMKITKgG NoeXNvr+fmHoQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4B399C79F8B; Mon, 5 Jan 2026 12:56:47 +0000 (UTC) From: Michael Reeves via B4 Relay Date: Mon, 05 Jan 2026 23:56:36 +1100 Subject: [PATCH 1/2] power: supply: Add macsmc-power driver for Apple Silicon Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260105-b4-macsmc-power-v1-1-62954c42a555@gmail.com> References: <20260105-b4-macsmc-power-v1-0-62954c42a555@gmail.com> In-Reply-To: <20260105-b4-macsmc-power-v1-0-62954c42a555@gmail.com> To: Sebastian Reichel , Sven Peter , Janne Grunau , Neal Gompa , Lee Jones Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, asahi@lists.linux.dev, linux-arm-kernel@lists.infradead.org, Michael Reeves , Hector Martin X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1767617806; l=30958; i=michael.reeves077@gmail.com; s=20260105; h=from:subject:message-id; bh=ddh3NlioMQq32EwSjo8NHw/vhbKzdHll+pHt6/HwmqA=; b=Bm5b+KN0XnTG0tHLYPJO09RabFvWhvFNrEFSp4mzbH7e2UalxZz+jbKqPYj4khqN5lJc0NTQh vVpFj+eEzuTCkSjDvRLR0Ke6X3iPh5IbCuitOXpvfk1xyz0momVlcnP X-Developer-Key: i=michael.reeves077@gmail.com; a=ed25519; pk=QIrgWBGCm3LG0YYc6MLCDkwuVXLTGGooVBdWX/KhSiU= X-Endpoint-Received: by B4 Relay for michael.reeves077@gmail.com/20260105 with auth_id=591 X-Original-From: Michael Reeves Reply-To: michael.reeves077@gmail.com From: Michael Reeves This driver provides battery and AC status monitoring for Apple Silicon Macs via the SMC (System Management Controller). It supports reporting capacity, voltage, current, and charging status. Co-developed-by: Hector Martin Signed-off-by: Hector Martin Signed-off-by: Michael Reeves Reviewed-by: Neal Gompa --- MAINTAINERS | 1 + drivers/power/supply/Kconfig | 11 + drivers/power/supply/Makefile | 1 + drivers/power/supply/macsmc-power.c | 872 ++++++++++++++++++++++++++++++++= ++++ 4 files changed, 885 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0dbf349fc1ed..c18da2295477 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2507,6 +2507,7 @@ F: drivers/nvmem/apple-efuses.c F: drivers/nvmem/apple-spmi-nvmem.c F: drivers/pinctrl/pinctrl-apple-gpio.c F: drivers/power/reset/macsmc-reboot.c +F: drivers/power/supply/macsmc-power.c F: drivers/pwm/pwm-apple.c F: drivers/rtc/rtc-macsmc.c F: drivers/soc/apple/* diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 92f9f7aae92f..3a5b7d9234c2 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -1132,4 +1132,15 @@ config FUEL_GAUGE_MM8013 the state of charge, temperature, cycle count, actual and design capacity, etc. =20 +config MACSMC_POWER + tristate "Apple SMC Battery and Power Driver" + depends on MFD_MACSMC + help + This driver provides support for the battery and AC adapter on + Apple Silicon machines. It exposes battery telemetry (voltage, + current, health) and AC adapter status through the standard Linux + power supply framework. + + Say Y or M here if you have an Apple Silicon based Mac. + endif # POWER_SUPPLY diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 4b79d5abc49a..f5333096f0c3 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -128,3 +128,4 @@ obj-$(CONFIG_CHARGER_SURFACE) +=3D surface_charger.o obj-$(CONFIG_BATTERY_UG3105) +=3D ug3105_battery.o obj-$(CONFIG_CHARGER_QCOM_SMB2) +=3D qcom_smbx.o obj-$(CONFIG_FUEL_GAUGE_MM8013) +=3D mm8013.o +obj-$(CONFIG_MACSMC_POWER) +=3D macsmc-power.o diff --git a/drivers/power/supply/macsmc-power.c b/drivers/power/supply/mac= smc-power.c new file mode 100644 index 000000000000..def9b12118c2 --- /dev/null +++ b/drivers/power/supply/macsmc-power.c @@ -0,0 +1,872 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple SMC Power/Battery Management Driver + * + * This driver exposes battery telemetry (voltage, current, temperature, h= ealth) + * and AC adapter status provided by the Apple SMC (System Management Cont= roller) + * on Apple Silicon systems. + * + * Copyright The Asahi Linux Contributors + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_STRING_LENGTH 256 + +/* + * The SMC reports charge in mAh (Coulombs) but energy in mWh (Joules). + * We lack a register for "Nominal Voltage" or "Energy Accumulator". + * We use a fixed 3.8V/cell constant to approximate energy stats for users= pace, + * derived from empirical data across supported MacBook models. + */ +#define MACSMC_NOMINAL_CELL_VOLTAGE_MV 3800 + +/* SMC Key Flags */ +#define CHNC_BATTERY_FULL BIT(0) +#define CHNC_NO_CHARGER BIT(7) +#define CHNC_NOCHG_CH0C BIT(14) +#define CHNC_NOCHG_CH0B_CH0K BIT(15) +#define CHNC_BATTERY_FULL_2 BIT(18) +#define CHNC_BMS_BUSY BIT(23) +#define CHNC_CHLS_LIMIT BIT(24) +#define CHNC_NOAC_CH0J BIT(53) +#define CHNC_NOAC_CH0I BIT(54) + +#define CH0R_LOWER_FLAGS GENMASK(15, 0) +#define CH0R_NOAC_CH0I BIT(0) +#define CH0R_NOAC_DISCONNECTED BIT(4) +#define CH0R_NOAC_CH0J BIT(5) +#define CH0R_BMS_BUSY BIT(8) +#define CH0R_NOAC_CH0K BIT(9) +#define CH0R_NOAC_CHWA BIT(11) + +#define CH0X_CH0C BIT(0) +#define CH0X_CH0B BIT(1) + +#define ACSt_CAN_BOOT_AP BIT(2) +#define ACSt_CAN_BOOT_IBOOT BIT(1) + +#define CHWA_CHLS_FIXED_START_OFFSET 5 +#define CHLS_MIN_END_THRESHOLD 10 +#define CHLS_FORCE_DISCHARGE 0x100 +#define CHWA_FIXED_END_THRESHOLD 80 +#define CHWA_PROP_WRITE_THRESHOLD 95 + +#define MACSMC_MAX_BATT_PROPS 50 +#define MACSMC_MAX_AC_PROPS 10 + +struct macsmc_power { + struct device *dev; + struct apple_smc *smc; + + struct power_supply_desc ac_desc; + struct power_supply_desc batt_desc; + + enum power_supply_property *ac_props; + enum power_supply_property *batt_props; + + struct power_supply *batt; + struct power_supply *ac; + + char model_name[MAX_STRING_LENGTH]; + char serial_number[MAX_STRING_LENGTH]; + char mfg_date[MAX_STRING_LENGTH]; + + bool has_chwa; + bool has_chls; + bool has_ch0i; + bool has_ch0c; + bool has_chte; + + u8 num_cells; + int nominal_voltage_mv; + + struct notifier_block nb; + struct work_struct critical_work; + bool shutdown_started; +}; + +static int macsmc_battery_get_status(struct macsmc_power *power) +{ + u64 nocharge_flags; + u32 nopower_flags; + u16 ac_current; + int charge_limit =3D 0; + bool limited =3D false; + bool flag; + int ret; + + /* + * Fallbacks exist for keys that may disappear in future hardware. + * CHCE/CHCC/BSFC/CHSC are considered fundamental; absence is an error. + */ + + /* Check if power input is inhibited (e.g. BMS balancing cycle) */ + ret =3D apple_smc_read_u32(power->smc, SMC_KEY(CH0R), &nopower_flags); + if (!ret && (nopower_flags & CH0R_LOWER_FLAGS & ~CH0R_BMS_BUSY)) + return POWER_SUPPLY_STATUS_DISCHARGING; + + /* Check if charger is present */ + ret =3D apple_smc_read_flag(power->smc, SMC_KEY(CHCE), &flag); + if (ret < 0) + return ret; + if (!flag) + return POWER_SUPPLY_STATUS_DISCHARGING; + + /* Check if AC is charge capable */ + ret =3D apple_smc_read_flag(power->smc, SMC_KEY(CHCC), &flag); + if (ret < 0) + return ret; + if (!flag) + return POWER_SUPPLY_STATUS_DISCHARGING; + + /* Check if AC input limit is too low */ + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(AC-i), &ac_current); + if (!ret && ac_current < 100) + return POWER_SUPPLY_STATUS_DISCHARGING; + + /* Check if battery is full */ + ret =3D apple_smc_read_flag(power->smc, SMC_KEY(BSFC), &flag); + if (ret < 0) + return ret; + if (flag) + return POWER_SUPPLY_STATUS_FULL; + + /* Check for user-defined charge limits */ + if (power->has_chls) { + u16 vu16; + + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(CHLS), &vu16); + if (ret =3D=3D 0 && (vu16 & 0xff) >=3D CHLS_MIN_END_THRESHOLD) + charge_limit =3D (vu16 & 0xff) - CHWA_CHLS_FIXED_START_OFFSET; + } else if (power->has_chwa) { + ret =3D apple_smc_read_flag(power->smc, SMC_KEY(CHWA), &flag); + if (ret =3D=3D 0 && flag) + charge_limit =3D CHWA_FIXED_END_THRESHOLD - CHWA_CHLS_FIXED_START_OFFSE= T; + } + + if (charge_limit > 0) { + u8 buic =3D 0; + + if (apple_smc_read_u8(power->smc, SMC_KEY(BUIC), &buic) >=3D 0 && + buic >=3D charge_limit) + limited =3D true; + } + + /* Check charging inhibitors */ + ret =3D apple_smc_read_u64(power->smc, SMC_KEY(CHNC), &nocharge_flags); + if (!ret) { + if (nocharge_flags & CHNC_BATTERY_FULL) + return POWER_SUPPLY_STATUS_FULL; + /* BMS busy shows up as inhibit, but we treat it as charging */ + else if (nocharge_flags =3D=3D CHNC_BMS_BUSY && !limited) + return POWER_SUPPLY_STATUS_CHARGING; + else if (nocharge_flags) + return POWER_SUPPLY_STATUS_NOT_CHARGING; + else + return POWER_SUPPLY_STATUS_CHARGING; + } + + /* Fallback: System charging flag */ + ret =3D apple_smc_read_flag(power->smc, SMC_KEY(CHSC), &flag); + if (ret < 0) + return ret; + if (!flag) + return POWER_SUPPLY_STATUS_NOT_CHARGING; + + return POWER_SUPPLY_STATUS_CHARGING; +} + +static int macsmc_battery_get_charge_behaviour(struct macsmc_power *power) +{ + int ret; + u8 val8; + u8 chte_buf[4]; + + if (power->has_ch0i) { + ret =3D apple_smc_read_u8(power->smc, SMC_KEY(CH0I), &val8); + if (ret) + return ret; + if (val8 & CH0R_NOAC_CH0I) + return POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE; + } + + if (power->has_chte) { + ret =3D apple_smc_read(power->smc, SMC_KEY(CHTE), chte_buf, 4); + if (ret < 0) + return ret; + + if (chte_buf[0] =3D=3D 0x01) + return POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; + } else if (power->has_ch0c) { + ret =3D apple_smc_read_u8(power->smc, SMC_KEY(CH0C), &val8); + if (ret) + return ret; + if (val8 & CH0X_CH0C) + return POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; + } + + return POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO; +} + +static int macsmc_battery_set_charge_behaviour(struct macsmc_power *power,= int val) +{ + int ret; + + /* First, reset all inhibitors to a known-good 'auto' state */ + if (power->has_ch0i) { + ret =3D apple_smc_write_u8(power->smc, SMC_KEY(CH0I), 0); + if (ret) + return ret; + } + + if (power->has_chte) { + ret =3D apple_smc_write_u32(power->smc, SMC_KEY(CHTE), 0); + if (ret) + return ret; + } else if (power->has_ch0c) { + ret =3D apple_smc_write_u8(power->smc, SMC_KEY(CH0C), 0); + if (ret) + return ret; + } + + switch (val) { + case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO: + return 0; + + case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE: + if (power->has_chte) + return apple_smc_write_u32(power->smc, SMC_KEY(CHTE), 1); + else if (power->has_ch0c) + return apple_smc_write_u8(power->smc, SMC_KEY(CH0C), 1); + else + return -EOPNOTSUPP; + break; + + case POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE: + if (!power->has_ch0i) + return -EOPNOTSUPP; + return apple_smc_write_u8(power->smc, SMC_KEY(CH0I), 1); + + default: + return -EINVAL; + } +} + +static int macsmc_battery_get_date(const char *s, int *out) +{ + if (!isdigit(s[0]) || !isdigit(s[1])) + return -EOPNOTSUPP; + + *out =3D (s[0] - '0') * 10 + s[1] - '0'; + return 0; +} + +static int macsmc_battery_get_capacity_level(struct macsmc_power *power) +{ + bool flag; + u32 val; + int ret; + + /* Check for emergency shutdown condition */ + if (apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &val) >=3D 0 && val) + return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; + + /* Check AC status for whether we could boot in this state */ + if (apple_smc_read_u32(power->smc, SMC_KEY(ACSt), &val) >=3D 0) { + if (!(val & ACSt_CAN_BOOT_IBOOT)) + return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; + + if (!(val & ACSt_CAN_BOOT_AP)) + return POWER_SUPPLY_CAPACITY_LEVEL_LOW; + } + + ret =3D apple_smc_read_flag(power->smc, SMC_KEY(BSFC), &flag); + if (ret < 0) + return POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; + + if (flag) + return POWER_SUPPLY_CAPACITY_LEVEL_FULL; + else + return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; +} + +static int macsmc_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct macsmc_power *power =3D power_supply_get_drvdata(psy); + int ret =3D 0; + u8 vu8; + u16 vu16; + s16 vs16; + s32 vs32; + s64 vs64; + bool flag; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval =3D macsmc_battery_get_status(power); + ret =3D val->intval < 0 ? val->intval : 0; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval =3D 1; + break; + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: + val->intval =3D macsmc_battery_get_charge_behaviour(power); + ret =3D val->intval < 0 ? val->intval : 0; + break; + case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(B0TE), &vu16); + val->intval =3D vu16 =3D=3D 0xffff ? 0 : vu16 * 60; + break; + case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(B0TF), &vu16); + val->intval =3D vu16 =3D=3D 0xffff ? 0 : vu16 * 60; + break; + case POWER_SUPPLY_PROP_CAPACITY: + ret =3D apple_smc_read_u8(power->smc, SMC_KEY(BUIC), &vu8); + val->intval =3D vu8; + break; + case POWER_SUPPLY_PROP_CAPACITY_LEVEL: + val->intval =3D macsmc_battery_get_capacity_level(power); + ret =3D val->intval < 0 ? val->intval : 0; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(B0AV), &vu16); + val->intval =3D vu16 * 1000; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + ret =3D apple_smc_read_s16(power->smc, SMC_KEY(B0AC), &vs16); + val->intval =3D vs16 * 1000; + break; + case POWER_SUPPLY_PROP_POWER_NOW: + ret =3D apple_smc_read_s32(power->smc, SMC_KEY(B0AP), &vs32); + val->intval =3D vs32 * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(BITV), &vu16); + val->intval =3D vu16 * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + /* Calculate total max design voltage from per-cell nominal voltage */ + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(BVVN), &vu16); + val->intval =3D vu16 * 1000 * power->num_cells; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + /* Lifetime min */ + ret =3D apple_smc_read_s16(power->smc, SMC_KEY(BLPM), &vs16); + val->intval =3D vs16 * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + /* Lifetime max */ + ret =3D apple_smc_read_s16(power->smc, SMC_KEY(BLPX), &vs16); + val->intval =3D vs16 * 1000; + break; + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(B0RC), &vu16); + val->intval =3D vu16 * 1000; + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(B0RI), &vu16); + val->intval =3D vu16 * 1000; + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(B0RV), &vu16); + val->intval =3D vu16 * 1000; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(B0DC), &vu16); + val->intval =3D vu16 * 1000; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(B0FC), &vu16); + val->intval =3D vu16 * 1000; + break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(B0RM), &vu16); + /* B0RM is Big Endian, likely pass through from TI gas gauge */ + val->intval =3D (s16)swab16(vu16) * 1000; + break; + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(B0DC), &vu16); + val->intval =3D vu16 * power->nominal_voltage_mv; + break; + case POWER_SUPPLY_PROP_ENERGY_FULL: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(B0FC), &vu16); + val->intval =3D vu16 * power->nominal_voltage_mv; + break; + case POWER_SUPPLY_PROP_ENERGY_NOW: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(B0RM), &vu16); + /* B0RM is Big Endian, likely pass through from TI gas gauge */ + val->intval =3D (s16)swab16(vu16) * power->nominal_voltage_mv; + break; + case POWER_SUPPLY_PROP_TEMP: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(B0AT), &vu16); + val->intval =3D vu16 - 2732; /* Kelvin x10 to Celsius x10 */ + break; + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + ret =3D apple_smc_read_s64(power->smc, SMC_KEY(BAAC), &vs64); + val->intval =3D vs64; + break; + case POWER_SUPPLY_PROP_CYCLE_COUNT: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(B0CT), &vu16); + val->intval =3D vu16; + break; + case POWER_SUPPLY_PROP_SCOPE: + val->intval =3D POWER_SUPPLY_SCOPE_SYSTEM; + break; + case POWER_SUPPLY_PROP_HEALTH: + flag =3D false; + ret =3D apple_smc_read_flag(power->smc, SMC_KEY(BBAD), &flag); + val->intval =3D flag ? POWER_SUPPLY_HEALTH_DEAD : POWER_SUPPLY_HEALTH_GO= OD; + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval =3D power->model_name; + break; + case POWER_SUPPLY_PROP_SERIAL_NUMBER: + val->strval =3D power->serial_number; + break; + case POWER_SUPPLY_PROP_MANUFACTURE_YEAR: + ret =3D macsmc_battery_get_date(&power->mfg_date[0], &val->intval); + /* The SMC reports the manufacture year as an offset from 1992. */ + val->intval +=3D 1992; + break; + case POWER_SUPPLY_PROP_MANUFACTURE_MONTH: + ret =3D macsmc_battery_get_date(&power->mfg_date[2], &val->intval); + break; + case POWER_SUPPLY_PROP_MANUFACTURE_DAY: + ret =3D macsmc_battery_get_date(&power->mfg_date[4], &val->intval); + break; + case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD: + case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: + if (power->has_chls) { + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(CHLS), &vu16); + val->intval =3D vu16 & 0xff; + if (val->intval < CHLS_MIN_END_THRESHOLD || val->intval >=3D 100) + val->intval =3D 100; + } else if (power->has_chwa) { + flag =3D false; + ret =3D apple_smc_read_flag(power->smc, SMC_KEY(CHWA), &flag); + val->intval =3D flag ? CHWA_FIXED_END_THRESHOLD : 100; + } else { + return -EINVAL; + } + if (psp =3D=3D POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD && + ret >=3D 0 && val->intval < 100 && val->intval >=3D CHLS_MIN_END_THR= ESHOLD) + val->intval -=3D CHWA_CHLS_FIXED_START_OFFSET; + break; + default: + return -EINVAL; + } + + return ret; +} + +static int macsmc_battery_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct macsmc_power *power =3D power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: + return macsmc_battery_set_charge_behaviour(power, val->intval); + case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD: + /* + * Read-only reflection of end threshold logic. + * Allowed to be written to avoid userspace confusion, but ignored. + */ + return 0; + case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: + if (power->has_chls) { + u16 kval =3D 0; + /* Configurable logic for future expansion */ + if (val->intval < CHLS_MIN_END_THRESHOLD) + kval =3D CHLS_FORCE_DISCHARGE | CHLS_MIN_END_THRESHOLD; + else if (val->intval < 100) + kval =3D CHLS_FORCE_DISCHARGE | (val->intval & 0xff); + + return apple_smc_write_u16(power->smc, SMC_KEY(CHLS), kval); + } else if (power->has_chwa) { + return apple_smc_write_flag(power->smc, SMC_KEY(CHWA), + val->intval <=3D CHWA_PROP_WRITE_THRESHOLD); + } else { + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int macsmc_battery_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + struct macsmc_power *power =3D power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: + return true; + case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD: + case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: + return power->has_chwa || power->has_chls; + default: + return false; + } +} + +static const struct power_supply_desc macsmc_battery_desc_template =3D { + .name =3D "macsmc-battery", + .type =3D POWER_SUPPLY_TYPE_BATTERY, + .get_property =3D macsmc_battery_get_property, + .set_property =3D macsmc_battery_set_property, + .property_is_writeable =3D macsmc_battery_property_is_writeable, +}; + +static int macsmc_ac_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct macsmc_power *power =3D power_supply_get_drvdata(psy); + int ret =3D 0; + u16 vu16; + u32 vu32; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + ret =3D apple_smc_read_u32(power->smc, SMC_KEY(CHIS), &vu32); + val->intval =3D !!vu32; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(AC-n), &vu16); + val->intval =3D vu16 * 1000; + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret =3D apple_smc_read_u16(power->smc, SMC_KEY(AC-i), &vu16); + val->intval =3D vu16 * 1000; + break; + case POWER_SUPPLY_PROP_INPUT_POWER_LIMIT: + ret =3D apple_smc_read_u32(power->smc, SMC_KEY(ACPW), &vu32); + val->intval =3D vu32 * 1000; + break; + default: + return -EINVAL; + } + + return ret; +} + +static const struct power_supply_desc macsmc_ac_desc_template =3D { + .name =3D "macsmc-ac", + .type =3D POWER_SUPPLY_TYPE_MAINS, + .get_property =3D macsmc_ac_get_property, +}; + +static void macsmc_power_critical_work(struct work_struct *wrk) +{ + struct macsmc_power *power =3D container_of(wrk, struct macsmc_power, cri= tical_work); + u16 bitv, b0av; + u32 bcf0; + + if (!power->batt) + return; + + /* + * EMERGENCY: Check voltage vs design minimum. + * If we are below BITV, the battery is physically exhausted. + * We must shut down NOW to protect the filesystem. + */ + if (apple_smc_read_u16(power->smc, SMC_KEY(BITV), &bitv) >=3D 0 && + apple_smc_read_u16(power->smc, SMC_KEY(B0AV), &b0av) >=3D 0 && + b0av < bitv) { + dev_crit(power->dev, + "Battery voltage (%d mV) below design minimum (%d mV)! Emergency shutd= own.\n", + b0av, bitv); + kernel_power_off(); + return; + } + + /* + * Avoid duplicate attempts at orderly shutdown. + * Voltage check is above this as we may want to + * "upgrade" an orderly shutdown to a critical power + * off if voltage drops. + */ + if (power->shutdown_started || system_state > SYSTEM_RUNNING) + return; + + /* + * 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) =3D=3D 0 && bcf0= !=3D 0) { + power->shutdown_started =3D true; + dev_emerg(power->dev, "Battery critical (empty flag set). Triggering ord= erly shutdown.\n"); + orderly_poweroff(true); + } +} + +static int macsmc_power_event(struct notifier_block *nb, unsigned long eve= nt, void *data) +{ + struct macsmc_power *power =3D container_of(nb, struct macsmc_power, nb); + + /* + * SMC Event IDs are reverse-engineered. + * 0x71... indicates power/battery events. + */ + if ((event & 0xffffff00) =3D=3D 0x71010100 || /* Charger status change */ + (event & 0xffff0000) =3D=3D 0x71060000 || /* Port charge state change= */ + (event & 0xffff0000) =3D=3D 0x71130000) { /* Connector insert/remove = event */ + if (power->batt) + power_supply_changed(power->batt); + if (power->ac) + power_supply_changed(power->ac); + return NOTIFY_OK; + } else if (event =3D=3D 0x71020000) { + /* Critical battery warning */ + if (power->batt) + schedule_work(&power->critical_work); + return NOTIFY_OK; + } + + return NOTIFY_DONE; +} + +static int macsmc_power_probe(struct platform_device *pdev) +{ + struct apple_smc *smc =3D dev_get_drvdata(pdev->dev.parent); + struct power_supply_config psy_cfg =3D {}; + struct macsmc_power *power; + bool has_battery =3D false; + int ret; + bool flag; + u16 vu16; + u32 val32; + enum power_supply_property *props; + size_t nprops; + + if (!smc) + return -ENODEV; + + power =3D devm_kzalloc(&pdev->dev, sizeof(*power), GFP_KERNEL); + if (!power) + return -ENOMEM; + + power->dev =3D &pdev->dev; + power->smc =3D smc; + dev_set_drvdata(&pdev->dev, power); + + /* + * Check for battery presence. + * B0AV is a fundamental key. + */ + if (apple_smc_read_u16(power->smc, SMC_KEY(B0AV), &vu16) =3D=3D 0 && + macsmc_battery_get_status(power) > POWER_SUPPLY_STATUS_UNKNOWN) + has_battery =3D true; + + if (has_battery) { + power->batt_desc =3D macsmc_battery_desc_template; + power->batt_props =3D devm_kcalloc(&pdev->dev, MACSMC_MAX_BATT_PROPS, + sizeof(enum power_supply_property), + GFP_KERNEL); + if (!power->batt_props) + return -ENOMEM; + + props =3D power->batt_props; + nprops =3D 0; + + /* Fundamental properties */ + props[nprops++] =3D POWER_SUPPLY_PROP_STATUS; + props[nprops++] =3D POWER_SUPPLY_PROP_PRESENT; + props[nprops++] =3D POWER_SUPPLY_PROP_VOLTAGE_NOW; + props[nprops++] =3D POWER_SUPPLY_PROP_CURRENT_NOW; + props[nprops++] =3D POWER_SUPPLY_PROP_POWER_NOW; + props[nprops++] =3D POWER_SUPPLY_PROP_CAPACITY; + props[nprops++] =3D POWER_SUPPLY_PROP_CAPACITY_LEVEL; + props[nprops++] =3D POWER_SUPPLY_PROP_TEMP; + props[nprops++] =3D POWER_SUPPLY_PROP_CYCLE_COUNT; + props[nprops++] =3D POWER_SUPPLY_PROP_HEALTH; + props[nprops++] =3D POWER_SUPPLY_PROP_SCOPE; + props[nprops++] =3D POWER_SUPPLY_PROP_MODEL_NAME; + props[nprops++] =3D POWER_SUPPLY_PROP_SERIAL_NUMBER; + props[nprops++] =3D POWER_SUPPLY_PROP_MANUFACTURE_YEAR; + props[nprops++] =3D POWER_SUPPLY_PROP_MANUFACTURE_MONTH; + props[nprops++] =3D POWER_SUPPLY_PROP_MANUFACTURE_DAY; + + /* Extended properties usually present */ + props[nprops++] =3D POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW; + props[nprops++] =3D POWER_SUPPLY_PROP_TIME_TO_FULL_NOW; + props[nprops++] =3D POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN; + props[nprops++] =3D POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN; + props[nprops++] =3D POWER_SUPPLY_PROP_VOLTAGE_MIN; + props[nprops++] =3D POWER_SUPPLY_PROP_VOLTAGE_MAX; + props[nprops++] =3D POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT; + props[nprops++] =3D POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX; + props[nprops++] =3D POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE; + props[nprops++] =3D POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN; + props[nprops++] =3D POWER_SUPPLY_PROP_CHARGE_FULL; + props[nprops++] =3D POWER_SUPPLY_PROP_CHARGE_NOW; + props[nprops++] =3D POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN; + props[nprops++] =3D POWER_SUPPLY_PROP_ENERGY_FULL; + props[nprops++] =3D POWER_SUPPLY_PROP_ENERGY_NOW; + props[nprops++] =3D POWER_SUPPLY_PROP_CHARGE_COUNTER; + + /* Detect features based on key availability */ + if (apple_smc_key_exists(smc, SMC_KEY(CHTE))) + power->has_chte =3D true; + if (apple_smc_key_exists(smc, SMC_KEY(CH0C))) + power->has_ch0c =3D true; + if (apple_smc_key_exists(smc, SMC_KEY(CH0I))) + power->has_ch0i =3D true; + + /* 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++] =3D POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR; + + power->batt_desc.charge_behaviours =3D + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO); + + if (power->has_ch0i) + power->batt_desc.charge_behaviours |=3D + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE); + + if (power->has_chte || power->has_ch0c) + power->batt_desc.charge_behaviours |=3D + 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) =3D=3D 0) + power->has_chwa =3D true; + else if (apple_smc_read_u16(power->smc, SMC_KEY(CHLS), &vu16) >=3D 0) + power->has_chls =3D true; + + if (power->has_chwa || power->has_chls) { + props[nprops++] =3D POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD; + props[nprops++] =3D POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD; + } + + power->batt_desc.properties =3D power->batt_props; + power->batt_desc.num_properties =3D 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 =3D MACSMC_NOMINAL_CELL_VOLTAGE_MV * power->nu= m_cells; + + /* Enable critical shutdown notifications by reading status once */ + apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &val32); + + psy_cfg.drv_data =3D power; + power->batt =3D devm_power_supply_register(&pdev->dev, &power->batt_desc= , &psy_cfg); + if (IS_ERR(power->batt)) { + ret =3D dev_err_probe(&pdev->dev, PTR_ERR(power->batt), + "Failed to register battery\n"); + /* Don't return failure yet; try AC registration first */ + power->batt =3D NULL; + } + } else { + dev_dbg(&pdev->dev, "No battery detected, proceeding with AC-only regist= ration.\n"); + } + + /* AC Adapter Registration */ + power->ac_desc =3D macsmc_ac_desc_template; + power->ac_props =3D devm_kcalloc(&pdev->dev, MACSMC_MAX_AC_PROPS, + sizeof(enum power_supply_property), + GFP_KERNEL); + if (!power->ac_props) + return -ENOMEM; + + props =3D power->ac_props; + nprops =3D 0; + + /* Online status is fundamental */ + props[nprops++] =3D POWER_SUPPLY_PROP_ONLINE; + + /* Input power limits are usually available */ + if (apple_smc_key_exists(power->smc, SMC_KEY(ACPW))) + props[nprops++] =3D 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) >=3D 0) { + props[nprops++] =3D POWER_SUPPLY_PROP_VOLTAGE_NOW; + props[nprops++] =3D POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT; + } + + power->ac_desc.properties =3D power->ac_props; + power->ac_desc.num_properties =3D nprops; + + psy_cfg.drv_data =3D power; + power->ac =3D devm_power_supply_register(&pdev->dev, &power->ac_desc, &ps= y_cfg); + if (IS_ERR(power->ac)) { + ret =3D dev_err_probe(&pdev->dev, PTR_ERR(power->ac), + "Failed to register AC adapter\n"); + /* If battery also failed or didn't exist, this is a fatal error */ + if (!power->batt) + return ret; + power->ac =3D NULL; + } + + /* Final check: did we register anything? */ + if (!power->batt && !power->ac) + return -ENODEV; + + power->nb.notifier_call =3D macsmc_power_event; + blocking_notifier_chain_register(&smc->event_handlers, &power->nb); + + INIT_WORK(&power->critical_work, macsmc_power_critical_work); + + return 0; +} + +static void macsmc_power_remove(struct platform_device *pdev) +{ + struct macsmc_power *power =3D dev_get_drvdata(&pdev->dev); + + blocking_notifier_chain_unregister(&power->smc->event_handlers, &power->n= b); + cancel_work_sync(&power->critical_work); +} + +static struct platform_driver macsmc_power_driver =3D { + .driver =3D { + .name =3D "macsmc-power", + .owner =3D THIS_MODULE, + }, + .probe =3D macsmc_power_probe, + .remove =3D macsmc_power_remove, +}; +module_platform_driver(macsmc_power_driver); + +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_DESCRIPTION("Apple SMC battery and power management driver"); +MODULE_AUTHOR("Hector Martin "); +MODULE_AUTHOR("Michael Reeves "); +MODULE_ALIAS("platform:macsmc-power"); --=20 2.51.2 From nobody Sun Feb 8 14:59:43 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D92293375A7; Mon, 5 Jan 2026 12:56:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767617809; cv=none; b=gB6dv9zaKhsVvfrfMxmTy8O9gpRLHjR13cxJBRF2u++iLLG1OoxNTEdN7VRBPBWJ8Qgf07CdE2HQvemSVewleHGUgcGrWK+g8osdsG5LnxbYxqKecF8oR9khjQ8QNdOF9t+H2pTlkrswd4Gvnr5WFoBsIcTPtK0tkpJL0HA7cno= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767617809; c=relaxed/simple; bh=qmt/PcU1Yu1EV0KhbS4i0pP6/2A6eNrCy2u0NVbxqrU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kujp228Lqac09wrG+nmX+8JusVpDonuROTHz+nMuCtYS9aX5NRcFrfc9FSRt7s9EBDd5at5T56pWhI48oKvUyyyQSJSY698nQCJIQWuo8ZayAEHRJk6PpIQ5clfO+MUqgPEEAzm/fY+z2mLKgKERgZ0MgNFozGtnoKm+SuCxrAA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=AvBt0Yot; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="AvBt0Yot" Received: by smtp.kernel.org (Postfix) with ESMTPS id 693D9C19425; Mon, 5 Jan 2026 12:56:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1767617807; bh=qmt/PcU1Yu1EV0KhbS4i0pP6/2A6eNrCy2u0NVbxqrU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=AvBt0Yots1PaxpFEKEg+PvmaPucv7i/OgnHLSBT4FW9QjA/BvNrvZmoC63BqXF9xa B92rlzLz9Yl+qsi4upuDW4q/orKSMz2oxqF1oY1S8jP6MXmWSVhwY7xmbJzYxwi1Rg GPsU3ZG2kVOy/bV5hc/KTpE8LpucyW9MoLzcCvaY243mQSLnJkwbWcPjMRYWhSPO6X W5oZN617UAwbZpN8DAdC1iqInFQkD1XUbX4OaBh1uk4gPNRFMJoO/Rc4cA3sufIt3n YDMOXnz0DajoJHQb5zGgVe8VhLpIS2PVnmS1YEnSbMBzsgVfM3LbphKCYRGpgm/EhL I2ubXsgUJ/oyA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5B325C79F87; Mon, 5 Jan 2026 12:56:47 +0000 (UTC) From: Michael Reeves via B4 Relay Date: Mon, 05 Jan 2026 23:56:37 +1100 Subject: [PATCH 2/2] mfd: macsmc: Wire up Apple SMC power driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260105-b4-macsmc-power-v1-2-62954c42a555@gmail.com> References: <20260105-b4-macsmc-power-v1-0-62954c42a555@gmail.com> In-Reply-To: <20260105-b4-macsmc-power-v1-0-62954c42a555@gmail.com> To: Sebastian Reichel , Sven Peter , Janne Grunau , Neal Gompa , Lee Jones Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, asahi@lists.linux.dev, linux-arm-kernel@lists.infradead.org, Michael Reeves , Hector Martin X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1767617806; l=759; i=michael.reeves077@gmail.com; s=20260105; h=from:subject:message-id; bh=vIxVriW7LVSbZfkV9TYc6jdqEm/Rah71gDngXrG5xT8=; b=gEO+8YJiCNJnMoPAkVVFkeBS2Bp+zqvI2YBPM8YBi4e8rNuaYViJT9wmJNVsFpR/BWU0KnzkM BEHGIxPEbgJAzaHpT36JJsDTt6mzSGCiZNC/Vd81ZOM8uz/gefQvheP X-Developer-Key: i=michael.reeves077@gmail.com; a=ed25519; pk=QIrgWBGCm3LG0YYc6MLCDkwuVXLTGGooVBdWX/KhSiU= X-Endpoint-Received: by B4 Relay for michael.reeves077@gmail.com/20260105 with auth_id=591 X-Original-From: Michael Reeves Reply-To: michael.reeves077@gmail.com From: Michael Reeves Add the cell for the macsmc-power driver so it is probed by the MFD core. Co-developed-by: Hector Martin Signed-off-by: Hector Martin Signed-off-by: Michael Reeves Reviewed-by: Neal Gompa --- drivers/mfd/macsmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c index e3893e255ce5..061b43fc842d 100644 --- a/drivers/mfd/macsmc.c +++ b/drivers/mfd/macsmc.c @@ -45,6 +45,7 @@ #define SMC_TIMEOUT_MS 500 =20 static const struct mfd_cell apple_smc_devs[] =3D { + MFD_CELL_NAME("macsmc-power"), MFD_CELL_OF("macsmc-gpio", NULL, NULL, 0, 0, "apple,smc-gpio"), MFD_CELL_OF("macsmc-reboot", NULL, NULL, 0, 0, "apple,smc-reboot"), }; --=20 2.51.2