1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * hwmon interface for the ACPI Fan driver.
5 * Copyright (C) 2024 Armin Wolf <W_Armin@gmx.de>
8 #include <linux/acpi.h>
9 #include <linux/device.h>
10 #include <linux/err.h>
11 #include <linux/hwmon.h>
12 #include <linux/limits.h>
13 #include <linux/types.h>
14 #include <linux/units.h>
18 /* Returned when the ACPI fan does not support speed reporting */
19 #define FAN_SPEED_UNAVAILABLE U32_MAX
20 #define FAN_POWER_UNAVAILABLE U32_MAX
22 static struct acpi_fan_fps
*acpi_fan_get_current_fps(struct acpi_fan
*fan
, u64 control
)
26 for (i
= 0; i
< fan
->fps_count
; i
++) {
27 if (fan
->fps
[i
].control
== control
)
34 static umode_t
acpi_fan_hwmon_is_visible(const void *drvdata
, enum hwmon_sensor_types type
,
35 u32 attr
, int channel
)
37 const struct acpi_fan
*fan
= drvdata
;
45 case hwmon_fan_target
:
47 * When in fine grain control mode, not every fan control value
48 * has an associated fan performance state.
50 if (fan
->fif
.fine_grain_ctrl
)
59 case hwmon_power_input
:
61 * When in fine grain control mode, not every fan control value
62 * has an associated fan performance state.
64 if (fan
->fif
.fine_grain_ctrl
)
68 * When all fan performance states contain no valid power data,
69 * when the associated attribute should not be created.
71 for (i
= 0; i
< fan
->fps_count
; i
++) {
72 if (fan
->fps
[i
].power
!= FAN_POWER_UNAVAILABLE
)
85 static int acpi_fan_hwmon_read(struct device
*dev
, enum hwmon_sensor_types type
, u32 attr
,
86 int channel
, long *val
)
88 struct acpi_device
*adev
= to_acpi_device(dev
->parent
);
89 struct acpi_fan
*fan
= dev_get_drvdata(dev
);
90 struct acpi_fan_fps
*fps
;
91 struct acpi_fan_fst fst
;
94 ret
= acpi_fan_get_fst(adev
, &fst
);
101 case hwmon_fan_input
:
102 if (fst
.speed
== FAN_SPEED_UNAVAILABLE
)
105 if (fst
.speed
> LONG_MAX
)
110 case hwmon_fan_target
:
111 fps
= acpi_fan_get_current_fps(fan
, fst
.control
);
115 if (fps
->speed
> LONG_MAX
)
125 case hwmon_power_input
:
126 fps
= acpi_fan_get_current_fps(fan
, fst
.control
);
130 if (fps
->power
== FAN_POWER_UNAVAILABLE
)
133 if (fps
->power
> LONG_MAX
/ MICROWATT_PER_MILLIWATT
)
136 *val
= fps
->power
* MICROWATT_PER_MILLIWATT
;
146 static const struct hwmon_ops acpi_fan_hwmon_ops
= {
147 .is_visible
= acpi_fan_hwmon_is_visible
,
148 .read
= acpi_fan_hwmon_read
,
151 static const struct hwmon_channel_info
* const acpi_fan_hwmon_info
[] = {
152 HWMON_CHANNEL_INFO(fan
, HWMON_F_INPUT
| HWMON_F_TARGET
),
153 HWMON_CHANNEL_INFO(power
, HWMON_P_INPUT
),
157 static const struct hwmon_chip_info acpi_fan_hwmon_chip_info
= {
158 .ops
= &acpi_fan_hwmon_ops
,
159 .info
= acpi_fan_hwmon_info
,
162 int devm_acpi_fan_create_hwmon(struct acpi_device
*device
)
164 struct acpi_fan
*fan
= acpi_driver_data(device
);
167 hdev
= devm_hwmon_device_register_with_info(&device
->dev
, "acpi_fan", fan
,
168 &acpi_fan_hwmon_chip_info
, NULL
);
169 return PTR_ERR_OR_ZERO(hdev
);