569 lines
16 KiB
C
569 lines
16 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* AAEON HWMON driver
|
|
* Copyright (c) 2021, AAEON Ltd.
|
|
*
|
|
* Author: Edward Lin <edward1_lin@aaeon.com.tw>
|
|
* Author: Kunyang Fan <kunyang_fan@aaeon.com.tw>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*/
|
|
#include <linux/acpi.h>
|
|
#include <linux/err.h>
|
|
#include <linux/jiffies.h>
|
|
#include <linux/hwmon.h>
|
|
#include <linux/hwmon-sysfs.h>
|
|
#include <linux/module.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/platform_data/x86/asus-wmi.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
#define DRVNAME "hwmon-aaeon"
|
|
|
|
#define AAEON_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
|
|
|
|
#define AAEON_VERSION_METHOD_ID 0x00000000
|
|
#define HWM_INFORMATION_METHOD_ID 0x00030000
|
|
#define HWM_METHOD_ID 0x00030001
|
|
|
|
#define BITMAP_TEMP_ARG 0x12
|
|
#define BITMAP_FAN_ARG 0x13
|
|
#define BITMAP_VOLTAGE_ARG 0x14
|
|
|
|
#define SENSOR_TEMP_NUMBER 0
|
|
#define SENSOR_FAN_NUMBER 1
|
|
#define SENSOR_VOLTAGE_NUMBER 2
|
|
#define SENSOR_MAX_NUMBER 2
|
|
|
|
static ssize_t aaeon_show_sensor(struct device *dev,
|
|
struct device_attribute *devattr, char *buf);
|
|
static ssize_t aaeon_show_sensor_name(struct device *dev,
|
|
struct device_attribute *devattr,
|
|
char *buf);
|
|
static ssize_t aaeon_show_version(struct device *dev,
|
|
struct device_attribute *devattr, char *buf);
|
|
static ssize_t name_show(struct device *dev, struct device_attribute *devattr,
|
|
char *buf);
|
|
static int aaeon_get_version(void);
|
|
static int aaeon_hwmon_probe(struct platform_device *pdev);
|
|
static int aaeon_hwmon_remove(struct platform_device *pdev);
|
|
|
|
static const char * const temp_sensors_name_table[] = {
|
|
"CPU_Temp",
|
|
"SYS1_Temp",
|
|
"SYS2_Temp",
|
|
};
|
|
|
|
static const char * const temp_sensors_name_table_V3[] = {
|
|
"SYS_Temp",
|
|
"CPU_Temp",
|
|
};
|
|
|
|
static const char * const fan_sensors_name_table[] = {
|
|
"CPU_FAN",
|
|
"SYS1_FAN",
|
|
"SYS2_FAN",
|
|
"Chasis1_FAN",
|
|
"Chasis2_FAN",
|
|
};
|
|
|
|
static const char * const fan_sensors_name_table_V3[] = {
|
|
"Chasis_FAN",
|
|
"CPU_FAN",
|
|
};
|
|
|
|
static const char * const voltage_sensors_name_table[] = {
|
|
"VCORE_Voltage",
|
|
"VMEM_Voltage",
|
|
"+12_Voltage",
|
|
"+5_Voltage",
|
|
"+3.3_Voltage",
|
|
"+1.8_Voltage",
|
|
"5VSB_Voltage",
|
|
"3VSB_Voltage",
|
|
"VBAT_Voltage",
|
|
};
|
|
|
|
static const char * const voltage_sensors_name_table_V3[] = {
|
|
"VCORE_Voltage",
|
|
"+5_Voltage",
|
|
"AVCC_Voltage",
|
|
"+3.3_Voltage",
|
|
"+12_Voltage",
|
|
"VCOREREFIN_Voltage",
|
|
"VIN4_Voltage",
|
|
"3VSB_Voltage",
|
|
"VBAT_Voltage",
|
|
};
|
|
|
|
struct aaeon_hwmon_data {
|
|
struct device *hwmon_dev;
|
|
int bfpi_version;
|
|
u32 temp_bitmap;
|
|
u32 fan_bitmap;
|
|
u32 voltage_bitmap;
|
|
unsigned int sensors_number[SENSOR_MAX_NUMBER + 1];
|
|
const char * const *temp_names;
|
|
const char * const *fan_names;
|
|
const char * const *voltage_names;
|
|
};
|
|
|
|
/* Temperature attributes */
|
|
static struct sensor_device_attribute_2 temp_sys_nodes_atts[] = {
|
|
SENSOR_ATTR_2(temp1_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_TEMP_NUMBER, 0),
|
|
SENSOR_ATTR_2(temp1_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_TEMP_NUMBER, 0),
|
|
SENSOR_ATTR_2(temp2_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_TEMP_NUMBER, 1),
|
|
SENSOR_ATTR_2(temp2_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_TEMP_NUMBER, 1),
|
|
SENSOR_ATTR_2(temp3_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_TEMP_NUMBER, 2),
|
|
SENSOR_ATTR_2(temp3_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_TEMP_NUMBER, 2),
|
|
};
|
|
|
|
/* Cooler Fan attributes */
|
|
static struct sensor_device_attribute_2 fan_sys_nodes_atts[] = {
|
|
SENSOR_ATTR_2(fan1_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_FAN_NUMBER, 0),
|
|
SENSOR_ATTR_2(fan1_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_FAN_NUMBER, 0),
|
|
SENSOR_ATTR_2(fan2_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_FAN_NUMBER, 1),
|
|
SENSOR_ATTR_2(fan2_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_FAN_NUMBER, 1),
|
|
SENSOR_ATTR_2(fan3_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_FAN_NUMBER, 2),
|
|
SENSOR_ATTR_2(fan3_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_FAN_NUMBER, 2),
|
|
SENSOR_ATTR_2(fan4_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_FAN_NUMBER, 3),
|
|
SENSOR_ATTR_2(fan4_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_FAN_NUMBER, 3),
|
|
SENSOR_ATTR_2(fan5_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_FAN_NUMBER, 4),
|
|
SENSOR_ATTR_2(fan5_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_FAN_NUMBER, 4),
|
|
};
|
|
|
|
/* Voltage attributes */
|
|
static struct sensor_device_attribute_2 voltage_sys_nodes_atts[] = {
|
|
SENSOR_ATTR_2(in1_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 0),
|
|
SENSOR_ATTR_2(in1_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 0),
|
|
SENSOR_ATTR_2(in2_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 1),
|
|
SENSOR_ATTR_2(in2_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 1),
|
|
SENSOR_ATTR_2(in3_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 2),
|
|
SENSOR_ATTR_2(in3_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 2),
|
|
SENSOR_ATTR_2(in4_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 3),
|
|
SENSOR_ATTR_2(in4_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 3),
|
|
SENSOR_ATTR_2(in5_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 4),
|
|
SENSOR_ATTR_2(in5_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 4),
|
|
SENSOR_ATTR_2(in6_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 5),
|
|
SENSOR_ATTR_2(in6_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 5),
|
|
SENSOR_ATTR_2(in7_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 6),
|
|
SENSOR_ATTR_2(in7_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 6),
|
|
SENSOR_ATTR_2(in8_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 7),
|
|
SENSOR_ATTR_2(in8_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 7),
|
|
SENSOR_ATTR_2(in9_input, 0444, aaeon_show_sensor, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 8),
|
|
SENSOR_ATTR_2(in9_label, 0444, aaeon_show_sensor_name, NULL,
|
|
SENSOR_VOLTAGE_NUMBER, 8),
|
|
|
|
};
|
|
|
|
static struct sensor_device_attribute_2 info_sys_nodes_atts[] = {
|
|
/* WMI version Information */
|
|
SENSOR_ATTR_2(AAEON_VERSION, 0444, aaeon_show_version, NULL, 0, 0),
|
|
};
|
|
|
|
DEVICE_ATTR_RO(name);
|
|
static ssize_t name_show(struct device *dev, struct device_attribute *devattr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "%s\n", DRVNAME);
|
|
}
|
|
|
|
static ssize_t aaeon_show_version(struct device *dev,
|
|
struct device_attribute *devattr, char *buf)
|
|
{
|
|
struct aaeon_hwmon_data *data =
|
|
(struct aaeon_hwmon_data *)dev_get_drvdata(dev);
|
|
|
|
return sprintf(buf, "%d\n", data->bfpi_version);
|
|
}
|
|
|
|
static ssize_t aaeon_show_sensor_name(struct device *dev,
|
|
struct device_attribute *devattr, char *buf)
|
|
{
|
|
u8 nr = to_sensor_dev_attr_2(devattr)->nr;
|
|
u8 index = to_sensor_dev_attr_2(devattr)->index;
|
|
struct aaeon_hwmon_data *data =
|
|
(struct aaeon_hwmon_data *)dev_get_drvdata(dev);
|
|
|
|
if (nr > SENSOR_MAX_NUMBER || index >= data->sensors_number[nr]) {
|
|
pr_debug("Can not check the device");
|
|
return -1;
|
|
}
|
|
|
|
switch (nr) {
|
|
case SENSOR_TEMP_NUMBER:
|
|
return sprintf(buf, "%s\n", data->temp_names[index]);
|
|
case SENSOR_FAN_NUMBER:
|
|
return sprintf(buf, "%s\n", data->fan_names[index]);
|
|
case SENSOR_VOLTAGE_NUMBER:
|
|
return sprintf(buf, "%s\n", data->voltage_names[index]);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t aaeon_show_sensor(struct device *dev,
|
|
struct device_attribute *devattr, char *buf)
|
|
{
|
|
u8 nr = to_sensor_dev_attr_2(devattr)->nr;
|
|
u8 index = to_sensor_dev_attr_2(devattr)->index;
|
|
u32 dev_id;
|
|
int retval, err;
|
|
struct aaeon_hwmon_data *data =
|
|
(struct aaeon_hwmon_data *)dev_get_drvdata(dev);
|
|
|
|
if (nr > SENSOR_MAX_NUMBER || index >= data->sensors_number[nr]) {
|
|
pr_debug("Can not check the device");
|
|
return -1;
|
|
}
|
|
|
|
/* For the V3 version, index need offset */
|
|
if (data->bfpi_version == 0x03 && nr != SENSOR_VOLTAGE_NUMBER)
|
|
index++;
|
|
|
|
dev_id = (index << 12) | (nr << 8);
|
|
err = asus_wmi_evaluate_method(HWM_METHOD_ID, dev_id, 0, &retval);
|
|
if (err)
|
|
return err;
|
|
|
|
/* For the V3 version, need to convert the raw value*/
|
|
if (nr == SENSOR_VOLTAGE_NUMBER && data->bfpi_version == 0x03) {
|
|
switch (index) {
|
|
case 0: /* VCORE */
|
|
retval = retval * 16;
|
|
break;
|
|
case 1: /* +5V */
|
|
retval = (retval * 2008) / 50;
|
|
break;
|
|
case 2: /* AVCC */
|
|
retval = retval * 16;
|
|
break;
|
|
case 3: /* +3.3V */
|
|
retval = retval * 16;
|
|
break;
|
|
case 4: /* +12V */
|
|
retval = retval * 96;
|
|
break;
|
|
case 5: /* VCOREREFIN */
|
|
retval = (retval * 552) / 41;
|
|
break;
|
|
case 6: /* VIN4 */
|
|
retval = retval * 8;
|
|
break;
|
|
case 7: /* 3VSB */
|
|
retval = retval * 16;
|
|
break;
|
|
case 8: /* VBAT */
|
|
retval = retval * 16;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (nr == SENSOR_TEMP_NUMBER && data->bfpi_version == 0x03)
|
|
retval = retval * 1000;
|
|
|
|
return sprintf(buf, "%d\n", retval);
|
|
}
|
|
|
|
static int aaeon_hwmon_create_sub_sysfs_fs(struct platform_device *pdev,
|
|
struct sensor_device_attribute_2 *attr,
|
|
int sensor_number,
|
|
u32 sensor_mask,
|
|
int bfpi_version)
|
|
{
|
|
int i, err = 0;
|
|
|
|
for (i = 0; i < sensor_number; i++) {
|
|
if (bfpi_version == 0x03 || sensor_mask & BIT(i)) {
|
|
err = device_create_file(&pdev->dev, &attr[2 * i].dev_attr);
|
|
if (err)
|
|
break;
|
|
err = device_create_file(&pdev->dev, &attr[2 * i + 1].dev_attr);
|
|
if (err)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int
|
|
aaeon_hwmon_create_sysfs_files(struct platform_device *pdev, struct aaeon_hwmon_data *data)
|
|
{
|
|
int err;
|
|
|
|
/* register sysfs interface files */
|
|
err = device_create_file(&pdev->dev, &dev_attr_name);
|
|
if (err)
|
|
return err;
|
|
|
|
/* registe sysfs to dump sensors BFPI version */
|
|
err = device_create_file(&pdev->dev, &info_sys_nodes_atts[0].dev_attr);
|
|
if (err)
|
|
return err;
|
|
|
|
/* create temperature name and value node */
|
|
err = aaeon_hwmon_create_sub_sysfs_fs(pdev, temp_sys_nodes_atts,
|
|
data->sensors_number[SENSOR_TEMP_NUMBER],
|
|
data->temp_bitmap, data->bfpi_version);
|
|
if (err)
|
|
return err;
|
|
|
|
/* create fan name and value node */
|
|
err = aaeon_hwmon_create_sub_sysfs_fs(pdev, fan_sys_nodes_atts,
|
|
data->sensors_number[SENSOR_FAN_NUMBER],
|
|
data->fan_bitmap, data->bfpi_version);
|
|
if (err)
|
|
return err;
|
|
|
|
/* create voltage name and value node */
|
|
err = aaeon_hwmon_create_sub_sysfs_fs(pdev, voltage_sys_nodes_atts,
|
|
data->sensors_number[SENSOR_VOLTAGE_NUMBER],
|
|
data->voltage_bitmap, data->bfpi_version);
|
|
if (err)
|
|
return err;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void aaeon_hwmon_remove_sub_sysfs_fs(struct platform_device *pdev,
|
|
struct sensor_device_attribute_2 *attr,
|
|
int sensor_number,
|
|
u32 sensor_mask,
|
|
int bfpi_version)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < sensor_number; i++) {
|
|
if (bfpi_version == 0x03 || sensor_mask & BIT(i)) {
|
|
device_remove_file(&pdev->dev, &attr[2 * i].dev_attr);
|
|
device_remove_file(&pdev->dev, &attr[2 * i + 1].dev_attr);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
aaeon_hwmon_remove_sysfs_files(struct platform_device *pdev,
|
|
struct aaeon_hwmon_data *data)
|
|
{
|
|
/* degister sysfs interface files */
|
|
device_remove_file(&pdev->dev, &dev_attr_name);
|
|
|
|
/* degiste sysfs to dump sensors BFPI version */
|
|
device_remove_file(&pdev->dev, &info_sys_nodes_atts[0].dev_attr);
|
|
|
|
/* remove temperature name and value node */
|
|
aaeon_hwmon_remove_sub_sysfs_fs(pdev, temp_sys_nodes_atts,
|
|
data->sensors_number[SENSOR_TEMP_NUMBER],
|
|
data->temp_bitmap,
|
|
data->bfpi_version);
|
|
|
|
/* remove fan name and value node */
|
|
aaeon_hwmon_remove_sub_sysfs_fs(pdev, fan_sys_nodes_atts,
|
|
data->sensors_number[SENSOR_FAN_NUMBER],
|
|
data->fan_bitmap,
|
|
data->bfpi_version);
|
|
|
|
/* remove voltage name and value node */
|
|
aaeon_hwmon_remove_sub_sysfs_fs(pdev, voltage_sys_nodes_atts,
|
|
data->sensors_number[SENSOR_VOLTAGE_NUMBER],
|
|
data->voltage_bitmap,
|
|
data->bfpi_version);
|
|
}
|
|
|
|
static int aaeon_hwmon_remove(struct platform_device *pdev)
|
|
{
|
|
struct aaeon_hwmon_data *data = platform_get_drvdata(pdev);
|
|
|
|
if (data->hwmon_dev)
|
|
hwmon_device_unregister(data->hwmon_dev);
|
|
|
|
aaeon_hwmon_remove_sysfs_files(pdev, data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aaeon_get_version(void)
|
|
{
|
|
int err, retval;
|
|
u32 dev_id = 0x00;
|
|
|
|
err = asus_wmi_evaluate_method(AAEON_VERSION_METHOD_ID, dev_id, 0,
|
|
&retval);
|
|
if (err)
|
|
return err;
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int aaeon_hwmon_init_drv_data(struct aaeon_hwmon_data *data)
|
|
{
|
|
int err;
|
|
|
|
data->bfpi_version = aaeon_get_version();
|
|
if (data->bfpi_version < 0) {
|
|
pr_debug("Error BFPI verion\n");
|
|
return -1;
|
|
}
|
|
|
|
if (data->bfpi_version == 0x03) {
|
|
/* set the number of bits in temp bitmap */
|
|
data->sensors_number[SENSOR_TEMP_NUMBER] =
|
|
ARRAY_SIZE(temp_sensors_name_table_V3);
|
|
data->temp_names = temp_sensors_name_table_V3;
|
|
|
|
/* set the number of bits in fan bitmap */
|
|
data->sensors_number[SENSOR_FAN_NUMBER] =
|
|
ARRAY_SIZE(fan_sensors_name_table_V3);
|
|
data->fan_names = fan_sensors_name_table_V3;
|
|
|
|
/* set the number of bits in voltage bitmap */
|
|
data->sensors_number[SENSOR_VOLTAGE_NUMBER] =
|
|
ARRAY_SIZE(voltage_sensors_name_table_V3);
|
|
data->voltage_names = voltage_sensors_name_table_V3;
|
|
} else {
|
|
/* set the number of bits in temp bitmap */
|
|
data->sensors_number[SENSOR_TEMP_NUMBER] =
|
|
ARRAY_SIZE(temp_sensors_name_table);
|
|
data->temp_names = temp_sensors_name_table;
|
|
|
|
/* set the number of bits in fan bitmap */
|
|
data->sensors_number[SENSOR_FAN_NUMBER] =
|
|
ARRAY_SIZE(fan_sensors_name_table);
|
|
data->fan_names = fan_sensors_name_table;
|
|
|
|
/* set the number of bits in voltage bitmap */
|
|
data->sensors_number[SENSOR_VOLTAGE_NUMBER] =
|
|
ARRAY_SIZE(voltage_sensors_name_table);
|
|
data->voltage_names = voltage_sensors_name_table;
|
|
}
|
|
|
|
/* get temp supported bitmap */
|
|
err = asus_wmi_evaluate_method(HWM_INFORMATION_METHOD_ID,
|
|
BITMAP_TEMP_ARG, 0, &data->temp_bitmap);
|
|
if (err)
|
|
return err;
|
|
|
|
/* get fan supported bitmap */
|
|
err = asus_wmi_evaluate_method(HWM_INFORMATION_METHOD_ID,
|
|
BITMAP_FAN_ARG, 0, &data->fan_bitmap);
|
|
if (err)
|
|
return err;
|
|
|
|
/* get voltage supported bitmap */
|
|
err = asus_wmi_evaluate_method(HWM_INFORMATION_METHOD_ID,
|
|
BITMAP_VOLTAGE_ARG, 0, &data->voltage_bitmap);
|
|
if (err)
|
|
return err;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aaeon_hwmon_probe(struct platform_device *pdev)
|
|
{
|
|
int err;
|
|
struct aaeon_hwmon_data *data;
|
|
|
|
pr_debug("aaeon hwomon device probe (support V3)!\n");
|
|
if (!wmi_has_guid(AAEON_WMI_MGMT_GUID)) {
|
|
pr_info("AAEON Management GUID not found\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
data = devm_kzalloc(&pdev->dev, sizeof(struct aaeon_hwmon_data),
|
|
GFP_KERNEL);
|
|
if (!data)
|
|
return -ENOMEM;
|
|
|
|
err = aaeon_hwmon_init_drv_data(data);
|
|
if (err) {
|
|
pr_info("Error to get sensor support bitmap\n");
|
|
goto exit;
|
|
}
|
|
|
|
if (data->bfpi_version != 0x03 && data->temp_bitmap == 0 &&
|
|
data->fan_bitmap == 0 && data->voltage_bitmap == 0) {
|
|
pr_debug("No sensors found\n");
|
|
err = -ENODEV;
|
|
goto exit;
|
|
}
|
|
|
|
platform_set_drvdata(pdev, data);
|
|
err = aaeon_hwmon_create_sysfs_files(pdev, data);
|
|
if (err)
|
|
goto exit;
|
|
|
|
data->hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
|
|
"AAEON_HWM",
|
|
data,
|
|
NULL,
|
|
NULL);
|
|
if (IS_ERR(data->hwmon_dev)) {
|
|
err = PTR_ERR(data->hwmon_dev);
|
|
data->hwmon_dev = NULL;
|
|
goto exit_unregister_sysfs;
|
|
}
|
|
|
|
return 0;
|
|
|
|
exit_unregister_sysfs:
|
|
aaeon_hwmon_remove(pdev);
|
|
exit:
|
|
return err;
|
|
}
|
|
|
|
static struct platform_driver aaeon_hwmon_driver = {
|
|
.driver = {
|
|
.name = DRVNAME,
|
|
.owner = THIS_MODULE,
|
|
},
|
|
.probe = aaeon_hwmon_probe,
|
|
.remove = aaeon_hwmon_remove,
|
|
};
|
|
|
|
module_platform_driver_probe(aaeon_hwmon_driver, aaeon_hwmon_probe);
|
|
|
|
MODULE_ALIAS("platform:hwmon-aaeon");
|
|
MODULE_DESCRIPTION("AAEON Hardware Monitoring Driver");
|
|
MODULE_AUTHOR("Edward Lin <edward1_lin@aaeon.com.tw>");
|
|
MODULE_AUTHOR("Kunyang Fan <kunyang_fan@aaeon.com.tw>");
|
|
MODULE_LICENSE("GPL v2");
|