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:
Juerg Haefliger 2008-08-06 22:41:03 +02:00 committed by Jean Delvare
parent 55d68d75ab
commit 549edb8332
3 changed files with 169 additions and 81 deletions

View file

@ -10,6 +10,10 @@ Supported chips:
Prefix: 'sch311x'
Addresses scanned: none, address read from Super-I/O config space
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:
Juerg Haefliger <juergh@gmail.com>
@ -27,33 +31,31 @@ Module Parameters
following boards:
- 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
-----------
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
chips. These chips feature monitoring of 3 temp sensors temp[1-3] (2 remote
diodes and 1 internal), 7 voltages in[0-6] (6 external and 1 internal) and up
to 6 fan speeds fan[1-6]. Additionally, the chips implement up to 5 PWM
outputs pwm[1-3,5-6] for controlling fan speeds both manually and
SMSC DME1737 and Asus A8000 (which are the same), SMSC SCH5027, and SMSC
SCH311x Super-I/O chips. These chips feature monitoring of 3 temp sensors
temp[1-3] (2 remote diodes and 1 internal), 7 voltages in[0-6] (6 external and
1 internal) and up to 6 fan speeds fan[1-6]. Additionally, the chips implement
up to 5 PWM outputs pwm[1-3,5-6] for controlling fan speeds both manually and
automatically.
For the DME1737 and A8000, fan[1-2] and pwm[1-2] are always present. Fan[3-6]
and pwm[3,5-6] are optional features and their availability depends on the
configuration of the chip. The driver will detect which features are present
during initialization and create the sysfs attributes accordingly.
For the DME1737, A8000 and SCH5027, fan[1-2] and pwm[1-2] are always present.
Fan[3-6] and pwm[3,5-6] are optional features and their availability depends on
the configuration of the chip. The driver will detect which features are
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
pwm[5-6] don't exist.
The hardware monitoring features of the DME1737 and A8000 are only accessible
via SMBus, while the SCH311x only provides access via the ISA bus. The driver
will therefore register itself as an I2C client driver if it detects a DME1737
or A8000 and as a platform driver if it detects a SCH311x chip.
The hardware monitoring features of the DME1737, A8000, and SCH5027 are only
accessible via SMBus, while the SCH311x only provides access via the ISA bus.
The driver will therefore register itself as an I2C client driver if it detects
a DME1737, A8000, or SCH5027 and as a platform driver if it detects a SCH311x
chip.
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
(the last column indicates the input ranges):
DME1737, A8000:
in0: +5VTR (+5V standby) 0V - 6.64V
in1: Vccp (processor core) 0V - 3V
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
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
when crossed.

View file

@ -575,8 +575,8 @@ config SENSORS_DME1737
select HWMON_VID
help
If you say yes here you get support for the hardware monitoring
and fan control features of the SMSC DME1737 (and compatibles
like the Asus A8000) and SCH311x Super-I/O chips.
and fan control features of the SMSC DME1737, SCH311x, SCH5027, and
Asus A8000 Super-I/O chips.
This driver can also be built as a module. If so, the module
will be called dme1737.

View file

@ -1,11 +1,11 @@
/*
* dme1737.c - Driver for the SMSC DME1737, Asus A8000, and SMSC SCH311x
* Super-I/O chips integrated hardware monitoring features.
* Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com>
* dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x and
* SCH5027 Super-I/O chips integrated hardware monitoring features.
* 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
* the chip registers if a DME1737 (or A8000) is found and the ISA bus if a
* SCH311x chip is found. Both types of chips have very similar hardware
* the chip registers if a DME1737, A8000, or SCH5027 is found and the ISA bus
* 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.
*
* 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};
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(dme1737);
I2C_CLIENT_INSMOD_2(dme1737, sch5027);
/* ISA chip types */
enum isa_chips { sch311x = sch5027 + 1 };
/* ---------------------------------------------------------------------
* 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_MASK 0xf8
#define SCH311X_DEVICE 0x8c
#define SCH5027_VERSTEP 0x69
/* Length of ISA address segment */
#define DME1737_EXTENT 2
@ -182,6 +186,7 @@ struct dme1737_data {
unsigned long last_update; /* in jiffies */
unsigned long last_vbat; /* in jiffies */
enum chips type;
const int *in_nominal; /* pointer to IN_NOMINAL array */
u8 vid;
u8 pwm_rr_en;
@ -220,23 +225,23 @@ static const int IN_NOMINAL_DME1737[] = {5000, 2250, 3300, 5000, 12000, 3300,
3300};
static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300,
3300};
#define IN_NOMINAL(ix, type) (((type) == dme1737) ? \
IN_NOMINAL_DME1737[(ix)] : \
IN_NOMINAL_SCH311x[(ix)])
static const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300,
3300};
#define IN_NOMINAL(type) ((type) == sch311x ? IN_NOMINAL_SCH311x : \
(type) == sch5027 ? IN_NOMINAL_SCH5027 : \
IN_NOMINAL_DME1737)
/* Voltage input
* Voltage inputs have 16 bits resolution, limit values have 8 bits
* 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))) /
(3 << (res - 2));
return (reg * nominal + (3 << (res - 3))) / (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) /
IN_NOMINAL(ix, type), 0, 255);
return SENSORS_LIMIT((val * 192 + nominal / 2) / nominal, 0, 255);
}
/* Temperature input
@ -565,7 +570,10 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
/* Sample register contents every 1 sec */
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 */
for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
@ -593,8 +601,10 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
DME1737_REG_TEMP_MIN(ix));
data->temp_max[ix] = dme1737_read(client,
DME1737_REG_TEMP_MAX(ix));
data->temp_offset[ix] = dme1737_read(client,
DME1737_REG_TEMP_OFFSET(ix));
if (data->type != sch5027) {
data->temp_offset[ix] = dme1737_read(client,
DME1737_REG_TEMP_OFFSET(ix));
}
}
/* In and temp LSB registers
@ -669,9 +679,11 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
data->zone_abs[ix] = dme1737_read(client,
DME1737_REG_ZONE_ABS(ix));
}
for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
data->zone_hyst[ix] = dme1737_read(client,
if (data->type != sch5027) {
for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
data->zone_hyst[ix] = dme1737_read(client,
DME1737_REG_ZONE_HYST(ix));
}
}
/* Alarm registers */
@ -735,13 +747,13 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
switch (fn) {
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;
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;
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;
case SYS_IN_ALARM:
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);
switch (fn) {
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),
data->in_min[ix]);
break;
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),
data->in_max[ix]);
break;
@ -1570,43 +1582,56 @@ static struct attribute *dme1737_attr[] ={
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_alarm.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_min.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp2_alarm.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_min.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_fault.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_point2_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_zone2_auto_point1_temp_hyst.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_point3_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_point2_temp.dev_attr.attr,
&sensor_dev_attr_zone3_auto_point3_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 */
&dev_attr_vrm.attr,
&dev_attr_cpu0_vid.attr,
NULL
};
static const struct attribute_group dme1737_group = {
.attrs = dme1737_attr,
static const struct attribute_group dme1737_misc_group = {
.attrs = dme1737_misc_attr,
};
/* 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_ramp_rate.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_point2_pwm.dev_attr.attr,
NULL
@ -1629,7 +1653,6 @@ static struct attribute *dme1737_pwm2_attr[] = {
&sensor_dev_attr_pwm2_enable.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_pwm_min.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
NULL
@ -1640,7 +1663,6 @@ static struct attribute *dme1737_pwm3_attr[] = {
&sensor_dev_attr_pwm3_enable.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_pwm_min.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
NULL
@ -1667,6 +1689,15 @@ static const struct attribute_group dme1737_pwm_group[] = {
{ .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.
* Their creation depends on the chip configuration which is determined during
* module load. */
@ -1722,31 +1753,23 @@ static const struct attribute_group dme1737_fan_group[] = {
{ .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. */
static struct attribute *dme1737_misc_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,
static struct attribute *dme1737_zone_chmod_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_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_point2_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_point2_temp.dev_attr.attr,
&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
NULL
};
static const struct attribute_group dme1737_misc_chmod_group = {
.attrs = dme1737_misc_chmod_attr,
static const struct attribute_group dme1737_zone_chmod_group = {
.attrs = dme1737_zone_chmod_attr,
};
/* 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_ramp_rate.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,
NULL
};
@ -1766,7 +1788,6 @@ static struct attribute *dme1737_pwm2_chmod_attr[] = {
&sensor_dev_attr_pwm2_enable.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_pwm_min.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
NULL
};
@ -1775,7 +1796,6 @@ static struct attribute *dme1737_pwm3_chmod_attr[] = {
&sensor_dev_attr_pwm3_enable.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_pwm_min.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
NULL
};
@ -1875,9 +1895,17 @@ static void dme1737_remove_files(struct device *dev)
if (data->has_pwm & (1 << ix)) {
sysfs_remove_group(&dev->kobj,
&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);
if (!data->client.driver) {
@ -1901,6 +1929,13 @@ static int dme1737_create_files(struct device *dev)
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 */
for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
if (data->has_fan & (1 << ix)) {
@ -1918,6 +1953,11 @@ static int dme1737_create_files(struct device *dev)
&dme1737_pwm_group[ix]))) {
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 "
"will be read-only.\n");
} else {
/* Change permissions of standard sysfs attributes */
dme1737_chmod_group(dev, &dme1737_misc_chmod_group,
/* Change permissions of zone sysfs attributes */
dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
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 */
for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_chmod_group); ix++) {
if (data->has_pwm & (1 << ix)) {
dme1737_chmod_group(dev,
&dme1737_pwm_chmod_group[ix],
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;
u8 reg;
/* Point to the right nominal voltages array */
data->in_nominal = IN_NOMINAL(data->type);
data->config = dme1737_read(client, DME1737_REG_CONFIG);
/* Inform if part is not monitoring/started */
if (!(data->config & 0x01)) {
@ -2076,7 +2130,9 @@ static int dme1737_init_device(struct device *dev)
data->pwm_acz[2] = 4; /* pwm3 -> zone3 */
/* Set VRM */
data->vrm = vid_which_vrm();
if (data->type != sch5027) {
data->vrm = vid_which_vrm();
}
return 0;
}
@ -2095,9 +2151,10 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
dme1737_sio_enter(sio_cip);
/* 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);
if (!(reg == 0x77 || reg == 0x78)) {
if (!(reg == 0x77 || reg == 0x78 || reg == 0x89)) {
err = -ENODEV;
goto exit;
}
@ -2166,15 +2223,24 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
company = dme1737_read(client, DME1737_REG_COMPANY);
verstep = dme1737_read(client, DME1737_REG_VERSTEP);
if (!((company == DME1737_COMPANY_SMSC) &&
((verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP))) {
if (company == DME1737_COMPANY_SMSC &&
(verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
kind = dme1737;
} else if (company == DME1737_COMPANY_SMSC &&
verstep == SCH5027_VERSTEP) {
kind = sch5027;
} else {
err = -ENODEV;
goto exit_kfree;
}
}
kind = dme1737;
name = "dme1737";
if (kind == sch5027) {
name = "sch5027";
} else {
kind = dme1737;
name = "dme1737";
}
data->type = kind;
/* 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;
}
dev_info(dev, "Found a DME1737 chip at 0x%02x (rev 0x%02x).\n",
client->addr, verstep);
dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n",
kind == sch5027 ? "SCH5027" : "DME1737", client->addr,
verstep);
/* Initialize the DME1737 chip */
if ((err = dme1737_init_device(dev))) {
@ -2371,7 +2438,7 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
goto exit_kfree;
}
}
data->type = -1;
data->type = sch311x;
/* Fill in the remaining client fields and initialize the mutex */
strlcpy(client->name, "sch311x", I2C_NAME_SIZE);