hwmon: (dme1737) Add support for the SMSC SCH5027
Add support for the SCH5027. The differences to the DME1737 are: - No support for programmable temp offsets - In auto mode, PWM outputs stay on min value if temp goes below low threshold and can't be programmed to fully turn off - Different voltage scaling - No VID input Signed-off-by: Juerg Haefliger <juergh@gmail.com> Signed-off-by: Jean Delvare <khali@linux-fr.org>
This commit is contained in:
parent
55d68d75ab
commit
549edb8332
3 changed files with 169 additions and 81 deletions
|
@ -10,6 +10,10 @@ Supported chips:
|
||||||
Prefix: 'sch311x'
|
Prefix: 'sch311x'
|
||||||
Addresses scanned: none, address read from Super-I/O config space
|
Addresses scanned: none, address read from Super-I/O config space
|
||||||
Datasheet: http://www.nuhorizons.com/FeaturedProducts/Volume1/SMSC/311x.pdf
|
Datasheet: http://www.nuhorizons.com/FeaturedProducts/Volume1/SMSC/311x.pdf
|
||||||
|
* SMSC SCH5027
|
||||||
|
Prefix: 'sch5027'
|
||||||
|
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
|
||||||
|
Datasheet: Provided by SMSC upon request and under NDA
|
||||||
|
|
||||||
Authors:
|
Authors:
|
||||||
Juerg Haefliger <juergh@gmail.com>
|
Juerg Haefliger <juergh@gmail.com>
|
||||||
|
@ -27,33 +31,31 @@ Module Parameters
|
||||||
following boards:
|
following boards:
|
||||||
- VIA EPIA SN18000
|
- VIA EPIA SN18000
|
||||||
|
|
||||||
Note that there is no need to use this parameter if the driver loads without
|
|
||||||
complaining. The driver will say so if it is necessary.
|
|
||||||
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
This driver implements support for the hardware monitoring capabilities of the
|
This driver implements support for the hardware monitoring capabilities of the
|
||||||
SMSC DME1737 and Asus A8000 (which are the same) and SMSC SCH311x Super-I/O
|
SMSC DME1737 and Asus A8000 (which are the same), SMSC SCH5027, and SMSC
|
||||||
chips. These chips feature monitoring of 3 temp sensors temp[1-3] (2 remote
|
SCH311x Super-I/O chips. These chips feature monitoring of 3 temp sensors
|
||||||
diodes and 1 internal), 7 voltages in[0-6] (6 external and 1 internal) and up
|
temp[1-3] (2 remote diodes and 1 internal), 7 voltages in[0-6] (6 external and
|
||||||
to 6 fan speeds fan[1-6]. Additionally, the chips implement up to 5 PWM
|
1 internal) and up to 6 fan speeds fan[1-6]. Additionally, the chips implement
|
||||||
outputs pwm[1-3,5-6] for controlling fan speeds both manually and
|
up to 5 PWM outputs pwm[1-3,5-6] for controlling fan speeds both manually and
|
||||||
automatically.
|
automatically.
|
||||||
|
|
||||||
For the DME1737 and A8000, fan[1-2] and pwm[1-2] are always present. Fan[3-6]
|
For the DME1737, A8000 and SCH5027, fan[1-2] and pwm[1-2] are always present.
|
||||||
and pwm[3,5-6] are optional features and their availability depends on the
|
Fan[3-6] and pwm[3,5-6] are optional features and their availability depends on
|
||||||
configuration of the chip. The driver will detect which features are present
|
the configuration of the chip. The driver will detect which features are
|
||||||
during initialization and create the sysfs attributes accordingly.
|
present during initialization and create the sysfs attributes accordingly.
|
||||||
|
|
||||||
For the SCH311x, fan[1-3] and pwm[1-3] are always present and fan[4-6] and
|
For the SCH311x, fan[1-3] and pwm[1-3] are always present and fan[4-6] and
|
||||||
pwm[5-6] don't exist.
|
pwm[5-6] don't exist.
|
||||||
|
|
||||||
The hardware monitoring features of the DME1737 and A8000 are only accessible
|
The hardware monitoring features of the DME1737, A8000, and SCH5027 are only
|
||||||
via SMBus, while the SCH311x only provides access via the ISA bus. The driver
|
accessible via SMBus, while the SCH311x only provides access via the ISA bus.
|
||||||
will therefore register itself as an I2C client driver if it detects a DME1737
|
The driver will therefore register itself as an I2C client driver if it detects
|
||||||
or A8000 and as a platform driver if it detects a SCH311x chip.
|
a DME1737, A8000, or SCH5027 and as a platform driver if it detects a SCH311x
|
||||||
|
chip.
|
||||||
|
|
||||||
|
|
||||||
Voltage Monitoring
|
Voltage Monitoring
|
||||||
|
@ -64,6 +66,7 @@ scaling resistors. The values returned by the driver therefore reflect true
|
||||||
millivolts and don't need scaling. The voltage inputs are mapped as follows
|
millivolts and don't need scaling. The voltage inputs are mapped as follows
|
||||||
(the last column indicates the input ranges):
|
(the last column indicates the input ranges):
|
||||||
|
|
||||||
|
DME1737, A8000:
|
||||||
in0: +5VTR (+5V standby) 0V - 6.64V
|
in0: +5VTR (+5V standby) 0V - 6.64V
|
||||||
in1: Vccp (processor core) 0V - 3V
|
in1: Vccp (processor core) 0V - 3V
|
||||||
in2: VCC (internal +3.3V) 0V - 4.38V
|
in2: VCC (internal +3.3V) 0V - 4.38V
|
||||||
|
@ -72,6 +75,24 @@ millivolts and don't need scaling. The voltage inputs are mapped as follows
|
||||||
in5: VTR (+3.3V standby) 0V - 4.38V
|
in5: VTR (+3.3V standby) 0V - 4.38V
|
||||||
in6: Vbat (+3.0V) 0V - 4.38V
|
in6: Vbat (+3.0V) 0V - 4.38V
|
||||||
|
|
||||||
|
SCH311x:
|
||||||
|
in0: +2.5V 0V - 6.64V
|
||||||
|
in1: Vccp (processor core) 0V - 2V
|
||||||
|
in2: VCC (internal +3.3V) 0V - 4.38V
|
||||||
|
in3: +5V 0V - 6.64V
|
||||||
|
in4: +12V 0V - 16V
|
||||||
|
in5: VTR (+3.3V standby) 0V - 4.38V
|
||||||
|
in6: Vbat (+3.0V) 0V - 4.38V
|
||||||
|
|
||||||
|
SCH5027:
|
||||||
|
in0: +5VTR (+5V standby) 0V - 6.64V
|
||||||
|
in1: Vccp (processor core) 0V - 3V
|
||||||
|
in2: VCC (internal +3.3V) 0V - 4.38V
|
||||||
|
in3: V2_IN 0V - 1.5V
|
||||||
|
in4: V1_IN 0V - 1.5V
|
||||||
|
in5: VTR (+3.3V standby) 0V - 4.38V
|
||||||
|
in6: Vbat (+3.0V) 0V - 4.38V
|
||||||
|
|
||||||
Each voltage input has associated min and max limits which trigger an alarm
|
Each voltage input has associated min and max limits which trigger an alarm
|
||||||
when crossed.
|
when crossed.
|
||||||
|
|
||||||
|
|
|
@ -575,8 +575,8 @@ config SENSORS_DME1737
|
||||||
select HWMON_VID
|
select HWMON_VID
|
||||||
help
|
help
|
||||||
If you say yes here you get support for the hardware monitoring
|
If you say yes here you get support for the hardware monitoring
|
||||||
and fan control features of the SMSC DME1737 (and compatibles
|
and fan control features of the SMSC DME1737, SCH311x, SCH5027, and
|
||||||
like the Asus A8000) and SCH311x Super-I/O chips.
|
Asus A8000 Super-I/O chips.
|
||||||
|
|
||||||
This driver can also be built as a module. If so, the module
|
This driver can also be built as a module. If so, the module
|
||||||
will be called dme1737.
|
will be called dme1737.
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* dme1737.c - Driver for the SMSC DME1737, Asus A8000, and SMSC SCH311x
|
* dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x and
|
||||||
* Super-I/O chips integrated hardware monitoring features.
|
* SCH5027 Super-I/O chips integrated hardware monitoring features.
|
||||||
* Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com>
|
* Copyright (c) 2007, 2008 Juerg Haefliger <juergh@gmail.com>
|
||||||
*
|
*
|
||||||
* This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access
|
* This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access
|
||||||
* the chip registers if a DME1737 (or A8000) is found and the ISA bus if a
|
* the chip registers if a DME1737, A8000, or SCH5027 is found and the ISA bus
|
||||||
* SCH311x chip is found. Both types of chips have very similar hardware
|
* if a SCH311x chip is found. Both types of chips have very similar hardware
|
||||||
* monitoring capabilities but differ in the way they can be accessed.
|
* monitoring capabilities but differ in the way they can be accessed.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -57,7 +57,10 @@ MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC "
|
||||||
static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
|
static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
|
||||||
|
|
||||||
/* Insmod parameters */
|
/* Insmod parameters */
|
||||||
I2C_CLIENT_INSMOD_1(dme1737);
|
I2C_CLIENT_INSMOD_2(dme1737, sch5027);
|
||||||
|
|
||||||
|
/* ISA chip types */
|
||||||
|
enum isa_chips { sch311x = sch5027 + 1 };
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------
|
/* ---------------------------------------------------------------------
|
||||||
* Registers
|
* Registers
|
||||||
|
@ -163,6 +166,7 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
|
||||||
#define DME1737_VERSTEP 0x88
|
#define DME1737_VERSTEP 0x88
|
||||||
#define DME1737_VERSTEP_MASK 0xf8
|
#define DME1737_VERSTEP_MASK 0xf8
|
||||||
#define SCH311X_DEVICE 0x8c
|
#define SCH311X_DEVICE 0x8c
|
||||||
|
#define SCH5027_VERSTEP 0x69
|
||||||
|
|
||||||
/* Length of ISA address segment */
|
/* Length of ISA address segment */
|
||||||
#define DME1737_EXTENT 2
|
#define DME1737_EXTENT 2
|
||||||
|
@ -182,6 +186,7 @@ struct dme1737_data {
|
||||||
unsigned long last_update; /* in jiffies */
|
unsigned long last_update; /* in jiffies */
|
||||||
unsigned long last_vbat; /* in jiffies */
|
unsigned long last_vbat; /* in jiffies */
|
||||||
enum chips type;
|
enum chips type;
|
||||||
|
const int *in_nominal; /* pointer to IN_NOMINAL array */
|
||||||
|
|
||||||
u8 vid;
|
u8 vid;
|
||||||
u8 pwm_rr_en;
|
u8 pwm_rr_en;
|
||||||
|
@ -220,23 +225,23 @@ static const int IN_NOMINAL_DME1737[] = {5000, 2250, 3300, 5000, 12000, 3300,
|
||||||
3300};
|
3300};
|
||||||
static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300,
|
static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300,
|
||||||
3300};
|
3300};
|
||||||
#define IN_NOMINAL(ix, type) (((type) == dme1737) ? \
|
static const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300,
|
||||||
IN_NOMINAL_DME1737[(ix)] : \
|
3300};
|
||||||
IN_NOMINAL_SCH311x[(ix)])
|
#define IN_NOMINAL(type) ((type) == sch311x ? IN_NOMINAL_SCH311x : \
|
||||||
|
(type) == sch5027 ? IN_NOMINAL_SCH5027 : \
|
||||||
|
IN_NOMINAL_DME1737)
|
||||||
|
|
||||||
/* Voltage input
|
/* Voltage input
|
||||||
* Voltage inputs have 16 bits resolution, limit values have 8 bits
|
* Voltage inputs have 16 bits resolution, limit values have 8 bits
|
||||||
* resolution. */
|
* resolution. */
|
||||||
static inline int IN_FROM_REG(int reg, int ix, int res, int type)
|
static inline int IN_FROM_REG(int reg, int nominal, int res)
|
||||||
{
|
{
|
||||||
return (reg * IN_NOMINAL(ix, type) + (3 << (res - 3))) /
|
return (reg * nominal + (3 << (res - 3))) / (3 << (res - 2));
|
||||||
(3 << (res - 2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int IN_TO_REG(int val, int ix, int type)
|
static inline int IN_TO_REG(int val, int nominal)
|
||||||
{
|
{
|
||||||
return SENSORS_LIMIT((val * 192 + IN_NOMINAL(ix, type) / 2) /
|
return SENSORS_LIMIT((val * 192 + nominal / 2) / nominal, 0, 255);
|
||||||
IN_NOMINAL(ix, type), 0, 255);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Temperature input
|
/* Temperature input
|
||||||
|
@ -565,7 +570,10 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||||
|
|
||||||
/* Sample register contents every 1 sec */
|
/* Sample register contents every 1 sec */
|
||||||
if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
|
if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
|
||||||
data->vid = dme1737_read(client, DME1737_REG_VID) & 0x3f;
|
if (data->type != sch5027) {
|
||||||
|
data->vid = dme1737_read(client, DME1737_REG_VID) &
|
||||||
|
0x3f;
|
||||||
|
}
|
||||||
|
|
||||||
/* In (voltage) registers */
|
/* In (voltage) registers */
|
||||||
for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
|
for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
|
||||||
|
@ -593,9 +601,11 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||||
DME1737_REG_TEMP_MIN(ix));
|
DME1737_REG_TEMP_MIN(ix));
|
||||||
data->temp_max[ix] = dme1737_read(client,
|
data->temp_max[ix] = dme1737_read(client,
|
||||||
DME1737_REG_TEMP_MAX(ix));
|
DME1737_REG_TEMP_MAX(ix));
|
||||||
|
if (data->type != sch5027) {
|
||||||
data->temp_offset[ix] = dme1737_read(client,
|
data->temp_offset[ix] = dme1737_read(client,
|
||||||
DME1737_REG_TEMP_OFFSET(ix));
|
DME1737_REG_TEMP_OFFSET(ix));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* In and temp LSB registers
|
/* In and temp LSB registers
|
||||||
* The LSBs are latched when the MSBs are read, so the order in
|
* The LSBs are latched when the MSBs are read, so the order in
|
||||||
|
@ -669,10 +679,12 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
||||||
data->zone_abs[ix] = dme1737_read(client,
|
data->zone_abs[ix] = dme1737_read(client,
|
||||||
DME1737_REG_ZONE_ABS(ix));
|
DME1737_REG_ZONE_ABS(ix));
|
||||||
}
|
}
|
||||||
|
if (data->type != sch5027) {
|
||||||
for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
|
for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
|
||||||
data->zone_hyst[ix] = dme1737_read(client,
|
data->zone_hyst[ix] = dme1737_read(client,
|
||||||
DME1737_REG_ZONE_HYST(ix));
|
DME1737_REG_ZONE_HYST(ix));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Alarm registers */
|
/* Alarm registers */
|
||||||
data->alarms = dme1737_read(client,
|
data->alarms = dme1737_read(client,
|
||||||
|
@ -735,13 +747,13 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
|
||||||
|
|
||||||
switch (fn) {
|
switch (fn) {
|
||||||
case SYS_IN_INPUT:
|
case SYS_IN_INPUT:
|
||||||
res = IN_FROM_REG(data->in[ix], ix, 16, data->type);
|
res = IN_FROM_REG(data->in[ix], data->in_nominal[ix], 16);
|
||||||
break;
|
break;
|
||||||
case SYS_IN_MIN:
|
case SYS_IN_MIN:
|
||||||
res = IN_FROM_REG(data->in_min[ix], ix, 8, data->type);
|
res = IN_FROM_REG(data->in_min[ix], data->in_nominal[ix], 8);
|
||||||
break;
|
break;
|
||||||
case SYS_IN_MAX:
|
case SYS_IN_MAX:
|
||||||
res = IN_FROM_REG(data->in_max[ix], ix, 8, data->type);
|
res = IN_FROM_REG(data->in_max[ix], data->in_nominal[ix], 8);
|
||||||
break;
|
break;
|
||||||
case SYS_IN_ALARM:
|
case SYS_IN_ALARM:
|
||||||
res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01;
|
res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01;
|
||||||
|
@ -768,12 +780,12 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
switch (fn) {
|
switch (fn) {
|
||||||
case SYS_IN_MIN:
|
case SYS_IN_MIN:
|
||||||
data->in_min[ix] = IN_TO_REG(val, ix, data->type);
|
data->in_min[ix] = IN_TO_REG(val, data->in_nominal[ix]);
|
||||||
dme1737_write(client, DME1737_REG_IN_MIN(ix),
|
dme1737_write(client, DME1737_REG_IN_MIN(ix),
|
||||||
data->in_min[ix]);
|
data->in_min[ix]);
|
||||||
break;
|
break;
|
||||||
case SYS_IN_MAX:
|
case SYS_IN_MAX:
|
||||||
data->in_max[ix] = IN_TO_REG(val, ix, data->type);
|
data->in_max[ix] = IN_TO_REG(val, data->in_nominal[ix]);
|
||||||
dme1737_write(client, DME1737_REG_IN_MAX(ix),
|
dme1737_write(client, DME1737_REG_IN_MAX(ix),
|
||||||
data->in_max[ix]);
|
data->in_max[ix]);
|
||||||
break;
|
break;
|
||||||
|
@ -1570,43 +1582,56 @@ static struct attribute *dme1737_attr[] ={
|
||||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
|
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp1_fault.dev_attr.attr,
|
&sensor_dev_attr_temp1_fault.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp1_offset.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
|
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_offset.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp3_min.dev_attr.attr,
|
&sensor_dev_attr_temp3_min.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
|
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp3_fault.dev_attr.attr,
|
&sensor_dev_attr_temp3_fault.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp3_offset.dev_attr.attr,
|
|
||||||
/* Zones */
|
/* Zones */
|
||||||
&sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr,
|
&sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr,
|
&sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr,
|
&sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone1_auto_channels_temp.dev_attr.attr,
|
&sensor_dev_attr_zone1_auto_channels_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
|
&sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
|
&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
|
&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone2_auto_channels_temp.dev_attr.attr,
|
&sensor_dev_attr_zone2_auto_channels_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
|
&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
|
&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
|
&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr,
|
&sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group dme1737_group = {
|
||||||
|
.attrs = dme1737_attr,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The following struct holds misc attributes, which are not available in all
|
||||||
|
* chips. Their creation depends on the chip type which is determined during
|
||||||
|
* module load. */
|
||||||
|
static struct attribute *dme1737_misc_attr[] = {
|
||||||
|
/* Temperatures */
|
||||||
|
&sensor_dev_attr_temp1_offset.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_temp2_offset.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_temp3_offset.dev_attr.attr,
|
||||||
|
/* Zones */
|
||||||
|
&sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
|
||||||
/* Misc */
|
/* Misc */
|
||||||
&dev_attr_vrm.attr,
|
&dev_attr_vrm.attr,
|
||||||
&dev_attr_cpu0_vid.attr,
|
&dev_attr_cpu0_vid.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct attribute_group dme1737_group = {
|
static const struct attribute_group dme1737_misc_group = {
|
||||||
.attrs = dme1737_attr,
|
.attrs = dme1737_misc_attr,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The following structs hold the PWM attributes, some of which are optional.
|
/* The following structs hold the PWM attributes, some of which are optional.
|
||||||
|
@ -1618,7 +1643,6 @@ static struct attribute *dme1737_pwm1_attr[] = {
|
||||||
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
|
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr,
|
&sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr,
|
&sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
|
@ -1629,7 +1653,6 @@ static struct attribute *dme1737_pwm2_attr[] = {
|
||||||
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
|
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr,
|
&sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr,
|
&sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
|
@ -1640,7 +1663,6 @@ static struct attribute *dme1737_pwm3_attr[] = {
|
||||||
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
|
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr,
|
&sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr,
|
&sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
|
@ -1667,6 +1689,15 @@ static const struct attribute_group dme1737_pwm_group[] = {
|
||||||
{ .attrs = dme1737_pwm6_attr },
|
{ .attrs = dme1737_pwm6_attr },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* The following struct holds misc PWM attributes, which are not available in
|
||||||
|
* all chips. Their creation depends on the chip type which is determined
|
||||||
|
* during module load. */
|
||||||
|
static struct attribute *dme1737_pwm_misc_attr[] = {
|
||||||
|
&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
|
||||||
|
};
|
||||||
|
|
||||||
/* The following structs hold the fan attributes, some of which are optional.
|
/* The following structs hold the fan attributes, some of which are optional.
|
||||||
* Their creation depends on the chip configuration which is determined during
|
* Their creation depends on the chip configuration which is determined during
|
||||||
* module load. */
|
* module load. */
|
||||||
|
@ -1722,31 +1753,23 @@ static const struct attribute_group dme1737_fan_group[] = {
|
||||||
{ .attrs = dme1737_fan6_attr },
|
{ .attrs = dme1737_fan6_attr },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The permissions of all of the following attributes are changed to read-
|
/* The permissions of the following zone attributes are changed to read-
|
||||||
* writeable if the chip is *not* locked. Otherwise they stay read-only. */
|
* writeable if the chip is *not* locked. Otherwise they stay read-only. */
|
||||||
static struct attribute *dme1737_misc_chmod_attr[] = {
|
static struct attribute *dme1737_zone_chmod_attr[] = {
|
||||||
/* Temperatures */
|
|
||||||
&sensor_dev_attr_temp1_offset.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_temp2_offset.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_temp3_offset.dev_attr.attr,
|
|
||||||
/* Zones */
|
|
||||||
&sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr,
|
&sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr,
|
&sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr,
|
&sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
|
&sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
|
&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
|
&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
|
&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
|
&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
|
&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct attribute_group dme1737_misc_chmod_group = {
|
static const struct attribute_group dme1737_zone_chmod_group = {
|
||||||
.attrs = dme1737_misc_chmod_attr,
|
.attrs = dme1737_zone_chmod_attr,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The permissions of the following PWM attributes are changed to read-
|
/* The permissions of the following PWM attributes are changed to read-
|
||||||
|
@ -1757,7 +1780,6 @@ static struct attribute *dme1737_pwm1_chmod_attr[] = {
|
||||||
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
|
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr,
|
&sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr,
|
&sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
@ -1766,7 +1788,6 @@ static struct attribute *dme1737_pwm2_chmod_attr[] = {
|
||||||
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
|
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr,
|
&sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr,
|
&sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
@ -1775,7 +1796,6 @@ static struct attribute *dme1737_pwm3_chmod_attr[] = {
|
||||||
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
|
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr,
|
&sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr,
|
&sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
@ -1875,8 +1895,16 @@ static void dme1737_remove_files(struct device *dev)
|
||||||
if (data->has_pwm & (1 << ix)) {
|
if (data->has_pwm & (1 << ix)) {
|
||||||
sysfs_remove_group(&dev->kobj,
|
sysfs_remove_group(&dev->kobj,
|
||||||
&dme1737_pwm_group[ix]);
|
&dme1737_pwm_group[ix]);
|
||||||
|
if (data->type != sch5027 && ix < 3) {
|
||||||
|
sysfs_remove_file(&dev->kobj,
|
||||||
|
dme1737_pwm_misc_attr[ix]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->type != sch5027) {
|
||||||
|
sysfs_remove_group(&dev->kobj, &dme1737_misc_group);
|
||||||
|
}
|
||||||
|
|
||||||
sysfs_remove_group(&dev->kobj, &dme1737_group);
|
sysfs_remove_group(&dev->kobj, &dme1737_group);
|
||||||
|
|
||||||
|
@ -1901,6 +1929,13 @@ static int dme1737_create_files(struct device *dev)
|
||||||
goto exit_remove;
|
goto exit_remove;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create misc sysfs attributes */
|
||||||
|
if ((data->type != sch5027) &&
|
||||||
|
(err = sysfs_create_group(&dev->kobj,
|
||||||
|
&dme1737_misc_group))) {
|
||||||
|
goto exit_remove;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create fan sysfs attributes */
|
/* Create fan sysfs attributes */
|
||||||
for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
|
for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
|
||||||
if (data->has_fan & (1 << ix)) {
|
if (data->has_fan & (1 << ix)) {
|
||||||
|
@ -1918,6 +1953,11 @@ static int dme1737_create_files(struct device *dev)
|
||||||
&dme1737_pwm_group[ix]))) {
|
&dme1737_pwm_group[ix]))) {
|
||||||
goto exit_remove;
|
goto exit_remove;
|
||||||
}
|
}
|
||||||
|
if (data->type != sch5027 && ix < 3 &&
|
||||||
|
(err = sysfs_create_file(&dev->kobj,
|
||||||
|
dme1737_pwm_misc_attr[ix]))) {
|
||||||
|
goto exit_remove;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1927,16 +1967,27 @@ static int dme1737_create_files(struct device *dev)
|
||||||
dev_info(dev, "Device is locked. Some attributes "
|
dev_info(dev, "Device is locked. Some attributes "
|
||||||
"will be read-only.\n");
|
"will be read-only.\n");
|
||||||
} else {
|
} else {
|
||||||
/* Change permissions of standard sysfs attributes */
|
/* Change permissions of zone sysfs attributes */
|
||||||
dme1737_chmod_group(dev, &dme1737_misc_chmod_group,
|
dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
|
||||||
S_IRUGO | S_IWUSR);
|
S_IRUGO | S_IWUSR);
|
||||||
|
|
||||||
|
/* Change permissions of misc sysfs attributes */
|
||||||
|
if (data->type != sch5027) {
|
||||||
|
dme1737_chmod_group(dev, &dme1737_misc_group,
|
||||||
|
S_IRUGO | S_IWUSR);
|
||||||
|
}
|
||||||
|
|
||||||
/* Change permissions of PWM sysfs attributes */
|
/* Change permissions of PWM sysfs attributes */
|
||||||
for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_chmod_group); ix++) {
|
for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_chmod_group); ix++) {
|
||||||
if (data->has_pwm & (1 << ix)) {
|
if (data->has_pwm & (1 << ix)) {
|
||||||
dme1737_chmod_group(dev,
|
dme1737_chmod_group(dev,
|
||||||
&dme1737_pwm_chmod_group[ix],
|
&dme1737_pwm_chmod_group[ix],
|
||||||
S_IRUGO | S_IWUSR);
|
S_IRUGO | S_IWUSR);
|
||||||
|
if (data->type != sch5027 && ix < 3) {
|
||||||
|
dme1737_chmod_file(dev,
|
||||||
|
dme1737_pwm_misc_attr[ix],
|
||||||
|
S_IRUGO | S_IWUSR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1966,6 +2017,9 @@ static int dme1737_init_device(struct device *dev)
|
||||||
int ix;
|
int ix;
|
||||||
u8 reg;
|
u8 reg;
|
||||||
|
|
||||||
|
/* Point to the right nominal voltages array */
|
||||||
|
data->in_nominal = IN_NOMINAL(data->type);
|
||||||
|
|
||||||
data->config = dme1737_read(client, DME1737_REG_CONFIG);
|
data->config = dme1737_read(client, DME1737_REG_CONFIG);
|
||||||
/* Inform if part is not monitoring/started */
|
/* Inform if part is not monitoring/started */
|
||||||
if (!(data->config & 0x01)) {
|
if (!(data->config & 0x01)) {
|
||||||
|
@ -2076,7 +2130,9 @@ static int dme1737_init_device(struct device *dev)
|
||||||
data->pwm_acz[2] = 4; /* pwm3 -> zone3 */
|
data->pwm_acz[2] = 4; /* pwm3 -> zone3 */
|
||||||
|
|
||||||
/* Set VRM */
|
/* Set VRM */
|
||||||
|
if (data->type != sch5027) {
|
||||||
data->vrm = vid_which_vrm();
|
data->vrm = vid_which_vrm();
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2095,9 +2151,10 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
|
||||||
dme1737_sio_enter(sio_cip);
|
dme1737_sio_enter(sio_cip);
|
||||||
|
|
||||||
/* Check device ID
|
/* Check device ID
|
||||||
* The DME1737 can return either 0x78 or 0x77 as its device ID. */
|
* The DME1737 can return either 0x78 or 0x77 as its device ID.
|
||||||
|
* The SCH5027 returns 0x89 as its device ID. */
|
||||||
reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
|
reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
|
||||||
if (!(reg == 0x77 || reg == 0x78)) {
|
if (!(reg == 0x77 || reg == 0x78 || reg == 0x89)) {
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
@ -2166,15 +2223,24 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
|
||||||
company = dme1737_read(client, DME1737_REG_COMPANY);
|
company = dme1737_read(client, DME1737_REG_COMPANY);
|
||||||
verstep = dme1737_read(client, DME1737_REG_VERSTEP);
|
verstep = dme1737_read(client, DME1737_REG_VERSTEP);
|
||||||
|
|
||||||
if (!((company == DME1737_COMPANY_SMSC) &&
|
if (company == DME1737_COMPANY_SMSC &&
|
||||||
((verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP))) {
|
(verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
|
||||||
|
kind = dme1737;
|
||||||
|
} else if (company == DME1737_COMPANY_SMSC &&
|
||||||
|
verstep == SCH5027_VERSTEP) {
|
||||||
|
kind = sch5027;
|
||||||
|
} else {
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto exit_kfree;
|
goto exit_kfree;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (kind == sch5027) {
|
||||||
|
name = "sch5027";
|
||||||
|
} else {
|
||||||
kind = dme1737;
|
kind = dme1737;
|
||||||
name = "dme1737";
|
name = "dme1737";
|
||||||
|
}
|
||||||
data->type = kind;
|
data->type = kind;
|
||||||
|
|
||||||
/* Fill in the remaining client fields and put it into the global
|
/* Fill in the remaining client fields and put it into the global
|
||||||
|
@ -2187,8 +2253,9 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
|
||||||
goto exit_kfree;
|
goto exit_kfree;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_info(dev, "Found a DME1737 chip at 0x%02x (rev 0x%02x).\n",
|
dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n",
|
||||||
client->addr, verstep);
|
kind == sch5027 ? "SCH5027" : "DME1737", client->addr,
|
||||||
|
verstep);
|
||||||
|
|
||||||
/* Initialize the DME1737 chip */
|
/* Initialize the DME1737 chip */
|
||||||
if ((err = dme1737_init_device(dev))) {
|
if ((err = dme1737_init_device(dev))) {
|
||||||
|
@ -2371,7 +2438,7 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
|
||||||
goto exit_kfree;
|
goto exit_kfree;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data->type = -1;
|
data->type = sch311x;
|
||||||
|
|
||||||
/* Fill in the remaining client fields and initialize the mutex */
|
/* Fill in the remaining client fields and initialize the mutex */
|
||||||
strlcpy(client->name, "sch311x", I2C_NAME_SIZE);
|
strlcpy(client->name, "sch311x", I2C_NAME_SIZE);
|
||||||
|
|
Loading…
Reference in a new issue