Refactoring
- Convert to use devm_hwmon_device_register_with_info
This commit is contained in:
parent
b4e1147445
commit
1cc308cd8a
396
zenpower.c
396
zenpower.c
|
@ -1,5 +1,4 @@
|
||||||
#include <linux/hwmon.h>
|
#include <linux/hwmon.h>
|
||||||
#include <linux/hwmon-sysfs.h>
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <asm/amd_nb.h>
|
#include <asm/amd_nb.h>
|
||||||
|
@ -76,28 +75,31 @@ static const struct tctl_offset tctl_offset_table[] = {
|
||||||
|
|
||||||
static DEFINE_MUTEX(nb_smu_ind_mutex);
|
static DEFINE_MUTEX(nb_smu_ind_mutex);
|
||||||
|
|
||||||
static umode_t zenpower_is_visible(struct kobject *kobj,
|
static umode_t zenpower_is_visible(const void *rdata,
|
||||||
struct attribute *attr, int index)
|
enum hwmon_sensor_types type,
|
||||||
|
u32 attr, int channel)
|
||||||
{
|
{
|
||||||
struct device *dev = container_of(kobj, struct device, kobj);
|
const struct zenpower_data *data = rdata;
|
||||||
struct zenpower_data *data = dev_get_drvdata(dev);
|
|
||||||
|
|
||||||
switch (index) {
|
switch (type) {
|
||||||
case 4 ... 11: // current and power
|
case hwmon_temp:
|
||||||
if (!data->amps_visible)
|
if (data->ccd1_visible == false && channel == 2) // Tccd1
|
||||||
|
return 0;
|
||||||
|
if (data->ccd2_visible == false && channel == 3) // Tccd2
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case 17 ... 18: // CCD1 temperature
|
|
||||||
if (!data->ccd1_visible)
|
case hwmon_curr:
|
||||||
|
case hwmon_power:
|
||||||
|
if (data->amps_visible == false)
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case 19 ... 20: // CCD2 temperature
|
|
||||||
if (!data->ccd2_visible)
|
default:
|
||||||
return 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return attr->mode;
|
return 0444;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 plane_to_vcc(u32 p)
|
static u32 plane_to_vcc(u32 p)
|
||||||
|
@ -153,122 +155,6 @@ static unsigned int get_ccd_temp(struct zenpower_data *data, u32 ccd_addr)
|
||||||
return (regval & 0xfff) * 125 - 305000;
|
return (regval & 0xfff) * 125 - 305000;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t temp1_input_show(struct device *dev,
|
|
||||||
struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
struct zenpower_data *data = dev_get_drvdata(dev);
|
|
||||||
unsigned int temp = get_ctl_temp(data);
|
|
||||||
|
|
||||||
if (temp > data->temp_offset)
|
|
||||||
temp -= data->temp_offset;
|
|
||||||
else
|
|
||||||
temp = 0;
|
|
||||||
|
|
||||||
return sprintf(buf, "%u\n", temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t temp1_max_show(struct device *dev,
|
|
||||||
struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
// source: https://www.amd.com/en/products/cpu/amd-ryzen-7-3700x
|
|
||||||
// other cpus have also same same* Tmax on AMD website
|
|
||||||
// * = note: AMD list on website max of Tctl, not max of Tdie
|
|
||||||
return sprintf(buf, "%d\n", 95 * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t temp2_input_show(struct device *dev,
|
|
||||||
struct device_attribute *devattr, char *buf)
|
|
||||||
{
|
|
||||||
struct zenpower_data *data = dev_get_drvdata(dev);
|
|
||||||
unsigned int temp = get_ctl_temp(data);
|
|
||||||
|
|
||||||
return sprintf(buf, "%u\n", temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t temp3_input_show(struct device *dev,
|
|
||||||
struct device_attribute *devattr, char *buf)
|
|
||||||
{
|
|
||||||
struct zenpower_data *data = dev_get_drvdata(dev);
|
|
||||||
unsigned int temp = get_ccd_temp(data, F17H_M70H_CCD1_TEMP);
|
|
||||||
|
|
||||||
return sprintf(buf, "%u\n", temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t temp4_input_show(struct device *dev,
|
|
||||||
struct device_attribute *devattr, char *buf)
|
|
||||||
{
|
|
||||||
struct zenpower_data *data = dev_get_drvdata(dev);
|
|
||||||
unsigned int temp = get_ccd_temp(data, F17H_M70H_CCD2_TEMP);
|
|
||||||
|
|
||||||
return sprintf(buf, "%u\n", temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t in1_input_show(struct device *dev,
|
|
||||||
struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
struct zenpower_data *data = dev_get_drvdata(dev);
|
|
||||||
u32 plane, vcc;
|
|
||||||
|
|
||||||
data->read_amdsmn_addr(data->pdev, data->svi_core_addr, &plane);
|
|
||||||
vcc = plane_to_vcc(plane);
|
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", vcc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t in2_input_show(struct device *dev,
|
|
||||||
struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
struct zenpower_data *data = dev_get_drvdata(dev);
|
|
||||||
u32 plane, vcc;
|
|
||||||
|
|
||||||
data->read_amdsmn_addr(data->pdev, data->svi_soc_addr, &plane);
|
|
||||||
vcc = plane_to_vcc(plane);
|
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", vcc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t curr1_input_show(struct device *dev,
|
|
||||||
struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
struct zenpower_data *data = dev_get_drvdata(dev);
|
|
||||||
u32 plane;
|
|
||||||
|
|
||||||
data->read_amdsmn_addr(data->pdev, data->svi_core_addr, &plane);
|
|
||||||
return sprintf(buf, "%d\n", get_core_current(plane, data->zen2));
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t curr2_input_show(struct device *dev,
|
|
||||||
struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
struct zenpower_data *data = dev_get_drvdata(dev);
|
|
||||||
u32 plane;
|
|
||||||
|
|
||||||
data->read_amdsmn_addr(data->pdev, data->svi_soc_addr, &plane);
|
|
||||||
return sprintf(buf, "%d\n", get_soc_current(plane, data->zen2));
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t power1_input_show(struct device *dev,
|
|
||||||
struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
struct zenpower_data *data = dev_get_drvdata(dev);
|
|
||||||
u32 plane;
|
|
||||||
|
|
||||||
data->read_amdsmn_addr(data->pdev, data->svi_core_addr, &plane);
|
|
||||||
return sprintf(buf, "%d\n",
|
|
||||||
get_core_current(plane, data->zen2) * plane_to_vcc(plane));
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t power2_input_show(struct device *dev,
|
|
||||||
struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
struct zenpower_data *data = dev_get_drvdata(dev);
|
|
||||||
u32 plane;
|
|
||||||
|
|
||||||
data->read_amdsmn_addr(data->pdev, data->svi_soc_addr, &plane);
|
|
||||||
return sprintf(buf, "%d\n",
|
|
||||||
get_soc_current(plane, data->zen2) * plane_to_vcc(plane));
|
|
||||||
}
|
|
||||||
|
|
||||||
int static debug_addrs_arr[] = {
|
int static debug_addrs_arr[] = {
|
||||||
F17H_M01H_SVI + 0x8, F17H_M01H_SVI_TEL_PLANE0, F17H_M01H_SVI_TEL_PLANE1,
|
F17H_M01H_SVI + 0x8, F17H_M01H_SVI_TEL_PLANE0, F17H_M01H_SVI_TEL_PLANE1,
|
||||||
0x000598BC, 0x0005994C, F17H_M70H_CCD1_TEMP, F17H_M70H_CCD2_TEMP,
|
0x000598BC, 0x0005994C, F17H_M70H_CCD1_TEMP, F17H_M70H_CCD2_TEMP,
|
||||||
|
@ -292,94 +178,139 @@ static ssize_t debug_data_show(struct device *dev,
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int zenpower_read(struct device *dev, enum hwmon_sensor_types type,
|
||||||
static ssize_t zen_label_show(struct device *dev,
|
u32 attr, int channel, long *val)
|
||||||
struct device_attribute *devattr, char *buf)
|
|
||||||
{
|
{
|
||||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
struct zenpower_data *data = dev_get_drvdata(dev);
|
||||||
|
u32 plane;
|
||||||
|
|
||||||
switch (attr->index){
|
switch (type) {
|
||||||
case 1:
|
|
||||||
return sprintf(buf, "SVI2_Core\n");
|
// Temperatures
|
||||||
case 2:
|
case hwmon_temp:
|
||||||
return sprintf(buf, "SVI2_SoC\n");
|
switch (attr) {
|
||||||
case 11:
|
case hwmon_temp_input:
|
||||||
return sprintf(buf, "SVI2_C_Core\n");
|
switch (channel) {
|
||||||
case 12:
|
case 0: // Tdie
|
||||||
return sprintf(buf, "SVI2_C_SoC\n");
|
*val = get_ctl_temp(data) - data->temp_offset;
|
||||||
case 21:
|
break;
|
||||||
return sprintf(buf, "SVI2_P_Core\n");
|
case 1: // Tctl
|
||||||
case 22:
|
*val = get_ctl_temp(data);
|
||||||
return sprintf(buf, "SVI2_P_SoC\n");
|
break;
|
||||||
case 31:
|
case 2: // Tccd1
|
||||||
return sprintf(buf, "Tdie\n");
|
*val = get_ccd_temp(data, F17H_M70H_CCD1_TEMP);
|
||||||
case 32:
|
break;
|
||||||
return sprintf(buf, "Tctl\n");
|
case 3: // Tccd2
|
||||||
case 33:
|
*val = get_ccd_temp(data, F17H_M70H_CCD2_TEMP);
|
||||||
return sprintf(buf, "Tccd1\n");
|
break;
|
||||||
case 34:
|
default:
|
||||||
return sprintf(buf, "Tccd2\n");
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case hwmon_temp_max: // Tdie max
|
||||||
|
// source: https://www.amd.com/en/products/cpu/amd-ryzen-7-3700x
|
||||||
|
// other cpus have also same* Tmax on AMD website
|
||||||
|
// * = when taking into consideration a tctl offset
|
||||||
|
*val = 95 * 1000;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Voltage / Power / Current
|
||||||
|
case hwmon_in:
|
||||||
|
case hwmon_curr:
|
||||||
|
case hwmon_power:
|
||||||
|
if (attr != hwmon_in_input && attr != hwmon_curr_input &&
|
||||||
|
attr != hwmon_power_input) {
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (channel) {
|
||||||
|
case 0: // Core SVI2
|
||||||
|
data->read_amdsmn_addr(data->pdev, data->svi_core_addr, &plane);
|
||||||
|
break;
|
||||||
|
case 1: // SoC SVI2
|
||||||
|
data->read_amdsmn_addr(data->pdev, data->svi_soc_addr, &plane);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case hwmon_in:
|
||||||
|
*val = plane_to_vcc(plane);
|
||||||
|
break;
|
||||||
|
case hwmon_curr:
|
||||||
|
*val = (channel == 0) ?
|
||||||
|
get_core_current(plane, data->zen2):
|
||||||
|
get_soc_current(plane, data->zen2);
|
||||||
|
break;
|
||||||
|
case hwmon_power:
|
||||||
|
*val = (channel == 0) ?
|
||||||
|
get_core_current(plane, data->zen2) * plane_to_vcc(plane):
|
||||||
|
get_soc_current(plane, data->zen2) * plane_to_vcc(plane);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR_RO(in1_input);
|
static const char *zenpower_temp_label[] = {
|
||||||
static SENSOR_DEVICE_ATTR(in1_label, 0444, zen_label_show, NULL, 1);
|
"Tdie",
|
||||||
static DEVICE_ATTR_RO(in2_input);
|
"Tctl",
|
||||||
static SENSOR_DEVICE_ATTR(in2_label, 0444, zen_label_show, NULL, 2);
|
"Tccd1",
|
||||||
static DEVICE_ATTR_RO(curr1_input);
|
"Tccd2",
|
||||||
static SENSOR_DEVICE_ATTR(curr1_label, 0444, zen_label_show, NULL, 11);
|
|
||||||
static DEVICE_ATTR_RO(curr2_input);
|
|
||||||
static SENSOR_DEVICE_ATTR(curr2_label, 0444, zen_label_show, NULL, 12);
|
|
||||||
static DEVICE_ATTR_RO(power1_input);
|
|
||||||
static SENSOR_DEVICE_ATTR(power1_label, 0444, zen_label_show, NULL, 21);
|
|
||||||
static DEVICE_ATTR_RO(power2_input);
|
|
||||||
static SENSOR_DEVICE_ATTR(power2_label, 0444, zen_label_show, NULL, 22);
|
|
||||||
static DEVICE_ATTR_RO(temp1_input);
|
|
||||||
static DEVICE_ATTR_RO(temp1_max);
|
|
||||||
static SENSOR_DEVICE_ATTR(temp1_label, 0444, zen_label_show, NULL, 31);
|
|
||||||
static DEVICE_ATTR_RO(temp2_input);
|
|
||||||
static SENSOR_DEVICE_ATTR(temp2_label, 0444, zen_label_show, NULL, 32);
|
|
||||||
static DEVICE_ATTR_RO(temp3_input);
|
|
||||||
static SENSOR_DEVICE_ATTR(temp3_label, 0444, zen_label_show, NULL, 33);
|
|
||||||
static DEVICE_ATTR_RO(temp4_input);
|
|
||||||
static SENSOR_DEVICE_ATTR(temp4_label, 0444, zen_label_show, NULL, 34);
|
|
||||||
static DEVICE_ATTR_RO(debug_data);
|
|
||||||
|
|
||||||
|
|
||||||
static struct attribute *zenpower_attrs[] = {
|
|
||||||
&dev_attr_in1_input.attr,
|
|
||||||
&sensor_dev_attr_in1_label.dev_attr.attr,
|
|
||||||
&dev_attr_in2_input.attr,
|
|
||||||
&sensor_dev_attr_in2_label.dev_attr.attr,
|
|
||||||
&dev_attr_curr1_input.attr,
|
|
||||||
&sensor_dev_attr_curr1_label.dev_attr.attr,
|
|
||||||
&dev_attr_curr2_input.attr,
|
|
||||||
&sensor_dev_attr_curr2_label.dev_attr.attr,
|
|
||||||
&dev_attr_power1_input.attr,
|
|
||||||
&sensor_dev_attr_power1_label.dev_attr.attr,
|
|
||||||
&dev_attr_power2_input.attr,
|
|
||||||
&sensor_dev_attr_power2_label.dev_attr.attr,
|
|
||||||
&dev_attr_temp1_input.attr,
|
|
||||||
&dev_attr_temp1_max.attr,
|
|
||||||
&sensor_dev_attr_temp1_label.dev_attr.attr,
|
|
||||||
&dev_attr_temp2_input.attr,
|
|
||||||
&sensor_dev_attr_temp2_label.dev_attr.attr,
|
|
||||||
&dev_attr_temp3_input.attr,
|
|
||||||
&sensor_dev_attr_temp3_label.dev_attr.attr,
|
|
||||||
&dev_attr_temp4_input.attr,
|
|
||||||
&sensor_dev_attr_temp4_label.dev_attr.attr,
|
|
||||||
&dev_attr_debug_data.attr,
|
|
||||||
NULL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct attribute_group zenpower_group = {
|
static const char *zenpower_in_label[] = {
|
||||||
.attrs = zenpower_attrs,
|
"SVI2_Core",
|
||||||
.is_visible = zenpower_is_visible,
|
"SVI2_SoC",
|
||||||
};
|
};
|
||||||
__ATTRIBUTE_GROUPS(zenpower);
|
|
||||||
|
|
||||||
|
static const char *zenpower_curr_label[] = {
|
||||||
|
"SVI2_C_Core",
|
||||||
|
"SVI2_C_SoC",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *zenpower_power_label[] = {
|
||||||
|
"SVI2_P_Core",
|
||||||
|
"SVI2_P_SoC",
|
||||||
|
};
|
||||||
|
|
||||||
|
static int zenpower_read_labels(struct device *dev,
|
||||||
|
enum hwmon_sensor_types type, u32 attr,
|
||||||
|
int channel, const char **str)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case hwmon_temp:
|
||||||
|
*str = zenpower_temp_label[channel];
|
||||||
|
break;
|
||||||
|
case hwmon_in:
|
||||||
|
*str = zenpower_in_label[channel];
|
||||||
|
break;
|
||||||
|
case hwmon_curr:
|
||||||
|
*str = zenpower_curr_label[channel];
|
||||||
|
break;
|
||||||
|
case hwmon_power:
|
||||||
|
*str = zenpower_power_label[channel];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void kernel_smn_read(struct pci_dev *pdev, u32 address, u32 *regval)
|
static void kernel_smn_read(struct pci_dev *pdev, u32 address, u32 *regval)
|
||||||
{
|
{
|
||||||
|
@ -396,6 +327,51 @@ static void nb_index_read(struct pci_dev *pdev, u32 address, u32 *regval)
|
||||||
mutex_unlock(&nb_smu_ind_mutex);
|
mutex_unlock(&nb_smu_ind_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct hwmon_channel_info *zenpower_info[] = {
|
||||||
|
HWMON_CHANNEL_INFO(temp,
|
||||||
|
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_LABEL, // Tdie
|
||||||
|
HWMON_T_INPUT | HWMON_T_LABEL, // Tctl
|
||||||
|
HWMON_T_INPUT | HWMON_T_LABEL, // Tccd1
|
||||||
|
HWMON_T_INPUT | HWMON_T_LABEL), // Tccd2
|
||||||
|
|
||||||
|
HWMON_CHANNEL_INFO(in,
|
||||||
|
HWMON_I_INPUT | HWMON_I_LABEL, // Core Voltage (SVI2)
|
||||||
|
HWMON_I_INPUT | HWMON_I_LABEL), // SoC Voltage (SVI2)
|
||||||
|
|
||||||
|
HWMON_CHANNEL_INFO(curr,
|
||||||
|
HWMON_C_INPUT | HWMON_C_LABEL, // Core Current (SVI2)
|
||||||
|
HWMON_C_INPUT | HWMON_C_LABEL), // SoC Current (SVI2)
|
||||||
|
|
||||||
|
HWMON_CHANNEL_INFO(power,
|
||||||
|
HWMON_C_INPUT | HWMON_C_LABEL, // Core Power (SVI2)
|
||||||
|
HWMON_C_INPUT | HWMON_C_LABEL), // SoC Power (SVI2)
|
||||||
|
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct hwmon_ops zenpower_hwmon_ops = {
|
||||||
|
.is_visible = zenpower_is_visible,
|
||||||
|
.read = zenpower_read,
|
||||||
|
.read_string = zenpower_read_labels,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct hwmon_chip_info zenpower_chip_info = {
|
||||||
|
.ops = &zenpower_hwmon_ops,
|
||||||
|
.info = zenpower_info,
|
||||||
|
};
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RO(debug_data);
|
||||||
|
|
||||||
|
static struct attribute *zenpower_attrs[] = {
|
||||||
|
&dev_attr_debug_data.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group zenpower_group = {
|
||||||
|
.attrs = zenpower_attrs
|
||||||
|
};
|
||||||
|
__ATTRIBUTE_GROUPS(zenpower);
|
||||||
|
|
||||||
static int zenpower_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
static int zenpower_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
|
@ -411,6 +387,7 @@ static int zenpower_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
|
|
||||||
data->zen2 = false;
|
data->zen2 = false;
|
||||||
data->pdev = pdev;
|
data->pdev = pdev;
|
||||||
|
data->temp_offset = 0;
|
||||||
data->read_amdsmn_addr = nb_index_read;
|
data->read_amdsmn_addr = nb_index_read;
|
||||||
data->kernel_smn_support = false;
|
data->kernel_smn_support = false;
|
||||||
data->amps_visible = false;
|
data->amps_visible = false;
|
||||||
|
@ -480,7 +457,10 @@ static int zenpower_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, "zenpower", data, zenpower_groups);
|
hwmon_dev = devm_hwmon_device_register_with_info(
|
||||||
|
dev, "zenpower", data, &zenpower_chip_info, zenpower_groups
|
||||||
|
);
|
||||||
|
|
||||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue