xref: /linux/drivers/hwmon/cros_ec_hwmon.c (revision 68a052239fc4b351e961f698b824f7654a346091)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  ChromeOS EC driver for hwmon
4  *
5  *  Copyright (C) 2024 Thomas Weißschuh <linux@weissschuh.net>
6  */
7 
8 #include <linux/device.h>
9 #include <linux/hwmon.h>
10 #include <linux/math.h>
11 #include <linux/mod_devicetable.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/platform_data/cros_ec_commands.h>
15 #include <linux/platform_data/cros_ec_proto.h>
16 #include <linux/thermal.h>
17 #include <linux/types.h>
18 #include <linux/units.h>
19 
20 #define DRV_NAME	"cros-ec-hwmon"
21 
22 #define CROS_EC_HWMON_PWM_GET_FAN_DUTY_CMD_VERSION	0
23 #define CROS_EC_HWMON_PWM_SET_FAN_DUTY_CMD_VERSION	1
24 #define CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION	2
25 
26 struct cros_ec_hwmon_priv {
27 	struct cros_ec_device *cros_ec;
28 	const char *temp_sensor_names[EC_TEMP_SENSOR_ENTRIES + EC_TEMP_SENSOR_B_ENTRIES];
29 	u8 usable_fans;
30 	bool fan_control_supported;
31 	u8 manual_fans; /* bits to indicate whether the fan is set to manual */
32 	u8 manual_fan_pwm[EC_FAN_SPEED_ENTRIES];
33 };
34 
35 struct cros_ec_hwmon_cooling_priv {
36 	struct cros_ec_hwmon_priv *hwmon_priv;
37 	u8 index;
38 };
39 
40 static int cros_ec_hwmon_read_fan_speed(struct cros_ec_device *cros_ec, u8 index, u16 *speed)
41 {
42 	int ret;
43 	__le16 __speed;
44 
45 	ret = cros_ec_cmd_readmem(cros_ec, EC_MEMMAP_FAN + index * 2, 2, &__speed);
46 	if (ret < 0)
47 		return ret;
48 
49 	*speed = le16_to_cpu(__speed);
50 	return 0;
51 }
52 
53 static int cros_ec_hwmon_read_pwm_value(struct cros_ec_device *cros_ec, u8 index, u8 *pwm_value)
54 {
55 	struct ec_params_pwm_get_fan_duty req = {
56 		.fan_idx = index,
57 	};
58 	struct ec_response_pwm_get_fan_duty resp;
59 	int ret;
60 
61 	ret = cros_ec_cmd(cros_ec, CROS_EC_HWMON_PWM_GET_FAN_DUTY_CMD_VERSION,
62 			  EC_CMD_PWM_GET_FAN_DUTY, &req, sizeof(req), &resp, sizeof(resp));
63 	if (ret < 0)
64 		return ret;
65 
66 	*pwm_value = (u8)DIV_ROUND_CLOSEST(le32_to_cpu(resp.percent) * 255, 100);
67 	return 0;
68 }
69 
70 static int cros_ec_hwmon_read_pwm_enable(struct cros_ec_device *cros_ec, u8 index,
71 					 u8 *control_method)
72 {
73 	struct ec_params_auto_fan_ctrl_v2 req = {
74 		.cmd = EC_AUTO_FAN_CONTROL_CMD_GET,
75 		.fan_idx = index,
76 	};
77 	struct ec_response_auto_fan_control resp;
78 	int ret;
79 
80 	ret = cros_ec_cmd(cros_ec, CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION,
81 			  EC_CMD_THERMAL_AUTO_FAN_CTRL, &req, sizeof(req), &resp, sizeof(resp));
82 	if (ret < 0)
83 		return ret;
84 
85 	*control_method = resp.is_auto ? 2 : 1;
86 	return 0;
87 }
88 
89 static int cros_ec_hwmon_read_temp(struct cros_ec_device *cros_ec, u8 index, u8 *temp)
90 {
91 	unsigned int offset;
92 	int ret;
93 
94 	if (index < EC_TEMP_SENSOR_ENTRIES)
95 		offset = EC_MEMMAP_TEMP_SENSOR + index;
96 	else
97 		offset = EC_MEMMAP_TEMP_SENSOR_B + index - EC_TEMP_SENSOR_ENTRIES;
98 
99 	ret = cros_ec_cmd_readmem(cros_ec, offset, 1, temp);
100 	if (ret < 0)
101 		return ret;
102 	return 0;
103 }
104 
105 static bool cros_ec_hwmon_is_error_fan(u16 speed)
106 {
107 	return speed == EC_FAN_SPEED_NOT_PRESENT || speed == EC_FAN_SPEED_STALLED;
108 }
109 
110 static bool cros_ec_hwmon_is_error_temp(u8 temp)
111 {
112 	return temp == EC_TEMP_SENSOR_NOT_PRESENT     ||
113 	       temp == EC_TEMP_SENSOR_ERROR           ||
114 	       temp == EC_TEMP_SENSOR_NOT_POWERED     ||
115 	       temp == EC_TEMP_SENSOR_NOT_CALIBRATED;
116 }
117 
118 static long cros_ec_hwmon_temp_to_millicelsius(u8 temp)
119 {
120 	return kelvin_to_millicelsius((((long)temp) + EC_TEMP_SENSOR_OFFSET));
121 }
122 
123 static int cros_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
124 			      u32 attr, int channel, long *val)
125 {
126 	struct cros_ec_hwmon_priv *priv = dev_get_drvdata(dev);
127 	int ret = -EOPNOTSUPP;
128 	u8 control_method;
129 	u8 pwm_value;
130 	u16 speed;
131 	u8 temp;
132 
133 	if (type == hwmon_fan) {
134 		if (attr == hwmon_fan_input) {
135 			ret = cros_ec_hwmon_read_fan_speed(priv->cros_ec, channel, &speed);
136 			if (ret == 0) {
137 				if (cros_ec_hwmon_is_error_fan(speed))
138 					ret = -ENODATA;
139 				else
140 					*val = speed;
141 			}
142 		} else if (attr == hwmon_fan_fault) {
143 			ret = cros_ec_hwmon_read_fan_speed(priv->cros_ec, channel, &speed);
144 			if (ret == 0)
145 				*val = cros_ec_hwmon_is_error_fan(speed);
146 		}
147 	} else if (type == hwmon_pwm) {
148 		if (attr == hwmon_pwm_enable) {
149 			ret = cros_ec_hwmon_read_pwm_enable(priv->cros_ec, channel,
150 							    &control_method);
151 			if (ret == 0)
152 				*val = control_method;
153 		} else if (attr == hwmon_pwm_input) {
154 			ret = cros_ec_hwmon_read_pwm_value(priv->cros_ec, channel, &pwm_value);
155 			if (ret == 0)
156 				*val = pwm_value;
157 		}
158 	} else if (type == hwmon_temp) {
159 		if (attr == hwmon_temp_input) {
160 			ret = cros_ec_hwmon_read_temp(priv->cros_ec, channel, &temp);
161 			if (ret == 0) {
162 				if (cros_ec_hwmon_is_error_temp(temp))
163 					ret = -ENODATA;
164 				else
165 					*val = cros_ec_hwmon_temp_to_millicelsius(temp);
166 			}
167 		} else if (attr == hwmon_temp_fault) {
168 			ret = cros_ec_hwmon_read_temp(priv->cros_ec, channel, &temp);
169 			if (ret == 0)
170 				*val = cros_ec_hwmon_is_error_temp(temp);
171 		}
172 	}
173 
174 	return ret;
175 }
176 
177 static int cros_ec_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type,
178 				     u32 attr, int channel, const char **str)
179 {
180 	struct cros_ec_hwmon_priv *priv = dev_get_drvdata(dev);
181 
182 	if (type == hwmon_temp && attr == hwmon_temp_label) {
183 		*str = priv->temp_sensor_names[channel];
184 		return 0;
185 	}
186 
187 	return -EOPNOTSUPP;
188 }
189 
190 static int cros_ec_hwmon_set_fan_pwm_val(struct cros_ec_device *cros_ec, u8 index, u8 val)
191 {
192 	struct ec_params_pwm_set_fan_duty_v1 req = {
193 		.fan_idx = index,
194 		.percent = DIV_ROUND_CLOSEST((uint32_t)val * 100, 255),
195 	};
196 	int ret;
197 
198 	ret = cros_ec_cmd(cros_ec, CROS_EC_HWMON_PWM_SET_FAN_DUTY_CMD_VERSION,
199 			  EC_CMD_PWM_SET_FAN_DUTY, &req, sizeof(req), NULL, 0);
200 	if (ret < 0)
201 		return ret;
202 	return 0;
203 }
204 
205 static int cros_ec_hwmon_write_pwm_input(struct cros_ec_device *cros_ec, u8 index, u8 val)
206 {
207 	u8 control_method;
208 	int ret;
209 
210 	ret = cros_ec_hwmon_read_pwm_enable(cros_ec, index, &control_method);
211 	if (ret)
212 		return ret;
213 	if (control_method != 1)
214 		return -EOPNOTSUPP;
215 
216 	return cros_ec_hwmon_set_fan_pwm_val(cros_ec, index, val);
217 }
218 
219 static int cros_ec_hwmon_write_pwm_enable(struct cros_ec_device *cros_ec, u8 index, u8 val)
220 {
221 	struct ec_params_auto_fan_ctrl_v2 req = {
222 		.fan_idx = index,
223 		.cmd = EC_AUTO_FAN_CONTROL_CMD_SET,
224 	};
225 	int ret;
226 
227 	/* No CrOS EC supports no fan speed control */
228 	if (val == 0)
229 		return -EOPNOTSUPP;
230 
231 	req.set_auto = (val != 1) ? true : false;
232 	ret = cros_ec_cmd(cros_ec, CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION,
233 			  EC_CMD_THERMAL_AUTO_FAN_CTRL, &req, sizeof(req), NULL, 0);
234 	if (ret < 0)
235 		return ret;
236 	return 0;
237 }
238 
239 static int cros_ec_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
240 			       int channel, long val)
241 {
242 	struct cros_ec_hwmon_priv *priv = dev_get_drvdata(dev);
243 
244 	if (type == hwmon_pwm) {
245 		switch (attr) {
246 		case hwmon_pwm_input:
247 			return cros_ec_hwmon_write_pwm_input(priv->cros_ec, channel, val);
248 		case hwmon_pwm_enable:
249 			return cros_ec_hwmon_write_pwm_enable(priv->cros_ec, channel, val);
250 		default:
251 			return -EOPNOTSUPP;
252 		}
253 	}
254 
255 	return -EOPNOTSUPP;
256 }
257 
258 static umode_t cros_ec_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
259 					u32 attr, int channel)
260 {
261 	const struct cros_ec_hwmon_priv *priv = data;
262 
263 	if (type == hwmon_fan) {
264 		if (priv->usable_fans & BIT(channel))
265 			return 0444;
266 	} else if (type == hwmon_pwm) {
267 		if (priv->fan_control_supported && priv->usable_fans & BIT(channel))
268 			return 0644;
269 	} else if (type == hwmon_temp) {
270 		if (priv->temp_sensor_names[channel])
271 			return 0444;
272 	}
273 
274 	return 0;
275 }
276 
277 static const struct hwmon_channel_info * const cros_ec_hwmon_info[] = {
278 	HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
279 	HWMON_CHANNEL_INFO(fan,
280 			   HWMON_F_INPUT | HWMON_F_FAULT,
281 			   HWMON_F_INPUT | HWMON_F_FAULT,
282 			   HWMON_F_INPUT | HWMON_F_FAULT,
283 			   HWMON_F_INPUT | HWMON_F_FAULT),
284 	HWMON_CHANNEL_INFO(pwm,
285 			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
286 			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
287 			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
288 			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
289 	HWMON_CHANNEL_INFO(temp,
290 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
291 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
292 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
293 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
294 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
295 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
296 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
297 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
298 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
299 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
300 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
301 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
302 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
303 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
304 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
305 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
306 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
307 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
308 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
309 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
310 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
311 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
312 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL,
313 			   HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL),
314 	NULL
315 };
316 
317 static int cros_ec_hwmon_cooling_get_max_state(struct thermal_cooling_device *cdev,
318 					       unsigned long *val)
319 {
320 	*val = 255;
321 	return 0;
322 }
323 
324 static int cros_ec_hwmon_cooling_get_cur_state(struct thermal_cooling_device *cdev,
325 					       unsigned long *val)
326 {
327 	const struct cros_ec_hwmon_cooling_priv *priv = cdev->devdata;
328 	u8 read_val;
329 	int ret;
330 
331 	ret = cros_ec_hwmon_read_pwm_value(priv->hwmon_priv->cros_ec, priv->index, &read_val);
332 	if (ret)
333 		return ret;
334 
335 	*val = read_val;
336 	return 0;
337 }
338 
339 static int cros_ec_hwmon_cooling_set_cur_state(struct thermal_cooling_device *cdev,
340 					       unsigned long val)
341 {
342 	const struct cros_ec_hwmon_cooling_priv *priv = cdev->devdata;
343 
344 	return cros_ec_hwmon_write_pwm_input(priv->hwmon_priv->cros_ec, priv->index, val);
345 }
346 
347 static const struct thermal_cooling_device_ops cros_ec_thermal_cooling_ops = {
348 	.get_max_state = cros_ec_hwmon_cooling_get_max_state,
349 	.get_cur_state = cros_ec_hwmon_cooling_get_cur_state,
350 	.set_cur_state = cros_ec_hwmon_cooling_set_cur_state,
351 };
352 
353 static const struct hwmon_ops cros_ec_hwmon_ops = {
354 	.read = cros_ec_hwmon_read,
355 	.read_string = cros_ec_hwmon_read_string,
356 	.write = cros_ec_hwmon_write,
357 	.is_visible = cros_ec_hwmon_is_visible,
358 };
359 
360 static const struct hwmon_chip_info cros_ec_hwmon_chip_info = {
361 	.ops = &cros_ec_hwmon_ops,
362 	.info = cros_ec_hwmon_info,
363 };
364 
365 static void cros_ec_hwmon_probe_temp_sensors(struct device *dev, struct cros_ec_hwmon_priv *priv,
366 					     u8 thermal_version)
367 {
368 	struct ec_params_temp_sensor_get_info req = {};
369 	struct ec_response_temp_sensor_get_info resp;
370 	size_t candidates, i, sensor_name_size;
371 	int ret;
372 	u8 temp;
373 
374 	if (thermal_version < 2)
375 		candidates = EC_TEMP_SENSOR_ENTRIES;
376 	else
377 		candidates = ARRAY_SIZE(priv->temp_sensor_names);
378 
379 	for (i = 0; i < candidates; i++) {
380 		if (cros_ec_hwmon_read_temp(priv->cros_ec, i, &temp) < 0)
381 			continue;
382 
383 		if (temp == EC_TEMP_SENSOR_NOT_PRESENT)
384 			continue;
385 
386 		req.id = i;
387 		ret = cros_ec_cmd(priv->cros_ec, 0, EC_CMD_TEMP_SENSOR_GET_INFO,
388 				  &req, sizeof(req), &resp, sizeof(resp));
389 		if (ret < 0)
390 			continue;
391 
392 		sensor_name_size = strnlen(resp.sensor_name, sizeof(resp.sensor_name));
393 		priv->temp_sensor_names[i] = devm_kasprintf(dev, GFP_KERNEL, "%.*s",
394 							    (int)sensor_name_size,
395 							    resp.sensor_name);
396 	}
397 }
398 
399 static void cros_ec_hwmon_probe_fans(struct cros_ec_hwmon_priv *priv)
400 {
401 	u16 speed;
402 	size_t i;
403 	int ret;
404 
405 	for (i = 0; i < EC_FAN_SPEED_ENTRIES; i++) {
406 		ret = cros_ec_hwmon_read_fan_speed(priv->cros_ec, i, &speed);
407 		if (ret == 0 && speed != EC_FAN_SPEED_NOT_PRESENT)
408 			priv->usable_fans |= BIT(i);
409 	}
410 }
411 
412 static inline bool is_cros_ec_cmd_available(struct cros_ec_device *cros_ec,
413 					    u16 cmd, u8 version)
414 {
415 	int ret;
416 
417 	ret = cros_ec_get_cmd_versions(cros_ec, cmd);
418 	return ret >= 0 && (ret & EC_VER_MASK(version));
419 }
420 
421 static bool cros_ec_hwmon_probe_fan_control_supported(struct cros_ec_device *cros_ec)
422 {
423 	return is_cros_ec_cmd_available(cros_ec, EC_CMD_PWM_GET_FAN_DUTY,
424 					CROS_EC_HWMON_PWM_GET_FAN_DUTY_CMD_VERSION) &&
425 	       is_cros_ec_cmd_available(cros_ec, EC_CMD_PWM_SET_FAN_DUTY,
426 					CROS_EC_HWMON_PWM_SET_FAN_DUTY_CMD_VERSION) &&
427 	       is_cros_ec_cmd_available(cros_ec, EC_CMD_THERMAL_AUTO_FAN_CTRL,
428 					CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION);
429 }
430 
431 static void cros_ec_hwmon_register_fan_cooling_devices(struct device *dev,
432 						       struct cros_ec_hwmon_priv *priv)
433 {
434 	struct cros_ec_hwmon_cooling_priv *cpriv;
435 	struct thermal_cooling_device *cdev;
436 	const char *type;
437 	size_t i;
438 
439 	if (!IS_ENABLED(CONFIG_THERMAL))
440 		return;
441 
442 	if (!priv->fan_control_supported)
443 		return;
444 
445 	for (i = 0; i < EC_FAN_SPEED_ENTRIES; i++) {
446 		if (!(priv->usable_fans & BIT(i)))
447 			continue;
448 
449 		cpriv = devm_kzalloc(dev, sizeof(*cpriv), GFP_KERNEL);
450 		if (!cpriv)
451 			continue;
452 
453 		type = devm_kasprintf(dev, GFP_KERNEL, "%s-fan%zu", dev_name(dev), i);
454 		if (!type) {
455 			dev_warn(dev, "no memory to compose cooling device type for fan %zu\n", i);
456 			continue;
457 		}
458 
459 		cpriv->hwmon_priv = priv;
460 		cpriv->index = i;
461 		cdev = devm_thermal_of_cooling_device_register(dev, NULL, type, cpriv,
462 							       &cros_ec_thermal_cooling_ops);
463 		if (IS_ERR(cdev)) {
464 			dev_warn(dev, "failed to register fan %zu as a cooling device: %pe\n", i,
465 				 cdev);
466 			continue;
467 		}
468 	}
469 }
470 
471 static int cros_ec_hwmon_probe(struct platform_device *pdev)
472 {
473 	struct device *dev = &pdev->dev;
474 	struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
475 	struct cros_ec_device *cros_ec = ec_dev->ec_dev;
476 	struct cros_ec_hwmon_priv *priv;
477 	struct device *hwmon_dev;
478 	u8 thermal_version;
479 	int ret;
480 
481 	ret = cros_ec_cmd_readmem(cros_ec, EC_MEMMAP_THERMAL_VERSION, 1, &thermal_version);
482 	if (ret < 0)
483 		return ret;
484 
485 	/* Covers both fan and temp sensors */
486 	if (thermal_version == 0)
487 		return -ENODEV;
488 
489 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
490 	if (!priv)
491 		return -ENOMEM;
492 
493 	priv->cros_ec = cros_ec;
494 
495 	cros_ec_hwmon_probe_temp_sensors(dev, priv, thermal_version);
496 	cros_ec_hwmon_probe_fans(priv);
497 	priv->fan_control_supported = cros_ec_hwmon_probe_fan_control_supported(priv->cros_ec);
498 	cros_ec_hwmon_register_fan_cooling_devices(dev, priv);
499 
500 	hwmon_dev = devm_hwmon_device_register_with_info(dev, "cros_ec", priv,
501 							 &cros_ec_hwmon_chip_info, NULL);
502 	platform_set_drvdata(pdev, priv);
503 
504 	return PTR_ERR_OR_ZERO(hwmon_dev);
505 }
506 
507 static int cros_ec_hwmon_suspend(struct platform_device *pdev, pm_message_t state)
508 {
509 	struct cros_ec_hwmon_priv *priv = platform_get_drvdata(pdev);
510 	u8 control_method;
511 	size_t i;
512 	int ret;
513 
514 	if (!priv->fan_control_supported)
515 		return 0;
516 
517 	/* EC sets fan control to auto after suspended, store settings before suspending. */
518 	for (i = 0; i < EC_FAN_SPEED_ENTRIES; i++) {
519 		if (!(priv->usable_fans & BIT(i)))
520 			continue;
521 
522 		ret = cros_ec_hwmon_read_pwm_enable(priv->cros_ec, i, &control_method);
523 		if (ret) {
524 			dev_warn(&pdev->dev, "failed to get mode setting for fan %zu: %d\n", i,
525 				 ret);
526 			continue;
527 		}
528 
529 		if (control_method != 1) {
530 			priv->manual_fans &= ~BIT(i);
531 			continue;
532 		} else {
533 			priv->manual_fans |= BIT(i);
534 		}
535 
536 		ret = cros_ec_hwmon_read_pwm_value(priv->cros_ec, i, &priv->manual_fan_pwm[i]);
537 		/*
538 		 * If storing the value failed, invalidate the stored mode value by setting it
539 		 * to auto control. EC will automatically switch to auto mode for that fan after
540 		 * suspended.
541 		 */
542 		if (ret) {
543 			dev_warn(&pdev->dev, "failed to get PWM setting for fan %zu: %pe\n", i,
544 				 ERR_PTR(ret));
545 			priv->manual_fans &= ~BIT(i);
546 			continue;
547 		}
548 	}
549 
550 	return 0;
551 }
552 
553 static int cros_ec_hwmon_resume(struct platform_device *pdev)
554 {
555 	const struct cros_ec_hwmon_priv *priv = platform_get_drvdata(pdev);
556 	size_t i;
557 	int ret;
558 
559 	if (!priv->fan_control_supported)
560 		return 0;
561 
562 	/* EC sets fan control to auto after suspend, restore to settings before suspend. */
563 	for (i = 0; i < EC_FAN_SPEED_ENTRIES; i++) {
564 		if (!(priv->manual_fans & BIT(i)))
565 			continue;
566 
567 		/*
568 		 * Setting fan PWM value to EC will change the mode to manual for that fan in EC as
569 		 * well, so we do not need to issue a separate fan mode to manual call.
570 		 */
571 		ret = cros_ec_hwmon_set_fan_pwm_val(priv->cros_ec, i, priv->manual_fan_pwm[i]);
572 		if (ret)
573 			dev_warn(&pdev->dev, "failed to restore settings for fan %zu: %pe\n", i,
574 				 ERR_PTR(ret));
575 	}
576 
577 	return 0;
578 }
579 
580 static const struct platform_device_id cros_ec_hwmon_id[] = {
581 	{ DRV_NAME, 0 },
582 	{}
583 };
584 
585 static struct platform_driver cros_ec_hwmon_driver = {
586 	.driver.name	= DRV_NAME,
587 	.probe		= cros_ec_hwmon_probe,
588 	.suspend	= pm_ptr(cros_ec_hwmon_suspend),
589 	.resume		= pm_ptr(cros_ec_hwmon_resume),
590 	.id_table	= cros_ec_hwmon_id,
591 };
592 module_platform_driver(cros_ec_hwmon_driver);
593 
594 MODULE_DEVICE_TABLE(platform, cros_ec_hwmon_id);
595 MODULE_DESCRIPTION("ChromeOS EC Hardware Monitoring Driver");
596 MODULE_AUTHOR("Thomas Weißschuh <linux@weissschuh.net");
597 MODULE_LICENSE("GPL");
598