Commit ea694431 authored by Juerg Haefliger's avatar Juerg Haefliger Committed by Jean Delvare

hwmon: (dme1737) Add SCH5127 support

Add support for the hardware monitoring capabilities of the SCH5127
chip to the dme1737 driver.
Signed-off-by: default avatarJuerg Haefliger <juergh@gmail.com>
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
Tested-by: default avatarJeff Rickman <jrickman@myamigos.us>
parent 38806bda
...@@ -9,11 +9,15 @@ Supported chips: ...@@ -9,11 +9,15 @@ Supported chips:
* SMSC SCH3112, SCH3114, SCH3116 * SMSC SCH3112, SCH3114, SCH3116
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: Available on the Internet
* SMSC SCH5027 * SMSC SCH5027
Prefix: 'sch5027' Prefix: 'sch5027'
Addresses scanned: I2C 0x2c, 0x2d, 0x2e Addresses scanned: I2C 0x2c, 0x2d, 0x2e
Datasheet: Provided by SMSC upon request and under NDA Datasheet: Provided by SMSC upon request and under NDA
* SMSC SCH5127
Prefix: 'sch5127'
Addresses scanned: none, address read from Super-I/O config space
Datasheet: Provided by SMSC upon request and under NDA
Authors: Authors:
Juerg Haefliger <juergh@gmail.com> Juerg Haefliger <juergh@gmail.com>
...@@ -36,8 +40,8 @@ Description ...@@ -36,8 +40,8 @@ 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), SMSC SCH5027, and SMSC SMSC DME1737 and Asus A8000 (which are the same), SMSC SCH5027, SCH311x,
SCH311x Super-I/O chips. These chips feature monitoring of 3 temp sensors and SCH5127 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 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 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 up to 5 PWM outputs pwm[1-3,5-6] for controlling fan speeds both manually and
...@@ -48,14 +52,14 @@ Fan[3-6] and pwm[3,5-6] are optional features and their availability depends on ...@@ -48,14 +52,14 @@ 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 the configuration of the chip. The driver will detect which features are
present 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 and SCH5127, fan[1-3] and pwm[1-3] are always present and
pwm[5-6] don't exist. fan[4-6] and pwm[5-6] don't exist.
The hardware monitoring features of the DME1737, A8000, and SCH5027 are only 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. accessible via SMBus, while the SCH311x and SCH5127 only provide access via
The driver will therefore register itself as an I2C client driver if it detects the ISA bus. The driver will therefore register itself as an I2C client driver
a DME1737, A8000, or SCH5027 and as a platform driver if it detects a SCH311x if it detects a DME1737, A8000, or SCH5027 and as a platform driver if it
chip. detects a SCH311x or SCH5127 chip.
Voltage Monitoring Voltage Monitoring
...@@ -76,7 +80,7 @@ DME1737, A8000: ...@@ -76,7 +80,7 @@ DME1737, A8000:
in6: Vbat (+3.0V) 0V - 4.38V in6: Vbat (+3.0V) 0V - 4.38V
SCH311x: SCH311x:
in0: +2.5V 0V - 6.64V in0: +2.5V 0V - 3.32V
in1: Vccp (processor core) 0V - 2V in1: Vccp (processor core) 0V - 2V
in2: VCC (internal +3.3V) 0V - 4.38V in2: VCC (internal +3.3V) 0V - 4.38V
in3: +5V 0V - 6.64V in3: +5V 0V - 6.64V
...@@ -93,6 +97,15 @@ SCH5027: ...@@ -93,6 +97,15 @@ SCH5027:
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
SCH5127:
in0: +2.5 0V - 3.32V
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.
...@@ -293,3 +306,21 @@ pwm[1-3]_auto_point1_pwm RW Auto PWM pwm point. Auto_point1 is the ...@@ -293,3 +306,21 @@ pwm[1-3]_auto_point1_pwm RW Auto PWM pwm point. Auto_point1 is the
pwm[1-3]_auto_point2_pwm RO Auto PWM pwm point. Auto_point2 is the pwm[1-3]_auto_point2_pwm RO Auto PWM pwm point. Auto_point2 is the
full-speed duty-cycle which is hard- full-speed duty-cycle which is hard-
wired to 255 (100% duty-cycle). wired to 255 (100% duty-cycle).
Chip Differences
----------------
Feature dme1737 sch311x sch5027 sch5127
-------------------------------------------------------
temp[1-3]_offset yes yes
vid yes
zone3 yes yes yes
zone[1-3]_hyst yes yes
pwm min/off yes yes
fan3 opt yes opt yes
pwm3 opt yes opt yes
fan4 opt opt
fan5 opt opt
pwm5 opt opt
fan6 opt opt
pwm6 opt opt
/* /*
* dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x and * dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x, SCH5027,
* SCH5027 Super-I/O chips integrated hardware monitoring features. * and SCH5127 Super-I/O chips integrated hardware monitoring
* Copyright (c) 2007, 2008 Juerg Haefliger <juergh@gmail.com> * features.
* Copyright (c) 2007, 2008, 2009, 2010 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, A8000, or SCH5027 is found and the ISA bus * 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 * if a SCH311x or SCH5127 chip is found. Both types of chips have very
* monitoring capabilities but differ in the way they can be accessed. * 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 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -57,7 +59,7 @@ MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC " ...@@ -57,7 +59,7 @@ MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC "
/* Addresses to scan */ /* Addresses to scan */
static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END}; static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
enum chips { dme1737, sch5027, sch311x }; enum chips { dme1737, sch5027, sch311x, sch5127 };
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
* Registers * Registers
...@@ -164,10 +166,29 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23}; ...@@ -164,10 +166,29 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
#define DME1737_VERSTEP_MASK 0xf8 #define DME1737_VERSTEP_MASK 0xf8
#define SCH311X_DEVICE 0x8c #define SCH311X_DEVICE 0x8c
#define SCH5027_VERSTEP 0x69 #define SCH5027_VERSTEP 0x69
#define SCH5127_DEVICE 0x8e
/* Device ID values (global configuration register index 0x20) */
#define DME1737_ID_1 0x77
#define DME1737_ID_2 0x78
#define SCH3112_ID 0x7c
#define SCH3114_ID 0x7d
#define SCH3116_ID 0x7f
#define SCH5027_ID 0x89
#define SCH5127_ID 0x86
/* Length of ISA address segment */ /* Length of ISA address segment */
#define DME1737_EXTENT 2 #define DME1737_EXTENT 2
/* chip-dependent features */
#define HAS_TEMP_OFFSET (1 << 0) /* bit 0 */
#define HAS_VID (1 << 1) /* bit 1 */
#define HAS_ZONE3 (1 << 2) /* bit 2 */
#define HAS_ZONE_HYST (1 << 3) /* bit 3 */
#define HAS_PWM_MIN (1 << 4) /* bit 4 */
#define HAS_FAN(ix) (1 << ((ix) + 5)) /* bits 5-10 */
#define HAS_PWM(ix) (1 << ((ix) + 11)) /* bits 11-16 */
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
* Data structures and manipulation thereof * Data structures and manipulation thereof
* --------------------------------------------------------------------- */ * --------------------------------------------------------------------- */
...@@ -187,8 +208,7 @@ struct dme1737_data { ...@@ -187,8 +208,7 @@ struct dme1737_data {
u8 vid; u8 vid;
u8 pwm_rr_en; u8 pwm_rr_en;
u8 has_pwm; u32 has_features;
u8 has_fan;
/* Register values */ /* Register values */
u16 in[7]; u16 in[7];
...@@ -224,8 +244,11 @@ static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300, ...@@ -224,8 +244,11 @@ static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300,
3300}; 3300};
static const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300, static const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300,
3300}; 3300};
static const int IN_NOMINAL_SCH5127[] = {2500, 2250, 3300, 1125, 1125, 3300,
3300};
#define IN_NOMINAL(type) ((type) == sch311x ? IN_NOMINAL_SCH311x : \ #define IN_NOMINAL(type) ((type) == sch311x ? IN_NOMINAL_SCH311x : \
(type) == sch5027 ? IN_NOMINAL_SCH5027 : \ (type) == sch5027 ? IN_NOMINAL_SCH5027 : \
(type) == sch5127 ? IN_NOMINAL_SCH5127 : \
IN_NOMINAL_DME1737) IN_NOMINAL_DME1737)
/* Voltage input /* Voltage input
...@@ -568,7 +591,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) ...@@ -568,7 +591,7 @@ 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) {
if (data->type == dme1737) { if (data->has_features & HAS_VID) {
data->vid = dme1737_read(data, DME1737_REG_VID) & data->vid = dme1737_read(data, DME1737_REG_VID) &
0x3f; 0x3f;
} }
...@@ -599,7 +622,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) ...@@ -599,7 +622,7 @@ 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(data, data->temp_max[ix] = dme1737_read(data,
DME1737_REG_TEMP_MAX(ix)); DME1737_REG_TEMP_MAX(ix));
if (data->type != sch5027) { if (data->has_features & HAS_TEMP_OFFSET) {
data->temp_offset[ix] = dme1737_read(data, data->temp_offset[ix] = dme1737_read(data,
DME1737_REG_TEMP_OFFSET(ix)); DME1737_REG_TEMP_OFFSET(ix));
} }
...@@ -626,7 +649,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) ...@@ -626,7 +649,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) { for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) {
/* Skip reading registers if optional fans are not /* Skip reading registers if optional fans are not
* present */ * present */
if (!(data->has_fan & (1 << ix))) { if (!(data->has_features & HAS_FAN(ix))) {
continue; continue;
} }
data->fan[ix] = dme1737_read(data, data->fan[ix] = dme1737_read(data,
...@@ -650,7 +673,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) ...@@ -650,7 +673,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
for (ix = 0; ix < ARRAY_SIZE(data->pwm); ix++) { for (ix = 0; ix < ARRAY_SIZE(data->pwm); ix++) {
/* Skip reading registers if optional PWMs are not /* Skip reading registers if optional PWMs are not
* present */ * present */
if (!(data->has_pwm & (1 << ix))) { if (!(data->has_features & HAS_PWM(ix))) {
continue; continue;
} }
data->pwm[ix] = dme1737_read(data, data->pwm[ix] = dme1737_read(data,
...@@ -672,12 +695,24 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) ...@@ -672,12 +695,24 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
/* Thermal zone registers */ /* Thermal zone registers */
for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) { for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) {
data->zone_low[ix] = dme1737_read(data, /* Skip reading registers if zone3 is not present */
DME1737_REG_ZONE_LOW(ix)); if ((ix == 2) && !(data->has_features & HAS_ZONE3)) {
data->zone_abs[ix] = dme1737_read(data, continue;
DME1737_REG_ZONE_ABS(ix)); }
/* sch5127 zone2 registers are special */
if ((ix == 1) && (data->type == sch5127)) {
data->zone_low[1] = dme1737_read(data,
DME1737_REG_ZONE_LOW(2));
data->zone_abs[1] = dme1737_read(data,
DME1737_REG_ZONE_ABS(2));
} else {
data->zone_low[ix] = dme1737_read(data,
DME1737_REG_ZONE_LOW(ix));
data->zone_abs[ix] = dme1737_read(data,
DME1737_REG_ZONE_ABS(ix));
}
} }
if (data->type != sch5027) { if (data->has_features & HAS_ZONE_HYST) {
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(data, data->zone_hyst[ix] = dme1737_read(data,
DME1737_REG_ZONE_HYST(ix)); DME1737_REG_ZONE_HYST(ix));
...@@ -1594,10 +1629,6 @@ static struct attribute *dme1737_attr[] ={ ...@@ -1594,10 +1629,6 @@ static struct attribute *dme1737_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.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 NULL
}; };
...@@ -1605,27 +1636,23 @@ static const struct attribute_group dme1737_group = { ...@@ -1605,27 +1636,23 @@ static const struct attribute_group dme1737_group = {
.attrs = dme1737_attr, .attrs = dme1737_attr,
}; };
/* The following struct holds misc attributes, which are not available in all /* The following struct holds temp offset attributes, which are not available
* chips. Their creation depends on the chip type which is determined during * in all chips. The following chips support them:
* module load. */ * DME1737, SCH311x */
static struct attribute *dme1737_misc_attr[] = { static struct attribute *dme1737_temp_offset_attr[] = {
/* Temperatures */
&sensor_dev_attr_temp1_offset.dev_attr.attr, &sensor_dev_attr_temp1_offset.dev_attr.attr,
&sensor_dev_attr_temp2_offset.dev_attr.attr, &sensor_dev_attr_temp2_offset.dev_attr.attr,
&sensor_dev_attr_temp3_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,
NULL NULL
}; };
static const struct attribute_group dme1737_misc_group = { static const struct attribute_group dme1737_temp_offset_group = {
.attrs = dme1737_misc_attr, .attrs = dme1737_temp_offset_attr,
}; };
/* The following struct holds VID-related attributes. Their creation /* The following struct holds VID related attributes, which are not available
depends on the chip type which is determined during module load. */ * in all chips. The following chips support them:
* DME1737 */
static struct attribute *dme1737_vid_attr[] = { static struct attribute *dme1737_vid_attr[] = {
&dev_attr_vrm.attr, &dev_attr_vrm.attr,
&dev_attr_cpu0_vid.attr, &dev_attr_cpu0_vid.attr,
...@@ -1636,6 +1663,36 @@ static const struct attribute_group dme1737_vid_group = { ...@@ -1636,6 +1663,36 @@ static const struct attribute_group dme1737_vid_group = {
.attrs = dme1737_vid_attr, .attrs = dme1737_vid_attr,
}; };
/* The following struct holds temp zone 3 related attributes, which are not
* available in all chips. The following chips support them:
* DME1737, SCH311x, SCH5027 */
static struct attribute *dme1737_zone3_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_zone3_group = {
.attrs = dme1737_zone3_attr,
};
/* The following struct holds temp zone hysteresis related attributes, which
* are not available in all chips. The following chips support them:
* DME1737, SCH311x */
static struct attribute *dme1737_zone_hyst_attr[] = {
&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,
NULL
};
static const struct attribute_group dme1737_zone_hyst_group = {
.attrs = dme1737_zone_hyst_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.
* 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. */
...@@ -1691,10 +1748,10 @@ static const struct attribute_group dme1737_pwm_group[] = { ...@@ -1691,10 +1748,10 @@ 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 /* The following struct holds auto PWM min attributes, which are not available
* all chips. Their creation depends on the chip type which is determined * in all chips. Their creation depends on the chip type which is determined
* during module load. */ * during module load. */
static struct attribute *dme1737_pwm_misc_attr[] = { static struct attribute *dme1737_auto_pwm_min_attr[] = {
&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr, &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
&sensor_dev_attr_pwm2_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, &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
...@@ -1764,14 +1821,25 @@ static struct attribute *dme1737_zone_chmod_attr[] = { ...@@ -1764,14 +1821,25 @@ static struct attribute *dme1737_zone_chmod_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,
NULL
};
static const struct attribute_group dme1737_zone_chmod_group = {
.attrs = dme1737_zone_chmod_attr,
};
/* The permissions of the following zone 3 attributes are changed to read-
* writeable if the chip is *not* locked. Otherwise they stay read-only. */
static struct attribute *dme1737_zone3_chmod_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_zone_chmod_group = { static const struct attribute_group dme1737_zone3_chmod_group = {
.attrs = dme1737_zone_chmod_attr, .attrs = dme1737_zone3_chmod_attr,
}; };
/* The permissions of the following PWM attributes are changed to read- /* The permissions of the following PWM attributes are changed to read-
...@@ -1887,30 +1955,35 @@ static void dme1737_remove_files(struct device *dev) ...@@ -1887,30 +1955,35 @@ static void dme1737_remove_files(struct device *dev)
int ix; int ix;
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_features & HAS_FAN(ix)) {
sysfs_remove_group(&dev->kobj, sysfs_remove_group(&dev->kobj,
&dme1737_fan_group[ix]); &dme1737_fan_group[ix]);
} }
} }
for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
if (data->has_pwm & (1 << ix)) { if (data->has_features & HAS_PWM(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) { if ((data->has_features & HAS_PWM_MIN) && ix < 3) {
sysfs_remove_file(&dev->kobj, sysfs_remove_file(&dev->kobj,
dme1737_pwm_misc_attr[ix]); dme1737_auto_pwm_min_attr[ix]);
} }
} }
} }
if (data->type != sch5027) { if (data->has_features & HAS_TEMP_OFFSET) {
sysfs_remove_group(&dev->kobj, &dme1737_misc_group); sysfs_remove_group(&dev->kobj, &dme1737_temp_offset_group);
} }
if (data->type == dme1737) { if (data->has_features & HAS_VID) {
sysfs_remove_group(&dev->kobj, &dme1737_vid_group); sysfs_remove_group(&dev->kobj, &dme1737_vid_group);
} }
if (data->has_features & HAS_ZONE3) {
sysfs_remove_group(&dev->kobj, &dme1737_zone3_group);
}
if (data->has_features & HAS_ZONE_HYST) {
sysfs_remove_group(&dev->kobj, &dme1737_zone_hyst_group);
}
sysfs_remove_group(&dev->kobj, &dme1737_group); sysfs_remove_group(&dev->kobj, &dme1737_group);
if (!data->client) { if (!data->client) {
...@@ -1934,23 +2007,31 @@ static int dme1737_create_files(struct device *dev) ...@@ -1934,23 +2007,31 @@ static int dme1737_create_files(struct device *dev)
goto exit_remove; goto exit_remove;
} }
/* Create misc sysfs attributes */ /* Create chip-dependent sysfs attributes */
if ((data->type != sch5027) && if ((data->has_features & HAS_TEMP_OFFSET) &&
(err = sysfs_create_group(&dev->kobj, (err = sysfs_create_group(&dev->kobj,
&dme1737_misc_group))) { &dme1737_temp_offset_group))) {
goto exit_remove; goto exit_remove;
} }
if ((data->has_features & HAS_VID) &&
/* Create VID-related sysfs attributes */
if ((data->type == dme1737) &&
(err = sysfs_create_group(&dev->kobj, (err = sysfs_create_group(&dev->kobj,
&dme1737_vid_group))) { &dme1737_vid_group))) {
goto exit_remove; goto exit_remove;
} }
if ((data->has_features & HAS_ZONE3) &&
(err = sysfs_create_group(&dev->kobj,
&dme1737_zone3_group))) {
goto exit_remove;
}
if ((data->has_features & HAS_ZONE_HYST) &&
(err = sysfs_create_group(&dev->kobj,
&dme1737_zone_hyst_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_features & HAS_FAN(ix)) {
if ((err = sysfs_create_group(&dev->kobj, if ((err = sysfs_create_group(&dev->kobj,
&dme1737_fan_group[ix]))) { &dme1737_fan_group[ix]))) {
goto exit_remove; goto exit_remove;
...@@ -1960,14 +2041,14 @@ static int dme1737_create_files(struct device *dev) ...@@ -1960,14 +2041,14 @@ static int dme1737_create_files(struct device *dev)
/* Create PWM sysfs attributes */ /* Create PWM sysfs attributes */
for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
if (data->has_pwm & (1 << ix)) { if (data->has_features & HAS_PWM(ix)) {
if ((err = sysfs_create_group(&dev->kobj, if ((err = sysfs_create_group(&dev->kobj,
&dme1737_pwm_group[ix]))) { &dme1737_pwm_group[ix]))) {
goto exit_remove; goto exit_remove;
} }
if (data->type != sch5027 && ix < 3 && if ((data->has_features & HAS_PWM_MIN) && ix < 3 &&
(err = sysfs_create_file(&dev->kobj, (err = sysfs_create_file(&dev->kobj,
dme1737_pwm_misc_attr[ix]))) { dme1737_auto_pwm_min_attr[ix]))) {
goto exit_remove; goto exit_remove;
} }
} }
...@@ -1983,21 +2064,30 @@ static int dme1737_create_files(struct device *dev) ...@@ -1983,21 +2064,30 @@ static int dme1737_create_files(struct device *dev)
dme1737_chmod_group(dev, &dme1737_zone_chmod_group, dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
S_IRUGO | S_IWUSR); S_IRUGO | S_IWUSR);
/* Change permissions of misc sysfs attributes */ /* Change permissions of chip-dependent sysfs attributes */
if (data->type != sch5027) { if (data->has_features & HAS_TEMP_OFFSET) {
dme1737_chmod_group(dev, &dme1737_misc_group, dme1737_chmod_group(dev, &dme1737_temp_offset_group,
S_IRUGO | S_IWUSR);
}
if (data->has_features & HAS_ZONE3) {
dme1737_chmod_group(dev, &dme1737_zone3_chmod_group,
S_IRUGO | S_IWUSR);
}
if (data->has_features & HAS_ZONE_HYST) {
dme1737_chmod_group(dev, &dme1737_zone_hyst_group,
S_IRUGO | S_IWUSR); 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_features & HAS_PWM(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) { if ((data->has_features & HAS_PWM_MIN) &&
ix < 3) {
dme1737_chmod_file(dev, dme1737_chmod_file(dev,
dme1737_pwm_misc_attr[ix], dme1737_auto_pwm_min_attr[ix],
S_IRUGO | S_IWUSR); S_IRUGO | S_IWUSR);
} }
} }
...@@ -2005,7 +2095,7 @@ static int dme1737_create_files(struct device *dev) ...@@ -2005,7 +2095,7 @@ static int dme1737_create_files(struct device *dev)
/* Change permissions of pwm[1-3] if in manual mode */ /* Change permissions of pwm[1-3] if in manual mode */
for (ix = 0; ix < 3; ix++) { for (ix = 0; ix < 3; ix++) {
if ((data->has_pwm & (1 << ix)) && if ((data->has_features & HAS_PWM(ix)) &&
(PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) { (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
dme1737_chmod_file(dev, dme1737_chmod_file(dev,
dme1737_pwm_chmod_attr[ix], dme1737_pwm_chmod_attr[ix],
...@@ -2052,20 +2142,20 @@ static int dme1737_init_device(struct device *dev) ...@@ -2052,20 +2142,20 @@ static int dme1737_init_device(struct device *dev)
return -EFAULT; return -EFAULT;
} }
/* Determine which optional fan and pwm features are enabled/present */ /* Determine which optional fan and pwm features are enabled (only
* valid for I2C devices) */
if (client) { /* I2C chip */ if (client) { /* I2C chip */
data->config2 = dme1737_read(data, DME1737_REG_CONFIG2); data->config2 = dme1737_read(data, DME1737_REG_CONFIG2);
/* Check if optional fan3 input is enabled */ /* Check if optional fan3 input is enabled */
if (data->config2 & 0x04) { if (data->config2 & 0x04) {
data->has_fan |= (1 << 2); data->has_features |= HAS_FAN(2);
} }
/* Fan4 and pwm3 are only available if the client's I2C address /* Fan4 and pwm3 are only available if the client's I2C address
* is the default 0x2e. Otherwise the I/Os associated with * is the default 0x2e. Otherwise the I/Os associated with
* these functions are used for addr enable/select. */ * these functions are used for addr enable/select. */
if (client->addr == 0x2e) { if (client->addr == 0x2e) {
data->has_fan |= (1 << 3); data->has_features |= HAS_FAN(3) | HAS_PWM(2);
data->has_pwm |= (1 << 2);
} }
/* Determine which of the optional fan[5-6] and pwm[5-6] /* Determine which of the optional fan[5-6] and pwm[5-6]
...@@ -2077,26 +2167,40 @@ static int dme1737_init_device(struct device *dev) ...@@ -2077,26 +2167,40 @@ static int dme1737_init_device(struct device *dev)
dev_warn(dev, "Failed to query Super-IO for optional " dev_warn(dev, "Failed to query Super-IO for optional "
"features.\n"); "features.\n");
} }
} else { /* ISA chip */
/* Fan3 and pwm3 are always available. Fan[4-5] and pwm[5-6]
* don't exist in the ISA chip. */
data->has_fan |= (1 << 2);
data->has_pwm |= (1 << 2);
} }
/* Fan1, fan2, pwm1, and pwm2 are always present */ /* Fan[1-2] and pwm[1-2] are present in all chips */
data->has_fan |= 0x03; data->has_features |= HAS_FAN(0) | HAS_FAN(1) | HAS_PWM(0) | HAS_PWM(1);
data->has_pwm |= 0x03;
/* Chip-dependent features */
switch (data->type) {
case dme1737:
data->has_features |= HAS_TEMP_OFFSET | HAS_VID | HAS_ZONE3 |
HAS_ZONE_HYST | HAS_PWM_MIN;
break;
case sch311x:
data->has_features |= HAS_TEMP_OFFSET | HAS_ZONE3 |
HAS_ZONE_HYST | HAS_PWM_MIN | HAS_FAN(2) | HAS_PWM(2);
break;
case sch5027:
data->has_features |= HAS_ZONE3;
break;
case sch5127:
data->has_features |= HAS_FAN(2) | HAS_PWM(2);
break;
default:
break;
}
dev_info(dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, " dev_info(dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
"fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n", "fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
(data->has_pwm & (1 << 2)) ? "yes" : "no", (data->has_features & HAS_PWM(2)) ? "yes" : "no",
(data->has_pwm & (1 << 4)) ? "yes" : "no", (data->has_features & HAS_PWM(4)) ? "yes" : "no",
(data->has_pwm & (1 << 5)) ? "yes" : "no", (data->has_features & HAS_PWM(5)) ? "yes" : "no",
(data->has_fan & (1 << 2)) ? "yes" : "no", (data->has_features & HAS_FAN(2)) ? "yes" : "no",
(data->has_fan & (1 << 3)) ? "yes" : "no", (data->has_features & HAS_FAN(3)) ? "yes" : "no",
(data->has_fan & (1 << 4)) ? "yes" : "no", (data->has_features & HAS_FAN(4)) ? "yes" : "no",
(data->has_fan & (1 << 5)) ? "yes" : "no"); (data->has_features & HAS_FAN(5)) ? "yes" : "no");
reg = dme1737_read(data, DME1737_REG_TACH_PWM); reg = dme1737_read(data, DME1737_REG_TACH_PWM);
/* Inform if fan-to-pwm mapping differs from the default */ /* Inform if fan-to-pwm mapping differs from the default */
...@@ -2122,7 +2226,7 @@ static int dme1737_init_device(struct device *dev) ...@@ -2122,7 +2226,7 @@ static int dme1737_init_device(struct device *dev)
for (ix = 0; ix < 3; ix++) { for (ix = 0; ix < 3; ix++) {
data->pwm_config[ix] = dme1737_read(data, data->pwm_config[ix] = dme1737_read(data,
DME1737_REG_PWM_CONFIG(ix)); DME1737_REG_PWM_CONFIG(ix));
if ((data->has_pwm & (1 << ix)) && if ((data->has_features & HAS_PWM(ix)) &&
(PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) { (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
dev_info(dev, "Switching pwm%d to " dev_info(dev, "Switching pwm%d to "
"manual mode.\n", ix + 1); "manual mode.\n", ix + 1);
...@@ -2142,7 +2246,7 @@ static int dme1737_init_device(struct device *dev) ...@@ -2142,7 +2246,7 @@ 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 == dme1737) { if (data->has_features & HAS_VID) {
data->vrm = vid_which_vrm(); data->vrm = vid_which_vrm();
} }
...@@ -2163,10 +2267,10 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data) ...@@ -2163,10 +2267,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. * We currently know about two kinds of DME1737 and SCH5027. */
* 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 || reg == 0x89)) { if (!(reg == DME1737_ID_1 || reg == DME1737_ID_2 ||
reg == SCH5027_ID)) {
err = -ENODEV; err = -ENODEV;
goto exit; goto exit;
} }
...@@ -2185,16 +2289,16 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data) ...@@ -2185,16 +2289,16 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
* are enabled and available. Bits [3:2] of registers 0x43-0x46 are set * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
* to '10' if the respective feature is enabled. */ * to '10' if the respective feature is enabled. */
if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */ if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */
data->has_fan |= (1 << 5); data->has_features |= HAS_FAN(5);
} }
if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */ if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */
data->has_pwm |= (1 << 5); data->has_features |= HAS_PWM(5);
} }
if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */ if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */
data->has_fan |= (1 << 4); data->has_features |= HAS_FAN(4);
} }
if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */ if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */
data->has_pwm |= (1 << 4); data->has_features |= HAS_PWM(4);
} }
exit: exit:
...@@ -2222,7 +2326,6 @@ static int dme1737_i2c_detect(struct i2c_client *client, ...@@ -2222,7 +2326,6 @@ static int dme1737_i2c_detect(struct i2c_client *client,
if (company == DME1737_COMPANY_SMSC && if (company == DME1737_COMPANY_SMSC &&
verstep == SCH5027_VERSTEP) { verstep == SCH5027_VERSTEP) {
name = "sch5027"; name = "sch5027";
} else if (company == DME1737_COMPANY_SMSC && } else if (company == DME1737_COMPANY_SMSC &&
(verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) { (verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
name = "dme1737"; name = "dme1737";
...@@ -2329,10 +2432,10 @@ static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr) ...@@ -2329,10 +2432,10 @@ static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr)
dme1737_sio_enter(sio_cip); dme1737_sio_enter(sio_cip);
/* Check device ID /* Check device ID
* We currently know about SCH3112 (0x7c), SCH3114 (0x7d), and * We currently know about SCH3112, SCH3114, SCH3116, and SCH5127 */
* SCH3116 (0x7f). */
reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20); reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) { if (!(reg == SCH3112_ID || reg == SCH3114_ID || reg == SCH3116_ID ||
reg == SCH5127_ID)) {
err = -ENODEV; err = -ENODEV;
goto exit; goto exit;
} }
...@@ -2424,23 +2527,42 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev) ...@@ -2424,23 +2527,42 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data); platform_set_drvdata(pdev, data);
/* Skip chip detection if module is loaded with force_id parameter */ /* Skip chip detection if module is loaded with force_id parameter */
if (!force_id) { switch (force_id) {
case SCH3112_ID:
case SCH3114_ID:
case SCH3116_ID:
data->type = sch311x;
break;
case SCH5127_ID:
data->type = sch5127;
break;
default:
company = dme1737_read(data, DME1737_REG_COMPANY); company = dme1737_read(data, DME1737_REG_COMPANY);
device = dme1737_read(data, DME1737_REG_DEVICE); device = dme1737_read(data, DME1737_REG_DEVICE);
if (!((company == DME1737_COMPANY_SMSC) && if ((company == DME1737_COMPANY_SMSC) &&
(device == SCH311X_DEVICE))) { (device == SCH311X_DEVICE)) {
data->type = sch311x;
} else if ((company == DME1737_COMPANY_SMSC) &&
(device == SCH5127_DEVICE)) {
data->type = sch5127;
} else {
err = -ENODEV; err = -ENODEV;
goto exit_kfree; goto exit_kfree;
} }
} }
data->type = sch311x;
/* Fill in the remaining client fields and initialize the mutex */ if (data->type == sch5127) {
data->name = "sch311x"; data->name = "sch5127";
} else {
data->name = "sch311x";
}
/* Initialize the mutex */
mutex_init(&data->update_lock); mutex_init(&data->update_lock);
dev_info(dev, "Found a SCH311x chip at 0x%04x\n", data->addr); dev_info(dev, "Found a %s chip at 0x%04x\n",
data->type == sch5127 ? "SCH5127" : "SCH311x", data->addr);
/* Initialize the chip */ /* Initialize the chip */
if ((err = dme1737_init_device(dev))) { if ((err = dme1737_init_device(dev))) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment