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>
This commit is contained in:
Ivor Wanders 2024-01-30 19:58:55 -05:00 committed by Guenter Roeck
parent cbc29538db
commit d612bf839f
6 changed files with 140 additions and 0 deletions

View File

@ -209,6 +209,7 @@ Hardware Monitoring Kernel Drivers
smsc47m1
sparx5-temp
stpddc60
surface_fan
sy7636a-hwmon
tc654
tc74

View File

@ -0,0 +1,25 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
Kernel driver surface_fan
=========================
Supported Devices:
* Microsoft Surface Pro 9
Author: Ivor Wanders <ivor@iwanders.net>
Description
-----------
This provides monitoring of the fan found in some Microsoft Surface Pro devices,
like the Surface Pro 9. The fan is always controlled by the onboard controller.
Sysfs interface
---------------
======================= ======= =========================================
Name Perm Description
======================= ======= =========================================
``fan1_input`` RO Current fan speed in RPM.
======================= ======= =========================================

View File

@ -14549,6 +14549,14 @@ F: Documentation/driver-api/surface_aggregator/clients/dtx.rst
F: drivers/platform/surface/surface_dtx.c
F: include/uapi/linux/surface_aggregator/dtx.h
MICROSOFT SURFACE SENSOR FAN DRIVER
M: Maximilian Luz <luzmaximilian@gmail.com>
M: Ivor Wanders <ivor@iwanders.net>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/hwmon/surface_fan.rst
F: drivers/hwmon/surface_fan.c
MICROSOFT SURFACE GPE LID SUPPORT DRIVER
M: Maximilian Luz <luzmaximilian@gmail.com>
L: platform-driver-x86@vger.kernel.org

View File

@ -2005,6 +2005,20 @@ config SENSORS_SFCTEMP
This driver can also be built as a module. If so, the module
will be called sfctemp.
config SENSORS_SURFACE_FAN
tristate "Surface Fan Driver"
depends on SURFACE_AGGREGATOR
depends on SURFACE_AGGREGATOR_BUS
help
Driver that provides monitoring of the fan on Surface Pro devices that
have a fan, like the Surface Pro 9.
This makes the fan's current speed accessible through the hwmon
system. It does not provide control over the fan, the firmware is
responsible for that, this driver merely provides monitoring.
Select M or Y here, if you want to be able to read the fan's speed.
config SENSORS_ADC128D818
tristate "Texas Instruments ADC128D818"
depends on I2C

View File

@ -202,6 +202,7 @@ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o
obj-$(CONFIG_SENSORS_STTS751) += stts751.o
obj-$(CONFIG_SENSORS_SURFACE_FAN)+= surface_fan.o
obj-$(CONFIG_SENSORS_SY7636A) += sy7636a-hwmon.o
obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o
obj-$(CONFIG_SENSORS_TC74) += tc74.o

View File

@ -0,0 +1,91 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Surface Fan driver for Surface System Aggregator Module. It provides access
* to the fan's rpm through the hwmon system.
*
* Copyright (C) 2023 Ivor Wanders <ivor@iwanders.net>
*/
#include <linux/hwmon.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/surface_aggregator/device.h>
#include <linux/types.h>
// SSAM
SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_fan_rpm_get, __le16, {
.target_category = SSAM_SSH_TC_FAN,
.command_id = 0x01,
});
// hwmon
static umode_t surface_fan_hwmon_is_visible(const void *drvdata,
enum hwmon_sensor_types type, u32 attr,
int channel)
{
return 0444;
}
static int surface_fan_hwmon_read(struct device *dev,
enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
{
struct ssam_device *sdev = dev_get_drvdata(dev);
int ret;
__le16 value;
ret = __ssam_fan_rpm_get(sdev, &value);
if (ret)
return ret;
*val = le16_to_cpu(value);
return 0;
}
static const struct hwmon_channel_info *const surface_fan_info[] = {
HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
NULL
};
static const struct hwmon_ops surface_fan_hwmon_ops = {
.is_visible = surface_fan_hwmon_is_visible,
.read = surface_fan_hwmon_read,
};
static const struct hwmon_chip_info surface_fan_chip_info = {
.ops = &surface_fan_hwmon_ops,
.info = surface_fan_info,
};
static int surface_fan_probe(struct ssam_device *sdev)
{
struct device *hdev;
hdev = devm_hwmon_device_register_with_info(&sdev->dev,
"surface_fan", sdev,
&surface_fan_chip_info,
NULL);
return PTR_ERR_OR_ZERO(hdev);
}
static const struct ssam_device_id ssam_fan_match[] = {
{ SSAM_SDEV(FAN, SAM, 0x01, 0x01) },
{},
};
MODULE_DEVICE_TABLE(ssam, ssam_fan_match);
static struct ssam_device_driver surface_fan = {
.probe = surface_fan_probe,
.match_table = ssam_fan_match,
.driver = {
.name = "surface_fan",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
module_ssam_device_driver(surface_fan);
MODULE_AUTHOR("Ivor Wanders <ivor@iwanders.net>");
MODULE_DESCRIPTION("Fan Driver for Surface System Aggregator Module");
MODULE_LICENSE("GPL");