eeepc-laptop: add hwmon fan control
Adds an hwmon interface to control the fan. Signed-off-by: Corentin Chary <corentincj@iksaif.net> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
a5fa429b4b
commit
e1faa9da28
|
@ -356,6 +356,7 @@ config EEEPC_LAPTOP
|
||||||
depends on X86
|
depends on X86
|
||||||
depends on ACPI
|
depends on ACPI
|
||||||
depends on BACKLIGHT_CLASS_DEVICE
|
depends on BACKLIGHT_CLASS_DEVICE
|
||||||
|
depends on HWMON
|
||||||
depends on EXPERIMENTAL
|
depends on EXPERIMENTAL
|
||||||
---help---
|
---help---
|
||||||
This driver supports the Fn-Fx keys on Eee PC laptops.
|
This driver supports the Fn-Fx keys on Eee PC laptops.
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/backlight.h>
|
#include <linux/backlight.h>
|
||||||
#include <linux/fb.h>
|
#include <linux/fb.h>
|
||||||
|
#include <linux/hwmon.h>
|
||||||
|
#include <linux/hwmon-sysfs.h>
|
||||||
#include <acpi/acpi_drivers.h>
|
#include <acpi/acpi_drivers.h>
|
||||||
#include <acpi/acpi_bus.h>
|
#include <acpi/acpi_bus.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
@ -103,6 +105,15 @@ const char *cm_setv[] = {
|
||||||
"CRDS", NULL
|
"CRDS", NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define EEEPC_EC "\\_SB.PCI0.SBRG.EC0."
|
||||||
|
|
||||||
|
#define EEEPC_EC_FAN_PWM EEEPC_EC "SC02" /* Fan PWM duty cycle (%) */
|
||||||
|
#define EEEPC_EC_SC02 0x63
|
||||||
|
#define EEEPC_EC_FAN_HRPM EEEPC_EC "SC05" /* High byte, fan speed (RPM) */
|
||||||
|
#define EEEPC_EC_FAN_LRPM EEEPC_EC "SC06" /* Low byte, fan speed (RPM) */
|
||||||
|
#define EEEPC_EC_FAN_CTRL EEEPC_EC "SFB3" /* Byte containing SF25 */
|
||||||
|
#define EEEPC_EC_SFB3 0xD3
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the main structure, we can use it to store useful information
|
* This is the main structure, we can use it to store useful information
|
||||||
* about the hotk device
|
* about the hotk device
|
||||||
|
@ -154,6 +165,9 @@ static struct acpi_driver eeepc_hotk_driver = {
|
||||||
/* The backlight device /sys/class/backlight */
|
/* The backlight device /sys/class/backlight */
|
||||||
static struct backlight_device *eeepc_backlight_device;
|
static struct backlight_device *eeepc_backlight_device;
|
||||||
|
|
||||||
|
/* The hwmon device */
|
||||||
|
static struct device *eeepc_hwmon_device;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The backlight class declaration
|
* The backlight class declaration
|
||||||
*/
|
*/
|
||||||
|
@ -428,6 +442,100 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hwmon
|
||||||
|
*/
|
||||||
|
static int eeepc_get_fan_pwm(void)
|
||||||
|
{
|
||||||
|
int value = 0;
|
||||||
|
|
||||||
|
read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value);
|
||||||
|
return (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eeepc_set_fan_pwm(int value)
|
||||||
|
{
|
||||||
|
value = SENSORS_LIMIT(value, 0, 100);
|
||||||
|
ec_write(EEEPC_EC_SC02, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int eeepc_get_fan_rpm(void)
|
||||||
|
{
|
||||||
|
int high = 0;
|
||||||
|
int low = 0;
|
||||||
|
|
||||||
|
read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high);
|
||||||
|
read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low);
|
||||||
|
return (high << 8 | low);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int eeepc_get_fan_ctrl(void)
|
||||||
|
{
|
||||||
|
int value = 0;
|
||||||
|
|
||||||
|
read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
|
||||||
|
return ((value & 0x02 ? 1 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eeepc_set_fan_ctrl(int manual)
|
||||||
|
{
|
||||||
|
int value = 0;
|
||||||
|
|
||||||
|
read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
|
||||||
|
if (manual)
|
||||||
|
value |= 0x02;
|
||||||
|
else
|
||||||
|
value &= ~0x02;
|
||||||
|
ec_write(EEEPC_EC_SFB3, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
int rv, value;
|
||||||
|
|
||||||
|
rv = parse_arg(buf, count, &value);
|
||||||
|
if (rv > 0)
|
||||||
|
set(value);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
|
||||||
|
{
|
||||||
|
return sprintf(buf, "%d\n", get());
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \
|
||||||
|
static ssize_t show_##_name(struct device *dev, \
|
||||||
|
struct device_attribute *attr, \
|
||||||
|
char *buf) \
|
||||||
|
{ \
|
||||||
|
return show_sys_hwmon(_set, buf); \
|
||||||
|
} \
|
||||||
|
static ssize_t store_##_name(struct device *dev, \
|
||||||
|
struct device_attribute *attr, \
|
||||||
|
const char *buf, size_t count) \
|
||||||
|
{ \
|
||||||
|
return store_sys_hwmon(_get, buf, count); \
|
||||||
|
} \
|
||||||
|
static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
|
||||||
|
|
||||||
|
EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
|
||||||
|
EEEPC_CREATE_SENSOR_ATTR(fan1_pwm, S_IRUGO | S_IWUSR,
|
||||||
|
eeepc_get_fan_pwm, eeepc_set_fan_pwm);
|
||||||
|
EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
|
||||||
|
eeepc_get_fan_ctrl, eeepc_set_fan_ctrl);
|
||||||
|
|
||||||
|
static struct attribute *hwmon_attributes[] = {
|
||||||
|
&sensor_dev_attr_fan1_pwm.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group hwmon_attribute_group = {
|
||||||
|
.attrs = hwmon_attributes
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* exit/init
|
* exit/init
|
||||||
*/
|
*/
|
||||||
|
@ -438,9 +546,23 @@ static void eeepc_backlight_exit(void)
|
||||||
eeepc_backlight_device = NULL;
|
eeepc_backlight_device = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void eeepc_hwmon_exit(void)
|
||||||
|
{
|
||||||
|
struct device *hwmon;
|
||||||
|
|
||||||
|
hwmon = eeepc_hwmon_device;
|
||||||
|
if (!hwmon)
|
||||||
|
return ;
|
||||||
|
hwmon_device_unregister(hwmon);
|
||||||
|
sysfs_remove_group(&hwmon->kobj,
|
||||||
|
&hwmon_attribute_group);
|
||||||
|
eeepc_hwmon_device = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void __exit eeepc_laptop_exit(void)
|
static void __exit eeepc_laptop_exit(void)
|
||||||
{
|
{
|
||||||
eeepc_backlight_exit();
|
eeepc_backlight_exit();
|
||||||
|
eeepc_hwmon_exit();
|
||||||
acpi_bus_unregister_driver(&eeepc_hotk_driver);
|
acpi_bus_unregister_driver(&eeepc_hotk_driver);
|
||||||
sysfs_remove_group(&platform_device->dev.kobj,
|
sysfs_remove_group(&platform_device->dev.kobj,
|
||||||
&platform_attribute_group);
|
&platform_attribute_group);
|
||||||
|
@ -468,6 +590,26 @@ static int eeepc_backlight_init(struct device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int eeepc_hwmon_init(struct device *dev)
|
||||||
|
{
|
||||||
|
struct device *hwmon;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
hwmon = hwmon_device_register(dev);
|
||||||
|
if (IS_ERR(hwmon)) {
|
||||||
|
printk(EEEPC_ERR
|
||||||
|
"Could not register eeepc hwmon device\n");
|
||||||
|
eeepc_hwmon_device = NULL;
|
||||||
|
return PTR_ERR(hwmon);
|
||||||
|
}
|
||||||
|
eeepc_hwmon_device = hwmon;
|
||||||
|
result = sysfs_create_group(&hwmon->kobj,
|
||||||
|
&hwmon_attribute_group);
|
||||||
|
if (result)
|
||||||
|
eeepc_hwmon_exit();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init eeepc_laptop_init(void)
|
static int __init eeepc_laptop_init(void)
|
||||||
{
|
{
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
@ -486,6 +628,9 @@ static int __init eeepc_laptop_init(void)
|
||||||
result = eeepc_backlight_init(dev);
|
result = eeepc_backlight_init(dev);
|
||||||
if (result)
|
if (result)
|
||||||
goto fail_backlight;
|
goto fail_backlight;
|
||||||
|
result = eeepc_hwmon_init(dev);
|
||||||
|
if (result)
|
||||||
|
goto fail_hwmon;
|
||||||
/* Register platform stuff */
|
/* Register platform stuff */
|
||||||
result = platform_driver_register(&platform_driver);
|
result = platform_driver_register(&platform_driver);
|
||||||
if (result)
|
if (result)
|
||||||
|
@ -510,6 +655,8 @@ fail_platform_device2:
|
||||||
fail_platform_device1:
|
fail_platform_device1:
|
||||||
platform_driver_unregister(&platform_driver);
|
platform_driver_unregister(&platform_driver);
|
||||||
fail_platform_driver:
|
fail_platform_driver:
|
||||||
|
eeepc_hwmon_exit();
|
||||||
|
fail_hwmon:
|
||||||
eeepc_backlight_exit();
|
eeepc_backlight_exit();
|
||||||
fail_backlight:
|
fail_backlight:
|
||||||
return result;
|
return result;
|
||||||
|
|
Loading…
Reference in New Issue