1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * hwmon interface for the ACPI Fan driver. 4 * 5 * Copyright (C) 2024 Armin Wolf <W_Armin@gmx.de> 6 */ 7 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> 15 16 #include "fan.h" 17 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 21 22 static struct acpi_fan_fps *acpi_fan_get_current_fps(struct acpi_fan *fan, u64 control) 23 { 24 unsigned int i; 25 26 for (i = 0; i < fan->fps_count; i++) { 27 if (fan->fps[i].control == control) 28 return &fan->fps[i]; 29 } 30 31 return NULL; 32 } 33 34 static umode_t acpi_fan_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type, 35 u32 attr, int channel) 36 { 37 const struct acpi_fan *fan = drvdata; 38 unsigned int i; 39 40 switch (type) { 41 case hwmon_fan: 42 switch (attr) { 43 case hwmon_fan_input: 44 return 0444; 45 case hwmon_fan_target: 46 /* 47 * When in fine grain control mode, not every fan control value 48 * has an associated fan performance state. 49 */ 50 if (fan->fif.fine_grain_ctrl) 51 return 0; 52 53 return 0444; 54 default: 55 return 0; 56 } 57 case hwmon_power: 58 switch (attr) { 59 case hwmon_power_input: 60 /* 61 * When in fine grain control mode, not every fan control value 62 * has an associated fan performance state. 63 */ 64 if (fan->fif.fine_grain_ctrl) 65 return 0; 66 67 /* 68 * When all fan performance states contain no valid power data, 69 * when the associated attribute should not be created. 70 */ 71 for (i = 0; i < fan->fps_count; i++) { 72 if (fan->fps[i].power != FAN_POWER_UNAVAILABLE) 73 return 0444; 74 } 75 76 return 0; 77 default: 78 return 0; 79 } 80 default: 81 return 0; 82 } 83 } 84 85 static int acpi_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, 86 int channel, long *val) 87 { 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; 92 int ret; 93 94 ret = acpi_fan_get_fst(adev, &fst); 95 if (ret < 0) 96 return ret; 97 98 switch (type) { 99 case hwmon_fan: 100 switch (attr) { 101 case hwmon_fan_input: 102 if (fst.speed == FAN_SPEED_UNAVAILABLE) 103 return -ENODEV; 104 105 if (fst.speed > LONG_MAX) 106 return -EOVERFLOW; 107 108 *val = fst.speed; 109 return 0; 110 case hwmon_fan_target: 111 fps = acpi_fan_get_current_fps(fan, fst.control); 112 if (!fps) 113 return -EIO; 114 115 if (fps->speed > LONG_MAX) 116 return -EOVERFLOW; 117 118 *val = fps->speed; 119 return 0; 120 default: 121 return -EOPNOTSUPP; 122 } 123 case hwmon_power: 124 switch (attr) { 125 case hwmon_power_input: 126 fps = acpi_fan_get_current_fps(fan, fst.control); 127 if (!fps) 128 return -EIO; 129 130 if (fps->power == FAN_POWER_UNAVAILABLE) 131 return -ENODEV; 132 133 if (fps->power > LONG_MAX / MICROWATT_PER_MILLIWATT) 134 return -EOVERFLOW; 135 136 *val = fps->power * MICROWATT_PER_MILLIWATT; 137 return 0; 138 default: 139 return -EOPNOTSUPP; 140 } 141 default: 142 return -EOPNOTSUPP; 143 } 144 } 145 146 static const struct hwmon_ops acpi_fan_hwmon_ops = { 147 .is_visible = acpi_fan_hwmon_is_visible, 148 .read = acpi_fan_hwmon_read, 149 }; 150 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), 154 NULL 155 }; 156 157 static const struct hwmon_chip_info acpi_fan_hwmon_chip_info = { 158 .ops = &acpi_fan_hwmon_ops, 159 .info = acpi_fan_hwmon_info, 160 }; 161 162 int devm_acpi_fan_create_hwmon(struct acpi_device *device) 163 { 164 struct acpi_fan *fan = acpi_driver_data(device); 165 struct device *hdev; 166 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); 170 } 171