Skip to content

Commit

Permalink
hwmon: (f71882fg) Add support for the f71889fg (version 2)
Browse files Browse the repository at this point in the history
This adds support for the Fintek f71889fg to the f71882fg driver,
many thanks to Gerd v. Egidy for providing (remote) access to a
machine which such an ic.

Note that this bit of the patch:
-	val = SENSORS_LIMIT(val, 0, 255);
+
+	if (data->type == f71889fg)
+		val = SENSORS_LIMIT(val, -128, 127);
+	else
+		val = SENSORS_LIMIT(val, 0, 127);

Changes behaviour for already supported models, the new behaviour is correct
as the already supported models have bit 7 of the involved registers fixed at
0, so the previous behaviour which allowed setting temp zone limits > 127
was not correct.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
  • Loading branch information
jwrdegoede authored and Jean Delvare committed Dec 9, 2009
1 parent fc16c56 commit 7669896
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 21 deletions.
10 changes: 10 additions & 0 deletions Documentation/hwmon/f71882fg
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ Supported chips:
Prefix: 'f71882fg'
Addresses scanned: none, address read from Super I/O config space
Datasheet: Available from the Fintek website
* Fintek F71889FG
Prefix: 'f71889fg'
Addresses scanned: none, address read from Super I/O config space
Datasheet: Should become available on the Fintek website soon
* Fintek F8000
Prefix: 'f8000'
Addresses scanned: none, address read from Super I/O config space
Expand Down Expand Up @@ -51,6 +55,12 @@ supported. The right one to use depends on external circuitry on the
motherboard, so the driver assumes that the BIOS set the method
properly.

Note that the lowest numbered temperature zone trip point corresponds to
to the border between the highest and one but highest temperature zones, and
vica versa. So the temperature zone trip points 1-4 (or 1-2) go from high temp
to low temp! This is how things are implemented in the IC, and the driver
mimicks this.

There are 2 modes to specify the speed of the fan, PWM duty cycle (or DC
voltage) mode, where 0-100% duty cycle (0-100% of 12V) is specified. And RPM
mode where the actual RPM of the fan (as measured) is controlled and the speed
Expand Down
6 changes: 3 additions & 3 deletions drivers/hwmon/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -305,12 +305,12 @@ config SENSORS_F71805F
will be called f71805f.

config SENSORS_F71882FG
tristate "Fintek F71858FG, F71862FG, F71882FG and F8000"
tristate "Fintek F71858FG, F71862FG, F71882FG, F71889FG and F8000"
depends on EXPERIMENTAL
help
If you say yes here you get support for hardware monitoring
features of the Fintek F71858FG, F71862FG/71863FG, F71882FG/F71883FG
and F8000 Super-I/O chips.
features of the Fintek F71858FG, F71862FG/71863FG, F71882FG/F71883FG,
F71889FG and F8000 Super-I/O chips.

This driver can also be built as a module. If so, the module
will be called f71882fg.
Expand Down
86 changes: 68 additions & 18 deletions drivers/hwmon/f71882fg.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#define SIO_F71858_ID 0x0507 /* Chipset ID */
#define SIO_F71862_ID 0x0601 /* Chipset ID */
#define SIO_F71882_ID 0x0541 /* Chipset ID */
#define SIO_F71889_ID 0x0723 /* Chipset ID */
#define SIO_F8000_ID 0x0581 /* Chipset ID */

#define REGION_LENGTH 8
Expand Down Expand Up @@ -95,12 +96,13 @@ static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");

enum chips { f71858fg, f71862fg, f71882fg, f8000 };
enum chips { f71858fg, f71862fg, f71882fg, f71889fg, f8000 };

static const char *f71882fg_names[] = {
"f71858fg",
"f71862fg",
"f71882fg",
"f71889fg",
"f8000",
};

Expand Down Expand Up @@ -155,7 +157,7 @@ struct f71882fg_data {
u8 pwm_auto_point_hyst[2];
u8 pwm_auto_point_mapping[4];
u8 pwm_auto_point_pwm[4][5];
u8 pwm_auto_point_temp[4][4];
s8 pwm_auto_point_temp[4][4];
};

/* Sysfs in */
Expand Down Expand Up @@ -945,7 +947,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
/* Update once every 60 seconds */
if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
!data->valid) {
if (data->type == f71882fg) {
if (data->type == f71882fg || data->type == f71889fg) {
data->in1_max =
f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
data->in_beep =
Expand All @@ -967,7 +969,8 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
F71882FG_REG_TEMP_HYST(1));
}

if (data->type == f71862fg || data->type == f71882fg) {
if (data->type == f71862fg || data->type == f71882fg ||
data->type == f71889fg) {
data->fan_beep = f71882fg_read8(data,
F71882FG_REG_FAN_BEEP);
data->temp_beep = f71882fg_read8(data,
Expand All @@ -977,15 +980,33 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
data->temp_type[2] = (reg & 0x04) ? 2 : 4;
data->temp_type[3] = (reg & 0x08) ? 2 : 4;
}
reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
if ((reg2 & 0x03) == 0x01)
data->temp_type[1] = 6 /* PECI */;
else if ((reg2 & 0x03) == 0x02)
data->temp_type[1] = 5 /* AMDSI */;
else if (data->type == f71862fg || data->type == f71882fg)
data->temp_type[1] = (reg & 0x02) ? 2 : 4;
else
data->temp_type[1] = 2; /* Only supports BJT */
/* Determine temp index 1 sensor type */
if (data->type == f71889fg) {
reg2 = f71882fg_read8(data, F71882FG_REG_START);
switch ((reg2 & 0x60) >> 5) {
case 0x00: /* BJT / Thermistor */
data->temp_type[1] = (reg & 0x02) ? 2 : 4;
break;
case 0x01: /* AMDSI */
data->temp_type[1] = 5;
break;
case 0x02: /* PECI */
case 0x03: /* Ibex Peak ?? Report as PECI for now */
data->temp_type[1] = 6;
break;
}
} else {
reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
if ((reg2 & 0x03) == 0x01)
data->temp_type[1] = 6; /* PECI */
else if ((reg2 & 0x03) == 0x02)
data->temp_type[1] = 5; /* AMDSI */
else if (data->type == f71862fg ||
data->type == f71882fg)
data->temp_type[1] = (reg & 0x02) ? 2 : 4;
else /* f71858fg and f8000 only support BJT */
data->temp_type[1] = 2;
}

data->pwm_enable = f71882fg_read8(data,
F71882FG_REG_PWM_ENABLE);
Expand Down Expand Up @@ -1062,7 +1083,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
if (data->type == f8000)
data->fan[3] = f71882fg_read16(data,
F71882FG_REG_FAN(3));
if (data->type == f71882fg)
if (data->type == f71882fg || data->type == f71889fg)
data->in_status = f71882fg_read8(data,
F71882FG_REG_IN_STATUS);
for (nr = 0; nr < nr_ins; nr++)
Expand Down Expand Up @@ -1780,7 +1801,11 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev,
int pwm = to_sensor_dev_attr_2(devattr)->index;
int point = to_sensor_dev_attr_2(devattr)->nr;
long val = simple_strtol(buf, NULL, 10) / 1000;
val = SENSORS_LIMIT(val, 0, 255);

if (data->type == f71889fg)
val = SENSORS_LIMIT(val, -128, 127);
else
val = SENSORS_LIMIT(val, 0, 127);

mutex_lock(&data->update_lock);
f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
Expand Down Expand Up @@ -1871,6 +1896,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
ARRAY_SIZE(f71858fg_in_temp_attr));
break;
case f71882fg:
case f71889fg:
err = f71882fg_create_sysfs_files(pdev,
fxxxx_in1_alarm_attr,
ARRAY_SIZE(fxxxx_in1_alarm_attr));
Expand Down Expand Up @@ -1908,6 +1934,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
err = (data->pwm_enable & 0x15) != 0x15;
break;
case f71882fg:
case f71889fg:
err = 0;
break;
case f8000:
Expand All @@ -1927,7 +1954,8 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
if (err)
goto exit_unregister_sysfs;

if (data->type == f71862fg || data->type == f71882fg) {
if (data->type == f71862fg || data->type == f71882fg ||
data->type == f71889fg) {
err = f71882fg_create_sysfs_files(pdev,
fxxxx_fan_beep_attr, nr_fans);
if (err)
Expand All @@ -1950,6 +1978,22 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
f8000_auto_pwm_attr,
ARRAY_SIZE(f8000_auto_pwm_attr));
break;
case f71889fg:
for (i = 0; i < nr_fans; i++) {
data->pwm_auto_point_mapping[i] =
f71882fg_read8(data,
F71882FG_REG_POINT_MAPPING(i));
if (data->pwm_auto_point_mapping[i] & 0x80)
break;
}
if (i != nr_fans) {
dev_warn(&pdev->dev,
"Auto pwm controlled by raw digital "
"data, disabling pwm auto_point "
"sysfs attributes\n");
break;
}
/* fall through */
default: /* f71858fg / f71882fg */
err = f71882fg_create_sysfs_files(pdev,
&fxxxx_auto_pwm_attr[0][0],
Expand Down Expand Up @@ -2006,6 +2050,7 @@ static int f71882fg_remove(struct platform_device *pdev)
ARRAY_SIZE(f71858fg_in_temp_attr));
break;
case f71882fg:
case f71889fg:
f71882fg_remove_sysfs_files(pdev,
fxxxx_in1_alarm_attr,
ARRAY_SIZE(fxxxx_in1_alarm_attr));
Expand All @@ -2027,7 +2072,8 @@ static int f71882fg_remove(struct platform_device *pdev)
f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);

if (data->type == f71862fg || data->type == f71882fg)
if (data->type == f71862fg || data->type == f71882fg ||
data->type == f71889fg)
f71882fg_remove_sysfs_files(pdev,
fxxxx_fan_beep_attr, nr_fans);

Expand Down Expand Up @@ -2082,11 +2128,15 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
case SIO_F71882_ID:
sio_data->type = f71882fg;
break;
case SIO_F71889_ID:
sio_data->type = f71889fg;
break;
case SIO_F8000_ID:
sio_data->type = f8000;
break;
default:
printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
printk(KERN_INFO DRVNAME ": Unsupported Fintek device: %04x\n",
(unsigned int)devid);
goto exit;
}

Expand Down

0 comments on commit 7669896

Please sign in to comment.