platform/x86: toshiba_acpi: Add fan RPM reading (hwmon interface)
This expands on the previous commit, exporting the fan RPM via hwmon. This will look something like the following when using the "sensors" command from lm_sensors: toshiba_acpi_sensors-acpi-0 Adapter: ACPI interface fan1: 0 RPM Signed-off-by: Arvid Norlander <lkml@vorpal.se> Acked-by: Guenter Roeck <linux@roeck-us.net> Link: https://lore.kernel.org/r/20220902174018.1720029-3-lkml@vorpal.se Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
Родитель
dd193dcdc9
Коммит
c727ba4cd9
|
@ -798,6 +798,7 @@ config ACPI_TOSHIBA
|
||||||
depends on INPUT
|
depends on INPUT
|
||||||
depends on SERIO_I8042 || SERIO_I8042 = n
|
depends on SERIO_I8042 || SERIO_I8042 = n
|
||||||
depends on ACPI_VIDEO || ACPI_VIDEO = n
|
depends on ACPI_VIDEO || ACPI_VIDEO = n
|
||||||
|
depends on HWMON || HWMON = n
|
||||||
depends on RFKILL || RFKILL = n
|
depends on RFKILL || RFKILL = n
|
||||||
depends on IIO
|
depends on IIO
|
||||||
select INPUT_SPARSEKMAP
|
select INPUT_SPARSEKMAP
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/miscdevice.h>
|
#include <linux/miscdevice.h>
|
||||||
#include <linux/rfkill.h>
|
#include <linux/rfkill.h>
|
||||||
|
#include <linux/hwmon.h>
|
||||||
#include <linux/iio/iio.h>
|
#include <linux/iio/iio.h>
|
||||||
#include <linux/toshiba.h>
|
#include <linux/toshiba.h>
|
||||||
#include <acpi/video.h>
|
#include <acpi/video.h>
|
||||||
|
@ -171,6 +172,9 @@ struct toshiba_acpi_dev {
|
||||||
struct miscdevice miscdev;
|
struct miscdevice miscdev;
|
||||||
struct rfkill *wwan_rfk;
|
struct rfkill *wwan_rfk;
|
||||||
struct iio_dev *indio_dev;
|
struct iio_dev *indio_dev;
|
||||||
|
#if IS_ENABLED(CONFIG_HWMON)
|
||||||
|
struct device *hwmon_device;
|
||||||
|
#endif
|
||||||
|
|
||||||
int force_fan;
|
int force_fan;
|
||||||
int last_key_event;
|
int last_key_event;
|
||||||
|
@ -2928,6 +2932,54 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* HWMON support for fan */
|
||||||
|
#if IS_ENABLED(CONFIG_HWMON)
|
||||||
|
static umode_t toshiba_acpi_hwmon_is_visible(const void *drvdata,
|
||||||
|
enum hwmon_sensor_types type,
|
||||||
|
u32 attr, int channel)
|
||||||
|
{
|
||||||
|
return 0444;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int toshiba_acpi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
||||||
|
u32 attr, int channel, long *val)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* There is only a single channel and single attribute (for the
|
||||||
|
* fan) at this point.
|
||||||
|
* This can be replaced with more advanced logic in the future,
|
||||||
|
* should the need arise.
|
||||||
|
*/
|
||||||
|
if (type == hwmon_fan && channel == 0 && attr == hwmon_fan_input) {
|
||||||
|
u32 value;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = get_fan_rpm(toshiba_acpi, &value);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*val = value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct hwmon_channel_info *toshiba_acpi_hwmon_info[] = {
|
||||||
|
HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct hwmon_ops toshiba_acpi_hwmon_ops = {
|
||||||
|
.is_visible = toshiba_acpi_hwmon_is_visible,
|
||||||
|
.read = toshiba_acpi_hwmon_read,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct hwmon_chip_info toshiba_acpi_hwmon_chip_info = {
|
||||||
|
.ops = &toshiba_acpi_hwmon_ops,
|
||||||
|
.info = toshiba_acpi_hwmon_info,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static void print_supported_features(struct toshiba_acpi_dev *dev)
|
static void print_supported_features(struct toshiba_acpi_dev *dev)
|
||||||
{
|
{
|
||||||
pr_info("Supported laptop features:");
|
pr_info("Supported laptop features:");
|
||||||
|
@ -2982,6 +3034,11 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
|
||||||
|
|
||||||
remove_toshiba_proc_entries(dev);
|
remove_toshiba_proc_entries(dev);
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_HWMON)
|
||||||
|
if (dev->hwmon_device)
|
||||||
|
hwmon_device_unregister(dev->hwmon_device);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (dev->accelerometer_supported && dev->indio_dev) {
|
if (dev->accelerometer_supported && dev->indio_dev) {
|
||||||
iio_device_unregister(dev->indio_dev);
|
iio_device_unregister(dev->indio_dev);
|
||||||
iio_device_free(dev->indio_dev);
|
iio_device_free(dev->indio_dev);
|
||||||
|
@ -3174,6 +3231,18 @@ iio_error:
|
||||||
ret = get_fan_rpm(dev, &dummy);
|
ret = get_fan_rpm(dev, &dummy);
|
||||||
dev->fan_rpm_supported = !ret;
|
dev->fan_rpm_supported = !ret;
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_HWMON)
|
||||||
|
if (dev->fan_rpm_supported) {
|
||||||
|
dev->hwmon_device = hwmon_device_register_with_info(
|
||||||
|
&dev->acpi_dev->dev, "toshiba_acpi_sensors", NULL,
|
||||||
|
&toshiba_acpi_hwmon_chip_info, NULL);
|
||||||
|
if (IS_ERR(dev->hwmon_device)) {
|
||||||
|
dev->hwmon_device = NULL;
|
||||||
|
pr_warn("unable to register hwmon device, skipping\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
toshiba_wwan_available(dev);
|
toshiba_wwan_available(dev);
|
||||||
if (dev->wwan_supported)
|
if (dev->wwan_supported)
|
||||||
toshiba_acpi_setup_wwan_rfkill(dev);
|
toshiba_acpi_setup_wwan_rfkill(dev);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче