xref: /linux/drivers/power/supply/macsmc-power.c (revision 59bd5ae0db22566e2b961742126269c151d587c7)
1*0ebf821cSHector Martin // SPDX-License-Identifier: GPL-2.0-only OR MIT
2*0ebf821cSHector Martin /*
3*0ebf821cSHector Martin  * Apple SMC Power/Battery Management Driver
4*0ebf821cSHector Martin  *
5*0ebf821cSHector Martin  * This driver exposes battery telemetry (voltage, current, temperature, health)
6*0ebf821cSHector Martin  * and AC adapter status provided by the Apple SMC (System Management Controller)
7*0ebf821cSHector Martin  * on Apple Silicon systems.
8*0ebf821cSHector Martin  *
9*0ebf821cSHector Martin  * Copyright The Asahi Linux Contributors
10*0ebf821cSHector Martin  */
11*0ebf821cSHector Martin 
12*0ebf821cSHector Martin #include <linux/ctype.h>
13*0ebf821cSHector Martin #include <linux/delay.h>
14*0ebf821cSHector Martin #include <linux/devm-helpers.h>
15*0ebf821cSHector Martin #include <linux/limits.h>
16*0ebf821cSHector Martin #include <linux/module.h>
17*0ebf821cSHector Martin #include <linux/mfd/macsmc.h>
18*0ebf821cSHector Martin #include <linux/notifier.h>
19*0ebf821cSHector Martin #include <linux/of.h>
20*0ebf821cSHector Martin #include <linux/platform_device.h>
21*0ebf821cSHector Martin #include <linux/power_supply.h>
22*0ebf821cSHector Martin #include <linux/reboot.h>
23*0ebf821cSHector Martin #include <linux/workqueue.h>
24*0ebf821cSHector Martin 
25*0ebf821cSHector Martin #define MAX_STRING_LENGTH 256
26*0ebf821cSHector Martin 
27*0ebf821cSHector Martin /*
28*0ebf821cSHector Martin  * The SMC reports charge in mAh (Coulombs) but energy in mWh (Joules).
29*0ebf821cSHector Martin  * We lack a register for "Nominal Voltage" or "Energy Accumulator".
30*0ebf821cSHector Martin  * We use a fixed 3.8V/cell constant to approximate energy stats for userspace,
31*0ebf821cSHector Martin  * derived from empirical data across supported MacBook models.
32*0ebf821cSHector Martin  */
33*0ebf821cSHector Martin #define MACSMC_NOMINAL_CELL_VOLTAGE_MV 3800
34*0ebf821cSHector Martin 
35*0ebf821cSHector Martin /* SMC Key Flags */
36*0ebf821cSHector Martin #define CHNC_BATTERY_FULL	BIT(0)
37*0ebf821cSHector Martin #define CHNC_NO_CHARGER		BIT(7)
38*0ebf821cSHector Martin #define CHNC_NOCHG_CH0C		BIT(14)
39*0ebf821cSHector Martin #define CHNC_NOCHG_CH0B_CH0K	BIT(15)
40*0ebf821cSHector Martin #define CHNC_BATTERY_FULL_2	BIT(18)
41*0ebf821cSHector Martin #define CHNC_BMS_BUSY		BIT(23)
42*0ebf821cSHector Martin #define CHNC_CHLS_LIMIT		BIT(24)
43*0ebf821cSHector Martin #define CHNC_NOAC_CH0J		BIT(53)
44*0ebf821cSHector Martin #define CHNC_NOAC_CH0I		BIT(54)
45*0ebf821cSHector Martin 
46*0ebf821cSHector Martin #define CH0R_LOWER_FLAGS	GENMASK(15, 0)
47*0ebf821cSHector Martin #define CH0R_NOAC_CH0I		BIT(0)
48*0ebf821cSHector Martin #define CH0R_NOAC_DISCONNECTED	BIT(4)
49*0ebf821cSHector Martin #define CH0R_NOAC_CH0J		BIT(5)
50*0ebf821cSHector Martin #define CH0R_BMS_BUSY		BIT(8)
51*0ebf821cSHector Martin #define CH0R_NOAC_CH0K		BIT(9)
52*0ebf821cSHector Martin #define CH0R_NOAC_CHWA		BIT(11)
53*0ebf821cSHector Martin 
54*0ebf821cSHector Martin #define CH0X_CH0C		BIT(0)
55*0ebf821cSHector Martin #define CH0X_CH0B		BIT(1)
56*0ebf821cSHector Martin 
57*0ebf821cSHector Martin #define ACSt_CAN_BOOT_AP	BIT(2)
58*0ebf821cSHector Martin #define ACSt_CAN_BOOT_IBOOT	BIT(1)
59*0ebf821cSHector Martin 
60*0ebf821cSHector Martin #define CHWA_CHLS_FIXED_START_OFFSET	5
61*0ebf821cSHector Martin #define CHLS_MIN_END_THRESHOLD		10
62*0ebf821cSHector Martin #define CHLS_FORCE_DISCHARGE		0x100
63*0ebf821cSHector Martin #define CHWA_FIXED_END_THRESHOLD	80
64*0ebf821cSHector Martin #define CHWA_PROP_WRITE_THRESHOLD	95
65*0ebf821cSHector Martin 
66*0ebf821cSHector Martin #define MACSMC_MAX_BATT_PROPS		50
67*0ebf821cSHector Martin #define MACSMC_MAX_AC_PROPS		10
68*0ebf821cSHector Martin 
69*0ebf821cSHector Martin struct macsmc_power {
70*0ebf821cSHector Martin 	struct device *dev;
71*0ebf821cSHector Martin 	struct apple_smc *smc;
72*0ebf821cSHector Martin 
73*0ebf821cSHector Martin 	struct power_supply_desc ac_desc;
74*0ebf821cSHector Martin 	struct power_supply_desc batt_desc;
75*0ebf821cSHector Martin 
76*0ebf821cSHector Martin 	struct power_supply *batt;
77*0ebf821cSHector Martin 	struct power_supply *ac;
78*0ebf821cSHector Martin 
79*0ebf821cSHector Martin 	char model_name[MAX_STRING_LENGTH];
80*0ebf821cSHector Martin 	char serial_number[MAX_STRING_LENGTH];
81*0ebf821cSHector Martin 	char mfg_date[MAX_STRING_LENGTH];
82*0ebf821cSHector Martin 
83*0ebf821cSHector Martin 	/* Supported feature flags based on SMC key presence */
84*0ebf821cSHector Martin 	bool has_chwa; /* Charge limit (Modern firmware) */
85*0ebf821cSHector Martin 	bool has_chls; /* Charge limit (Older firmware) */
86*0ebf821cSHector Martin 	bool has_ch0i; /* Force discharge (Older firmware) */
87*0ebf821cSHector Martin 	bool has_ch0c; /* Inhibit charge (Older firmware) */
88*0ebf821cSHector Martin 	bool has_chte; /* Inhibit charge (Modern firmware) */
89*0ebf821cSHector Martin 
90*0ebf821cSHector Martin 	u8 num_cells;
91*0ebf821cSHector Martin 	int nominal_voltage_mv;
92*0ebf821cSHector Martin 
93*0ebf821cSHector Martin 	struct notifier_block nb;
94*0ebf821cSHector Martin 	struct work_struct critical_work;
95*0ebf821cSHector Martin 	bool emergency_shutdown_triggered;
96*0ebf821cSHector Martin 	bool orderly_shutdown_triggered;
97*0ebf821cSHector Martin };
98*0ebf821cSHector Martin 
99*0ebf821cSHector Martin static int macsmc_battery_get_status(struct macsmc_power *power)
100*0ebf821cSHector Martin {
101*0ebf821cSHector Martin 	u64 nocharge_flags;
102*0ebf821cSHector Martin 	u32 nopower_flags;
103*0ebf821cSHector Martin 	u16 ac_current;
104*0ebf821cSHector Martin 	int charge_limit = 0;
105*0ebf821cSHector Martin 	bool limited = false;
106*0ebf821cSHector Martin 	bool flag;
107*0ebf821cSHector Martin 	int ret;
108*0ebf821cSHector Martin 
109*0ebf821cSHector Martin 	/*
110*0ebf821cSHector Martin 	 * B0AV (Voltage) is fundamental. If we can't read it, we assume the
111*0ebf821cSHector Martin 	 * battery is gone. CHCE (Hardware charger present) / CHCC (Hardware
112*0ebf821cSHector Martin 	 * charger capable) are fundamental status flags.
113*0ebf821cSHector Martin 	 * BSFC (System full charge) / CHSC (System charging) are fundamental
114*0ebf821cSHector Martin 	 * status flags.
115*0ebf821cSHector Martin 	 */
116*0ebf821cSHector Martin 
117*0ebf821cSHector Martin 	/* Check if power input is inhibited (e.g. BMS balancing cycle) */
118*0ebf821cSHector Martin 	ret = apple_smc_read_u32(power->smc, SMC_KEY(CH0R), &nopower_flags);
119*0ebf821cSHector Martin 	if (!ret && (nopower_flags & CH0R_LOWER_FLAGS & ~CH0R_BMS_BUSY))
120*0ebf821cSHector Martin 		return POWER_SUPPLY_STATUS_DISCHARGING;
121*0ebf821cSHector Martin 
122*0ebf821cSHector Martin 	/* Check if charger is present */
123*0ebf821cSHector Martin 	ret = apple_smc_read_flag(power->smc, SMC_KEY(CHCE), &flag);
124*0ebf821cSHector Martin 	if (ret < 0)
125*0ebf821cSHector Martin 		return ret;
126*0ebf821cSHector Martin 	if (!flag)
127*0ebf821cSHector Martin 		return POWER_SUPPLY_STATUS_DISCHARGING;
128*0ebf821cSHector Martin 
129*0ebf821cSHector Martin 	/* Check if AC is charge capable */
130*0ebf821cSHector Martin 	ret = apple_smc_read_flag(power->smc, SMC_KEY(CHCC), &flag);
131*0ebf821cSHector Martin 	if (ret < 0)
132*0ebf821cSHector Martin 		return ret;
133*0ebf821cSHector Martin 	if (!flag)
134*0ebf821cSHector Martin 		return POWER_SUPPLY_STATUS_DISCHARGING;
135*0ebf821cSHector Martin 
136*0ebf821cSHector Martin 	/* Check if AC input limit is too low */
137*0ebf821cSHector Martin 	ret = apple_smc_read_u16(power->smc, SMC_KEY(AC-i), &ac_current);
138*0ebf821cSHector Martin 	if (!ret && ac_current < 100)
139*0ebf821cSHector Martin 		return POWER_SUPPLY_STATUS_DISCHARGING;
140*0ebf821cSHector Martin 
141*0ebf821cSHector Martin 	/* Check if battery is full */
142*0ebf821cSHector Martin 	ret = apple_smc_read_flag(power->smc, SMC_KEY(BSFC), &flag);
143*0ebf821cSHector Martin 	if (ret < 0)
144*0ebf821cSHector Martin 		return ret;
145*0ebf821cSHector Martin 	if (flag)
146*0ebf821cSHector Martin 		return POWER_SUPPLY_STATUS_FULL;
147*0ebf821cSHector Martin 
148*0ebf821cSHector Martin 	/* Check for user-defined charge limits */
149*0ebf821cSHector Martin 	if (power->has_chls) {
150*0ebf821cSHector Martin 		u16 vu16;
151*0ebf821cSHector Martin 
152*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(CHLS), &vu16);
153*0ebf821cSHector Martin 		if (ret == 0 && (vu16 & 0xff) >= CHLS_MIN_END_THRESHOLD)
154*0ebf821cSHector Martin 			charge_limit = (vu16 & 0xff) - CHWA_CHLS_FIXED_START_OFFSET;
155*0ebf821cSHector Martin 	} else if (power->has_chwa) {
156*0ebf821cSHector Martin 		ret = apple_smc_read_flag(power->smc, SMC_KEY(CHWA), &flag);
157*0ebf821cSHector Martin 		if (ret == 0 && flag)
158*0ebf821cSHector Martin 			charge_limit = CHWA_FIXED_END_THRESHOLD - CHWA_CHLS_FIXED_START_OFFSET;
159*0ebf821cSHector Martin 	}
160*0ebf821cSHector Martin 
161*0ebf821cSHector Martin 	if (charge_limit > 0) {
162*0ebf821cSHector Martin 		u8 buic = 0;
163*0ebf821cSHector Martin 
164*0ebf821cSHector Martin 		if (apple_smc_read_u8(power->smc, SMC_KEY(BUIC), &buic) >= 0 &&
165*0ebf821cSHector Martin 		    buic >= charge_limit)
166*0ebf821cSHector Martin 			limited = true;
167*0ebf821cSHector Martin 	}
168*0ebf821cSHector Martin 
169*0ebf821cSHector Martin 	/* Check charging inhibitors */
170*0ebf821cSHector Martin 	ret = apple_smc_read_u64(power->smc, SMC_KEY(CHNC), &nocharge_flags);
171*0ebf821cSHector Martin 	if (!ret) {
172*0ebf821cSHector Martin 		if (nocharge_flags & CHNC_BATTERY_FULL)
173*0ebf821cSHector Martin 			return POWER_SUPPLY_STATUS_FULL;
174*0ebf821cSHector Martin 		/* BMS busy shows up as inhibit, but we treat it as charging */
175*0ebf821cSHector Martin 		else if (nocharge_flags == CHNC_BMS_BUSY && !limited)
176*0ebf821cSHector Martin 			return POWER_SUPPLY_STATUS_CHARGING;
177*0ebf821cSHector Martin 		else if (nocharge_flags)
178*0ebf821cSHector Martin 			return POWER_SUPPLY_STATUS_NOT_CHARGING;
179*0ebf821cSHector Martin 		else
180*0ebf821cSHector Martin 			return POWER_SUPPLY_STATUS_CHARGING;
181*0ebf821cSHector Martin 	}
182*0ebf821cSHector Martin 
183*0ebf821cSHector Martin 	/* Fallback: System charging flag */
184*0ebf821cSHector Martin 	ret = apple_smc_read_flag(power->smc, SMC_KEY(CHSC), &flag);
185*0ebf821cSHector Martin 	if (ret < 0)
186*0ebf821cSHector Martin 		return ret;
187*0ebf821cSHector Martin 	if (!flag)
188*0ebf821cSHector Martin 		return POWER_SUPPLY_STATUS_NOT_CHARGING;
189*0ebf821cSHector Martin 
190*0ebf821cSHector Martin 	return POWER_SUPPLY_STATUS_CHARGING;
191*0ebf821cSHector Martin }
192*0ebf821cSHector Martin 
193*0ebf821cSHector Martin static int macsmc_battery_get_charge_behaviour(struct macsmc_power *power)
194*0ebf821cSHector Martin {
195*0ebf821cSHector Martin 	int ret;
196*0ebf821cSHector Martin 	u8 val8;
197*0ebf821cSHector Martin 	u8 chte_buf[4];
198*0ebf821cSHector Martin 
199*0ebf821cSHector Martin 	if (power->has_ch0i) {
200*0ebf821cSHector Martin 		ret = apple_smc_read_u8(power->smc, SMC_KEY(CH0I), &val8);
201*0ebf821cSHector Martin 		if (ret)
202*0ebf821cSHector Martin 			return ret;
203*0ebf821cSHector Martin 		if (val8 & CH0R_NOAC_CH0I)
204*0ebf821cSHector Martin 			return POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE;
205*0ebf821cSHector Martin 	}
206*0ebf821cSHector Martin 
207*0ebf821cSHector Martin 	if (power->has_chte) {
208*0ebf821cSHector Martin 		ret = apple_smc_read(power->smc, SMC_KEY(CHTE), chte_buf, 4);
209*0ebf821cSHector Martin 		if (ret < 0)
210*0ebf821cSHector Martin 			return ret;
211*0ebf821cSHector Martin 
212*0ebf821cSHector Martin 		if (chte_buf[0] == 0x01)
213*0ebf821cSHector Martin 			return POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
214*0ebf821cSHector Martin 	} else if (power->has_ch0c) {
215*0ebf821cSHector Martin 		ret = apple_smc_read_u8(power->smc, SMC_KEY(CH0C), &val8);
216*0ebf821cSHector Martin 		if (ret)
217*0ebf821cSHector Martin 			return ret;
218*0ebf821cSHector Martin 		if (val8 & CH0X_CH0C)
219*0ebf821cSHector Martin 			return POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
220*0ebf821cSHector Martin 	}
221*0ebf821cSHector Martin 
222*0ebf821cSHector Martin 	return POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO;
223*0ebf821cSHector Martin }
224*0ebf821cSHector Martin 
225*0ebf821cSHector Martin static int macsmc_battery_set_charge_behaviour(struct macsmc_power *power, int val)
226*0ebf821cSHector Martin {
227*0ebf821cSHector Martin 	int ret;
228*0ebf821cSHector Martin 
229*0ebf821cSHector Martin 	switch (val) {
230*0ebf821cSHector Martin 	case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO:
231*0ebf821cSHector Martin 		/* Reset all inhibitors to a known-good 'auto' state */
232*0ebf821cSHector Martin 		if (power->has_ch0i) {
233*0ebf821cSHector Martin 			ret = apple_smc_write_u8(power->smc, SMC_KEY(CH0I), 0);
234*0ebf821cSHector Martin 			if (ret)
235*0ebf821cSHector Martin 				return ret;
236*0ebf821cSHector Martin 		}
237*0ebf821cSHector Martin 
238*0ebf821cSHector Martin 		if (power->has_chte) {
239*0ebf821cSHector Martin 			ret = apple_smc_write_u32(power->smc, SMC_KEY(CHTE), 0);
240*0ebf821cSHector Martin 			if (ret)
241*0ebf821cSHector Martin 				return ret;
242*0ebf821cSHector Martin 		} else if (power->has_ch0c) {
243*0ebf821cSHector Martin 			ret = apple_smc_write_u8(power->smc, SMC_KEY(CH0C), 0);
244*0ebf821cSHector Martin 			if (ret)
245*0ebf821cSHector Martin 				return ret;
246*0ebf821cSHector Martin 		}
247*0ebf821cSHector Martin 		return 0;
248*0ebf821cSHector Martin 
249*0ebf821cSHector Martin 	case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE:
250*0ebf821cSHector Martin 		if (power->has_chte)
251*0ebf821cSHector Martin 			return apple_smc_write_u32(power->smc, SMC_KEY(CHTE), 1);
252*0ebf821cSHector Martin 		else if (power->has_ch0c)
253*0ebf821cSHector Martin 			return apple_smc_write_u8(power->smc, SMC_KEY(CH0C), 1);
254*0ebf821cSHector Martin 		else
255*0ebf821cSHector Martin 			return -EOPNOTSUPP;
256*0ebf821cSHector Martin 
257*0ebf821cSHector Martin 	case POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE:
258*0ebf821cSHector Martin 		if (!power->has_ch0i)
259*0ebf821cSHector Martin 			return -EOPNOTSUPP;
260*0ebf821cSHector Martin 		return apple_smc_write_u8(power->smc, SMC_KEY(CH0I), 1);
261*0ebf821cSHector Martin 
262*0ebf821cSHector Martin 	default:
263*0ebf821cSHector Martin 		return -EINVAL;
264*0ebf821cSHector Martin 	}
265*0ebf821cSHector Martin }
266*0ebf821cSHector Martin 
267*0ebf821cSHector Martin static int macsmc_battery_get_date(const char *s, int *out)
268*0ebf821cSHector Martin {
269*0ebf821cSHector Martin 	if (!isdigit(s[0]) || !isdigit(s[1]))
270*0ebf821cSHector Martin 		return -EOPNOTSUPP;
271*0ebf821cSHector Martin 
272*0ebf821cSHector Martin 	*out = (s[0] - '0') * 10 + s[1] - '0';
273*0ebf821cSHector Martin 	return 0;
274*0ebf821cSHector Martin }
275*0ebf821cSHector Martin 
276*0ebf821cSHector Martin static int macsmc_battery_get_capacity_level(struct macsmc_power *power)
277*0ebf821cSHector Martin {
278*0ebf821cSHector Martin 	bool flag;
279*0ebf821cSHector Martin 	u32 val;
280*0ebf821cSHector Martin 	int ret;
281*0ebf821cSHector Martin 
282*0ebf821cSHector Martin 	/* Check for emergency shutdown condition */
283*0ebf821cSHector Martin 	if (apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &val) >= 0 && val)
284*0ebf821cSHector Martin 		return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
285*0ebf821cSHector Martin 
286*0ebf821cSHector Martin 	/* Check AC status for whether we could boot in this state */
287*0ebf821cSHector Martin 	if (apple_smc_read_u32(power->smc, SMC_KEY(ACSt), &val) >= 0) {
288*0ebf821cSHector Martin 		if (!(val & ACSt_CAN_BOOT_IBOOT))
289*0ebf821cSHector Martin 			return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
290*0ebf821cSHector Martin 
291*0ebf821cSHector Martin 		if (!(val & ACSt_CAN_BOOT_AP))
292*0ebf821cSHector Martin 			return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
293*0ebf821cSHector Martin 	}
294*0ebf821cSHector Martin 
295*0ebf821cSHector Martin 	/* BSFC = Battery System Full Charge */
296*0ebf821cSHector Martin 	ret = apple_smc_read_flag(power->smc, SMC_KEY(BSFC), &flag);
297*0ebf821cSHector Martin 	if (ret < 0)
298*0ebf821cSHector Martin 		return POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
299*0ebf821cSHector Martin 
300*0ebf821cSHector Martin 	if (flag)
301*0ebf821cSHector Martin 		return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
302*0ebf821cSHector Martin 	else
303*0ebf821cSHector Martin 		return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
304*0ebf821cSHector Martin }
305*0ebf821cSHector Martin 
306*0ebf821cSHector Martin static int macsmc_battery_get_property(struct power_supply *psy,
307*0ebf821cSHector Martin 				       enum power_supply_property psp,
308*0ebf821cSHector Martin 				       union power_supply_propval *val)
309*0ebf821cSHector Martin {
310*0ebf821cSHector Martin 	struct macsmc_power *power = power_supply_get_drvdata(psy);
311*0ebf821cSHector Martin 	int ret = 0;
312*0ebf821cSHector Martin 	u8 vu8;
313*0ebf821cSHector Martin 	u16 vu16;
314*0ebf821cSHector Martin 	s16 vs16;
315*0ebf821cSHector Martin 	s32 vs32;
316*0ebf821cSHector Martin 	s64 vs64;
317*0ebf821cSHector Martin 	bool flag;
318*0ebf821cSHector Martin 
319*0ebf821cSHector Martin 	switch (psp) {
320*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_STATUS:
321*0ebf821cSHector Martin 		val->intval = macsmc_battery_get_status(power);
322*0ebf821cSHector Martin 		ret = val->intval < 0 ? val->intval : 0;
323*0ebf821cSHector Martin 		break;
324*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_PRESENT:
325*0ebf821cSHector Martin 		val->intval = 1;
326*0ebf821cSHector Martin 		break;
327*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
328*0ebf821cSHector Martin 		val->intval = macsmc_battery_get_charge_behaviour(power);
329*0ebf821cSHector Martin 		ret = val->intval < 0 ? val->intval : 0;
330*0ebf821cSHector Martin 		break;
331*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
332*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(B0TE), &vu16);
333*0ebf821cSHector Martin 		val->intval = vu16 == 0xffff ? 0 : vu16 * 60;
334*0ebf821cSHector Martin 		break;
335*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
336*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(B0TF), &vu16);
337*0ebf821cSHector Martin 		val->intval = vu16 == 0xffff ? 0 : vu16 * 60;
338*0ebf821cSHector Martin 		break;
339*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_CAPACITY:
340*0ebf821cSHector Martin 		ret = apple_smc_read_u8(power->smc, SMC_KEY(BUIC), &vu8);
341*0ebf821cSHector Martin 		val->intval = vu8;
342*0ebf821cSHector Martin 		break;
343*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
344*0ebf821cSHector Martin 		val->intval = macsmc_battery_get_capacity_level(power);
345*0ebf821cSHector Martin 		ret = val->intval < 0 ? val->intval : 0;
346*0ebf821cSHector Martin 		break;
347*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
348*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(B0AV), &vu16);
349*0ebf821cSHector Martin 		val->intval = vu16 * 1000;
350*0ebf821cSHector Martin 		break;
351*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_CURRENT_NOW:
352*0ebf821cSHector Martin 		ret = apple_smc_read_s16(power->smc, SMC_KEY(B0AC), &vs16);
353*0ebf821cSHector Martin 		val->intval = vs16 * 1000;
354*0ebf821cSHector Martin 		break;
355*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_POWER_NOW:
356*0ebf821cSHector Martin 		ret = apple_smc_read_s32(power->smc, SMC_KEY(B0AP), &vs32);
357*0ebf821cSHector Martin 		val->intval = vs32 * 1000;
358*0ebf821cSHector Martin 		break;
359*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
360*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(BITV), &vu16);
361*0ebf821cSHector Martin 		val->intval = vu16 * 1000;
362*0ebf821cSHector Martin 		break;
363*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
364*0ebf821cSHector Martin 		/* Calculate total max design voltage from per-cell maximum voltage */
365*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(BVVN), &vu16);
366*0ebf821cSHector Martin 		val->intval = vu16 * 1000 * power->num_cells;
367*0ebf821cSHector Martin 		break;
368*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
369*0ebf821cSHector Martin 		/* Lifetime min */
370*0ebf821cSHector Martin 		ret = apple_smc_read_s16(power->smc, SMC_KEY(BLPM), &vs16);
371*0ebf821cSHector Martin 		val->intval = vs16 * 1000;
372*0ebf821cSHector Martin 		break;
373*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
374*0ebf821cSHector Martin 		/* Lifetime max */
375*0ebf821cSHector Martin 		ret = apple_smc_read_s16(power->smc, SMC_KEY(BLPX), &vs16);
376*0ebf821cSHector Martin 		val->intval = vs16 * 1000;
377*0ebf821cSHector Martin 		break;
378*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
379*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RC), &vu16);
380*0ebf821cSHector Martin 		val->intval = vu16 * 1000;
381*0ebf821cSHector Martin 		break;
382*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
383*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RI), &vu16);
384*0ebf821cSHector Martin 		val->intval = vu16 * 1000;
385*0ebf821cSHector Martin 		break;
386*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
387*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RV), &vu16);
388*0ebf821cSHector Martin 		val->intval = vu16 * 1000;
389*0ebf821cSHector Martin 		break;
390*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
391*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(B0DC), &vu16);
392*0ebf821cSHector Martin 		val->intval = vu16 * 1000;
393*0ebf821cSHector Martin 		break;
394*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_CHARGE_FULL:
395*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(B0FC), &vu16);
396*0ebf821cSHector Martin 		val->intval = vu16 * 1000;
397*0ebf821cSHector Martin 		break;
398*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_CHARGE_NOW:
399*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RM), &vu16);
400*0ebf821cSHector Martin 		/* B0RM is Big Endian, likely pass through from TI gas gauge */
401*0ebf821cSHector Martin 		val->intval = (s16)swab16(vu16) * 1000;
402*0ebf821cSHector Martin 		break;
403*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
404*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(B0DC), &vu16);
405*0ebf821cSHector Martin 		val->intval = vu16 * power->nominal_voltage_mv;
406*0ebf821cSHector Martin 		break;
407*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_ENERGY_FULL:
408*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(B0FC), &vu16);
409*0ebf821cSHector Martin 		val->intval = vu16 * power->nominal_voltage_mv;
410*0ebf821cSHector Martin 		break;
411*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_ENERGY_NOW:
412*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(B0RM), &vu16);
413*0ebf821cSHector Martin 		/* B0RM is Big Endian, likely pass through from TI gas gauge */
414*0ebf821cSHector Martin 		val->intval = (s16)swab16(vu16) * power->nominal_voltage_mv;
415*0ebf821cSHector Martin 		break;
416*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_TEMP:
417*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(B0AT), &vu16);
418*0ebf821cSHector Martin 		val->intval = vu16 - 2732; /* Kelvin x10 to Celsius x10 */
419*0ebf821cSHector Martin 		break;
420*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
421*0ebf821cSHector Martin 		ret = apple_smc_read_s64(power->smc, SMC_KEY(BAAC), &vs64);
422*0ebf821cSHector Martin 		val->intval = vs64;
423*0ebf821cSHector Martin 		break;
424*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_CYCLE_COUNT:
425*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(B0CT), &vu16);
426*0ebf821cSHector Martin 		val->intval = vu16;
427*0ebf821cSHector Martin 		break;
428*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_SCOPE:
429*0ebf821cSHector Martin 		val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
430*0ebf821cSHector Martin 		break;
431*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_HEALTH:
432*0ebf821cSHector Martin 		flag = false;
433*0ebf821cSHector Martin 		ret = apple_smc_read_flag(power->smc, SMC_KEY(BBAD), &flag);
434*0ebf821cSHector Martin 		val->intval = flag ? POWER_SUPPLY_HEALTH_DEAD : POWER_SUPPLY_HEALTH_GOOD;
435*0ebf821cSHector Martin 		break;
436*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_MODEL_NAME:
437*0ebf821cSHector Martin 		val->strval = power->model_name;
438*0ebf821cSHector Martin 		break;
439*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_SERIAL_NUMBER:
440*0ebf821cSHector Martin 		val->strval = power->serial_number;
441*0ebf821cSHector Martin 		break;
442*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_MANUFACTURE_YEAR:
443*0ebf821cSHector Martin 		ret = macsmc_battery_get_date(&power->mfg_date[0], &val->intval);
444*0ebf821cSHector Martin 		/* The SMC reports the manufacture year as an offset from 1992. */
445*0ebf821cSHector Martin 		val->intval += 1992;
446*0ebf821cSHector Martin 		break;
447*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_MANUFACTURE_MONTH:
448*0ebf821cSHector Martin 		ret = macsmc_battery_get_date(&power->mfg_date[2], &val->intval);
449*0ebf821cSHector Martin 		break;
450*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_MANUFACTURE_DAY:
451*0ebf821cSHector Martin 		ret = macsmc_battery_get_date(&power->mfg_date[4], &val->intval);
452*0ebf821cSHector Martin 		break;
453*0ebf821cSHector Martin 	default:
454*0ebf821cSHector Martin 		return -EINVAL;
455*0ebf821cSHector Martin 	}
456*0ebf821cSHector Martin 
457*0ebf821cSHector Martin 	return ret;
458*0ebf821cSHector Martin }
459*0ebf821cSHector Martin 
460*0ebf821cSHector Martin static int macsmc_battery_set_property(struct power_supply *psy,
461*0ebf821cSHector Martin 				       enum power_supply_property psp,
462*0ebf821cSHector Martin 				       const union power_supply_propval *val)
463*0ebf821cSHector Martin {
464*0ebf821cSHector Martin 	struct macsmc_power *power = power_supply_get_drvdata(psy);
465*0ebf821cSHector Martin 
466*0ebf821cSHector Martin 	switch (psp) {
467*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
468*0ebf821cSHector Martin 		return macsmc_battery_set_charge_behaviour(power, val->intval);
469*0ebf821cSHector Martin 	default:
470*0ebf821cSHector Martin 		return -EINVAL;
471*0ebf821cSHector Martin 	}
472*0ebf821cSHector Martin }
473*0ebf821cSHector Martin 
474*0ebf821cSHector Martin static int macsmc_battery_property_is_writeable(struct power_supply *psy,
475*0ebf821cSHector Martin 						enum power_supply_property psp)
476*0ebf821cSHector Martin {
477*0ebf821cSHector Martin 	switch (psp) {
478*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
479*0ebf821cSHector Martin 		return true;
480*0ebf821cSHector Martin 	default:
481*0ebf821cSHector Martin 		return false;
482*0ebf821cSHector Martin 	}
483*0ebf821cSHector Martin }
484*0ebf821cSHector Martin 
485*0ebf821cSHector Martin static const struct power_supply_desc macsmc_battery_desc_template = {
486*0ebf821cSHector Martin 	.name			= "macsmc-battery",
487*0ebf821cSHector Martin 	.type			= POWER_SUPPLY_TYPE_BATTERY,
488*0ebf821cSHector Martin 	.get_property		= macsmc_battery_get_property,
489*0ebf821cSHector Martin 	.set_property		= macsmc_battery_set_property,
490*0ebf821cSHector Martin 	.property_is_writeable	= macsmc_battery_property_is_writeable,
491*0ebf821cSHector Martin };
492*0ebf821cSHector Martin 
493*0ebf821cSHector Martin static int macsmc_ac_get_property(struct power_supply *psy,
494*0ebf821cSHector Martin 				  enum power_supply_property psp,
495*0ebf821cSHector Martin 				  union power_supply_propval *val)
496*0ebf821cSHector Martin {
497*0ebf821cSHector Martin 	struct macsmc_power *power = power_supply_get_drvdata(psy);
498*0ebf821cSHector Martin 	int ret = 0;
499*0ebf821cSHector Martin 	u16 vu16;
500*0ebf821cSHector Martin 	u32 vu32;
501*0ebf821cSHector Martin 
502*0ebf821cSHector Martin 	switch (psp) {
503*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_ONLINE:
504*0ebf821cSHector Martin 		ret = apple_smc_read_u32(power->smc, SMC_KEY(CHIS), &vu32);
505*0ebf821cSHector Martin 		val->intval = !!vu32;
506*0ebf821cSHector Martin 		break;
507*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
508*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(AC-n), &vu16);
509*0ebf821cSHector Martin 		val->intval = vu16 * 1000;
510*0ebf821cSHector Martin 		break;
511*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
512*0ebf821cSHector Martin 		ret = apple_smc_read_u16(power->smc, SMC_KEY(AC-i), &vu16);
513*0ebf821cSHector Martin 		val->intval = vu16 * 1000;
514*0ebf821cSHector Martin 		break;
515*0ebf821cSHector Martin 	case POWER_SUPPLY_PROP_INPUT_POWER_LIMIT:
516*0ebf821cSHector Martin 		ret = apple_smc_read_u32(power->smc, SMC_KEY(ACPW), &vu32);
517*0ebf821cSHector Martin 		val->intval = vu32 * 1000;
518*0ebf821cSHector Martin 		break;
519*0ebf821cSHector Martin 	default:
520*0ebf821cSHector Martin 		return -EINVAL;
521*0ebf821cSHector Martin 	}
522*0ebf821cSHector Martin 
523*0ebf821cSHector Martin 	return ret;
524*0ebf821cSHector Martin }
525*0ebf821cSHector Martin 
526*0ebf821cSHector Martin static const struct power_supply_desc macsmc_ac_desc_template = {
527*0ebf821cSHector Martin 	.name			= "macsmc-ac",
528*0ebf821cSHector Martin 	.type			= POWER_SUPPLY_TYPE_MAINS,
529*0ebf821cSHector Martin 	.get_property		= macsmc_ac_get_property,
530*0ebf821cSHector Martin };
531*0ebf821cSHector Martin 
532*0ebf821cSHector Martin static void macsmc_power_critical_work(struct work_struct *wrk)
533*0ebf821cSHector Martin {
534*0ebf821cSHector Martin 	struct macsmc_power *power = container_of(wrk, struct macsmc_power, critical_work);
535*0ebf821cSHector Martin 	u16 bitv, b0av;
536*0ebf821cSHector Martin 	u32 bcf0;
537*0ebf821cSHector Martin 
538*0ebf821cSHector Martin 	if (!power->batt)
539*0ebf821cSHector Martin 		return;
540*0ebf821cSHector Martin 
541*0ebf821cSHector Martin 	/*
542*0ebf821cSHector Martin 	 * Avoid duplicate atempts at emergency shutdown
543*0ebf821cSHector Martin 	 */
544*0ebf821cSHector Martin 	if (power->emergency_shutdown_triggered || system_state > SYSTEM_RUNNING)
545*0ebf821cSHector Martin 		return;
546*0ebf821cSHector Martin 
547*0ebf821cSHector Martin 	/*
548*0ebf821cSHector Martin 	 * EMERGENCY: Check voltage vs design minimum.
549*0ebf821cSHector Martin 	 * If we are below BITV, the battery is physically exhausted.
550*0ebf821cSHector Martin 	 * We must shut down NOW to protect the filesystem.
551*0ebf821cSHector Martin 	 */
552*0ebf821cSHector Martin 	if (apple_smc_read_u16(power->smc, SMC_KEY(BITV), &bitv) >= 0 &&
553*0ebf821cSHector Martin 	    apple_smc_read_u16(power->smc, SMC_KEY(B0AV), &b0av) >= 0 &&
554*0ebf821cSHector Martin 	    b0av < bitv) {
555*0ebf821cSHector Martin 		power->emergency_shutdown_triggered = true;
556*0ebf821cSHector Martin 		dev_emerg(power->dev,
557*0ebf821cSHector Martin 			  "Battery voltage (%d mV) below design minimum (%d mV)! Emergency shutdown.\n",
558*0ebf821cSHector Martin 			  b0av, bitv);
559*0ebf821cSHector Martin 
560*0ebf821cSHector Martin 		/*
561*0ebf821cSHector Martin 		 * Shutdown is now imminent. Kick userspace again and give it some
562*0ebf821cSHector Martin 		 * brief time to (hopefully) flush what's needed, before forcing.
563*0ebf821cSHector Martin 		 */
564*0ebf821cSHector Martin 		hw_protection_trigger("Battery voltage below design minimum", 1500);
565*0ebf821cSHector Martin 	}
566*0ebf821cSHector Martin 
567*0ebf821cSHector Martin 	/*
568*0ebf821cSHector Martin 	 * Avoid duplicate attempts at orderly shutdown.
569*0ebf821cSHector Martin 	 * Voltage check is above this as we may want to
570*0ebf821cSHector Martin 	 * "upgrade" an orderly shutdown to a critical power
571*0ebf821cSHector Martin 	 * off if voltage drops.
572*0ebf821cSHector Martin 	 */
573*0ebf821cSHector Martin 	if (power->orderly_shutdown_triggered || system_state > SYSTEM_RUNNING)
574*0ebf821cSHector Martin 		return;
575*0ebf821cSHector Martin 
576*0ebf821cSHector Martin 	/*
577*0ebf821cSHector Martin 	 * Check if SMC flagged the battery as empty.
578*0ebf821cSHector Martin 	 * We trigger a graceful shutdown to let the OS save data.
579*0ebf821cSHector Martin 	 */
580*0ebf821cSHector Martin 	if (apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &bcf0) == 0 && bcf0 != 0) {
581*0ebf821cSHector Martin 		power->orderly_shutdown_triggered = true;
582*0ebf821cSHector Martin 		dev_crit(power->dev, "Battery critical (empty flag set). Triggering orderly shutdown.\n");
583*0ebf821cSHector Martin 		orderly_poweroff(true);
584*0ebf821cSHector Martin 	}
585*0ebf821cSHector Martin }
586*0ebf821cSHector Martin 
587*0ebf821cSHector Martin static int macsmc_power_event(struct notifier_block *nb, unsigned long event, void *data)
588*0ebf821cSHector Martin {
589*0ebf821cSHector Martin 	struct macsmc_power *power = container_of(nb, struct macsmc_power, nb);
590*0ebf821cSHector Martin 
591*0ebf821cSHector Martin 	/*
592*0ebf821cSHector Martin 	 * SMC Event IDs are correlated to physical events (e.g. charger
593*0ebf821cSHector Martin 	 * connect/disconnect) but the exact meaning of each ID is predicted.
594*0ebf821cSHector Martin 	 * 0x71... indicates power/battery events.
595*0ebf821cSHector Martin 	 */
596*0ebf821cSHector Martin 	if ((event & 0xffffff00) == 0x71010100 || /* Charger status change */
597*0ebf821cSHector Martin 	    (event & 0xffff0000) == 0x71060000 || /* Port charge state change */
598*0ebf821cSHector Martin 	    (event & 0xffff0000) == 0x71130000) { /* Connector insert/remove event */
599*0ebf821cSHector Martin 		if (power->batt)
600*0ebf821cSHector Martin 			power_supply_changed(power->batt);
601*0ebf821cSHector Martin 		if (power->ac)
602*0ebf821cSHector Martin 			power_supply_changed(power->ac);
603*0ebf821cSHector Martin 		return NOTIFY_OK;
604*0ebf821cSHector Martin 	} else if (event == 0x71020000) {
605*0ebf821cSHector Martin 		/* Critical battery warning */
606*0ebf821cSHector Martin 		if (power->batt)
607*0ebf821cSHector Martin 			schedule_work(&power->critical_work);
608*0ebf821cSHector Martin 		return NOTIFY_OK;
609*0ebf821cSHector Martin 	}
610*0ebf821cSHector Martin 
611*0ebf821cSHector Martin 	return NOTIFY_DONE;
612*0ebf821cSHector Martin }
613*0ebf821cSHector Martin 
614*0ebf821cSHector Martin static int macsmc_power_probe(struct platform_device *pdev)
615*0ebf821cSHector Martin {
616*0ebf821cSHector Martin 	struct device *dev = &pdev->dev;
617*0ebf821cSHector Martin 	struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent);
618*0ebf821cSHector Martin 	struct power_supply_config psy_cfg = {};
619*0ebf821cSHector Martin 	struct macsmc_power *power;
620*0ebf821cSHector Martin 	bool has_battery = false;
621*0ebf821cSHector Martin 	bool has_ac_adapter = false;
622*0ebf821cSHector Martin 	int ret = -ENODEV;
623*0ebf821cSHector Martin 	bool flag;
624*0ebf821cSHector Martin 	u16 vu16;
625*0ebf821cSHector Martin 	u32 val32;
626*0ebf821cSHector Martin 	enum power_supply_property *props;
627*0ebf821cSHector Martin 	size_t nprops;
628*0ebf821cSHector Martin 
629*0ebf821cSHector Martin 	if (!smc)
630*0ebf821cSHector Martin 		return -ENODEV;
631*0ebf821cSHector Martin 
632*0ebf821cSHector Martin 	power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
633*0ebf821cSHector Martin 	if (!power)
634*0ebf821cSHector Martin 		return -ENOMEM;
635*0ebf821cSHector Martin 
636*0ebf821cSHector Martin 	power->dev = dev;
637*0ebf821cSHector Martin 	power->smc = smc;
638*0ebf821cSHector Martin 	dev_set_drvdata(dev, power);
639*0ebf821cSHector Martin 
640*0ebf821cSHector Martin 	INIT_WORK(&power->critical_work, macsmc_power_critical_work);
641*0ebf821cSHector Martin 	ret = devm_work_autocancel(dev, &power->critical_work, macsmc_power_critical_work);
642*0ebf821cSHector Martin 	if (ret)
643*0ebf821cSHector Martin 		return ret;
644*0ebf821cSHector Martin 
645*0ebf821cSHector Martin 	/*
646*0ebf821cSHector Martin 	 * Check for battery presence.
647*0ebf821cSHector Martin 	 * B0AV is a fundamental key.
648*0ebf821cSHector Martin 	 */
649*0ebf821cSHector Martin 	if (apple_smc_read_u16(power->smc, SMC_KEY(B0AV), &vu16) == 0 &&
650*0ebf821cSHector Martin 	    macsmc_battery_get_status(power) > POWER_SUPPLY_STATUS_UNKNOWN)
651*0ebf821cSHector Martin 		has_battery = true;
652*0ebf821cSHector Martin 
653*0ebf821cSHector Martin 	/*
654*0ebf821cSHector Martin 	 * Check for AC adapter presence.
655*0ebf821cSHector Martin 	 * CHIS is a fundamental key.
656*0ebf821cSHector Martin 	 */
657*0ebf821cSHector Martin 	if (apple_smc_key_exists(smc, SMC_KEY(CHIS)))
658*0ebf821cSHector Martin 		has_ac_adapter = true;
659*0ebf821cSHector Martin 
660*0ebf821cSHector Martin 	if (!has_battery && !has_ac_adapter)
661*0ebf821cSHector Martin 		return -ENODEV;
662*0ebf821cSHector Martin 
663*0ebf821cSHector Martin 	if (has_battery) {
664*0ebf821cSHector Martin 		power->batt_desc = macsmc_battery_desc_template;
665*0ebf821cSHector Martin 		props = devm_kcalloc(dev, MACSMC_MAX_BATT_PROPS,
666*0ebf821cSHector Martin 				     sizeof(enum power_supply_property),
667*0ebf821cSHector Martin 				     GFP_KERNEL);
668*0ebf821cSHector Martin 		if (!props)
669*0ebf821cSHector Martin 			return -ENOMEM;
670*0ebf821cSHector Martin 
671*0ebf821cSHector Martin 		nprops = 0;
672*0ebf821cSHector Martin 
673*0ebf821cSHector Martin 		/* Fundamental properties */
674*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_STATUS;
675*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_PRESENT;
676*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_NOW;
677*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_CURRENT_NOW;
678*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_POWER_NOW;
679*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_CAPACITY;
680*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_CAPACITY_LEVEL;
681*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_TEMP;
682*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_CYCLE_COUNT;
683*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_HEALTH;
684*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_SCOPE;
685*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_MODEL_NAME;
686*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_SERIAL_NUMBER;
687*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_MANUFACTURE_YEAR;
688*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_MANUFACTURE_MONTH;
689*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_MANUFACTURE_DAY;
690*0ebf821cSHector Martin 
691*0ebf821cSHector Martin 		/* Extended properties usually present */
692*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW;
693*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_TIME_TO_FULL_NOW;
694*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
695*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
696*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_MIN;
697*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_MAX;
698*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT;
699*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX;
700*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE;
701*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
702*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_CHARGE_FULL;
703*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_CHARGE_NOW;
704*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
705*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_ENERGY_FULL;
706*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_ENERGY_NOW;
707*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_CHARGE_COUNTER;
708*0ebf821cSHector Martin 
709*0ebf821cSHector Martin 		/* Detect features based on key availability */
710*0ebf821cSHector Martin 		if (apple_smc_key_exists(smc, SMC_KEY(CHTE)))
711*0ebf821cSHector Martin 			power->has_chte = true;
712*0ebf821cSHector Martin 		if (apple_smc_key_exists(smc, SMC_KEY(CH0C)))
713*0ebf821cSHector Martin 			power->has_ch0c = true;
714*0ebf821cSHector Martin 		if (apple_smc_key_exists(smc, SMC_KEY(CH0I)))
715*0ebf821cSHector Martin 			power->has_ch0i = true;
716*0ebf821cSHector Martin 
717*0ebf821cSHector Martin 		/* Reset "Optimised Battery Charging" flags to default state */
718*0ebf821cSHector Martin 		if (power->has_chte)
719*0ebf821cSHector Martin 			apple_smc_write_u32(smc, SMC_KEY(CHTE), 0);
720*0ebf821cSHector Martin 		else if (power->has_ch0c)
721*0ebf821cSHector Martin 			apple_smc_write_u8(smc, SMC_KEY(CH0C), 0);
722*0ebf821cSHector Martin 
723*0ebf821cSHector Martin 		if (power->has_ch0i)
724*0ebf821cSHector Martin 			apple_smc_write_u8(smc, SMC_KEY(CH0I), 0);
725*0ebf821cSHector Martin 
726*0ebf821cSHector Martin 		apple_smc_write_u8(smc, SMC_KEY(CH0K), 0);
727*0ebf821cSHector Martin 		apple_smc_write_u8(smc, SMC_KEY(CH0B), 0);
728*0ebf821cSHector Martin 
729*0ebf821cSHector Martin 		/* Configure charge behaviour if supported */
730*0ebf821cSHector Martin 		if (power->has_ch0i || power->has_ch0c || power->has_chte) {
731*0ebf821cSHector Martin 			props[nprops++] = POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR;
732*0ebf821cSHector Martin 
733*0ebf821cSHector Martin 			power->batt_desc.charge_behaviours =
734*0ebf821cSHector Martin 				BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO);
735*0ebf821cSHector Martin 
736*0ebf821cSHector Martin 			if (power->has_ch0i)
737*0ebf821cSHector Martin 				power->batt_desc.charge_behaviours |=
738*0ebf821cSHector Martin 					BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE);
739*0ebf821cSHector Martin 
740*0ebf821cSHector Martin 			if (power->has_chte || power->has_ch0c)
741*0ebf821cSHector Martin 				power->batt_desc.charge_behaviours |=
742*0ebf821cSHector Martin 					BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE);
743*0ebf821cSHector Martin 		}
744*0ebf821cSHector Martin 
745*0ebf821cSHector Martin 		/* Detect charge limit method (CHWA vs CHLS) */
746*0ebf821cSHector Martin 		if (apple_smc_read_flag(power->smc, SMC_KEY(CHWA), &flag) == 0)
747*0ebf821cSHector Martin 			power->has_chwa = true;
748*0ebf821cSHector Martin 		else if (apple_smc_read_u16(power->smc, SMC_KEY(CHLS), &vu16) >= 0)
749*0ebf821cSHector Martin 			power->has_chls = true;
750*0ebf821cSHector Martin 
751*0ebf821cSHector Martin 		if (nprops > MACSMC_MAX_BATT_PROPS)
752*0ebf821cSHector Martin 			return -ENOMEM;
753*0ebf821cSHector Martin 
754*0ebf821cSHector Martin 		power->batt_desc.properties = props;
755*0ebf821cSHector Martin 		power->batt_desc.num_properties = nprops;
756*0ebf821cSHector Martin 
757*0ebf821cSHector Martin 		/* Fetch identity strings */
758*0ebf821cSHector Martin 		apple_smc_read(smc, SMC_KEY(BMDN), power->model_name,
759*0ebf821cSHector Martin 			       sizeof(power->model_name) - 1);
760*0ebf821cSHector Martin 		apple_smc_read(smc, SMC_KEY(BMSN), power->serial_number,
761*0ebf821cSHector Martin 			       sizeof(power->serial_number) - 1);
762*0ebf821cSHector Martin 		apple_smc_read(smc, SMC_KEY(BMDT), power->mfg_date,
763*0ebf821cSHector Martin 			       sizeof(power->mfg_date) - 1);
764*0ebf821cSHector Martin 
765*0ebf821cSHector Martin 		apple_smc_read_u8(power->smc, SMC_KEY(BNCB), &power->num_cells);
766*0ebf821cSHector Martin 		power->nominal_voltage_mv = MACSMC_NOMINAL_CELL_VOLTAGE_MV * power->num_cells;
767*0ebf821cSHector Martin 
768*0ebf821cSHector Martin 		/* Enable critical shutdown notifications by reading status once */
769*0ebf821cSHector Martin 		apple_smc_read_u32(power->smc, SMC_KEY(BCF0), &val32);
770*0ebf821cSHector Martin 
771*0ebf821cSHector Martin 		psy_cfg.drv_data = power;
772*0ebf821cSHector Martin 		power->batt = devm_power_supply_register(dev, &power->batt_desc, &psy_cfg);
773*0ebf821cSHector Martin 		if (IS_ERR(power->batt)) {
774*0ebf821cSHector Martin 			dev_err_probe(dev, PTR_ERR(power->batt),
775*0ebf821cSHector Martin 				      "Failed to register battery\n");
776*0ebf821cSHector Martin 			/* Don't return failure yet; try AC registration first */
777*0ebf821cSHector Martin 			power->batt = NULL;
778*0ebf821cSHector Martin 		}
779*0ebf821cSHector Martin 	}
780*0ebf821cSHector Martin 
781*0ebf821cSHector Martin 	if (has_ac_adapter) {
782*0ebf821cSHector Martin 		power->ac_desc = macsmc_ac_desc_template;
783*0ebf821cSHector Martin 		props = devm_kcalloc(dev, MACSMC_MAX_AC_PROPS,
784*0ebf821cSHector Martin 				     sizeof(enum power_supply_property),
785*0ebf821cSHector Martin 				     GFP_KERNEL);
786*0ebf821cSHector Martin 		if (!props)
787*0ebf821cSHector Martin 			return -ENOMEM;
788*0ebf821cSHector Martin 
789*0ebf821cSHector Martin 		nprops = 0;
790*0ebf821cSHector Martin 
791*0ebf821cSHector Martin 		/* Online status is fundamental */
792*0ebf821cSHector Martin 		props[nprops++] = POWER_SUPPLY_PROP_ONLINE;
793*0ebf821cSHector Martin 
794*0ebf821cSHector Martin 		/* Input power limits are usually available */
795*0ebf821cSHector Martin 		if (apple_smc_key_exists(power->smc, SMC_KEY(ACPW)))
796*0ebf821cSHector Martin 			props[nprops++] = POWER_SUPPLY_PROP_INPUT_POWER_LIMIT;
797*0ebf821cSHector Martin 
798*0ebf821cSHector Martin 		/* macOS 15.4+ firmware dropped legacy AC keys (AC-n, AC-i) */
799*0ebf821cSHector Martin 		if (apple_smc_read_u16(power->smc, SMC_KEY(AC-n), &vu16) >= 0) {
800*0ebf821cSHector Martin 			props[nprops++] = POWER_SUPPLY_PROP_VOLTAGE_NOW;
801*0ebf821cSHector Martin 			props[nprops++] = POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT;
802*0ebf821cSHector Martin 		}
803*0ebf821cSHector Martin 
804*0ebf821cSHector Martin 		if (nprops > MACSMC_MAX_AC_PROPS)
805*0ebf821cSHector Martin 			return -ENOMEM;
806*0ebf821cSHector Martin 
807*0ebf821cSHector Martin 		power->ac_desc.properties = props;
808*0ebf821cSHector Martin 		power->ac_desc.num_properties = nprops;
809*0ebf821cSHector Martin 
810*0ebf821cSHector Martin 		psy_cfg.drv_data = power;
811*0ebf821cSHector Martin 		power->ac = devm_power_supply_register(dev, &power->ac_desc, &psy_cfg);
812*0ebf821cSHector Martin 		if (IS_ERR(power->ac)) {
813*0ebf821cSHector Martin 			dev_err_probe(dev, PTR_ERR(power->ac),
814*0ebf821cSHector Martin 				      "Failed to register AC adapter\n");
815*0ebf821cSHector Martin 			power->ac = NULL;
816*0ebf821cSHector Martin 		}
817*0ebf821cSHector Martin 	}
818*0ebf821cSHector Martin 
819*0ebf821cSHector Martin 	/* Final check: did we register anything? */
820*0ebf821cSHector Martin 	if (!power->batt && !power->ac)
821*0ebf821cSHector Martin 		return -ENODEV;
822*0ebf821cSHector Martin 
823*0ebf821cSHector Martin 	power->nb.notifier_call = macsmc_power_event;
824*0ebf821cSHector Martin 	blocking_notifier_chain_register(&smc->event_handlers, &power->nb);
825*0ebf821cSHector Martin 
826*0ebf821cSHector Martin 	return 0;
827*0ebf821cSHector Martin }
828*0ebf821cSHector Martin 
829*0ebf821cSHector Martin static void macsmc_power_remove(struct platform_device *pdev)
830*0ebf821cSHector Martin {
831*0ebf821cSHector Martin 	struct macsmc_power *power = dev_get_drvdata(&pdev->dev);
832*0ebf821cSHector Martin 
833*0ebf821cSHector Martin 	blocking_notifier_chain_unregister(&power->smc->event_handlers, &power->nb);
834*0ebf821cSHector Martin }
835*0ebf821cSHector Martin 
836*0ebf821cSHector Martin static const struct platform_device_id macsmc_power_id[] = {
837*0ebf821cSHector Martin 	{ "macsmc-power" },
838*0ebf821cSHector Martin 	{ /* sentinel */ }
839*0ebf821cSHector Martin };
840*0ebf821cSHector Martin MODULE_DEVICE_TABLE(platform, macsmc_power_id);
841*0ebf821cSHector Martin 
842*0ebf821cSHector Martin static struct platform_driver macsmc_power_driver = {
843*0ebf821cSHector Martin 	.driver = {
844*0ebf821cSHector Martin 		.name = "macsmc-power",
845*0ebf821cSHector Martin 	},
846*0ebf821cSHector Martin 	.id_table = macsmc_power_id,
847*0ebf821cSHector Martin 	.probe = macsmc_power_probe,
848*0ebf821cSHector Martin 	.remove = macsmc_power_remove,
849*0ebf821cSHector Martin };
850*0ebf821cSHector Martin module_platform_driver(macsmc_power_driver);
851*0ebf821cSHector Martin 
852*0ebf821cSHector Martin MODULE_LICENSE("Dual MIT/GPL");
853*0ebf821cSHector Martin MODULE_DESCRIPTION("Apple SMC battery and power management driver");
854*0ebf821cSHector Martin MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
855*0ebf821cSHector Martin MODULE_AUTHOR("Michael Reeves <michael.reeves077@gmail.com>");
856