瀏覽代碼

hwmon: (f71882fg) Add support for the F71858F

Add support for the hwmon part of the Fintek F71858FG superio IC to the
f71882fg driver. Many thanks to Jelle de Jong for lending me a motherboard 
with this superio on it.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Hans de Goede 16 年之前
父節點
當前提交
09475d32e6
共有 3 個文件被更改,包括 166 次插入42 次删除
  1. 8 4
      Documentation/hwmon/f71882fg
  2. 2 2
      drivers/hwmon/Kconfig
  3. 156 36
      drivers/hwmon/f71882fg.c

+ 8 - 4
Documentation/hwmon/f71882fg

@@ -2,14 +2,18 @@ Kernel driver f71882fg
 ======================
 ======================
 
 
 Supported chips:
 Supported chips:
-  * Fintek F71882FG and F71883FG
-    Prefix: 'f71882fg'
+  * Fintek F71858FG
+    Prefix: 'f71858fg'
     Addresses scanned: none, address read from Super I/O config space
     Addresses scanned: none, address read from Super I/O config space
     Datasheet: Available from the Fintek website
     Datasheet: Available from the Fintek website
   * Fintek F71862FG and F71863FG
   * Fintek F71862FG and F71863FG
     Prefix: 'f71862fg'
     Prefix: 'f71862fg'
     Addresses scanned: none, address read from Super I/O config space
     Addresses scanned: none, address read from Super I/O config space
     Datasheet: Available from the Fintek website
     Datasheet: Available from the Fintek website
+  * Fintek F71882FG and F71883FG
+    Prefix: 'f71882fg'
+    Addresses scanned: none, address read from Super I/O config space
+    Datasheet: Available from the Fintek website
   * Fintek F8000
   * Fintek F8000
     Prefix: 'f8000'
     Prefix: 'f8000'
     Addresses scanned: none, address read from Super I/O config space
     Addresses scanned: none, address read from Super I/O config space
@@ -66,13 +70,13 @@ printed when loading the driver.
 
 
 Three different fan control modes are supported; the mode number is written
 Three different fan control modes are supported; the mode number is written
 to the pwm#_enable file. Note that not all modes are supported on all
 to the pwm#_enable file. Note that not all modes are supported on all
-chips, and some modes may only be available in RPM / PWM mode on the F8000.
+chips, and some modes may only be available in RPM / PWM mode.
 Writing an unsupported mode will result in an invalid parameter error.
 Writing an unsupported mode will result in an invalid parameter error.
 
 
 * 1: Manual mode
 * 1: Manual mode
   You ask for a specific PWM duty cycle / DC voltage or a specific % of
   You ask for a specific PWM duty cycle / DC voltage or a specific % of
   fan#_full_speed by writing to the pwm# file. This mode is only
   fan#_full_speed by writing to the pwm# file. This mode is only
-  available on the F8000 if the fan channel is in RPM mode.
+  available on the F71858FG / F8000 if the fan channel is in RPM mode.
 
 
 * 2: Normal auto mode
 * 2: Normal auto mode
   You can define a number of temperature/fan speed trip points, which % the
   You can define a number of temperature/fan speed trip points, which % the

+ 2 - 2
drivers/hwmon/Kconfig

@@ -306,11 +306,11 @@ config SENSORS_F71805F
 	  will be called f71805f.
 	  will be called f71805f.
 
 
 config SENSORS_F71882FG
 config SENSORS_F71882FG
-	tristate "Fintek F71862FG, F71882FG and F8000"
+	tristate "Fintek F71858FG, F71862FG, F71882FG and F8000"
 	depends on EXPERIMENTAL
 	depends on EXPERIMENTAL
 	help
 	help
 	  If you say yes here you get support for hardware monitoring
 	  If you say yes here you get support for hardware monitoring
-	  features of the Fintek F71882FG/F71883FG, F71862FG/71863FG
+	  features of the Fintek F71858FG, F71862FG/71863FG, F71882FG/F71883FG
 	  and F8000 Super-I/O chips.
 	  and F8000 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

+ 156 - 36
drivers/hwmon/f71882fg.c

@@ -32,6 +32,7 @@
 
 
 #define DRVNAME "f71882fg"
 #define DRVNAME "f71882fg"
 
 
+#define SIO_F71858FG_LD_HWM	0x02	/* Hardware monitor logical device */
 #define SIO_F71882FG_LD_HWM	0x04	/* Hardware monitor logical device */
 #define SIO_F71882FG_LD_HWM	0x04	/* Hardware monitor logical device */
 #define SIO_UNLOCK_KEY		0x87	/* Key to enable Super-I/O */
 #define SIO_UNLOCK_KEY		0x87	/* Key to enable Super-I/O */
 #define SIO_LOCK_KEY		0xAA	/* Key to diasble Super-I/O */
 #define SIO_LOCK_KEY		0xAA	/* Key to diasble Super-I/O */
@@ -44,6 +45,7 @@
 #define SIO_REG_ADDR		0x60	/* Logical device address (2 bytes) */
 #define SIO_REG_ADDR		0x60	/* Logical device address (2 bytes) */
 
 
 #define SIO_FINTEK_ID		0x1934	/* Manufacturers ID */
 #define SIO_FINTEK_ID		0x1934	/* Manufacturers ID */
+#define SIO_F71858_ID		0x0507  /* Chipset ID */
 #define SIO_F71862_ID		0x0601	/* Chipset ID */
 #define SIO_F71862_ID		0x0601	/* Chipset ID */
 #define SIO_F71882_ID		0x0541	/* Chipset ID */
 #define SIO_F71882_ID		0x0541	/* Chipset ID */
 #define SIO_F8000_ID		0x0581	/* Chipset ID */
 #define SIO_F8000_ID		0x0581	/* Chipset ID */
@@ -70,6 +72,7 @@
 #define F71882FG_REG_TEMP_HIGH(nr)	(0x81 + 2 * (nr))
 #define F71882FG_REG_TEMP_HIGH(nr)	(0x81 + 2 * (nr))
 #define F71882FG_REG_TEMP_STATUS	0x62
 #define F71882FG_REG_TEMP_STATUS	0x62
 #define F71882FG_REG_TEMP_BEEP		0x63
 #define F71882FG_REG_TEMP_BEEP		0x63
+#define F71882FG_REG_TEMP_CONFIG	0x69
 #define F71882FG_REG_TEMP_HYST(nr)	(0x6C + (nr))
 #define F71882FG_REG_TEMP_HYST(nr)	(0x6C + (nr))
 #define F71882FG_REG_TEMP_TYPE		0x6B
 #define F71882FG_REG_TEMP_TYPE		0x6B
 #define F71882FG_REG_TEMP_DIODE_OPEN	0x6F
 #define F71882FG_REG_TEMP_DIODE_OPEN	0x6F
@@ -92,9 +95,10 @@ static unsigned short force_id;
 module_param(force_id, ushort, 0);
 module_param(force_id, ushort, 0);
 MODULE_PARM_DESC(force_id, "Override the detected device ID");
 MODULE_PARM_DESC(force_id, "Override the detected device ID");
 
 
-enum chips { f71862fg, f71882fg, f8000 };
+enum chips { f71858fg, f71862fg, f71882fg, f8000 };
 
 
 static const char *f71882fg_names[] = {
 static const char *f71882fg_names[] = {
+	"f71858fg",
 	"f71862fg",
 	"f71862fg",
 	"f71882fg",
 	"f71882fg",
 	"f8000",
 	"f8000",
@@ -119,6 +123,7 @@ struct f71882fg_data {
 	struct device *hwmon_dev;
 	struct device *hwmon_dev;
 
 
 	struct mutex update_lock;
 	struct mutex update_lock;
+	int temp_start;			/* temp numbering start (0 or 1) */
 	char valid;			/* !=0 if following fields are valid */
 	char valid;			/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 	unsigned long last_updated;	/* In jiffies */
 	unsigned long last_limits;	/* In jiffies */
 	unsigned long last_limits;	/* In jiffies */
@@ -136,7 +141,7 @@ struct f71882fg_data {
 	/* Note: all models have only 3 temperature channels, but on some
 	/* Note: all models have only 3 temperature channels, but on some
 	   they are addressed as 0-2 and on others as 1-3, so for coding
 	   they are addressed as 0-2 and on others as 1-3, so for coding
 	   convenience we reserve space for 4 channels */
 	   convenience we reserve space for 4 channels */
-	u8	temp[4];
+	u16	temp[4];
 	u8	temp_ovt[4];
 	u8	temp_ovt[4];
 	u8	temp_high[4];
 	u8	temp_high[4];
 	u8	temp_hyst[2]; /* 2 hysts stored per reg */
 	u8	temp_hyst[2]; /* 2 hysts stored per reg */
@@ -144,6 +149,7 @@ struct f71882fg_data {
 	u8	temp_status;
 	u8	temp_status;
 	u8	temp_beep;
 	u8	temp_beep;
 	u8	temp_diode_open;
 	u8	temp_diode_open;
+	u8	temp_config;
 	u8	pwm[4];
 	u8	pwm[4];
 	u8	pwm_enable;
 	u8	pwm_enable;
 	u8	pwm_auto_point_hyst[2];
 	u8	pwm_auto_point_hyst[2];
@@ -252,6 +258,50 @@ static struct platform_driver f71882fg_driver = {
 
 
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
 
+/* Temp and in attr for the f71858fg */
+static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = {
+	SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
+	SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
+	SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
+	SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
+	SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
+		store_temp_max, 0, 0),
+	SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+		store_temp_max_hyst, 0, 0),
+	SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
+	SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+		store_temp_crit, 0, 0),
+	SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+		0, 0),
+	SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
+	SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
+	SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
+	SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
+		store_temp_max, 0, 1),
+	SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+		store_temp_max_hyst, 0, 1),
+	SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
+	SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+		store_temp_crit, 0, 1),
+	SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+		0, 1),
+	SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
+	SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
+	SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
+	SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
+	SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
+		store_temp_max, 0, 2),
+	SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+		store_temp_max_hyst, 0, 2),
+	SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
+	SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+		store_temp_crit, 0, 2),
+	SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+		0, 2),
+	SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
+	SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
+};
+
 /* Temp and in attr common to both the f71862fg and f71882fg */
 /* Temp and in attr common to both the f71862fg and f71882fg */
 static struct sensor_device_attribute_2 f718x2fg_in_temp_attr[] = {
 static struct sensor_device_attribute_2 f718x2fg_in_temp_attr[] = {
 	SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
 	SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
@@ -476,22 +526,8 @@ static struct sensor_device_attribute_2 f71862fg_fan_attr[] = {
 		      show_pwm_auto_point_temp_hyst, NULL, 3, 2),
 		      show_pwm_auto_point_temp_hyst, NULL, 3, 2),
 };
 };
 
 
-/* Fan / PWM attr for the f71882fg */
-static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
-	SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
-		store_fan_beep, 0, 0),
-	SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
-		store_fan_beep, 0, 1),
-	SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
-		store_fan_beep, 0, 2),
-	SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
-	SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
-		      show_fan_full_speed,
-		      store_fan_full_speed, 0, 3),
-	SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
-		store_fan_beep, 0, 3),
-	SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
-
+/* Fan / PWM attr common to both the f71882fg and f71858fg */
+static struct sensor_device_attribute_2 f71882fg_f71858fg_fan_attr[] = {
 	SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
 	SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
 		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
 		      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
 		      0, 0),
 		      0, 0),
@@ -605,6 +641,24 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
 		      show_pwm_auto_point_temp_hyst, NULL, 2, 2),
 		      show_pwm_auto_point_temp_hyst, NULL, 2, 2),
 	SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
 	SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
 		      show_pwm_auto_point_temp_hyst, NULL, 3, 2),
 		      show_pwm_auto_point_temp_hyst, NULL, 3, 2),
+};
+
+/* Fan / PWM attr found on the f71882fg but not on the f71858fg */
+static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
+	SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+		store_fan_beep, 0, 0),
+	SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+		store_fan_beep, 0, 1),
+	SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+		store_fan_beep, 0, 2),
+
+	SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
+	SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
+		      show_fan_full_speed,
+		      store_fan_full_speed, 0, 3),
+	SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+		store_fan_beep, 0, 3),
+	SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
 
 
 	SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
 	SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
 	SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
 	SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
@@ -855,13 +909,20 @@ static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
 	outb(val & 255, data->addr + DATA_REG_OFFSET);
 	outb(val & 255, data->addr + DATA_REG_OFFSET);
 }
 }
 
 
+static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
+{
+	if (data->type == f71858fg)
+		return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
+	else
+		return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
+}
+
 static struct f71882fg_data *f71882fg_update_device(struct device *dev)
 static struct f71882fg_data *f71882fg_update_device(struct device *dev)
 {
 {
 	struct f71882fg_data *data = dev_get_drvdata(dev);
 	struct f71882fg_data *data = dev_get_drvdata(dev);
 	int nr, reg = 0, reg2;
 	int nr, reg = 0, reg2;
 	int nr_fans = (data->type == f71882fg) ? 4 : 3;
 	int nr_fans = (data->type == f71882fg) ? 4 : 3;
-	int nr_ins = (data->type == f8000) ? 3 : 9;
-	int temp_start = (data->type == f8000) ? 0 : 1;
+	int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9;
 
 
 	mutex_lock(&data->update_lock);
 	mutex_lock(&data->update_lock);
 
 
@@ -876,7 +937,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
 		}
 		}
 
 
 		/* Get High & boundary temps*/
 		/* Get High & boundary temps*/
-		for (nr = temp_start; nr < 3 + temp_start; nr++) {
+		for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
 			data->temp_ovt[nr] = f71882fg_read8(data,
 			data->temp_ovt[nr] = f71882fg_read8(data,
 						F71882FG_REG_TEMP_OVT(nr));
 						F71882FG_REG_TEMP_OVT(nr));
 			data->temp_high[nr] = f71882fg_read8(data,
 			data->temp_high[nr] = f71882fg_read8(data,
@@ -884,14 +945,17 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
 		}
 		}
 
 
 		if (data->type != f8000) {
 		if (data->type != f8000) {
-			data->fan_beep = f71882fg_read8(data,
-						F71882FG_REG_FAN_BEEP);
-			data->temp_beep = f71882fg_read8(data,
-						F71882FG_REG_TEMP_BEEP);
 			data->temp_hyst[0] = f71882fg_read8(data,
 			data->temp_hyst[0] = f71882fg_read8(data,
 						F71882FG_REG_TEMP_HYST(0));
 						F71882FG_REG_TEMP_HYST(0));
 			data->temp_hyst[1] = f71882fg_read8(data,
 			data->temp_hyst[1] = f71882fg_read8(data,
 						F71882FG_REG_TEMP_HYST(1));
 						F71882FG_REG_TEMP_HYST(1));
+		}
+
+		if (data->type == f71862fg || data->type == f71882fg) {
+			data->fan_beep = f71882fg_read8(data,
+						F71882FG_REG_FAN_BEEP);
+			data->temp_beep = f71882fg_read8(data,
+						F71882FG_REG_TEMP_BEEP);
 			/* Have to hardcode type, because temp1 is special */
 			/* Have to hardcode type, because temp1 is special */
 			reg  = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
 			reg  = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
 			data->temp_type[2] = (reg & 0x04) ? 2 : 4;
 			data->temp_type[2] = (reg & 0x04) ? 2 : 4;
@@ -902,10 +966,10 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
 			data->temp_type[1] = 6 /* PECI */;
 			data->temp_type[1] = 6 /* PECI */;
 		else if ((reg2 & 0x03) == 0x02)
 		else if ((reg2 & 0x03) == 0x02)
 			data->temp_type[1] = 5 /* AMDSI */;
 			data->temp_type[1] = 5 /* AMDSI */;
-		else if (data->type != f8000)
+		else if (data->type == f71862fg || data->type == f71882fg)
 			data->temp_type[1] = (reg & 0x02) ? 2 : 4;
 			data->temp_type[1] = (reg & 0x02) ? 2 : 4;
 		else
 		else
-			data->temp_type[1] = 2; /* F8000 only supports BJT */
+			data->temp_type[1] = 2; /* Only supports BJT */
 
 
 		data->pwm_enable = f71882fg_read8(data,
 		data->pwm_enable = f71882fg_read8(data,
 						  F71882FG_REG_PWM_ENABLE);
 						  F71882FG_REG_PWM_ENABLE);
@@ -961,9 +1025,8 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
 						F71882FG_REG_TEMP_STATUS);
 						F71882FG_REG_TEMP_STATUS);
 		data->temp_diode_open = f71882fg_read8(data,
 		data->temp_diode_open = f71882fg_read8(data,
 						F71882FG_REG_TEMP_DIODE_OPEN);
 						F71882FG_REG_TEMP_DIODE_OPEN);
-		for (nr = temp_start; nr < 3 + temp_start; nr++)
-			data->temp[nr] = f71882fg_read8(data,
-						F71882FG_REG_TEMP(nr));
+		for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
+			data->temp[nr] = f71882fg_read_temp(data, nr);
 
 
 		data->fan_status = f71882fg_read8(data,
 		data->fan_status = f71882fg_read8(data,
 						F71882FG_REG_FAN_STATUS);
 						F71882FG_REG_FAN_STATUS);
@@ -1166,8 +1229,24 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
 {
 {
 	struct f71882fg_data *data = f71882fg_update_device(dev);
 	struct f71882fg_data *data = f71882fg_update_device(dev);
 	int nr = to_sensor_dev_attr_2(devattr)->index;
 	int nr = to_sensor_dev_attr_2(devattr)->index;
+	int sign, temp;
+
+	if (data->type == f71858fg) {
+		/* TEMP_TABLE_SEL 1 or 3 ? */
+		if (data->temp_config & 1) {
+			sign = data->temp[nr] & 0x0001;
+			temp = (data->temp[nr] >> 5) & 0x7ff;
+		} else {
+			sign = data->temp[nr] & 0x8000;
+			temp = (data->temp[nr] >> 5) & 0x3ff;
+		}
+		temp *= 125;
+		if (sign)
+			temp -= 128000;
+	} else
+		temp = data->temp[nr] * 1000;
 
 
-	return sprintf(buf, "%d\n", data->temp[nr] * 1000);
+	return sprintf(buf, "%d\n", temp);
 }
 }
 
 
 static ssize_t show_temp_max(struct device *dev, struct device_attribute
 static ssize_t show_temp_max(struct device *dev, struct device_attribute
@@ -1460,6 +1539,12 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
 	} else {
 	} else {
 		switch (val) {
 		switch (val) {
 		case 1:
 		case 1:
+			/* The f71858fg does not support manual RPM mode */
+			if (data->type == f71858fg &&
+			    ((data->pwm_enable >> (2 * nr)) & 1)) {
+				count = -EINVAL;
+				goto leave;
+			}
 			data->pwm_enable |= 2 << (2 * nr);
 			data->pwm_enable |= 2 << (2 * nr);
 			break;		/* Manual */
 			break;		/* Manual */
 		case 2:
 		case 2:
@@ -1618,9 +1703,9 @@ static ssize_t show_pwm_auto_point_channel(struct device *dev,
 	int result;
 	int result;
 	struct f71882fg_data *data = f71882fg_update_device(dev);
 	struct f71882fg_data *data = f71882fg_update_device(dev);
 	int nr = to_sensor_dev_attr_2(devattr)->index;
 	int nr = to_sensor_dev_attr_2(devattr)->index;
-	int temp_start = (data->type == f8000) ? 0 : 1;
 
 
-	result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - temp_start);
+	result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
+		       data->temp_start);
 
 
 	return sprintf(buf, "%d\n", result);
 	return sprintf(buf, "%d\n", result);
 }
 }
@@ -1631,7 +1716,6 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev,
 {
 {
 	struct f71882fg_data *data = dev_get_drvdata(dev);
 	struct f71882fg_data *data = dev_get_drvdata(dev);
 	int nr = to_sensor_dev_attr_2(devattr)->index;
 	int nr = to_sensor_dev_attr_2(devattr)->index;
-	int temp_start = (data->type == f8000) ? 0 : 1;
 	long val = simple_strtol(buf, NULL, 10);
 	long val = simple_strtol(buf, NULL, 10);
 
 
 	switch (val) {
 	switch (val) {
@@ -1647,7 +1731,7 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev,
 	default:
 	default:
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
-	val += temp_start;
+	val += data->temp_start;
 	mutex_lock(&data->update_lock);
 	mutex_lock(&data->update_lock);
 	data->pwm_auto_point_mapping[nr] =
 	data->pwm_auto_point_mapping[nr] =
 		f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
 		f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
@@ -1723,6 +1807,8 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
 
 
 	data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
 	data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
 	data->type = sio_data->type;
 	data->type = sio_data->type;
+	data->temp_start =
+	    (data->type == f71858fg || data->type == f8000) ? 0 : 1;
 	mutex_init(&data->update_lock);
 	mutex_init(&data->update_lock);
 	platform_set_drvdata(pdev, data);
 	platform_set_drvdata(pdev, data);
 
 
@@ -1745,6 +1831,20 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
 
 
 	if (start_reg & 0x01) {
 	if (start_reg & 0x01) {
 		switch (data->type) {
 		switch (data->type) {
+		case f71858fg:
+			data->temp_config =
+				f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
+			if (data->temp_config & 0x10)
+				/* The f71858fg temperature alarms behave as
+				   the f8000 alarms in this mode */
+				err = f71882fg_create_sysfs_files(pdev,
+					f8000_in_temp_attr,
+					ARRAY_SIZE(f8000_in_temp_attr));
+			else
+				err = f71882fg_create_sysfs_files(pdev,
+					f71858fg_in_temp_attr,
+					ARRAY_SIZE(f71858fg_in_temp_attr));
+			break;
 		case f71882fg:
 		case f71882fg:
 			err = f71882fg_create_sysfs_files(pdev,
 			err = f71882fg_create_sysfs_files(pdev,
 					f71882fg_in_temp_attr,
 					f71882fg_in_temp_attr,
@@ -1773,6 +1873,12 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
 
 
 		/* Sanity check the pwm settings */
 		/* Sanity check the pwm settings */
 		switch (data->type) {
 		switch (data->type) {
+		case f71858fg:
+			err = 0;
+			for (i = 0; i < nr_fans; i++)
+				if (((data->pwm_enable >> (i * 2)) & 3) == 3)
+					err = 1;
+			break;
 		case f71862fg:
 		case f71862fg:
 			err = (data->pwm_enable & 0x15) != 0x15;
 			err = (data->pwm_enable & 0x15) != 0x15;
 			break;
 			break;
@@ -1806,6 +1912,13 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
 			err = f71882fg_create_sysfs_files(pdev,
 			err = f71882fg_create_sysfs_files(pdev,
 					f71882fg_fan_attr,
 					f71882fg_fan_attr,
 					ARRAY_SIZE(f71882fg_fan_attr));
 					ARRAY_SIZE(f71882fg_fan_attr));
+			if (err)
+				goto exit_unregister_sysfs;
+			/* fall through! */
+		case f71858fg:
+			err = f71882fg_create_sysfs_files(pdev,
+					f71882fg_f71858fg_fan_attr,
+					ARRAY_SIZE(f71882fg_f71858fg_fan_attr));
 			break;
 			break;
 		case f8000:
 		case f8000:
 			err = f71882fg_create_sysfs_files(pdev,
 			err = f71882fg_create_sysfs_files(pdev,
@@ -1890,6 +2003,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
 
 
 	devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
 	devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
 	switch (devid) {
 	switch (devid) {
+	case SIO_F71858_ID:
+		sio_data->type = f71858fg;
+		break;
 	case SIO_F71862_ID:
 	case SIO_F71862_ID:
 		sio_data->type = f71862fg;
 		sio_data->type = f71862fg;
 		break;
 		break;
@@ -1904,7 +2020,11 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
 		goto exit;
 		goto exit;
 	}
 	}
 
 
-	superio_select(sioaddr, SIO_F71882FG_LD_HWM);
+	if (sio_data->type == f71858fg)
+		superio_select(sioaddr, SIO_F71858FG_LD_HWM);
+	else
+		superio_select(sioaddr, SIO_F71882FG_LD_HWM);
+
 	if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
 	if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
 		printk(KERN_WARNING DRVNAME ": Device not activated\n");
 		printk(KERN_WARNING DRVNAME ": Device not activated\n");
 		goto exit;
 		goto exit;