xref: /linux/drivers/hwmon/macsmc-hwmon.c (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
1*785205fdSJames Calligeros // SPDX-License-Identifier: GPL-2.0-only OR MIT
2*785205fdSJames Calligeros /*
3*785205fdSJames Calligeros  * Apple SMC hwmon driver for Apple Silicon platforms
4*785205fdSJames Calligeros  *
5*785205fdSJames Calligeros  * The System Management Controller on Apple Silicon devices is responsible for
6*785205fdSJames Calligeros  * measuring data from sensors across the SoC and machine. These include power,
7*785205fdSJames Calligeros  * temperature, voltage and current sensors. Some "sensors" actually expose
8*785205fdSJames Calligeros  * derived values. An example of this is the key PHPC, which is an estimate
9*785205fdSJames Calligeros  * of the heat energy being dissipated by the SoC.
10*785205fdSJames Calligeros  *
11*785205fdSJames Calligeros  * While each SoC only has one SMC variant, each platform exposes a different
12*785205fdSJames Calligeros  * set of sensors. For example, M1 MacBooks expose battery telemetry sensors
13*785205fdSJames Calligeros  * which are not present on the M1 Mac mini. For this reason, the available
14*785205fdSJames Calligeros  * sensors for a given platform are described in the device tree in a child
15*785205fdSJames Calligeros  * node of the SMC device. We must walk this list of available sensors and
16*785205fdSJames Calligeros  * populate the required hwmon data structures at runtime.
17*785205fdSJames Calligeros  *
18*785205fdSJames Calligeros  * Originally based on a concept by Jean-Francois Bortolotti <jeff@borto.fr>
19*785205fdSJames Calligeros  *
20*785205fdSJames Calligeros  * Copyright The Asahi Linux Contributors
21*785205fdSJames Calligeros  */
22*785205fdSJames Calligeros 
23*785205fdSJames Calligeros #include <linux/bitfield.h>
24*785205fdSJames Calligeros #include <linux/hwmon.h>
25*785205fdSJames Calligeros #include <linux/mfd/macsmc.h>
26*785205fdSJames Calligeros #include <linux/module.h>
27*785205fdSJames Calligeros #include <linux/of.h>
28*785205fdSJames Calligeros #include <linux/platform_device.h>
29*785205fdSJames Calligeros 
30*785205fdSJames Calligeros #define MAX_LABEL_LENGTH	32
31*785205fdSJames Calligeros 
32*785205fdSJames Calligeros /* Temperature, voltage, current, power, fan(s) */
33*785205fdSJames Calligeros #define NUM_SENSOR_TYPES	5
34*785205fdSJames Calligeros 
35*785205fdSJames Calligeros #define FLT_EXP_BIAS	127
36*785205fdSJames Calligeros #define FLT_EXP_MASK	GENMASK(30, 23)
37*785205fdSJames Calligeros #define FLT_MANT_BIAS	23
38*785205fdSJames Calligeros #define FLT_MANT_MASK	GENMASK(22, 0)
39*785205fdSJames Calligeros #define FLT_SIGN_MASK	BIT(31)
40*785205fdSJames Calligeros 
41*785205fdSJames Calligeros static bool fan_control;
42*785205fdSJames Calligeros module_param_unsafe(fan_control, bool, 0644);
43*785205fdSJames Calligeros MODULE_PARM_DESC(fan_control,
44*785205fdSJames Calligeros 		 "Override the SMC to set your own fan speeds on supported machines");
45*785205fdSJames Calligeros 
46*785205fdSJames Calligeros struct macsmc_hwmon_sensor {
47*785205fdSJames Calligeros 	struct apple_smc_key_info info;
48*785205fdSJames Calligeros 	smc_key macsmc_key;
49*785205fdSJames Calligeros 	char label[MAX_LABEL_LENGTH];
50*785205fdSJames Calligeros 	u32 attrs;
51*785205fdSJames Calligeros };
52*785205fdSJames Calligeros 
53*785205fdSJames Calligeros struct macsmc_hwmon_fan {
54*785205fdSJames Calligeros 	struct macsmc_hwmon_sensor now;
55*785205fdSJames Calligeros 	struct macsmc_hwmon_sensor min;
56*785205fdSJames Calligeros 	struct macsmc_hwmon_sensor max;
57*785205fdSJames Calligeros 	struct macsmc_hwmon_sensor set;
58*785205fdSJames Calligeros 	struct macsmc_hwmon_sensor mode;
59*785205fdSJames Calligeros 	char label[MAX_LABEL_LENGTH];
60*785205fdSJames Calligeros 	u32 attrs;
61*785205fdSJames Calligeros 	bool manual;
62*785205fdSJames Calligeros };
63*785205fdSJames Calligeros 
64*785205fdSJames Calligeros struct macsmc_hwmon_sensors {
65*785205fdSJames Calligeros 	struct hwmon_channel_info channel_info;
66*785205fdSJames Calligeros 	struct macsmc_hwmon_sensor *sensors;
67*785205fdSJames Calligeros 	u32 count;
68*785205fdSJames Calligeros };
69*785205fdSJames Calligeros 
70*785205fdSJames Calligeros struct macsmc_hwmon_fans {
71*785205fdSJames Calligeros 	struct hwmon_channel_info channel_info;
72*785205fdSJames Calligeros 	struct macsmc_hwmon_fan *fans;
73*785205fdSJames Calligeros 	u32 count;
74*785205fdSJames Calligeros };
75*785205fdSJames Calligeros 
76*785205fdSJames Calligeros struct macsmc_hwmon {
77*785205fdSJames Calligeros 	struct device *dev;
78*785205fdSJames Calligeros 	struct apple_smc *smc;
79*785205fdSJames Calligeros 	struct device *hwmon_dev;
80*785205fdSJames Calligeros 	struct hwmon_chip_info chip_info;
81*785205fdSJames Calligeros 	/* Chip + sensor types + NULL */
82*785205fdSJames Calligeros 	const struct hwmon_channel_info *channel_infos[1 + NUM_SENSOR_TYPES + 1];
83*785205fdSJames Calligeros 	struct macsmc_hwmon_sensors temp;
84*785205fdSJames Calligeros 	struct macsmc_hwmon_sensors volt;
85*785205fdSJames Calligeros 	struct macsmc_hwmon_sensors curr;
86*785205fdSJames Calligeros 	struct macsmc_hwmon_sensors power;
87*785205fdSJames Calligeros 	struct macsmc_hwmon_fans fan;
88*785205fdSJames Calligeros };
89*785205fdSJames Calligeros 
90*785205fdSJames Calligeros static int macsmc_hwmon_read_label(struct device *dev,
91*785205fdSJames Calligeros 				   enum hwmon_sensor_types type, u32 attr,
92*785205fdSJames Calligeros 				   int channel, const char **str)
93*785205fdSJames Calligeros {
94*785205fdSJames Calligeros 	struct macsmc_hwmon *hwmon = dev_get_drvdata(dev);
95*785205fdSJames Calligeros 
96*785205fdSJames Calligeros 	switch (type) {
97*785205fdSJames Calligeros 	case hwmon_temp:
98*785205fdSJames Calligeros 		*str = hwmon->temp.sensors[channel].label;
99*785205fdSJames Calligeros 		break;
100*785205fdSJames Calligeros 	case hwmon_in:
101*785205fdSJames Calligeros 		*str = hwmon->volt.sensors[channel].label;
102*785205fdSJames Calligeros 		break;
103*785205fdSJames Calligeros 	case hwmon_curr:
104*785205fdSJames Calligeros 		*str = hwmon->curr.sensors[channel].label;
105*785205fdSJames Calligeros 		break;
106*785205fdSJames Calligeros 	case hwmon_power:
107*785205fdSJames Calligeros 		*str = hwmon->power.sensors[channel].label;
108*785205fdSJames Calligeros 		break;
109*785205fdSJames Calligeros 	case hwmon_fan:
110*785205fdSJames Calligeros 		*str = hwmon->fan.fans[channel].label;
111*785205fdSJames Calligeros 		break;
112*785205fdSJames Calligeros 	default:
113*785205fdSJames Calligeros 		return -EOPNOTSUPP;
114*785205fdSJames Calligeros 	}
115*785205fdSJames Calligeros 
116*785205fdSJames Calligeros 	return 0;
117*785205fdSJames Calligeros }
118*785205fdSJames Calligeros 
119*785205fdSJames Calligeros /*
120*785205fdSJames Calligeros  * A number of sensors report data in a 48.16 fixed-point decimal format that is
121*785205fdSJames Calligeros  * not used by any other function of the SMC.
122*785205fdSJames Calligeros  */
123*785205fdSJames Calligeros static int macsmc_hwmon_read_ioft_scaled(struct apple_smc *smc, smc_key key,
124*785205fdSJames Calligeros 					 u64 *p, int scale)
125*785205fdSJames Calligeros {
126*785205fdSJames Calligeros 	u64 val;
127*785205fdSJames Calligeros 	int ret;
128*785205fdSJames Calligeros 
129*785205fdSJames Calligeros 	ret = apple_smc_read_u64(smc, key, &val);
130*785205fdSJames Calligeros 	if (ret < 0)
131*785205fdSJames Calligeros 		return ret;
132*785205fdSJames Calligeros 
133*785205fdSJames Calligeros 	*p = mult_frac(val, scale, 65536);
134*785205fdSJames Calligeros 
135*785205fdSJames Calligeros 	return 0;
136*785205fdSJames Calligeros }
137*785205fdSJames Calligeros 
138*785205fdSJames Calligeros /*
139*785205fdSJames Calligeros  * Many sensors report their data as IEEE-754 floats. No other SMC function uses
140*785205fdSJames Calligeros  * them.
141*785205fdSJames Calligeros  */
142*785205fdSJames Calligeros static int macsmc_hwmon_read_f32_scaled(struct apple_smc *smc, smc_key key,
143*785205fdSJames Calligeros 					int *p, int scale)
144*785205fdSJames Calligeros {
145*785205fdSJames Calligeros 	u32 fval;
146*785205fdSJames Calligeros 	u64 val;
147*785205fdSJames Calligeros 	int ret, exp;
148*785205fdSJames Calligeros 
149*785205fdSJames Calligeros 	ret = apple_smc_read_u32(smc, key, &fval);
150*785205fdSJames Calligeros 	if (ret < 0)
151*785205fdSJames Calligeros 		return ret;
152*785205fdSJames Calligeros 
153*785205fdSJames Calligeros 	val = ((u64)((fval & FLT_MANT_MASK) | BIT(23)));
154*785205fdSJames Calligeros 	exp = ((fval >> 23) & 0xff) - FLT_EXP_BIAS - FLT_MANT_BIAS;
155*785205fdSJames Calligeros 
156*785205fdSJames Calligeros 	/* We never have negatively scaled SMC floats */
157*785205fdSJames Calligeros 	val *= scale;
158*785205fdSJames Calligeros 
159*785205fdSJames Calligeros 	if (exp > 63)
160*785205fdSJames Calligeros 		val = U64_MAX;
161*785205fdSJames Calligeros 	else if (exp < -63)
162*785205fdSJames Calligeros 		val = 0;
163*785205fdSJames Calligeros 	else if (exp < 0)
164*785205fdSJames Calligeros 		val >>= -exp;
165*785205fdSJames Calligeros 	else if (exp != 0 && (val & ~((1UL << (64 - exp)) - 1))) /* overflow */
166*785205fdSJames Calligeros 		val = U64_MAX;
167*785205fdSJames Calligeros 	else
168*785205fdSJames Calligeros 		val <<= exp;
169*785205fdSJames Calligeros 
170*785205fdSJames Calligeros 	if (fval & FLT_SIGN_MASK) {
171*785205fdSJames Calligeros 		if (val > (-(s64)INT_MIN))
172*785205fdSJames Calligeros 			*p = INT_MIN;
173*785205fdSJames Calligeros 		else
174*785205fdSJames Calligeros 			*p = -val;
175*785205fdSJames Calligeros 	} else {
176*785205fdSJames Calligeros 		if (val > INT_MAX)
177*785205fdSJames Calligeros 			*p = INT_MAX;
178*785205fdSJames Calligeros 		else
179*785205fdSJames Calligeros 			*p = val;
180*785205fdSJames Calligeros 	}
181*785205fdSJames Calligeros 
182*785205fdSJames Calligeros 	return 0;
183*785205fdSJames Calligeros }
184*785205fdSJames Calligeros 
185*785205fdSJames Calligeros /*
186*785205fdSJames Calligeros  * The SMC has keys of multiple types, denoted by a FourCC of the same format
187*785205fdSJames Calligeros  * as the key ID. We don't know what data type a key encodes until we poke at it.
188*785205fdSJames Calligeros  */
189*785205fdSJames Calligeros static int macsmc_hwmon_read_key(struct apple_smc *smc,
190*785205fdSJames Calligeros 				 struct macsmc_hwmon_sensor *sensor, int scale,
191*785205fdSJames Calligeros 				 long *val)
192*785205fdSJames Calligeros {
193*785205fdSJames Calligeros 	int ret;
194*785205fdSJames Calligeros 
195*785205fdSJames Calligeros 	switch (sensor->info.type_code) {
196*785205fdSJames Calligeros 	/* 32-bit IEEE 754 float */
197*785205fdSJames Calligeros 	case __SMC_KEY('f', 'l', 't', ' '): {
198*785205fdSJames Calligeros 		u32 flt_ = 0;
199*785205fdSJames Calligeros 
200*785205fdSJames Calligeros 		ret = macsmc_hwmon_read_f32_scaled(smc, sensor->macsmc_key,
201*785205fdSJames Calligeros 						   &flt_, scale);
202*785205fdSJames Calligeros 		if (ret)
203*785205fdSJames Calligeros 			return ret;
204*785205fdSJames Calligeros 
205*785205fdSJames Calligeros 		*val = flt_;
206*785205fdSJames Calligeros 		break;
207*785205fdSJames Calligeros 	}
208*785205fdSJames Calligeros 	/* 48.16 fixed point decimal */
209*785205fdSJames Calligeros 	case __SMC_KEY('i', 'o', 'f', 't'): {
210*785205fdSJames Calligeros 		u64 ioft = 0;
211*785205fdSJames Calligeros 
212*785205fdSJames Calligeros 		ret = macsmc_hwmon_read_ioft_scaled(smc, sensor->macsmc_key,
213*785205fdSJames Calligeros 						    &ioft, scale);
214*785205fdSJames Calligeros 		if (ret)
215*785205fdSJames Calligeros 			return ret;
216*785205fdSJames Calligeros 
217*785205fdSJames Calligeros 		*val = (long)ioft;
218*785205fdSJames Calligeros 		break;
219*785205fdSJames Calligeros 	}
220*785205fdSJames Calligeros 	default:
221*785205fdSJames Calligeros 		return -EOPNOTSUPP;
222*785205fdSJames Calligeros 	}
223*785205fdSJames Calligeros 
224*785205fdSJames Calligeros 	return 0;
225*785205fdSJames Calligeros }
226*785205fdSJames Calligeros 
227*785205fdSJames Calligeros static int macsmc_hwmon_write_f32(struct apple_smc *smc, smc_key key, int value)
228*785205fdSJames Calligeros {
229*785205fdSJames Calligeros 	u64 val;
230*785205fdSJames Calligeros 	u32 fval = 0;
231*785205fdSJames Calligeros 	int exp = 0, neg;
232*785205fdSJames Calligeros 
233*785205fdSJames Calligeros 	val = abs(value);
234*785205fdSJames Calligeros 	neg = val != value;
235*785205fdSJames Calligeros 
236*785205fdSJames Calligeros 	if (val) {
237*785205fdSJames Calligeros 		int msb = __fls(val) - exp;
238*785205fdSJames Calligeros 
239*785205fdSJames Calligeros 		if (msb > 23) {
240*785205fdSJames Calligeros 			val >>= msb - FLT_MANT_BIAS;
241*785205fdSJames Calligeros 			exp -= msb - FLT_MANT_BIAS;
242*785205fdSJames Calligeros 		} else if (msb < 23) {
243*785205fdSJames Calligeros 			val <<= FLT_MANT_BIAS - msb;
244*785205fdSJames Calligeros 			exp += msb;
245*785205fdSJames Calligeros 		}
246*785205fdSJames Calligeros 
247*785205fdSJames Calligeros 		fval = FIELD_PREP(FLT_SIGN_MASK, neg) |
248*785205fdSJames Calligeros 		       FIELD_PREP(FLT_EXP_MASK, exp + FLT_EXP_BIAS) |
249*785205fdSJames Calligeros 		       FIELD_PREP(FLT_MANT_MASK, val);
250*785205fdSJames Calligeros 	}
251*785205fdSJames Calligeros 
252*785205fdSJames Calligeros 	return apple_smc_write_u32(smc, key, fval);
253*785205fdSJames Calligeros }
254*785205fdSJames Calligeros 
255*785205fdSJames Calligeros static int macsmc_hwmon_write_key(struct apple_smc *smc,
256*785205fdSJames Calligeros 				  struct macsmc_hwmon_sensor *sensor, long val)
257*785205fdSJames Calligeros {
258*785205fdSJames Calligeros 	switch (sensor->info.type_code) {
259*785205fdSJames Calligeros 	/* 32-bit IEEE 754 float */
260*785205fdSJames Calligeros 	case __SMC_KEY('f', 'l', 't', ' '):
261*785205fdSJames Calligeros 		return macsmc_hwmon_write_f32(smc, sensor->macsmc_key, val);
262*785205fdSJames Calligeros 	/* unsigned 8-bit integer */
263*785205fdSJames Calligeros 	case __SMC_KEY('u', 'i', '8', ' '):
264*785205fdSJames Calligeros 		return apple_smc_write_u8(smc, sensor->macsmc_key, val);
265*785205fdSJames Calligeros 	default:
266*785205fdSJames Calligeros 		return -EOPNOTSUPP;
267*785205fdSJames Calligeros 	}
268*785205fdSJames Calligeros }
269*785205fdSJames Calligeros 
270*785205fdSJames Calligeros static int macsmc_hwmon_read_fan(struct macsmc_hwmon *hwmon, u32 attr, int chan,
271*785205fdSJames Calligeros 				 long *val)
272*785205fdSJames Calligeros {
273*785205fdSJames Calligeros 	switch (attr) {
274*785205fdSJames Calligeros 	case hwmon_fan_input:
275*785205fdSJames Calligeros 		return macsmc_hwmon_read_key(hwmon->smc,
276*785205fdSJames Calligeros 					     &hwmon->fan.fans[chan].now, 1, val);
277*785205fdSJames Calligeros 	case hwmon_fan_min:
278*785205fdSJames Calligeros 		return macsmc_hwmon_read_key(hwmon->smc,
279*785205fdSJames Calligeros 					     &hwmon->fan.fans[chan].min, 1, val);
280*785205fdSJames Calligeros 	case hwmon_fan_max:
281*785205fdSJames Calligeros 		return macsmc_hwmon_read_key(hwmon->smc,
282*785205fdSJames Calligeros 					     &hwmon->fan.fans[chan].max, 1, val);
283*785205fdSJames Calligeros 	case hwmon_fan_target:
284*785205fdSJames Calligeros 		return macsmc_hwmon_read_key(hwmon->smc,
285*785205fdSJames Calligeros 					     &hwmon->fan.fans[chan].set, 1, val);
286*785205fdSJames Calligeros 	default:
287*785205fdSJames Calligeros 		return -EOPNOTSUPP;
288*785205fdSJames Calligeros 	}
289*785205fdSJames Calligeros }
290*785205fdSJames Calligeros 
291*785205fdSJames Calligeros static int macsmc_hwmon_write_fan(struct device *dev, u32 attr, int channel,
292*785205fdSJames Calligeros 				  long val)
293*785205fdSJames Calligeros {
294*785205fdSJames Calligeros 	struct macsmc_hwmon *hwmon = dev_get_drvdata(dev);
295*785205fdSJames Calligeros 	long min, max;
296*785205fdSJames Calligeros 	int ret;
297*785205fdSJames Calligeros 
298*785205fdSJames Calligeros 	if (!fan_control || hwmon->fan.fans[channel].mode.macsmc_key == 0)
299*785205fdSJames Calligeros 		return -EOPNOTSUPP;
300*785205fdSJames Calligeros 
301*785205fdSJames Calligeros 	/*
302*785205fdSJames Calligeros 	 * The SMC does no sanity checks on requested fan speeds, so we need to.
303*785205fdSJames Calligeros 	 */
304*785205fdSJames Calligeros 	ret = macsmc_hwmon_read_key(hwmon->smc, &hwmon->fan.fans[channel].min,
305*785205fdSJames Calligeros 				    1, &min);
306*785205fdSJames Calligeros 	if (ret)
307*785205fdSJames Calligeros 		return ret;
308*785205fdSJames Calligeros 
309*785205fdSJames Calligeros 	ret = macsmc_hwmon_read_key(hwmon->smc, &hwmon->fan.fans[channel].max,
310*785205fdSJames Calligeros 				    1, &max);
311*785205fdSJames Calligeros 	if (ret)
312*785205fdSJames Calligeros 		return ret;
313*785205fdSJames Calligeros 
314*785205fdSJames Calligeros 	if (val >= min && val <= max) {
315*785205fdSJames Calligeros 		if (!hwmon->fan.fans[channel].manual) {
316*785205fdSJames Calligeros 			/* Write 1 to mode key for manual control */
317*785205fdSJames Calligeros 			ret = macsmc_hwmon_write_key(hwmon->smc,
318*785205fdSJames Calligeros 						     &hwmon->fan.fans[channel].mode, 1);
319*785205fdSJames Calligeros 			if (ret < 0)
320*785205fdSJames Calligeros 				return ret;
321*785205fdSJames Calligeros 
322*785205fdSJames Calligeros 			hwmon->fan.fans[channel].manual = true;
323*785205fdSJames Calligeros 		}
324*785205fdSJames Calligeros 		return macsmc_hwmon_write_key(hwmon->smc,
325*785205fdSJames Calligeros 					      &hwmon->fan.fans[channel].set, val);
326*785205fdSJames Calligeros 	} else if (!val) {
327*785205fdSJames Calligeros 		if (hwmon->fan.fans[channel].manual) {
328*785205fdSJames Calligeros 			ret = macsmc_hwmon_write_key(hwmon->smc,
329*785205fdSJames Calligeros 						     &hwmon->fan.fans[channel].mode, 0);
330*785205fdSJames Calligeros 			if (ret < 0)
331*785205fdSJames Calligeros 				return ret;
332*785205fdSJames Calligeros 
333*785205fdSJames Calligeros 			hwmon->fan.fans[channel].manual = false;
334*785205fdSJames Calligeros 		}
335*785205fdSJames Calligeros 	} else {
336*785205fdSJames Calligeros 		return -EINVAL;
337*785205fdSJames Calligeros 	}
338*785205fdSJames Calligeros 
339*785205fdSJames Calligeros 	return 0;
340*785205fdSJames Calligeros }
341*785205fdSJames Calligeros 
342*785205fdSJames Calligeros static int macsmc_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
343*785205fdSJames Calligeros 			     u32 attr, int channel, long *val)
344*785205fdSJames Calligeros {
345*785205fdSJames Calligeros 	struct macsmc_hwmon *hwmon = dev_get_drvdata(dev);
346*785205fdSJames Calligeros 	int ret = 0;
347*785205fdSJames Calligeros 
348*785205fdSJames Calligeros 	switch (type) {
349*785205fdSJames Calligeros 	case hwmon_temp:
350*785205fdSJames Calligeros 		ret = macsmc_hwmon_read_key(hwmon->smc,
351*785205fdSJames Calligeros 					    &hwmon->temp.sensors[channel], 1000, val);
352*785205fdSJames Calligeros 		break;
353*785205fdSJames Calligeros 	case hwmon_in:
354*785205fdSJames Calligeros 		ret = macsmc_hwmon_read_key(hwmon->smc,
355*785205fdSJames Calligeros 					    &hwmon->volt.sensors[channel], 1000, val);
356*785205fdSJames Calligeros 		break;
357*785205fdSJames Calligeros 	case hwmon_curr:
358*785205fdSJames Calligeros 		ret = macsmc_hwmon_read_key(hwmon->smc,
359*785205fdSJames Calligeros 					    &hwmon->curr.sensors[channel], 1000, val);
360*785205fdSJames Calligeros 		break;
361*785205fdSJames Calligeros 	case hwmon_power:
362*785205fdSJames Calligeros 		/* SMC returns power in Watts with acceptable precision to scale to uW */
363*785205fdSJames Calligeros 		ret = macsmc_hwmon_read_key(hwmon->smc,
364*785205fdSJames Calligeros 					    &hwmon->power.sensors[channel],
365*785205fdSJames Calligeros 					    1000000, val);
366*785205fdSJames Calligeros 		break;
367*785205fdSJames Calligeros 	case hwmon_fan:
368*785205fdSJames Calligeros 		ret = macsmc_hwmon_read_fan(hwmon, attr, channel, val);
369*785205fdSJames Calligeros 		break;
370*785205fdSJames Calligeros 	default:
371*785205fdSJames Calligeros 		return -EOPNOTSUPP;
372*785205fdSJames Calligeros 	}
373*785205fdSJames Calligeros 
374*785205fdSJames Calligeros 	return ret;
375*785205fdSJames Calligeros }
376*785205fdSJames Calligeros 
377*785205fdSJames Calligeros static int macsmc_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
378*785205fdSJames Calligeros 			      u32 attr, int channel, long val)
379*785205fdSJames Calligeros {
380*785205fdSJames Calligeros 	switch (type) {
381*785205fdSJames Calligeros 	case hwmon_fan:
382*785205fdSJames Calligeros 		return macsmc_hwmon_write_fan(dev, attr, channel, val);
383*785205fdSJames Calligeros 	default:
384*785205fdSJames Calligeros 		return -EOPNOTSUPP;
385*785205fdSJames Calligeros 	}
386*785205fdSJames Calligeros }
387*785205fdSJames Calligeros 
388*785205fdSJames Calligeros static umode_t macsmc_hwmon_fan_is_visible(const struct macsmc_hwmon_fan *fan,
389*785205fdSJames Calligeros 					   u32 attr)
390*785205fdSJames Calligeros {
391*785205fdSJames Calligeros 	if (fan->attrs & BIT(attr)) {
392*785205fdSJames Calligeros 		if (attr == hwmon_fan_target && fan_control && fan->mode.macsmc_key)
393*785205fdSJames Calligeros 			return 0644;
394*785205fdSJames Calligeros 
395*785205fdSJames Calligeros 		return 0444;
396*785205fdSJames Calligeros 	}
397*785205fdSJames Calligeros 
398*785205fdSJames Calligeros 	return 0;
399*785205fdSJames Calligeros }
400*785205fdSJames Calligeros 
401*785205fdSJames Calligeros static umode_t macsmc_hwmon_is_visible(const void *data,
402*785205fdSJames Calligeros 				       enum hwmon_sensor_types type, u32 attr,
403*785205fdSJames Calligeros 				       int channel)
404*785205fdSJames Calligeros {
405*785205fdSJames Calligeros 	const struct macsmc_hwmon *hwmon = data;
406*785205fdSJames Calligeros 	struct macsmc_hwmon_sensor *sensor;
407*785205fdSJames Calligeros 
408*785205fdSJames Calligeros 	switch (type) {
409*785205fdSJames Calligeros 	case hwmon_in:
410*785205fdSJames Calligeros 		sensor = &hwmon->volt.sensors[channel];
411*785205fdSJames Calligeros 		break;
412*785205fdSJames Calligeros 	case hwmon_curr:
413*785205fdSJames Calligeros 		sensor = &hwmon->curr.sensors[channel];
414*785205fdSJames Calligeros 		break;
415*785205fdSJames Calligeros 	case hwmon_power:
416*785205fdSJames Calligeros 		sensor = &hwmon->power.sensors[channel];
417*785205fdSJames Calligeros 		break;
418*785205fdSJames Calligeros 	case hwmon_temp:
419*785205fdSJames Calligeros 		sensor = &hwmon->temp.sensors[channel];
420*785205fdSJames Calligeros 		break;
421*785205fdSJames Calligeros 	case hwmon_fan:
422*785205fdSJames Calligeros 		return macsmc_hwmon_fan_is_visible(&hwmon->fan.fans[channel], attr);
423*785205fdSJames Calligeros 	default:
424*785205fdSJames Calligeros 		return 0;
425*785205fdSJames Calligeros 	}
426*785205fdSJames Calligeros 
427*785205fdSJames Calligeros 	/* Sensors only register ro attributes */
428*785205fdSJames Calligeros 	if (sensor->attrs & BIT(attr))
429*785205fdSJames Calligeros 		return 0444;
430*785205fdSJames Calligeros 
431*785205fdSJames Calligeros 	return 0;
432*785205fdSJames Calligeros }
433*785205fdSJames Calligeros 
434*785205fdSJames Calligeros static const struct hwmon_ops macsmc_hwmon_ops = {
435*785205fdSJames Calligeros 	.is_visible = macsmc_hwmon_is_visible,
436*785205fdSJames Calligeros 	.read = macsmc_hwmon_read,
437*785205fdSJames Calligeros 	.read_string = macsmc_hwmon_read_label,
438*785205fdSJames Calligeros 	.write = macsmc_hwmon_write,
439*785205fdSJames Calligeros };
440*785205fdSJames Calligeros 
441*785205fdSJames Calligeros /*
442*785205fdSJames Calligeros  * Get the key metadata, including key data type, from the SMC.
443*785205fdSJames Calligeros  */
444*785205fdSJames Calligeros static int macsmc_hwmon_parse_key(struct device *dev, struct apple_smc *smc,
445*785205fdSJames Calligeros 				  struct macsmc_hwmon_sensor *sensor,
446*785205fdSJames Calligeros 				  const char *key)
447*785205fdSJames Calligeros {
448*785205fdSJames Calligeros 	int ret;
449*785205fdSJames Calligeros 
450*785205fdSJames Calligeros 	ret = apple_smc_get_key_info(smc, _SMC_KEY(key), &sensor->info);
451*785205fdSJames Calligeros 	if (ret) {
452*785205fdSJames Calligeros 		dev_dbg(dev, "Failed to retrieve key info for %s\n", key);
453*785205fdSJames Calligeros 		return ret;
454*785205fdSJames Calligeros 	}
455*785205fdSJames Calligeros 
456*785205fdSJames Calligeros 	sensor->macsmc_key = _SMC_KEY(key);
457*785205fdSJames Calligeros 
458*785205fdSJames Calligeros 	return 0;
459*785205fdSJames Calligeros }
460*785205fdSJames Calligeros 
461*785205fdSJames Calligeros /*
462*785205fdSJames Calligeros  * A sensor is a single key-value pair as made available by the SMC.
463*785205fdSJames Calligeros  * The devicetree gives us the SMC key ID and a friendly name where the
464*785205fdSJames Calligeros  * purpose of the sensor is known.
465*785205fdSJames Calligeros  */
466*785205fdSJames Calligeros static int macsmc_hwmon_create_sensor(struct device *dev, struct apple_smc *smc,
467*785205fdSJames Calligeros 				      struct device_node *sensor_node,
468*785205fdSJames Calligeros 				      struct macsmc_hwmon_sensor *sensor)
469*785205fdSJames Calligeros {
470*785205fdSJames Calligeros 	const char *key, *label;
471*785205fdSJames Calligeros 	int ret;
472*785205fdSJames Calligeros 
473*785205fdSJames Calligeros 	ret = of_property_read_string(sensor_node, "apple,key-id", &key);
474*785205fdSJames Calligeros 	if (ret) {
475*785205fdSJames Calligeros 		dev_dbg(dev, "Could not find apple,key-id in sensor node\n");
476*785205fdSJames Calligeros 		return ret;
477*785205fdSJames Calligeros 	}
478*785205fdSJames Calligeros 
479*785205fdSJames Calligeros 	ret = macsmc_hwmon_parse_key(dev, smc, sensor, key);
480*785205fdSJames Calligeros 	if (ret)
481*785205fdSJames Calligeros 		return ret;
482*785205fdSJames Calligeros 
483*785205fdSJames Calligeros 	ret = of_property_read_string(sensor_node, "label", &label);
484*785205fdSJames Calligeros 	if (ret)
485*785205fdSJames Calligeros 		dev_dbg(dev, "No label found for sensor %s\n", key);
486*785205fdSJames Calligeros 	else
487*785205fdSJames Calligeros 		strscpy_pad(sensor->label, label, sizeof(sensor->label));
488*785205fdSJames Calligeros 
489*785205fdSJames Calligeros 	return 0;
490*785205fdSJames Calligeros }
491*785205fdSJames Calligeros 
492*785205fdSJames Calligeros /*
493*785205fdSJames Calligeros  * Fan data is exposed by the SMC as multiple sensors.
494*785205fdSJames Calligeros  *
495*785205fdSJames Calligeros  * The devicetree schema reuses apple,key-id for the actual fan speed sensor.
496*785205fdSJames Calligeros  * Min, max and target keys do not need labels, so we can reuse label
497*785205fdSJames Calligeros  * for naming the entire fan.
498*785205fdSJames Calligeros  */
499*785205fdSJames Calligeros static int macsmc_hwmon_create_fan(struct device *dev, struct apple_smc *smc,
500*785205fdSJames Calligeros 				   struct device_node *fan_node,
501*785205fdSJames Calligeros 				   struct macsmc_hwmon_fan *fan)
502*785205fdSJames Calligeros {
503*785205fdSJames Calligeros 	const char *label, *now, *min, *max, *set, *mode;
504*785205fdSJames Calligeros 	int ret;
505*785205fdSJames Calligeros 
506*785205fdSJames Calligeros 	ret = of_property_read_string(fan_node, "apple,key-id", &now);
507*785205fdSJames Calligeros 	if (ret) {
508*785205fdSJames Calligeros 		dev_err(dev, "apple,key-id not found in fan node!\n");
509*785205fdSJames Calligeros 		return ret;
510*785205fdSJames Calligeros 	}
511*785205fdSJames Calligeros 
512*785205fdSJames Calligeros 	ret = macsmc_hwmon_parse_key(dev, smc, &fan->now, now);
513*785205fdSJames Calligeros 	if (ret)
514*785205fdSJames Calligeros 		return ret;
515*785205fdSJames Calligeros 
516*785205fdSJames Calligeros 	fan->attrs = HWMON_F_INPUT;
517*785205fdSJames Calligeros 
518*785205fdSJames Calligeros 	ret = of_property_read_string(fan_node, "label", &label);
519*785205fdSJames Calligeros 	if (ret) {
520*785205fdSJames Calligeros 		dev_dbg(dev, "No label found for fan %s\n", now);
521*785205fdSJames Calligeros 	} else {
522*785205fdSJames Calligeros 		strscpy_pad(fan->label, label, sizeof(fan->label));
523*785205fdSJames Calligeros 		fan->attrs |= HWMON_F_LABEL;
524*785205fdSJames Calligeros 	}
525*785205fdSJames Calligeros 
526*785205fdSJames Calligeros 	/* The following keys are not required to simply monitor fan speed */
527*785205fdSJames Calligeros 	if (!of_property_read_string(fan_node, "apple,fan-minimum", &min)) {
528*785205fdSJames Calligeros 		ret = macsmc_hwmon_parse_key(dev, smc, &fan->min, min);
529*785205fdSJames Calligeros 		if (ret)
530*785205fdSJames Calligeros 			return ret;
531*785205fdSJames Calligeros 
532*785205fdSJames Calligeros 		fan->attrs |= HWMON_F_MIN;
533*785205fdSJames Calligeros 	}
534*785205fdSJames Calligeros 
535*785205fdSJames Calligeros 	if (!of_property_read_string(fan_node, "apple,fan-maximum", &max)) {
536*785205fdSJames Calligeros 		ret = macsmc_hwmon_parse_key(dev, smc, &fan->max, max);
537*785205fdSJames Calligeros 		if (ret)
538*785205fdSJames Calligeros 			return ret;
539*785205fdSJames Calligeros 
540*785205fdSJames Calligeros 		fan->attrs |= HWMON_F_MAX;
541*785205fdSJames Calligeros 	}
542*785205fdSJames Calligeros 
543*785205fdSJames Calligeros 	if (!of_property_read_string(fan_node, "apple,fan-target", &set)) {
544*785205fdSJames Calligeros 		ret = macsmc_hwmon_parse_key(dev, smc, &fan->set, set);
545*785205fdSJames Calligeros 		if (ret)
546*785205fdSJames Calligeros 			return ret;
547*785205fdSJames Calligeros 
548*785205fdSJames Calligeros 		fan->attrs |= HWMON_F_TARGET;
549*785205fdSJames Calligeros 	}
550*785205fdSJames Calligeros 
551*785205fdSJames Calligeros 	if (!of_property_read_string(fan_node, "apple,fan-mode", &mode)) {
552*785205fdSJames Calligeros 		ret = macsmc_hwmon_parse_key(dev, smc, &fan->mode, mode);
553*785205fdSJames Calligeros 		if (ret)
554*785205fdSJames Calligeros 			return ret;
555*785205fdSJames Calligeros 	}
556*785205fdSJames Calligeros 
557*785205fdSJames Calligeros 	/* Initialise fan control mode to automatic */
558*785205fdSJames Calligeros 	fan->manual = false;
559*785205fdSJames Calligeros 
560*785205fdSJames Calligeros 	return 0;
561*785205fdSJames Calligeros }
562*785205fdSJames Calligeros 
563*785205fdSJames Calligeros static int macsmc_hwmon_populate_sensors(struct macsmc_hwmon *hwmon,
564*785205fdSJames Calligeros 					 struct device_node *hwmon_node)
565*785205fdSJames Calligeros {
566*785205fdSJames Calligeros 	struct device_node *key_node __maybe_unused;
567*785205fdSJames Calligeros 	struct macsmc_hwmon_sensor *sensor;
568*785205fdSJames Calligeros 	u32 n_current = 0, n_fan = 0, n_power = 0, n_temperature = 0, n_voltage = 0;
569*785205fdSJames Calligeros 
570*785205fdSJames Calligeros 	for_each_child_of_node_with_prefix(hwmon_node, key_node, "current-") {
571*785205fdSJames Calligeros 		n_current++;
572*785205fdSJames Calligeros 	}
573*785205fdSJames Calligeros 
574*785205fdSJames Calligeros 	if (n_current) {
575*785205fdSJames Calligeros 		hwmon->curr.sensors = devm_kcalloc(hwmon->dev, n_current,
576*785205fdSJames Calligeros 						   sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
577*785205fdSJames Calligeros 		if (!hwmon->curr.sensors)
578*785205fdSJames Calligeros 			return -ENOMEM;
579*785205fdSJames Calligeros 
580*785205fdSJames Calligeros 		for_each_child_of_node_with_prefix(hwmon_node, key_node, "current-") {
581*785205fdSJames Calligeros 			sensor = &hwmon->curr.sensors[hwmon->curr.count];
582*785205fdSJames Calligeros 			if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
583*785205fdSJames Calligeros 				sensor->attrs = HWMON_C_INPUT;
584*785205fdSJames Calligeros 
585*785205fdSJames Calligeros 				if (*sensor->label)
586*785205fdSJames Calligeros 					sensor->attrs |= HWMON_C_LABEL;
587*785205fdSJames Calligeros 
588*785205fdSJames Calligeros 				hwmon->curr.count++;
589*785205fdSJames Calligeros 			}
590*785205fdSJames Calligeros 		}
591*785205fdSJames Calligeros 	}
592*785205fdSJames Calligeros 
593*785205fdSJames Calligeros 	for_each_child_of_node_with_prefix(hwmon_node, key_node, "fan-") {
594*785205fdSJames Calligeros 		n_fan++;
595*785205fdSJames Calligeros 	}
596*785205fdSJames Calligeros 
597*785205fdSJames Calligeros 	if (n_fan) {
598*785205fdSJames Calligeros 		hwmon->fan.fans = devm_kcalloc(hwmon->dev, n_fan,
599*785205fdSJames Calligeros 					       sizeof(struct macsmc_hwmon_fan), GFP_KERNEL);
600*785205fdSJames Calligeros 		if (!hwmon->fan.fans)
601*785205fdSJames Calligeros 			return -ENOMEM;
602*785205fdSJames Calligeros 
603*785205fdSJames Calligeros 		for_each_child_of_node_with_prefix(hwmon_node, key_node, "fan-") {
604*785205fdSJames Calligeros 			if (!macsmc_hwmon_create_fan(hwmon->dev, hwmon->smc, key_node,
605*785205fdSJames Calligeros 						     &hwmon->fan.fans[hwmon->fan.count]))
606*785205fdSJames Calligeros 				hwmon->fan.count++;
607*785205fdSJames Calligeros 		}
608*785205fdSJames Calligeros 	}
609*785205fdSJames Calligeros 
610*785205fdSJames Calligeros 	for_each_child_of_node_with_prefix(hwmon_node, key_node, "power-") {
611*785205fdSJames Calligeros 		n_power++;
612*785205fdSJames Calligeros 	}
613*785205fdSJames Calligeros 
614*785205fdSJames Calligeros 	if (n_power) {
615*785205fdSJames Calligeros 		hwmon->power.sensors = devm_kcalloc(hwmon->dev, n_power,
616*785205fdSJames Calligeros 						    sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
617*785205fdSJames Calligeros 		if (!hwmon->power.sensors)
618*785205fdSJames Calligeros 			return -ENOMEM;
619*785205fdSJames Calligeros 
620*785205fdSJames Calligeros 		for_each_child_of_node_with_prefix(hwmon_node, key_node, "power-") {
621*785205fdSJames Calligeros 			sensor = &hwmon->power.sensors[hwmon->power.count];
622*785205fdSJames Calligeros 			if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
623*785205fdSJames Calligeros 				sensor->attrs = HWMON_P_INPUT;
624*785205fdSJames Calligeros 
625*785205fdSJames Calligeros 				if (*sensor->label)
626*785205fdSJames Calligeros 					sensor->attrs |= HWMON_P_LABEL;
627*785205fdSJames Calligeros 
628*785205fdSJames Calligeros 				hwmon->power.count++;
629*785205fdSJames Calligeros 			}
630*785205fdSJames Calligeros 		}
631*785205fdSJames Calligeros 	}
632*785205fdSJames Calligeros 
633*785205fdSJames Calligeros 	for_each_child_of_node_with_prefix(hwmon_node, key_node, "temperature-") {
634*785205fdSJames Calligeros 		n_temperature++;
635*785205fdSJames Calligeros 	}
636*785205fdSJames Calligeros 
637*785205fdSJames Calligeros 	if (n_temperature) {
638*785205fdSJames Calligeros 		hwmon->temp.sensors = devm_kcalloc(hwmon->dev, n_temperature,
639*785205fdSJames Calligeros 						   sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
640*785205fdSJames Calligeros 		if (!hwmon->temp.sensors)
641*785205fdSJames Calligeros 			return -ENOMEM;
642*785205fdSJames Calligeros 
643*785205fdSJames Calligeros 		for_each_child_of_node_with_prefix(hwmon_node, key_node, "temperature-") {
644*785205fdSJames Calligeros 			sensor = &hwmon->temp.sensors[hwmon->temp.count];
645*785205fdSJames Calligeros 			if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
646*785205fdSJames Calligeros 				sensor->attrs = HWMON_T_INPUT;
647*785205fdSJames Calligeros 
648*785205fdSJames Calligeros 				if (*sensor->label)
649*785205fdSJames Calligeros 					sensor->attrs |= HWMON_T_LABEL;
650*785205fdSJames Calligeros 
651*785205fdSJames Calligeros 				hwmon->temp.count++;
652*785205fdSJames Calligeros 			}
653*785205fdSJames Calligeros 		}
654*785205fdSJames Calligeros 	}
655*785205fdSJames Calligeros 
656*785205fdSJames Calligeros 	for_each_child_of_node_with_prefix(hwmon_node, key_node, "voltage-") {
657*785205fdSJames Calligeros 		n_voltage++;
658*785205fdSJames Calligeros 	}
659*785205fdSJames Calligeros 
660*785205fdSJames Calligeros 	if (n_voltage) {
661*785205fdSJames Calligeros 		hwmon->volt.sensors = devm_kcalloc(hwmon->dev, n_voltage,
662*785205fdSJames Calligeros 						   sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
663*785205fdSJames Calligeros 		if (!hwmon->volt.sensors)
664*785205fdSJames Calligeros 			return -ENOMEM;
665*785205fdSJames Calligeros 
666*785205fdSJames Calligeros 		for_each_child_of_node_with_prefix(hwmon_node, key_node, "volt-") {
667*785205fdSJames Calligeros 			sensor = &hwmon->temp.sensors[hwmon->temp.count];
668*785205fdSJames Calligeros 			if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
669*785205fdSJames Calligeros 				sensor->attrs = HWMON_I_INPUT;
670*785205fdSJames Calligeros 
671*785205fdSJames Calligeros 				if (*sensor->label)
672*785205fdSJames Calligeros 					sensor->attrs |= HWMON_I_LABEL;
673*785205fdSJames Calligeros 
674*785205fdSJames Calligeros 				hwmon->volt.count++;
675*785205fdSJames Calligeros 			}
676*785205fdSJames Calligeros 		}
677*785205fdSJames Calligeros 	}
678*785205fdSJames Calligeros 
679*785205fdSJames Calligeros 	return 0;
680*785205fdSJames Calligeros }
681*785205fdSJames Calligeros 
682*785205fdSJames Calligeros /* Create NULL-terminated config arrays */
683*785205fdSJames Calligeros static void macsmc_hwmon_populate_configs(u32 *configs, const struct macsmc_hwmon_sensors *sensors)
684*785205fdSJames Calligeros {
685*785205fdSJames Calligeros 	int idx;
686*785205fdSJames Calligeros 
687*785205fdSJames Calligeros 	for (idx = 0; idx < sensors->count; idx++)
688*785205fdSJames Calligeros 		configs[idx] = sensors->sensors[idx].attrs;
689*785205fdSJames Calligeros }
690*785205fdSJames Calligeros 
691*785205fdSJames Calligeros static void macsmc_hwmon_populate_fan_configs(u32 *configs, const struct macsmc_hwmon_fans *fans)
692*785205fdSJames Calligeros {
693*785205fdSJames Calligeros 	int idx;
694*785205fdSJames Calligeros 
695*785205fdSJames Calligeros 	for (idx = 0; idx < fans->count; idx++)
696*785205fdSJames Calligeros 		configs[idx] = fans->fans[idx].attrs;
697*785205fdSJames Calligeros }
698*785205fdSJames Calligeros 
699*785205fdSJames Calligeros static const struct hwmon_channel_info *const macsmc_chip_channel_info =
700*785205fdSJames Calligeros 	HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ);
701*785205fdSJames Calligeros 
702*785205fdSJames Calligeros static int macsmc_hwmon_create_infos(struct macsmc_hwmon *hwmon)
703*785205fdSJames Calligeros {
704*785205fdSJames Calligeros 	struct hwmon_channel_info *channel_info;
705*785205fdSJames Calligeros 	int i = 0;
706*785205fdSJames Calligeros 
707*785205fdSJames Calligeros 	/* chip */
708*785205fdSJames Calligeros 	hwmon->channel_infos[i++] = macsmc_chip_channel_info;
709*785205fdSJames Calligeros 
710*785205fdSJames Calligeros 	if (hwmon->curr.count) {
711*785205fdSJames Calligeros 		channel_info = &hwmon->curr.channel_info;
712*785205fdSJames Calligeros 		channel_info->type = hwmon_curr;
713*785205fdSJames Calligeros 		channel_info->config = devm_kcalloc(hwmon->dev, hwmon->curr.count + 1,
714*785205fdSJames Calligeros 						    sizeof(u32), GFP_KERNEL);
715*785205fdSJames Calligeros 		if (!channel_info->config)
716*785205fdSJames Calligeros 			return -ENOMEM;
717*785205fdSJames Calligeros 
718*785205fdSJames Calligeros 		macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->curr);
719*785205fdSJames Calligeros 		hwmon->channel_infos[i++] = channel_info;
720*785205fdSJames Calligeros 	}
721*785205fdSJames Calligeros 
722*785205fdSJames Calligeros 	if (hwmon->fan.count) {
723*785205fdSJames Calligeros 		channel_info = &hwmon->fan.channel_info;
724*785205fdSJames Calligeros 		channel_info->type = hwmon_fan;
725*785205fdSJames Calligeros 		channel_info->config = devm_kcalloc(hwmon->dev, hwmon->fan.count + 1,
726*785205fdSJames Calligeros 						    sizeof(u32), GFP_KERNEL);
727*785205fdSJames Calligeros 		if (!channel_info->config)
728*785205fdSJames Calligeros 			return -ENOMEM;
729*785205fdSJames Calligeros 
730*785205fdSJames Calligeros 		macsmc_hwmon_populate_fan_configs((u32 *)channel_info->config, &hwmon->fan);
731*785205fdSJames Calligeros 		hwmon->channel_infos[i++] = channel_info;
732*785205fdSJames Calligeros 	}
733*785205fdSJames Calligeros 
734*785205fdSJames Calligeros 	if (hwmon->power.count) {
735*785205fdSJames Calligeros 		channel_info = &hwmon->power.channel_info;
736*785205fdSJames Calligeros 		channel_info->type = hwmon_power;
737*785205fdSJames Calligeros 		channel_info->config = devm_kcalloc(hwmon->dev, hwmon->power.count + 1,
738*785205fdSJames Calligeros 						    sizeof(u32), GFP_KERNEL);
739*785205fdSJames Calligeros 		if (!channel_info->config)
740*785205fdSJames Calligeros 			return -ENOMEM;
741*785205fdSJames Calligeros 
742*785205fdSJames Calligeros 		macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->power);
743*785205fdSJames Calligeros 		hwmon->channel_infos[i++] = channel_info;
744*785205fdSJames Calligeros 	}
745*785205fdSJames Calligeros 
746*785205fdSJames Calligeros 	if (hwmon->temp.count) {
747*785205fdSJames Calligeros 		channel_info = &hwmon->temp.channel_info;
748*785205fdSJames Calligeros 		channel_info->type = hwmon_temp;
749*785205fdSJames Calligeros 		channel_info->config = devm_kcalloc(hwmon->dev, hwmon->temp.count + 1,
750*785205fdSJames Calligeros 						    sizeof(u32), GFP_KERNEL);
751*785205fdSJames Calligeros 		if (!channel_info->config)
752*785205fdSJames Calligeros 			return -ENOMEM;
753*785205fdSJames Calligeros 
754*785205fdSJames Calligeros 		macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->temp);
755*785205fdSJames Calligeros 		hwmon->channel_infos[i++] = channel_info;
756*785205fdSJames Calligeros 	}
757*785205fdSJames Calligeros 
758*785205fdSJames Calligeros 	if (hwmon->volt.count) {
759*785205fdSJames Calligeros 		channel_info = &hwmon->volt.channel_info;
760*785205fdSJames Calligeros 		channel_info->type = hwmon_in;
761*785205fdSJames Calligeros 		channel_info->config = devm_kcalloc(hwmon->dev, hwmon->volt.count + 1,
762*785205fdSJames Calligeros 						    sizeof(u32), GFP_KERNEL);
763*785205fdSJames Calligeros 		if (!channel_info->config)
764*785205fdSJames Calligeros 			return -ENOMEM;
765*785205fdSJames Calligeros 
766*785205fdSJames Calligeros 		macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->volt);
767*785205fdSJames Calligeros 		hwmon->channel_infos[i++] = channel_info;
768*785205fdSJames Calligeros 	}
769*785205fdSJames Calligeros 
770*785205fdSJames Calligeros 	return 0;
771*785205fdSJames Calligeros }
772*785205fdSJames Calligeros 
773*785205fdSJames Calligeros static int macsmc_hwmon_probe(struct platform_device *pdev)
774*785205fdSJames Calligeros {
775*785205fdSJames Calligeros 	struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent);
776*785205fdSJames Calligeros 	struct macsmc_hwmon *hwmon;
777*785205fdSJames Calligeros 	int ret;
778*785205fdSJames Calligeros 
779*785205fdSJames Calligeros 	/*
780*785205fdSJames Calligeros 	 * The MFD driver will try to probe us unconditionally. Some devices
781*785205fdSJames Calligeros 	 * with the SMC do not have hwmon capabilities. Only probe if we have
782*785205fdSJames Calligeros 	 * a hwmon node.
783*785205fdSJames Calligeros 	 */
784*785205fdSJames Calligeros 	if (!pdev->dev.of_node)
785*785205fdSJames Calligeros 		return -ENODEV;
786*785205fdSJames Calligeros 
787*785205fdSJames Calligeros 	hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon),
788*785205fdSJames Calligeros 			     GFP_KERNEL);
789*785205fdSJames Calligeros 	if (!hwmon)
790*785205fdSJames Calligeros 		return -ENOMEM;
791*785205fdSJames Calligeros 
792*785205fdSJames Calligeros 	hwmon->dev = &pdev->dev;
793*785205fdSJames Calligeros 	hwmon->smc = smc;
794*785205fdSJames Calligeros 
795*785205fdSJames Calligeros 	ret = macsmc_hwmon_populate_sensors(hwmon, hwmon->dev->of_node);
796*785205fdSJames Calligeros 	if (ret) {
797*785205fdSJames Calligeros 		dev_err(hwmon->dev, "Could not parse sensors\n");
798*785205fdSJames Calligeros 		return ret;
799*785205fdSJames Calligeros 	}
800*785205fdSJames Calligeros 
801*785205fdSJames Calligeros 	if (!hwmon->curr.count && !hwmon->fan.count &&
802*785205fdSJames Calligeros 	    !hwmon->power.count && !hwmon->temp.count &&
803*785205fdSJames Calligeros 	    !hwmon->volt.count) {
804*785205fdSJames Calligeros 		dev_err(hwmon->dev,
805*785205fdSJames Calligeros 			"No valid sensors found of any supported type\n");
806*785205fdSJames Calligeros 		return -ENODEV;
807*785205fdSJames Calligeros 	}
808*785205fdSJames Calligeros 
809*785205fdSJames Calligeros 	ret = macsmc_hwmon_create_infos(hwmon);
810*785205fdSJames Calligeros 	if (ret)
811*785205fdSJames Calligeros 		return ret;
812*785205fdSJames Calligeros 
813*785205fdSJames Calligeros 	hwmon->chip_info.ops = &macsmc_hwmon_ops;
814*785205fdSJames Calligeros 	hwmon->chip_info.info =
815*785205fdSJames Calligeros 		(const struct hwmon_channel_info *const *)&hwmon->channel_infos;
816*785205fdSJames Calligeros 
817*785205fdSJames Calligeros 	hwmon->hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
818*785205fdSJames Calligeros 								"macsmc_hwmon", hwmon,
819*785205fdSJames Calligeros 								&hwmon->chip_info, NULL);
820*785205fdSJames Calligeros 	if (IS_ERR(hwmon->hwmon_dev))
821*785205fdSJames Calligeros 		return dev_err_probe(hwmon->dev, PTR_ERR(hwmon->hwmon_dev),
822*785205fdSJames Calligeros 				     "Probing SMC hwmon device failed\n");
823*785205fdSJames Calligeros 
824*785205fdSJames Calligeros 	dev_dbg(hwmon->dev, "Registered SMC hwmon device. Sensors:\n");
825*785205fdSJames Calligeros 	dev_dbg(hwmon->dev,
826*785205fdSJames Calligeros 		"Current: %d, Fans: %d, Power: %d, Temperature: %d, Voltage: %d",
827*785205fdSJames Calligeros 		hwmon->curr.count, hwmon->fan.count,
828*785205fdSJames Calligeros 		hwmon->power.count, hwmon->temp.count,
829*785205fdSJames Calligeros 		hwmon->volt.count);
830*785205fdSJames Calligeros 
831*785205fdSJames Calligeros 	return 0;
832*785205fdSJames Calligeros }
833*785205fdSJames Calligeros 
834*785205fdSJames Calligeros static const struct of_device_id macsmc_hwmon_of_table[] = {
835*785205fdSJames Calligeros 	{ .compatible = "apple,smc-hwmon" },
836*785205fdSJames Calligeros 	{}
837*785205fdSJames Calligeros };
838*785205fdSJames Calligeros MODULE_DEVICE_TABLE(of, macsmc_hwmon_of_table);
839*785205fdSJames Calligeros 
840*785205fdSJames Calligeros static struct platform_driver macsmc_hwmon_driver = {
841*785205fdSJames Calligeros 	.probe = macsmc_hwmon_probe,
842*785205fdSJames Calligeros 	.driver = {
843*785205fdSJames Calligeros 		.name = "macsmc-hwmon",
844*785205fdSJames Calligeros 		.of_match_table = macsmc_hwmon_of_table,
845*785205fdSJames Calligeros 	},
846*785205fdSJames Calligeros };
847*785205fdSJames Calligeros module_platform_driver(macsmc_hwmon_driver);
848*785205fdSJames Calligeros 
849*785205fdSJames Calligeros MODULE_DESCRIPTION("Apple Silicon SMC hwmon driver");
850*785205fdSJames Calligeros MODULE_AUTHOR("James Calligeros <jcalligeros99@gmail.com>");
851*785205fdSJames Calligeros MODULE_LICENSE("Dual MIT/GPL");
852