Skip to content

Commit 5798b62

Browse files
Sung-Chi Ligroeck
authored andcommitted
hwmon: (cros_ec) register fans into thermal framework cooling devices
Register fans connected under EC as thermal cooling devices as well, so these fans can then work with the thermal framework. During the driver probing phase, we will also try to register each fan as a thermal cooling device based on previous probe result (whether the there are fans connected on that channel, and whether EC supports fan control). The basic get max state, get current state, and set current state methods are then implemented as well. Signed-off-by: Sung-Chi Li <lschyi@chromium.org> Acked-by: Thomas Weißschuh <linux@weissschuh.net> Link: https://lore.kernel.org/r/20250911-cros_ec_fan-v6-3-a1446cc098af@google.com Signed-off-by: Guenter Roeck <linux@roeck-us.net>
1 parent fb8e659 commit 5798b62

2 files changed

Lines changed: 85 additions & 0 deletions

File tree

Documentation/hwmon/cros_ec_hwmon.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,5 @@ Fan and temperature readings are supported. PWM fan control is also supported if
2727
the EC also supports setting fan PWM values and fan mode. Note that EC will
2828
switch fan control mode back to auto when suspended. This driver will restore
2929
the fan state to what they were before suspended when resumed.
30+
If a fan is controllable, this driver will register that fan as a cooling device
31+
in the thermal framework as well.

drivers/hwmon/cros_ec_hwmon.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/platform_device.h>
1414
#include <linux/platform_data/cros_ec_commands.h>
1515
#include <linux/platform_data/cros_ec_proto.h>
16+
#include <linux/thermal.h>
1617
#include <linux/types.h>
1718
#include <linux/units.h>
1819

@@ -31,6 +32,11 @@ struct cros_ec_hwmon_priv {
3132
u8 manual_fan_pwm[EC_FAN_SPEED_ENTRIES];
3233
};
3334

35+
struct cros_ec_hwmon_cooling_priv {
36+
struct cros_ec_hwmon_priv *hwmon_priv;
37+
u8 index;
38+
};
39+
3440
static int cros_ec_hwmon_read_fan_speed(struct cros_ec_device *cros_ec, u8 index, u16 *speed)
3541
{
3642
int ret;
@@ -308,6 +314,42 @@ static const struct hwmon_channel_info * const cros_ec_hwmon_info[] = {
308314
NULL
309315
};
310316

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+
311353
static const struct hwmon_ops cros_ec_hwmon_ops = {
312354
.read = cros_ec_hwmon_read,
313355
.read_string = cros_ec_hwmon_read_string,
@@ -386,6 +428,46 @@ static bool cros_ec_hwmon_probe_fan_control_supported(struct cros_ec_device *cro
386428
CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION);
387429
}
388430

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+
389471
static int cros_ec_hwmon_probe(struct platform_device *pdev)
390472
{
391473
struct device *dev = &pdev->dev;
@@ -413,6 +495,7 @@ static int cros_ec_hwmon_probe(struct platform_device *pdev)
413495
cros_ec_hwmon_probe_temp_sensors(dev, priv, thermal_version);
414496
cros_ec_hwmon_probe_fans(priv);
415497
priv->fan_control_supported = cros_ec_hwmon_probe_fan_control_supported(priv->cros_ec);
498+
cros_ec_hwmon_register_fan_cooling_devices(dev, priv);
416499

417500
hwmon_dev = devm_hwmon_device_register_with_info(dev, "cros_ec", priv,
418501
&cros_ec_hwmon_chip_info, NULL);

0 commit comments

Comments
 (0)