Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hwmon: add fan speed monitoring driver for Surface devices

Adds a driver that provides read only access to the fan speed for Microsoft
Surface Pro devices. The fan speed is always regulated by the EC and cannot
be influenced directly.

Signed-off-by: Ivor Wanders <ivor@iwanders.net>
Link: https://github.com/linux-surface/kernel/pull/144
Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com>
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Link: https://lore.kernel.org/r/20240131005856.10180-2-ivor@iwanders.net
[groeck:
- Declare surface_fan_hwmon_is_visible() static
- Add dependency on SURFACE_AGGREGATOR_BUS
]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>

authored by

Ivor Wanders and committed by
Guenter Roeck
d612bf83 cbc29538

+140
+1
Documentation/hwmon/index.rst
··· 209 209 smsc47m1 210 210 sparx5-temp 211 211 stpddc60 212 + surface_fan 212 213 sy7636a-hwmon 213 214 tc654 214 215 tc74
+25
Documentation/hwmon/surface_fan.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + Kernel driver surface_fan 4 + ========================= 5 + 6 + Supported Devices: 7 + 8 + * Microsoft Surface Pro 9 9 + 10 + Author: Ivor Wanders <ivor@iwanders.net> 11 + 12 + Description 13 + ----------- 14 + 15 + This provides monitoring of the fan found in some Microsoft Surface Pro devices, 16 + like the Surface Pro 9. The fan is always controlled by the onboard controller. 17 + 18 + Sysfs interface 19 + --------------- 20 + 21 + ======================= ======= ========================================= 22 + Name Perm Description 23 + ======================= ======= ========================================= 24 + ``fan1_input`` RO Current fan speed in RPM. 25 + ======================= ======= =========================================
+8
MAINTAINERS
··· 14549 14549 F: drivers/platform/surface/surface_dtx.c 14550 14550 F: include/uapi/linux/surface_aggregator/dtx.h 14551 14551 14552 + MICROSOFT SURFACE SENSOR FAN DRIVER 14553 + M: Maximilian Luz <luzmaximilian@gmail.com> 14554 + M: Ivor Wanders <ivor@iwanders.net> 14555 + L: linux-hwmon@vger.kernel.org 14556 + S: Maintained 14557 + F: Documentation/hwmon/surface_fan.rst 14558 + F: drivers/hwmon/surface_fan.c 14559 + 14552 14560 MICROSOFT SURFACE GPE LID SUPPORT DRIVER 14553 14561 M: Maximilian Luz <luzmaximilian@gmail.com> 14554 14562 L: platform-driver-x86@vger.kernel.org
+14
drivers/hwmon/Kconfig
··· 2005 2005 This driver can also be built as a module. If so, the module 2006 2006 will be called sfctemp. 2007 2007 2008 + config SENSORS_SURFACE_FAN 2009 + tristate "Surface Fan Driver" 2010 + depends on SURFACE_AGGREGATOR 2011 + depends on SURFACE_AGGREGATOR_BUS 2012 + help 2013 + Driver that provides monitoring of the fan on Surface Pro devices that 2014 + have a fan, like the Surface Pro 9. 2015 + 2016 + This makes the fan's current speed accessible through the hwmon 2017 + system. It does not provide control over the fan, the firmware is 2018 + responsible for that, this driver merely provides monitoring. 2019 + 2020 + Select M or Y here, if you want to be able to read the fan's speed. 2021 + 2008 2022 config SENSORS_ADC128D818 2009 2023 tristate "Texas Instruments ADC128D818" 2010 2024 depends on I2C
+1
drivers/hwmon/Makefile
··· 202 202 obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o 203 203 obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o 204 204 obj-$(CONFIG_SENSORS_STTS751) += stts751.o 205 + obj-$(CONFIG_SENSORS_SURFACE_FAN)+= surface_fan.o 205 206 obj-$(CONFIG_SENSORS_SY7636A) += sy7636a-hwmon.o 206 207 obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o 207 208 obj-$(CONFIG_SENSORS_TC74) += tc74.o
+91
drivers/hwmon/surface_fan.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Surface Fan driver for Surface System Aggregator Module. It provides access 4 + * to the fan's rpm through the hwmon system. 5 + * 6 + * Copyright (C) 2023 Ivor Wanders <ivor@iwanders.net> 7 + */ 8 + 9 + #include <linux/hwmon.h> 10 + #include <linux/kernel.h> 11 + #include <linux/module.h> 12 + #include <linux/surface_aggregator/device.h> 13 + #include <linux/types.h> 14 + 15 + // SSAM 16 + SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_fan_rpm_get, __le16, { 17 + .target_category = SSAM_SSH_TC_FAN, 18 + .command_id = 0x01, 19 + }); 20 + 21 + // hwmon 22 + static umode_t surface_fan_hwmon_is_visible(const void *drvdata, 23 + enum hwmon_sensor_types type, u32 attr, 24 + int channel) 25 + { 26 + return 0444; 27 + } 28 + 29 + static int surface_fan_hwmon_read(struct device *dev, 30 + enum hwmon_sensor_types type, u32 attr, 31 + int channel, long *val) 32 + { 33 + struct ssam_device *sdev = dev_get_drvdata(dev); 34 + int ret; 35 + __le16 value; 36 + 37 + ret = __ssam_fan_rpm_get(sdev, &value); 38 + if (ret) 39 + return ret; 40 + 41 + *val = le16_to_cpu(value); 42 + 43 + return 0; 44 + } 45 + 46 + static const struct hwmon_channel_info *const surface_fan_info[] = { 47 + HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT), 48 + NULL 49 + }; 50 + 51 + static const struct hwmon_ops surface_fan_hwmon_ops = { 52 + .is_visible = surface_fan_hwmon_is_visible, 53 + .read = surface_fan_hwmon_read, 54 + }; 55 + 56 + static const struct hwmon_chip_info surface_fan_chip_info = { 57 + .ops = &surface_fan_hwmon_ops, 58 + .info = surface_fan_info, 59 + }; 60 + 61 + static int surface_fan_probe(struct ssam_device *sdev) 62 + { 63 + struct device *hdev; 64 + 65 + hdev = devm_hwmon_device_register_with_info(&sdev->dev, 66 + "surface_fan", sdev, 67 + &surface_fan_chip_info, 68 + NULL); 69 + 70 + return PTR_ERR_OR_ZERO(hdev); 71 + } 72 + 73 + static const struct ssam_device_id ssam_fan_match[] = { 74 + { SSAM_SDEV(FAN, SAM, 0x01, 0x01) }, 75 + {}, 76 + }; 77 + MODULE_DEVICE_TABLE(ssam, ssam_fan_match); 78 + 79 + static struct ssam_device_driver surface_fan = { 80 + .probe = surface_fan_probe, 81 + .match_table = ssam_fan_match, 82 + .driver = { 83 + .name = "surface_fan", 84 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 85 + }, 86 + }; 87 + module_ssam_device_driver(surface_fan); 88 + 89 + MODULE_AUTHOR("Ivor Wanders <ivor@iwanders.net>"); 90 + MODULE_DESCRIPTION("Fan Driver for Surface System Aggregator Module"); 91 + MODULE_LICENSE("GPL");