-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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: linux-surface/kernel#144 Patchset: surface-sam
- Loading branch information
1 parent
5ea8172
commit 342a627
Showing
6 changed files
with
141 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
======================= ======= ========================================= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// 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 | ||
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 ret; | ||
} | ||
|
||
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); | ||
if (IS_ERR(hdev)) | ||
return PTR_ERR(hdev); | ||
|
||
return 0; | ||
} | ||
|
||
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"); |