mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
hwmon: (pc87427) Add temperature monitoring support
Add support for the 6 temperature monitoring channels of the PC87427. Note that the sensors resolution can vary, and I couldn't find a way to figure it out, so we might have to compensate in user-space. Signed-off-by: Jean Delvare <khali@linux-fr.org> Acked-by: Guenter Roeck <guenter.roeck@ericsson.com>
This commit is contained in:
parent
9d32df192d
commit
008e5f3350
@ -18,7 +18,8 @@ Description
|
||||
|
||||
The National Semiconductor Super I/O chip includes complete hardware
|
||||
monitoring capabilities. It can monitor up to 18 voltages, 8 fans and
|
||||
6 temperature sensors. Only the fans are supported at the moment.
|
||||
6 temperature sensors. Only the fans and temperatures are supported at
|
||||
the moment, voltages aren't.
|
||||
|
||||
This chip also has fan controlling features (up to 4 PWM outputs),
|
||||
which are partly supported by this driver.
|
||||
@ -45,3 +46,14 @@ Fan speed can be controlled by PWM outputs. There are 4 possible modes:
|
||||
always off, always on, manual and automatic. The latter isn't supported
|
||||
by the driver: you can only return to that mode if it was the original
|
||||
setting, and the configuration interface is missing.
|
||||
|
||||
|
||||
Temperature Monitoring
|
||||
----------------------
|
||||
|
||||
The PC87427 relies on external sensors (following the SensorPath
|
||||
standard), so the resolution and range depend on the type of sensor
|
||||
connected. The integer part can be 8-bit or 9-bit, and can be signed or
|
||||
not. I couldn't find a way to figure out the external sensor data
|
||||
temperature format, so user-space adjustment (typically by a factor 2)
|
||||
may be required.
|
||||
|
@ -711,8 +711,8 @@ config SENSORS_PC87427
|
||||
functions of the National Semiconductor PC87427 Super-I/O chip.
|
||||
The chip has two distinct logical devices, one for fan speed
|
||||
monitoring and control, and one for voltage and temperature
|
||||
monitoring. Only fan speed monitoring and control is supported
|
||||
right now.
|
||||
monitoring. Fan speed monitoring and control are supported, as
|
||||
well as temperature monitoring. Voltages aren't supported yet.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called pc87427.
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* pc87427.c - hardware monitoring driver for the
|
||||
* National Semiconductor PC87427 Super-I/O chip
|
||||
* Copyright (C) 2006, 2008 Jean Delvare <khali@linux-fr.org>
|
||||
* Copyright (C) 2006, 2008, 2010 Jean Delvare <khali@linux-fr.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@ -15,10 +15,11 @@
|
||||
* Supports the following chips:
|
||||
*
|
||||
* Chip #vin #fan #pwm #temp devid
|
||||
* PC87427 - 8 4 - 0xF2
|
||||
* PC87427 - 8 4 6 0xF2
|
||||
*
|
||||
* This driver assumes that no more than one chip is present.
|
||||
* Only fans are supported so far, although the chip can do much more.
|
||||
* Only fans are fully supported so far. Temperatures are in read-only
|
||||
* mode, and voltages aren't supported at all.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -62,6 +63,14 @@ struct pc87427_data {
|
||||
u8 pwm_auto_ok; /* bit vector */
|
||||
u8 pwm_enable[4]; /* register values */
|
||||
u8 pwm[4]; /* register values */
|
||||
|
||||
u8 temp_enabled; /* bit vector */
|
||||
s16 temp[6]; /* register values */
|
||||
s8 temp_min[6]; /* register values */
|
||||
s8 temp_max[6]; /* register values */
|
||||
s8 temp_crit[6]; /* register values */
|
||||
u8 temp_status[6]; /* register values */
|
||||
u8 temp_type[6]; /* register values */
|
||||
};
|
||||
|
||||
struct pc87427_sio_data {
|
||||
@ -120,6 +129,8 @@ static inline void superio_exit(int sioaddr)
|
||||
#define BANK_FM(nr) (nr)
|
||||
#define BANK_FT(nr) (0x08 + (nr))
|
||||
#define BANK_FC(nr) (0x10 + (nr) * 2)
|
||||
#define BANK_TM(nr) (nr)
|
||||
#define BANK_VM(nr) (0x08 + (nr))
|
||||
|
||||
/*
|
||||
* I/O access functions
|
||||
@ -251,6 +262,72 @@ static inline u8 pwm_enable_to_reg(unsigned long val, u8 pwmval)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Temperature registers and conversions
|
||||
*/
|
||||
|
||||
#define PC87427_REG_TEMP_STATUS 0x10
|
||||
#define PC87427_REG_TEMP 0x14
|
||||
#define PC87427_REG_TEMP_MAX 0x18
|
||||
#define PC87427_REG_TEMP_MIN 0x19
|
||||
#define PC87427_REG_TEMP_CRIT 0x1a
|
||||
#define PC87427_REG_TEMP_TYPE 0x1d
|
||||
|
||||
#define TEMP_STATUS_CHANEN (1 << 0)
|
||||
#define TEMP_STATUS_LOWFLG (1 << 1)
|
||||
#define TEMP_STATUS_HIGHFLG (1 << 2)
|
||||
#define TEMP_STATUS_CRITFLG (1 << 3)
|
||||
#define TEMP_STATUS_SENSERR (1 << 5)
|
||||
#define TEMP_TYPE_MASK (3 << 5)
|
||||
|
||||
#define TEMP_TYPE_THERMISTOR (1 << 5)
|
||||
#define TEMP_TYPE_REMOTE_DIODE (2 << 5)
|
||||
#define TEMP_TYPE_LOCAL_DIODE (3 << 5)
|
||||
|
||||
/* Dedicated function to read all registers related to a given temperature
|
||||
input. This saves us quite a few locks and bank selections.
|
||||
Must be called with data->lock held.
|
||||
nr is from 0 to 5 */
|
||||
static void pc87427_readall_temp(struct pc87427_data *data, u8 nr)
|
||||
{
|
||||
int iobase = data->address[LD_TEMP];
|
||||
|
||||
outb(BANK_TM(nr), iobase + PC87427_REG_BANK);
|
||||
data->temp[nr] = le16_to_cpu(inw(iobase + PC87427_REG_TEMP));
|
||||
data->temp_max[nr] = inb(iobase + PC87427_REG_TEMP_MAX);
|
||||
data->temp_min[nr] = inb(iobase + PC87427_REG_TEMP_MIN);
|
||||
data->temp_crit[nr] = inb(iobase + PC87427_REG_TEMP_CRIT);
|
||||
data->temp_type[nr] = inb(iobase + PC87427_REG_TEMP_TYPE);
|
||||
data->temp_status[nr] = inb(iobase + PC87427_REG_TEMP_STATUS);
|
||||
/* Clear fan alarm bits */
|
||||
outb(data->temp_status[nr], iobase + PC87427_REG_TEMP_STATUS);
|
||||
}
|
||||
|
||||
static inline unsigned int temp_type_from_reg(u8 reg)
|
||||
{
|
||||
switch (reg & TEMP_TYPE_MASK) {
|
||||
case TEMP_TYPE_THERMISTOR:
|
||||
return 4;
|
||||
case TEMP_TYPE_REMOTE_DIODE:
|
||||
case TEMP_TYPE_LOCAL_DIODE:
|
||||
return 3;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* We assume 8-bit thermal sensors; 9-bit thermal sensors are possible
|
||||
too, but I have no idea how to figure out when they are used. */
|
||||
static inline long temp_from_reg(s16 reg)
|
||||
{
|
||||
return reg * 1000 / 256;
|
||||
}
|
||||
|
||||
static inline long temp_from_reg8(s8 reg)
|
||||
{
|
||||
return reg * 1000;
|
||||
}
|
||||
|
||||
/*
|
||||
* Data interface
|
||||
*/
|
||||
@ -279,6 +356,13 @@ static struct pc87427_data *pc87427_update_device(struct device *dev)
|
||||
pc87427_readall_pwm(data, i);
|
||||
}
|
||||
|
||||
/* Temperature channels */
|
||||
for (i = 0; i < 6; i++) {
|
||||
if (!(data->temp_enabled & (1 << i)))
|
||||
continue;
|
||||
pc87427_readall_temp(data, i);
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
|
||||
done:
|
||||
@ -595,6 +679,251 @@ static const struct attribute_group pc87427_group_pwm[4] = {
|
||||
{ .attrs = pc87427_attributes_pwm[3] },
|
||||
};
|
||||
|
||||
static ssize_t show_temp_input(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct pc87427_data *data = pc87427_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%ld\n", temp_from_reg(data->temp[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_min(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct pc87427_data *data = pc87427_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_min[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_max(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct pc87427_data *data = pc87427_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_max[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_crit(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct pc87427_data *data = pc87427_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_crit[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_type(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct pc87427_data *data = pc87427_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%u\n", temp_type_from_reg(data->temp_type[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_min_alarm(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct pc87427_data *data = pc87427_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%d\n", !!(data->temp_status[nr]
|
||||
& TEMP_STATUS_LOWFLG));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_max_alarm(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct pc87427_data *data = pc87427_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%d\n", !!(data->temp_status[nr]
|
||||
& TEMP_STATUS_HIGHFLG));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_crit_alarm(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct pc87427_data *data = pc87427_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%d\n", !!(data->temp_status[nr]
|
||||
& TEMP_STATUS_CRITFLG));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_fault(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct pc87427_data *data = pc87427_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%d\n", !!(data->temp_status[nr]
|
||||
& TEMP_STATUS_SENSERR));
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp_input, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp_input, NULL, 5);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp_min, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, show_temp_min, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO, show_temp_min, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO, show_temp_min, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp5_min, S_IRUGO, show_temp_min, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp6_min, S_IRUGO, show_temp_min, NULL, 5);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp_max, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp_max, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO, show_temp_max, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp5_max, S_IRUGO, show_temp_max, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp6_max, S_IRUGO, show_temp_max, NULL, 5);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp5_crit, S_IRUGO, show_temp_crit, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp6_crit, S_IRUGO, show_temp_crit, NULL, 5);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp4_type, S_IRUGO, show_temp_type, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp5_type, S_IRUGO, show_temp_type, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp6_type, S_IRUGO, show_temp_type, NULL, 5);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO,
|
||||
show_temp_min_alarm, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO,
|
||||
show_temp_min_alarm, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO,
|
||||
show_temp_min_alarm, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp4_min_alarm, S_IRUGO,
|
||||
show_temp_min_alarm, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp5_min_alarm, S_IRUGO,
|
||||
show_temp_min_alarm, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp6_min_alarm, S_IRUGO,
|
||||
show_temp_min_alarm, NULL, 5);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
|
||||
show_temp_max_alarm, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO,
|
||||
show_temp_max_alarm, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO,
|
||||
show_temp_max_alarm, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO,
|
||||
show_temp_max_alarm, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO,
|
||||
show_temp_max_alarm, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp6_max_alarm, S_IRUGO,
|
||||
show_temp_max_alarm, NULL, 5);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
|
||||
show_temp_crit_alarm, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO,
|
||||
show_temp_crit_alarm, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO,
|
||||
show_temp_crit_alarm, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO,
|
||||
show_temp_crit_alarm, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp5_crit_alarm, S_IRUGO,
|
||||
show_temp_crit_alarm, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp6_crit_alarm, S_IRUGO,
|
||||
show_temp_crit_alarm, NULL, 5);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_temp_fault, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_temp_fault, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_temp_fault, NULL, 5);
|
||||
|
||||
static struct attribute *pc87427_attributes_temp[6][10] = {
|
||||
{
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_type.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_fault.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_type.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_type.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_fault.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_type.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_fault.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_type.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_fault.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_type.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_fault.dev_attr.attr,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static const struct attribute_group pc87427_group_temp[6] = {
|
||||
{ .attrs = pc87427_attributes_temp[0] },
|
||||
{ .attrs = pc87427_attributes_temp[1] },
|
||||
{ .attrs = pc87427_attributes_temp[2] },
|
||||
{ .attrs = pc87427_attributes_temp[3] },
|
||||
{ .attrs = pc87427_attributes_temp[4] },
|
||||
{ .attrs = pc87427_attributes_temp[5] },
|
||||
};
|
||||
|
||||
static ssize_t show_name(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
@ -659,7 +988,7 @@ static void __devinit pc87427_init_device(struct device *dev)
|
||||
/* The FMC module should be ready */
|
||||
reg = pc87427_read8(data, LD_FAN, PC87427_REG_BANK);
|
||||
if (!(reg & 0x80))
|
||||
dev_warn(dev, "FMC module not ready!\n");
|
||||
dev_warn(dev, "%s module not ready!\n", "FMC");
|
||||
|
||||
/* Check which fans are enabled */
|
||||
for (i = 0; i < 8; i++) {
|
||||
@ -701,6 +1030,19 @@ static void __devinit pc87427_init_device(struct device *dev)
|
||||
data->pwm_auto_ok |= (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
/* The HMC module should be ready */
|
||||
reg = pc87427_read8(data, LD_TEMP, PC87427_REG_BANK);
|
||||
if (!(reg & 0x80))
|
||||
dev_warn(dev, "%s module not ready!\n", "HMC");
|
||||
|
||||
/* Check which temperature channels are enabled */
|
||||
for (i = 0; i < 6; i++) {
|
||||
reg = pc87427_read8_bank(data, LD_TEMP, BANK_TM(i),
|
||||
PC87427_REG_TEMP_STATUS);
|
||||
if (reg & TEMP_STATUS_CHANEN)
|
||||
data->temp_enabled |= (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
static int __devinit pc87427_probe(struct platform_device *pdev)
|
||||
@ -749,6 +1091,14 @@ static int __devinit pc87427_probe(struct platform_device *pdev)
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
}
|
||||
for (i = 0; i < 6; i++) {
|
||||
if (!(data->temp_enabled & (1 << i)))
|
||||
continue;
|
||||
err = sysfs_create_group(&pdev->dev.kobj,
|
||||
&pc87427_group_temp[i]);
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
@ -770,6 +1120,11 @@ exit_remove_files:
|
||||
continue;
|
||||
sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_pwm[i]);
|
||||
}
|
||||
for (i = 0; i < 6; i++) {
|
||||
if (!(data->temp_enabled & (1 << i)))
|
||||
continue;
|
||||
sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_temp[i]);
|
||||
}
|
||||
exit_release_region:
|
||||
pc87427_release_regions(pdev, res_count);
|
||||
exit_kfree:
|
||||
@ -798,6 +1153,11 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
|
||||
continue;
|
||||
sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_pwm[i]);
|
||||
}
|
||||
for (i = 0; i < 6; i++) {
|
||||
if (!(data->temp_enabled & (1 << i)))
|
||||
continue;
|
||||
sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_temp[i]);
|
||||
}
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(data);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user