All of lore.kernel.org
 help / color / mirror / Atom feed
* [lm-sensors] [PATCH v5 00/11] hwmon: (w83627ehf) Add support for
@ 2011-03-04 17:57 ` Guenter Roeck
  0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:57 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

The following patch series adds support for NCT6775F and NCT6776F to the
w83627ehf driver. It also includes some cleanup and adds support for
the fourth temperature sensor on W83677HG-B.

No code changes since v4. Resubmitting and widening audience in the hope that
someone may find the time to review the changes prior to the next commit window.

v5:
- Update Kconfig to reference W83667HG, NCT6775F, and NCT6776F.

v4:
- Store rpm instead of raw fan speed readings
- For NCT6775F, increase fan divisor if the fan speed reads 0
  [ On NCT6775F, fan speed readings can return 0 instead of 0xff if the
    fan divisor value is too low ]
- Separate changes into more patches to simplify review

v3:
- Documentation: Remove references to datasheets which no longer exist
- Documentation: Add information about limits of SmartFan IV support.
- SmartFan III mode is not supported on NCT6776F, so remove related attributes
  and refuse to configure it.
- (additional patch) Improve support for chips with 16-bit fan count registers

v2:
- W83677HG-B does share the AUXTIN/VIN3 pin, so we can not skip this check.
- Cosmetic changes to fix a couple of checkpatch errors and to undo some
  unnecessary formatting changes in patch 5.
- Patch 1 introduced a bug in temp_to_reg which was fixed in a later patch.
  Modified code to not introduce the bug in the first place.
- Two dev_dbg messages were changed to dev_info for testing. Changed back
  to dev_dbg.

The patched driver can be downloaded as stand-alone driver from
	http://www.roeck-us.net/linux/drivers/w83627ehf/

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F
@ 2011-03-04 17:57 ` Guenter Roeck
  0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:57 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

The following patch series adds support for NCT6775F and NCT6776F to the
w83627ehf driver. It also includes some cleanup and adds support for
the fourth temperature sensor on W83677HG-B.

No code changes since v4. Resubmitting and widening audience in the hope that
someone may find the time to review the changes prior to the next commit window.

v5:
- Update Kconfig to reference W83667HG, NCT6775F, and NCT6776F.

v4:
- Store rpm instead of raw fan speed readings
- For NCT6775F, increase fan divisor if the fan speed reads 0
  [ On NCT6775F, fan speed readings can return 0 instead of 0xff if the
    fan divisor value is too low ]
- Separate changes into more patches to simplify review

v3:
- Documentation: Remove references to datasheets which no longer exist
- Documentation: Add information about limits of SmartFan IV support.
- SmartFan III mode is not supported on NCT6776F, so remove related attributes
  and refuse to configure it.
- (additional patch) Improve support for chips with 16-bit fan count registers

v2:
- W83677HG-B does share the AUXTIN/VIN3 pin, so we can not skip this check.
- Cosmetic changes to fix a couple of checkpatch errors and to undo some
  unnecessary formatting changes in patch 5.
- Patch 1 introduced a bug in temp_to_reg which was fixed in a later patch.
  Modified code to not introduce the bug in the first place.
- Two dev_dbg messages were changed to dev_info for testing. Changed back
  to dev_dbg.

The patched driver can be downloaded as stand-alone driver from
	http://www.roeck-us.net/linux/drivers/w83627ehf/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [lm-sensors] [PATCH v5 01/11] hwmon: (w83627ehf) Unify temperature
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
@ 2011-03-04 17:57   ` Guenter Roeck
  -1 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:57 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

This patch unifies temperature register access, and replaces simple_strtoXXX
with strict_strtoXXX throughout the driver.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/w83627ehf.c |  219 +++++++++++++++++++++++----------------------
 1 files changed, 113 insertions(+), 106 deletions(-)

diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 073eabe..66e6855 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -164,13 +164,10 @@ static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
 #define W83627EHF_REG_IN(nr)		((nr < 7) ? (0x20 + (nr)) : \
 					 (0x550 + (nr) - 7))
 
-#define W83627EHF_REG_TEMP1		0x27
-#define W83627EHF_REG_TEMP1_HYST	0x3a
-#define W83627EHF_REG_TEMP1_OVER	0x39
-static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
-static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
-static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
-static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
+static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250 };
+static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253 };
+static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255 };
+static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252 };
 
 /* Fan clock dividers are spread over the following five registers */
 #define W83627EHF_REG_FANDIV1		0x47
@@ -216,6 +213,15 @@ static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
 static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
 static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c };
 
+static inline int is_word_sized(u16 reg)
+{
+	return (((reg & 0xff00) = 0x100
+	      || (reg & 0xff00) = 0x200)
+	     && ((reg & 0x00ff) = 0x50
+	      || (reg & 0x00ff) = 0x53
+	      || (reg & 0x00ff) = 0x55));
+}
+
 /*
  * Conversions
  */
@@ -247,21 +253,19 @@ div_from_reg(u8 reg)
 }
 
 static inline int
-temp1_from_reg(s8 reg)
+temp_from_reg(u16 reg, s16 regval)
 {
-	return reg * 1000;
+	if (is_word_sized(reg))
+		return LM75_TEMP_FROM_REG(regval);
+	return regval * 1000;
 }
 
-static inline s8
-temp1_to_reg(long temp, int min, int max)
+static inline s16
+temp_to_reg(u16 reg, long temp)
 {
-	if (temp <= min)
-		return min / 1000;
-	if (temp >= max)
-		return max / 1000;
-	if (temp < 0)
-		return (temp - 500) / 1000;
-	return (temp + 500) / 1000;
+	if (is_word_sized(reg))
+		return LM75_TEMP_TO_REG(temp);
+	return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000), 1000);
 }
 
 /* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
@@ -308,12 +312,9 @@ struct w83627ehf_data {
 	u8 fan_div[5];
 	u8 has_fan;		/* some fan inputs can be disabled */
 	u8 temp_type[3];
-	s8 temp1;
-	s8 temp1_max;
-	s8 temp1_max_hyst;
-	s16 temp[2];
-	s16 temp_max[2];
-	s16 temp_max_hyst[2];
+	s16 temp[3];
+	s16 temp_max[3];
+	s16 temp_max_hyst[3];
 	u32 alarms;
 
 	u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
@@ -344,15 +345,6 @@ struct w83627ehf_sio_data {
 	enum kinds kind;
 };
 
-static inline int is_word_sized(u16 reg)
-{
-	return (((reg & 0xff00) = 0x100
-	      || (reg & 0xff00) = 0x200)
-	     && ((reg & 0x00ff) = 0x50
-	      || (reg & 0x00ff) = 0x53
-	      || (reg & 0x00ff) = 0x55));
-}
-
 /* Registers 0x50-0x5f are banked */
 static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
 {
@@ -586,13 +578,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 		}
 
 		/* Measured temperatures and limits */
-		data->temp1 = w83627ehf_read_value(data,
-			      W83627EHF_REG_TEMP1);
-		data->temp1_max = w83627ehf_read_value(data,
-				  W83627EHF_REG_TEMP1_OVER);
-		data->temp1_max_hyst = w83627ehf_read_value(data,
-				       W83627EHF_REG_TEMP1_HYST);
-		for (i = 0; i < 2; i++) {
+		for (i = 0; i < 3; i++) {
 			data->temp[i] = w83627ehf_read_value(data,
 					W83627EHF_REG_TEMP[i]);
 			data->temp_max[i] = w83627ehf_read_value(data,
@@ -641,8 +627,11 @@ store_in_##reg (struct device *dev, struct device_attribute *attr, \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
-	u32 val = simple_strtoul(buf, NULL, 10); \
- \
+	unsigned long val; \
+	int err; \
+	err = strict_strtoul(buf, 10, &val); \
+	if (err < 0) \
+		return err; \
 	mutex_lock(&data->update_lock); \
 	data->in_##reg[nr] = in_to_reg(val, nr); \
 	w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
@@ -746,10 +735,15 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	unsigned int val = simple_strtoul(buf, NULL, 10);
+	unsigned long val;
+	int err;
 	unsigned int reg;
 	u8 new_div;
 
+	err = strict_strtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
 	mutex_lock(&data->update_lock);
 	if (!val) {
 		/* No min limit, alarm disabled */
@@ -761,14 +755,14 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 		   even with the highest divider (128) */
 		data->fan_min[nr] = 254;
 		new_div = 7; /* 128 = (1 << 7) */
-		dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
+		dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
 			 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
 	} else if (!reg) {
 		/* Speed above this value cannot possibly be represented,
 		   even with the lowest divider (1) */
 		data->fan_min[nr] = 1;
 		new_div = 0; /* 1 = (1 << 0) */
-		dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
+		dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
 			 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
 	} else {
 		/* Automatically pick the best divider, i.e. the one such
@@ -847,37 +841,7 @@ static struct sensor_device_attribute sda_fan_div[] = {
 	SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
 };
 
-#define show_temp1_reg(reg) \
-static ssize_t \
-show_##reg(struct device *dev, struct device_attribute *attr, \
-	   char *buf) \
-{ \
-	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
-}
-show_temp1_reg(temp1);
-show_temp1_reg(temp1_max);
-show_temp1_reg(temp1_max_hyst);
-
-#define store_temp1_reg(REG, reg) \
-static ssize_t \
-store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
-		  const char *buf, size_t count) \
-{ \
-	struct w83627ehf_data *data = dev_get_drvdata(dev); \
-	long val = simple_strtol(buf, NULL, 10); \
- \
-	mutex_lock(&data->update_lock); \
-	data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
-	w83627ehf_write_value(data, W83627EHF_REG_TEMP1_##REG, \
-			      data->temp1_##reg); \
-	mutex_unlock(&data->update_lock); \
-	return count; \
-}
-store_temp1_reg(OVER, max);
-store_temp1_reg(HYST, max_hyst);
-
-#define show_temp_reg(reg) \
+#define show_temp_reg(REG, reg) \
 static ssize_t \
 show_##reg(struct device *dev, struct device_attribute *attr, \
 	   char *buf) \
@@ -886,11 +850,11 @@ show_##reg(struct device *dev, struct device_attribute *attr, \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", \
-		       LM75_TEMP_FROM_REG(data->reg[nr])); \
+		       temp_from_reg(W83627EHF_REG_##REG[nr], data->reg[nr])); \
 }
-show_temp_reg(temp);
-show_temp_reg(temp_max);
-show_temp_reg(temp_max_hyst);
+show_temp_reg(TEMP, temp);
+show_temp_reg(TEMP_OVER, temp_max);
+show_temp_reg(TEMP_HYST, temp_max_hyst);
 
 #define store_temp_reg(REG, reg) \
 static ssize_t \
@@ -900,10 +864,13 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
-	long val = simple_strtol(buf, NULL, 10); \
- \
+	int err; \
+	long val; \
+	err = strict_strtol(buf, 10, &val); \
+	if (err < 0) \
+		return err; \
 	mutex_lock(&data->update_lock); \
-	data->reg[nr] = LM75_TEMP_TO_REG(val); \
+	data->reg[nr] = temp_to_reg(W83627EHF_REG_TEMP_##REG[nr], val); \
 	w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
 			      data->reg[nr]); \
 	mutex_unlock(&data->update_lock); \
@@ -922,27 +889,27 @@ show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
 }
 
 static struct sensor_device_attribute sda_temp_input[] = {
-	SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
-	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
-	SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
+	SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
+	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
+	SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
 };
 
 static struct sensor_device_attribute sda_temp_max[] = {
-	SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
-		    store_temp1_max, 0),
-	SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
+	SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp_max,
 		    store_temp_max, 0),
-	SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
+	SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
 		    store_temp_max, 1),
+	SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 2),
 };
 
 static struct sensor_device_attribute sda_temp_max_hyst[] = {
-	SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
-		    store_temp1_max_hyst, 0),
-	SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+	SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
 		    store_temp_max_hyst, 0),
-	SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+	SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
 		    store_temp_max_hyst, 1),
+	SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 2),
 };
 
 static struct sensor_device_attribute sda_temp_alarm[] = {
@@ -978,9 +945,14 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	u32 val = simple_strtoul(buf, NULL, 10);
+	unsigned long val;
+	int err;
 	u16 reg;
 
+	err = strict_strtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
 	if (val > 1)
 		return -EINVAL;
 	mutex_lock(&data->update_lock);
@@ -1001,7 +973,14 @@ store_pwm(struct device *dev, struct device_attribute *attr,
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
+	unsigned long val;
+	int err;
+
+	err = strict_strtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = SENSORS_LIMIT(val, 0, 255);
 
 	mutex_lock(&data->update_lock);
 	data->pwm[nr] = val;
@@ -1017,9 +996,14 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	u32 val = simple_strtoul(buf, NULL, 10);
+	unsigned long val;
+	int err;
 	u16 reg;
 
+	err = strict_strtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
 	if (!val || (val > 4))
 		return -EINVAL;
 	mutex_lock(&data->update_lock);
@@ -1040,7 +1024,7 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
-	return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \
+	return sprintf(buf, "%d\n", data->reg[nr] * 1000); \
 }
 
 show_tol_temp(tolerance)
@@ -1053,7 +1037,14 @@ store_target_temp(struct device *dev, struct device_attribute *attr,
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
+	long val;
+	int err;
+
+	err = strict_strtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
 
 	mutex_lock(&data->update_lock);
 	data->target_temp[nr] = val;
@@ -1070,8 +1061,15 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	u16 reg;
+	long val;
+	int err;
+
+	err = strict_strtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
 	/* Limit the temp to 0C - 15C */
-	u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
+	val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
 
 	mutex_lock(&data->update_lock);
 	reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
@@ -1154,7 +1152,12 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
-	u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
+	unsigned long val; \
+	int err; \
+	err = strict_strtoul(buf, 10, &val); \
+	if (err < 0) \
+		return err; \
+	val = SENSORS_LIMIT(val, 1, 255); \
 	mutex_lock(&data->update_lock); \
 	data->reg[nr] = val; \
 	w83627ehf_write_value(data, data->REG_##REG[nr], val); \
@@ -1185,8 +1188,12 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
-	u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
-					data->pwm_mode[nr]); \
+	unsigned long val; \
+	int err; \
+	err = strict_strtoul(buf, 10, &val); \
+	if (err < 0) \
+		return err; \
+	val = step_time_to_reg(val, data->pwm_mode[nr]); \
 	mutex_lock(&data->update_lock); \
 	data->reg[nr] = val; \
 	w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
@@ -1336,10 +1343,10 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
 				      tmp | 0x01);
 
 	/* Enable temp2 and temp3 if needed */
-	for (i = 0; i < 2; i++) {
+	for (i = 1; i < 3; i++) {
 		tmp = w83627ehf_read_value(data,
 					   W83627EHF_REG_TEMP_CONFIG[i]);
-		if ((i = 1) && data->temp3_disable)
+		if ((i = 2) && data->temp3_disable)
 			continue;
 		if (tmp & 0x01)
 			w83627ehf_write_value(data,
@@ -1400,7 +1407,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	/* Check temp3 configuration bit for 667HG */
 	if (sio_data->kind = w83667hg || sio_data->kind = w83667hg_b) {
 		data->temp3_disable = w83627ehf_read_value(data,
-					W83627EHF_REG_TEMP_CONFIG[1]) & 0x01;
+					W83627EHF_REG_TEMP_CONFIG[2]) & 0x01;
 		data->in6_skip = !data->temp3_disable;
 	}
 
-- 
1.7.3.1


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 01/11] hwmon: (w83627ehf) Unify temperature register access, and use strict string conversions
@ 2011-03-04 17:57   ` Guenter Roeck
  0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:57 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

This patch unifies temperature register access, and replaces simple_strtoXXX
with strict_strtoXXX throughout the driver.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/w83627ehf.c |  219 +++++++++++++++++++++++----------------------
 1 files changed, 113 insertions(+), 106 deletions(-)

diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 073eabe..66e6855 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -164,13 +164,10 @@ static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
 #define W83627EHF_REG_IN(nr)		((nr < 7) ? (0x20 + (nr)) : \
 					 (0x550 + (nr) - 7))
 
-#define W83627EHF_REG_TEMP1		0x27
-#define W83627EHF_REG_TEMP1_HYST	0x3a
-#define W83627EHF_REG_TEMP1_OVER	0x39
-static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
-static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
-static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
-static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
+static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250 };
+static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253 };
+static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255 };
+static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252 };
 
 /* Fan clock dividers are spread over the following five registers */
 #define W83627EHF_REG_FANDIV1		0x47
@@ -216,6 +213,15 @@ static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
 static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
 static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c };
 
+static inline int is_word_sized(u16 reg)
+{
+	return (((reg & 0xff00) == 0x100
+	      || (reg & 0xff00) == 0x200)
+	     && ((reg & 0x00ff) == 0x50
+	      || (reg & 0x00ff) == 0x53
+	      || (reg & 0x00ff) == 0x55));
+}
+
 /*
  * Conversions
  */
@@ -247,21 +253,19 @@ div_from_reg(u8 reg)
 }
 
 static inline int
-temp1_from_reg(s8 reg)
+temp_from_reg(u16 reg, s16 regval)
 {
-	return reg * 1000;
+	if (is_word_sized(reg))
+		return LM75_TEMP_FROM_REG(regval);
+	return regval * 1000;
 }
 
-static inline s8
-temp1_to_reg(long temp, int min, int max)
+static inline s16
+temp_to_reg(u16 reg, long temp)
 {
-	if (temp <= min)
-		return min / 1000;
-	if (temp >= max)
-		return max / 1000;
-	if (temp < 0)
-		return (temp - 500) / 1000;
-	return (temp + 500) / 1000;
+	if (is_word_sized(reg))
+		return LM75_TEMP_TO_REG(temp);
+	return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000), 1000);
 }
 
 /* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
@@ -308,12 +312,9 @@ struct w83627ehf_data {
 	u8 fan_div[5];
 	u8 has_fan;		/* some fan inputs can be disabled */
 	u8 temp_type[3];
-	s8 temp1;
-	s8 temp1_max;
-	s8 temp1_max_hyst;
-	s16 temp[2];
-	s16 temp_max[2];
-	s16 temp_max_hyst[2];
+	s16 temp[3];
+	s16 temp_max[3];
+	s16 temp_max_hyst[3];
 	u32 alarms;
 
 	u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
@@ -344,15 +345,6 @@ struct w83627ehf_sio_data {
 	enum kinds kind;
 };
 
-static inline int is_word_sized(u16 reg)
-{
-	return (((reg & 0xff00) == 0x100
-	      || (reg & 0xff00) == 0x200)
-	     && ((reg & 0x00ff) == 0x50
-	      || (reg & 0x00ff) == 0x53
-	      || (reg & 0x00ff) == 0x55));
-}
-
 /* Registers 0x50-0x5f are banked */
 static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
 {
@@ -586,13 +578,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 		}
 
 		/* Measured temperatures and limits */
-		data->temp1 = w83627ehf_read_value(data,
-			      W83627EHF_REG_TEMP1);
-		data->temp1_max = w83627ehf_read_value(data,
-				  W83627EHF_REG_TEMP1_OVER);
-		data->temp1_max_hyst = w83627ehf_read_value(data,
-				       W83627EHF_REG_TEMP1_HYST);
-		for (i = 0; i < 2; i++) {
+		for (i = 0; i < 3; i++) {
 			data->temp[i] = w83627ehf_read_value(data,
 					W83627EHF_REG_TEMP[i]);
 			data->temp_max[i] = w83627ehf_read_value(data,
@@ -641,8 +627,11 @@ store_in_##reg (struct device *dev, struct device_attribute *attr, \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
-	u32 val = simple_strtoul(buf, NULL, 10); \
- \
+	unsigned long val; \
+	int err; \
+	err = strict_strtoul(buf, 10, &val); \
+	if (err < 0) \
+		return err; \
 	mutex_lock(&data->update_lock); \
 	data->in_##reg[nr] = in_to_reg(val, nr); \
 	w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
@@ -746,10 +735,15 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	unsigned int val = simple_strtoul(buf, NULL, 10);
+	unsigned long val;
+	int err;
 	unsigned int reg;
 	u8 new_div;
 
+	err = strict_strtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
 	mutex_lock(&data->update_lock);
 	if (!val) {
 		/* No min limit, alarm disabled */
@@ -761,14 +755,14 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 		   even with the highest divider (128) */
 		data->fan_min[nr] = 254;
 		new_div = 7; /* 128 == (1 << 7) */
-		dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
+		dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
 			 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
 	} else if (!reg) {
 		/* Speed above this value cannot possibly be represented,
 		   even with the lowest divider (1) */
 		data->fan_min[nr] = 1;
 		new_div = 0; /* 1 == (1 << 0) */
-		dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
+		dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
 			 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
 	} else {
 		/* Automatically pick the best divider, i.e. the one such
@@ -847,37 +841,7 @@ static struct sensor_device_attribute sda_fan_div[] = {
 	SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
 };
 
-#define show_temp1_reg(reg) \
-static ssize_t \
-show_##reg(struct device *dev, struct device_attribute *attr, \
-	   char *buf) \
-{ \
-	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
-}
-show_temp1_reg(temp1);
-show_temp1_reg(temp1_max);
-show_temp1_reg(temp1_max_hyst);
-
-#define store_temp1_reg(REG, reg) \
-static ssize_t \
-store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
-		  const char *buf, size_t count) \
-{ \
-	struct w83627ehf_data *data = dev_get_drvdata(dev); \
-	long val = simple_strtol(buf, NULL, 10); \
- \
-	mutex_lock(&data->update_lock); \
-	data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
-	w83627ehf_write_value(data, W83627EHF_REG_TEMP1_##REG, \
-			      data->temp1_##reg); \
-	mutex_unlock(&data->update_lock); \
-	return count; \
-}
-store_temp1_reg(OVER, max);
-store_temp1_reg(HYST, max_hyst);
-
-#define show_temp_reg(reg) \
+#define show_temp_reg(REG, reg) \
 static ssize_t \
 show_##reg(struct device *dev, struct device_attribute *attr, \
 	   char *buf) \
@@ -886,11 +850,11 @@ show_##reg(struct device *dev, struct device_attribute *attr, \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", \
-		       LM75_TEMP_FROM_REG(data->reg[nr])); \
+		       temp_from_reg(W83627EHF_REG_##REG[nr], data->reg[nr])); \
 }
-show_temp_reg(temp);
-show_temp_reg(temp_max);
-show_temp_reg(temp_max_hyst);
+show_temp_reg(TEMP, temp);
+show_temp_reg(TEMP_OVER, temp_max);
+show_temp_reg(TEMP_HYST, temp_max_hyst);
 
 #define store_temp_reg(REG, reg) \
 static ssize_t \
@@ -900,10 +864,13 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
-	long val = simple_strtol(buf, NULL, 10); \
- \
+	int err; \
+	long val; \
+	err = strict_strtol(buf, 10, &val); \
+	if (err < 0) \
+		return err; \
 	mutex_lock(&data->update_lock); \
-	data->reg[nr] = LM75_TEMP_TO_REG(val); \
+	data->reg[nr] = temp_to_reg(W83627EHF_REG_TEMP_##REG[nr], val); \
 	w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
 			      data->reg[nr]); \
 	mutex_unlock(&data->update_lock); \
@@ -922,27 +889,27 @@ show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
 }
 
 static struct sensor_device_attribute sda_temp_input[] = {
-	SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
-	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
-	SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
+	SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
+	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
+	SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
 };
 
 static struct sensor_device_attribute sda_temp_max[] = {
-	SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
-		    store_temp1_max, 0),
-	SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
+	SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp_max,
 		    store_temp_max, 0),
-	SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
+	SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
 		    store_temp_max, 1),
+	SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 2),
 };
 
 static struct sensor_device_attribute sda_temp_max_hyst[] = {
-	SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
-		    store_temp1_max_hyst, 0),
-	SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+	SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
 		    store_temp_max_hyst, 0),
-	SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+	SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
 		    store_temp_max_hyst, 1),
+	SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 2),
 };
 
 static struct sensor_device_attribute sda_temp_alarm[] = {
@@ -978,9 +945,14 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	u32 val = simple_strtoul(buf, NULL, 10);
+	unsigned long val;
+	int err;
 	u16 reg;
 
+	err = strict_strtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
 	if (val > 1)
 		return -EINVAL;
 	mutex_lock(&data->update_lock);
@@ -1001,7 +973,14 @@ store_pwm(struct device *dev, struct device_attribute *attr,
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
+	unsigned long val;
+	int err;
+
+	err = strict_strtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = SENSORS_LIMIT(val, 0, 255);
 
 	mutex_lock(&data->update_lock);
 	data->pwm[nr] = val;
@@ -1017,9 +996,14 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	u32 val = simple_strtoul(buf, NULL, 10);
+	unsigned long val;
+	int err;
 	u16 reg;
 
+	err = strict_strtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
 	if (!val || (val > 4))
 		return -EINVAL;
 	mutex_lock(&data->update_lock);
@@ -1040,7 +1024,7 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
-	return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \
+	return sprintf(buf, "%d\n", data->reg[nr] * 1000); \
 }
 
 show_tol_temp(tolerance)
@@ -1053,7 +1037,14 @@ store_target_temp(struct device *dev, struct device_attribute *attr,
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
+	long val;
+	int err;
+
+	err = strict_strtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
 
 	mutex_lock(&data->update_lock);
 	data->target_temp[nr] = val;
@@ -1070,8 +1061,15 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	u16 reg;
+	long val;
+	int err;
+
+	err = strict_strtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
 	/* Limit the temp to 0C - 15C */
-	u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
+	val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
 
 	mutex_lock(&data->update_lock);
 	reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
@@ -1154,7 +1152,12 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
-	u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
+	unsigned long val; \
+	int err; \
+	err = strict_strtoul(buf, 10, &val); \
+	if (err < 0) \
+		return err; \
+	val = SENSORS_LIMIT(val, 1, 255); \
 	mutex_lock(&data->update_lock); \
 	data->reg[nr] = val; \
 	w83627ehf_write_value(data, data->REG_##REG[nr], val); \
@@ -1185,8 +1188,12 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
-	u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
-					data->pwm_mode[nr]); \
+	unsigned long val; \
+	int err; \
+	err = strict_strtoul(buf, 10, &val); \
+	if (err < 0) \
+		return err; \
+	val = step_time_to_reg(val, data->pwm_mode[nr]); \
 	mutex_lock(&data->update_lock); \
 	data->reg[nr] = val; \
 	w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
@@ -1336,10 +1343,10 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
 				      tmp | 0x01);
 
 	/* Enable temp2 and temp3 if needed */
-	for (i = 0; i < 2; i++) {
+	for (i = 1; i < 3; i++) {
 		tmp = w83627ehf_read_value(data,
 					   W83627EHF_REG_TEMP_CONFIG[i]);
-		if ((i == 1) && data->temp3_disable)
+		if ((i == 2) && data->temp3_disable)
 			continue;
 		if (tmp & 0x01)
 			w83627ehf_write_value(data,
@@ -1400,7 +1407,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	/* Check temp3 configuration bit for 667HG */
 	if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
 		data->temp3_disable = w83627ehf_read_value(data,
-					W83627EHF_REG_TEMP_CONFIG[1]) & 0x01;
+					W83627EHF_REG_TEMP_CONFIG[2]) & 0x01;
 		data->in6_skip = !data->temp3_disable;
 	}
 
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [lm-sensors] [PATCH v5 02/11] hwmon: (w83627ehf) Fixed most
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
@ 2011-03-04 17:57   ` Guenter Roeck
  -1 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:57 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

This cleanup fixes most of the checkpatch warnings and errors in the w83627ehf
driver. Remaining warnings and errors are left untouched on purpose to avoid
making the code less readable.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/w83627ehf.c |  149 +++++++++++++++++++++++++-------------------
 1 files changed, 85 insertions(+), 64 deletions(-)

diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 66e6855..1128eac 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -1,10 +1,10 @@
 /*
     w83627ehf - Driver for the hardware monitoring functionality of
-                the Winbond W83627EHF Super-I/O chip
+		the Winbond W83627EHF Super-I/O chip
     Copyright (C) 2005  Jean Delvare <khali@linux-fr.org>
     Copyright (C) 2006  Yuan Mu (Winbond),
-                        Rudolf Marek <r.marek@assembler.cz>
-                        David Hubbard <david.c.hubbard@gmail.com>
+			Rudolf Marek <r.marek@assembler.cz>
+			David Hubbard <david.c.hubbard@gmail.com>
 			Daniel J Blueman <daniel.blueman@gmail.com>
 
     Shamelessly ripped from the w83627hf driver
@@ -35,7 +35,7 @@
 
     Chip        #vin    #fan    #pwm    #temp  chip IDs       man ID
     w83627ehf   10      5       4       3      0x8850 0x88    0x5ca3
-                                               0x8860 0xa1
+					       0x8860 0xa1
     w83627dhg    9      5       4       3      0xa020 0xc1    0x5ca3
     w83627dhg-p  9      5       4       3      0xb070 0xc1    0x5ca3
     w83667hg     9      5       3       3      0xa510 0xc1    0x5ca3
@@ -61,7 +61,7 @@
 enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b };
 
 /* used to set data->name = w83627ehf_device_names[data->sio_kind] */
-static const char * w83627ehf_device_names[] = {
+static const char * const w83627ehf_device_names[] = {
 	"w83627ehf",
 	"w83627dhg",
 	"w83627dhg",
@@ -80,7 +80,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
  */
 
 #define W83627EHF_LD_HWM	0x0b
-#define W83667HG_LD_VID 	0x0d
+#define W83667HG_LD_VID		0x0d
 
 #define SIO_REG_LDSEL		0x07	/* Logical device select */
 #define SIO_REG_DEVID		0x20	/* Device ID (2 bytes) */
@@ -94,7 +94,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
 #define SIO_W83627EHG_ID	0x8860
 #define SIO_W83627DHG_ID	0xa020
 #define SIO_W83627DHG_P_ID	0xb070
-#define SIO_W83667HG_ID 	0xa510
+#define SIO_W83667HG_ID		0xa510
 #define SIO_W83667HG_B_ID	0xb350
 #define SIO_ID_MASK		0xFFF0
 
@@ -138,7 +138,7 @@ superio_exit(int ioreg)
  * ISA constants
  */
 
-#define IOREGION_ALIGNMENT	~7
+#define IOREGION_ALIGNMENT	(~7)
 #define IOREGION_OFFSET		5
 #define IOREGION_LENGTH		2
 #define ADDR_REG_OFFSET		0
@@ -279,7 +279,8 @@ static inline long in_from_reg(u8 reg, u8 nr)
 
 static inline u8 in_to_reg(u32 val, u8 nr)
 {
-	return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255);
+	return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0,
+			     255);
 }
 
 /*
@@ -321,7 +322,8 @@ struct w83627ehf_data {
 	u8 pwm_enable[4]; /* 1->manual
 			     2->thermal cruise mode (also called SmartFan I)
 			     3->fan speed cruise mode
-			     4->variable thermal cruise (also called SmartFan III) */
+			     4->variable thermal cruise (also called
+				SmartFan III) */
 	u8 pwm_num;		/* number of pwm */
 	u8 pwm[4];
 	u8 target_temp[4];
@@ -384,7 +386,8 @@ static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
 	return res;
 }
 
-static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value)
+static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
+				 u16 value)
 {
 	int word_sized = is_word_sized(reg);
 
@@ -518,7 +521,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 			   time */
 			if (data->fan[i] = 0xff
 			 && data->fan_div[i] < 0x07) {
-			 	dev_dbg(dev, "Increasing fan%d "
+				dev_dbg(dev, "Increasing fan%d "
 					"clock divider from %u to %u\n",
 					i + 1, div_from_reg(data->fan_div[i]),
 					div_from_reg(data->fan_div[i] + 1));
@@ -548,16 +551,16 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 				((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
 				? 0 : 1;
 			data->pwm_enable[i] -					((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
-						& 3) + 1;
+				((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
+				& 3) + 1;
 			data->pwm[i] = w83627ehf_read_value(data,
 						W83627EHF_REG_PWM[i]);
 			data->fan_start_output[i] = w83627ehf_read_value(data,
-						W83627EHF_REG_FAN_START_OUTPUT[i]);
+					W83627EHF_REG_FAN_START_OUTPUT[i]);
 			data->fan_stop_output[i] = w83627ehf_read_value(data,
-						W83627EHF_REG_FAN_STOP_OUTPUT[i]);
+					W83627EHF_REG_FAN_STOP_OUTPUT[i]);
 			data->fan_stop_time[i] = w83627ehf_read_value(data,
-						W83627EHF_REG_FAN_STOP_TIME[i]);
+					W83627EHF_REG_FAN_STOP_TIME[i]);
 
 			if (data->REG_FAN_MAX_OUTPUT[i] != 0xff)
 				data->fan_max_output[i] @@ -611,7 +614,8 @@ show_##reg(struct device *dev, struct device_attribute *attr, \
 	   char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
 }
@@ -621,11 +625,12 @@ show_in_reg(in_max)
 
 #define store_in_reg(REG, reg) \
 static ssize_t \
-store_in_##reg (struct device *dev, struct device_attribute *attr, \
-			const char *buf, size_t count) \
+store_in_##reg(struct device *dev, struct device_attribute *attr, \
+	       const char *buf, size_t count) \
 { \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	unsigned long val; \
 	int err; \
@@ -643,7 +648,8 @@ store_in_##reg (struct device *dev, struct device_attribute *attr, \
 store_in_reg(MIN, min)
 store_in_reg(MAX, max)
 
-static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
 {
 	struct w83627ehf_data *data = w83627ehf_update_device(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
@@ -678,29 +684,29 @@ static struct sensor_device_attribute sda_in_alarm[] = {
 };
 
 static struct sensor_device_attribute sda_in_min[] = {
-       SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
-       SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
-       SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
-       SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
-       SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
-       SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
-       SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
-       SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
-       SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
-       SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
+	SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
+	SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
+	SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
+	SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
+	SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
+	SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
+	SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
+	SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
+	SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
+	SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
 };
 
 static struct sensor_device_attribute sda_in_max[] = {
-       SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
-       SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
-       SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
-       SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
-       SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
-       SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
-       SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
-       SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
-       SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
-       SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
+	SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
+	SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
+	SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
+	SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
+	SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
+	SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
+	SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
+	SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
+	SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
+	SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
 };
 
 #define show_fan_reg(reg) \
@@ -709,7 +715,8 @@ show_##reg(struct device *dev, struct device_attribute *attr, \
 	   char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", \
 		       fan_from_reg(data->reg[nr], \
@@ -847,7 +854,8 @@ show_##reg(struct device *dev, struct device_attribute *attr, \
 	   char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", \
 		       temp_from_reg(W83627EHF_REG_##REG[nr], data->reg[nr])); \
@@ -862,7 +870,8 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
 	    const char *buf, size_t count) \
 { \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	int err; \
 	long val; \
@@ -925,11 +934,12 @@ static struct sensor_device_attribute sda_temp_type[] = {
 };
 
 #define show_pwm_reg(reg) \
-static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
-				char *buf) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+			  char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", data->reg[nr]); \
 }
@@ -1022,7 +1032,8 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
 				char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", data->reg[nr] * 1000); \
 }
@@ -1141,16 +1152,18 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
 		       char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", data->reg[nr]); \
-}\
+} \
 static ssize_t \
 store_##reg(struct device *dev, struct device_attribute *attr, \
 			    const char *buf, size_t count) \
-{\
+{ \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	unsigned long val; \
 	int err; \
@@ -1175,10 +1188,12 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
 				char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", \
-			step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \
+			step_time_from_reg(data->reg[nr], \
+					   data->pwm_mode[nr])); \
 } \
 \
 static ssize_t \
@@ -1186,7 +1201,8 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
 			const char *buf, size_t count) \
 { \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	unsigned long val; \
 	int err; \
@@ -1387,7 +1403,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 		goto exit;
 	}
 
-	if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
+	data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL);
+	if (!data) {
 		err = -ENOMEM;
 		goto exit_release;
 	}
@@ -1508,10 +1525,11 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	w83627ehf_update_fan_div(data);
 
 	/* Register sysfs hooks */
-  	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
-		if ((err = device_create_file(dev,
-			&sda_sf3_arrays[i].dev_attr)))
+	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) {
+		err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr);
+		if (err)
 			goto exit_remove;
+	}
 
 	for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
 		struct sensor_device_attribute *attr @@ -1525,8 +1543,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	/* if fan4 is enabled create the sf3 files for it */
 	if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
 		for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
-			if ((err = device_create_file(dev,
-				&sda_sf3_arrays_fan4[i].dev_attr)))
+			err = device_create_file(dev,
+					&sda_sf3_arrays_fan4[i].dev_attr);
+			if (err)
 				goto exit_remove;
 		}
 
@@ -1696,7 +1715,8 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
 	/* Activate logical device if needed */
 	val = superio_inb(sioaddr, SIO_REG_ENABLE);
 	if (!(val & 0x01)) {
-		pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
+		pr_warn("Forcibly enabling Super-I/O. "
+			"Sensor is probably unusable.\n");
 		superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
 	}
 
@@ -1733,7 +1753,8 @@ static int __init sensors_w83627ehf_init(void)
 	if (err)
 		goto exit;
 
-	if (!(pdev = platform_device_alloc(DRVNAME, address))) {
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
 		err = -ENOMEM;
 		pr_err("Device allocation failed\n");
 		goto exit_unregister;
-- 
1.7.3.1


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 02/11] hwmon: (w83627ehf) Fixed most checkpatch warnings and errors
@ 2011-03-04 17:57   ` Guenter Roeck
  0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:57 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

This cleanup fixes most of the checkpatch warnings and errors in the w83627ehf
driver. Remaining warnings and errors are left untouched on purpose to avoid
making the code less readable.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/w83627ehf.c |  149 +++++++++++++++++++++++++-------------------
 1 files changed, 85 insertions(+), 64 deletions(-)

diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 66e6855..1128eac 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -1,10 +1,10 @@
 /*
     w83627ehf - Driver for the hardware monitoring functionality of
-                the Winbond W83627EHF Super-I/O chip
+		the Winbond W83627EHF Super-I/O chip
     Copyright (C) 2005  Jean Delvare <khali@linux-fr.org>
     Copyright (C) 2006  Yuan Mu (Winbond),
-                        Rudolf Marek <r.marek@assembler.cz>
-                        David Hubbard <david.c.hubbard@gmail.com>
+			Rudolf Marek <r.marek@assembler.cz>
+			David Hubbard <david.c.hubbard@gmail.com>
 			Daniel J Blueman <daniel.blueman@gmail.com>
 
     Shamelessly ripped from the w83627hf driver
@@ -35,7 +35,7 @@
 
     Chip        #vin    #fan    #pwm    #temp  chip IDs       man ID
     w83627ehf   10      5       4       3      0x8850 0x88    0x5ca3
-                                               0x8860 0xa1
+					       0x8860 0xa1
     w83627dhg    9      5       4       3      0xa020 0xc1    0x5ca3
     w83627dhg-p  9      5       4       3      0xb070 0xc1    0x5ca3
     w83667hg     9      5       3       3      0xa510 0xc1    0x5ca3
@@ -61,7 +61,7 @@
 enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b };
 
 /* used to set data->name = w83627ehf_device_names[data->sio_kind] */
-static const char * w83627ehf_device_names[] = {
+static const char * const w83627ehf_device_names[] = {
 	"w83627ehf",
 	"w83627dhg",
 	"w83627dhg",
@@ -80,7 +80,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
  */
 
 #define W83627EHF_LD_HWM	0x0b
-#define W83667HG_LD_VID 	0x0d
+#define W83667HG_LD_VID		0x0d
 
 #define SIO_REG_LDSEL		0x07	/* Logical device select */
 #define SIO_REG_DEVID		0x20	/* Device ID (2 bytes) */
@@ -94,7 +94,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
 #define SIO_W83627EHG_ID	0x8860
 #define SIO_W83627DHG_ID	0xa020
 #define SIO_W83627DHG_P_ID	0xb070
-#define SIO_W83667HG_ID 	0xa510
+#define SIO_W83667HG_ID		0xa510
 #define SIO_W83667HG_B_ID	0xb350
 #define SIO_ID_MASK		0xFFF0
 
@@ -138,7 +138,7 @@ superio_exit(int ioreg)
  * ISA constants
  */
 
-#define IOREGION_ALIGNMENT	~7
+#define IOREGION_ALIGNMENT	(~7)
 #define IOREGION_OFFSET		5
 #define IOREGION_LENGTH		2
 #define ADDR_REG_OFFSET		0
@@ -279,7 +279,8 @@ static inline long in_from_reg(u8 reg, u8 nr)
 
 static inline u8 in_to_reg(u32 val, u8 nr)
 {
-	return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255);
+	return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0,
+			     255);
 }
 
 /*
@@ -321,7 +322,8 @@ struct w83627ehf_data {
 	u8 pwm_enable[4]; /* 1->manual
 			     2->thermal cruise mode (also called SmartFan I)
 			     3->fan speed cruise mode
-			     4->variable thermal cruise (also called SmartFan III) */
+			     4->variable thermal cruise (also called
+				SmartFan III) */
 	u8 pwm_num;		/* number of pwm */
 	u8 pwm[4];
 	u8 target_temp[4];
@@ -384,7 +386,8 @@ static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
 	return res;
 }
 
-static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value)
+static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
+				 u16 value)
 {
 	int word_sized = is_word_sized(reg);
 
@@ -518,7 +521,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 			   time */
 			if (data->fan[i] == 0xff
 			 && data->fan_div[i] < 0x07) {
-			 	dev_dbg(dev, "Increasing fan%d "
+				dev_dbg(dev, "Increasing fan%d "
 					"clock divider from %u to %u\n",
 					i + 1, div_from_reg(data->fan_div[i]),
 					div_from_reg(data->fan_div[i] + 1));
@@ -548,16 +551,16 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 				((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
 				? 0 : 1;
 			data->pwm_enable[i] =
-					((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
-						& 3) + 1;
+				((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
+				& 3) + 1;
 			data->pwm[i] = w83627ehf_read_value(data,
 						W83627EHF_REG_PWM[i]);
 			data->fan_start_output[i] = w83627ehf_read_value(data,
-						W83627EHF_REG_FAN_START_OUTPUT[i]);
+					W83627EHF_REG_FAN_START_OUTPUT[i]);
 			data->fan_stop_output[i] = w83627ehf_read_value(data,
-						W83627EHF_REG_FAN_STOP_OUTPUT[i]);
+					W83627EHF_REG_FAN_STOP_OUTPUT[i]);
 			data->fan_stop_time[i] = w83627ehf_read_value(data,
-						W83627EHF_REG_FAN_STOP_TIME[i]);
+					W83627EHF_REG_FAN_STOP_TIME[i]);
 
 			if (data->REG_FAN_MAX_OUTPUT[i] != 0xff)
 				data->fan_max_output[i] =
@@ -611,7 +614,8 @@ show_##reg(struct device *dev, struct device_attribute *attr, \
 	   char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
 }
@@ -621,11 +625,12 @@ show_in_reg(in_max)
 
 #define store_in_reg(REG, reg) \
 static ssize_t \
-store_in_##reg (struct device *dev, struct device_attribute *attr, \
-			const char *buf, size_t count) \
+store_in_##reg(struct device *dev, struct device_attribute *attr, \
+	       const char *buf, size_t count) \
 { \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	unsigned long val; \
 	int err; \
@@ -643,7 +648,8 @@ store_in_##reg (struct device *dev, struct device_attribute *attr, \
 store_in_reg(MIN, min)
 store_in_reg(MAX, max)
 
-static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+			  char *buf)
 {
 	struct w83627ehf_data *data = w83627ehf_update_device(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
@@ -678,29 +684,29 @@ static struct sensor_device_attribute sda_in_alarm[] = {
 };
 
 static struct sensor_device_attribute sda_in_min[] = {
-       SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
-       SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
-       SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
-       SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
-       SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
-       SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
-       SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
-       SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
-       SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
-       SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
+	SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
+	SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
+	SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
+	SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
+	SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
+	SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
+	SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
+	SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
+	SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
+	SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
 };
 
 static struct sensor_device_attribute sda_in_max[] = {
-       SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
-       SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
-       SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
-       SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
-       SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
-       SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
-       SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
-       SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
-       SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
-       SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
+	SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
+	SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
+	SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
+	SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
+	SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
+	SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
+	SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
+	SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
+	SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
+	SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
 };
 
 #define show_fan_reg(reg) \
@@ -709,7 +715,8 @@ show_##reg(struct device *dev, struct device_attribute *attr, \
 	   char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", \
 		       fan_from_reg(data->reg[nr], \
@@ -847,7 +854,8 @@ show_##reg(struct device *dev, struct device_attribute *attr, \
 	   char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", \
 		       temp_from_reg(W83627EHF_REG_##REG[nr], data->reg[nr])); \
@@ -862,7 +870,8 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
 	    const char *buf, size_t count) \
 { \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	int err; \
 	long val; \
@@ -925,11 +934,12 @@ static struct sensor_device_attribute sda_temp_type[] = {
 };
 
 #define show_pwm_reg(reg) \
-static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
-				char *buf) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+			  char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", data->reg[nr]); \
 }
@@ -1022,7 +1032,8 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
 				char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", data->reg[nr] * 1000); \
 }
@@ -1141,16 +1152,18 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
 		       char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", data->reg[nr]); \
-}\
+} \
 static ssize_t \
 store_##reg(struct device *dev, struct device_attribute *attr, \
 			    const char *buf, size_t count) \
-{\
+{ \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	unsigned long val; \
 	int err; \
@@ -1175,10 +1188,12 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
 				char *buf) \
 { \
 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", \
-			step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \
+			step_time_from_reg(data->reg[nr], \
+					   data->pwm_mode[nr])); \
 } \
 \
 static ssize_t \
@@ -1186,7 +1201,8 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
 			const char *buf, size_t count) \
 { \
 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
-	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+	struct sensor_device_attribute *sensor_attr = \
+		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	unsigned long val; \
 	int err; \
@@ -1387,7 +1403,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 		goto exit;
 	}
 
-	if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
+	data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL);
+	if (!data) {
 		err = -ENOMEM;
 		goto exit_release;
 	}
@@ -1508,10 +1525,11 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	w83627ehf_update_fan_div(data);
 
 	/* Register sysfs hooks */
-  	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
-		if ((err = device_create_file(dev,
-			&sda_sf3_arrays[i].dev_attr)))
+	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) {
+		err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr);
+		if (err)
 			goto exit_remove;
+	}
 
 	for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
 		struct sensor_device_attribute *attr =
@@ -1525,8 +1543,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	/* if fan4 is enabled create the sf3 files for it */
 	if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
 		for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
-			if ((err = device_create_file(dev,
-				&sda_sf3_arrays_fan4[i].dev_attr)))
+			err = device_create_file(dev,
+					&sda_sf3_arrays_fan4[i].dev_attr);
+			if (err)
 				goto exit_remove;
 		}
 
@@ -1696,7 +1715,8 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
 	/* Activate logical device if needed */
 	val = superio_inb(sioaddr, SIO_REG_ENABLE);
 	if (!(val & 0x01)) {
-		pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
+		pr_warn("Forcibly enabling Super-I/O. "
+			"Sensor is probably unusable.\n");
 		superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
 	}
 
@@ -1733,7 +1753,8 @@ static int __init sensors_w83627ehf_init(void)
 	if (err)
 		goto exit;
 
-	if (!(pdev = platform_device_alloc(DRVNAME, address))) {
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
 		err = -ENOMEM;
 		pr_err("Device allocation failed\n");
 		goto exit_unregister;
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [lm-sensors] [PATCH v5 03/11] hwmon: (w83627ehf) Optimize
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
@ 2011-03-04 17:57   ` Guenter Roeck
  -1 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:57 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

Assume that each register is banked, and set the bank for each access.
Cache the bank number so it only needs to be set if it changes.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/w83627ehf.c |   26 +++++++++++---------------
 1 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 1128eac..5a627b9 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -304,6 +304,7 @@ struct w83627ehf_data {
 	unsigned long last_updated;	/* In jiffies */
 
 	/* Register values */
+	u8 bank;		/* current register bank */
 	u8 in_num;		/* number of in inputs we have */
 	u8 in[10];		/* Register value */
 	u8 in_max[10];		/* Register value */
@@ -347,21 +348,19 @@ struct w83627ehf_sio_data {
 	enum kinds kind;
 };
 
-/* Registers 0x50-0x5f are banked */
+/*
+ * On older chips, only registers 0x50-0x5f are banked.
+ * On more recent chips, all registers are banked.
+ * Assume that is the case and set the bank number for each access.
+ * Cache the bank number so it only needs to be set if it changes.
+ */
 static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
 {
-	if ((reg & 0x00f0) = 0x50) {
-		outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
-		outb_p(reg >> 8, data->addr + DATA_REG_OFFSET);
-	}
-}
-
-/* Not strictly necessary, but play it safe for now */
-static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg)
-{
-	if (reg & 0xff00) {
+	u8 bank = reg >> 8;
+	if (data->bank != bank) {
 		outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
-		outb_p(0, data->addr + DATA_REG_OFFSET);
+		outb_p(bank, data->addr + DATA_REG_OFFSET);
+		data->bank = bank;
 	}
 }
 
@@ -379,10 +378,8 @@ static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
 		       data->addr + ADDR_REG_OFFSET);
 		res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
 	}
-	w83627ehf_reset_bank(data, reg);
 
 	mutex_unlock(&data->lock);
-
 	return res;
 }
 
@@ -401,7 +398,6 @@ static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
 		       data->addr + ADDR_REG_OFFSET);
 	}
 	outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
-	w83627ehf_reset_bank(data, reg);
 
 	mutex_unlock(&data->lock);
 	return 0;
-- 
1.7.3.1


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 03/11] hwmon: (w83627ehf) Optimize multi-bank register access
@ 2011-03-04 17:57   ` Guenter Roeck
  0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:57 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

Assume that each register is banked, and set the bank for each access.
Cache the bank number so it only needs to be set if it changes.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/w83627ehf.c |   26 +++++++++++---------------
 1 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 1128eac..5a627b9 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -304,6 +304,7 @@ struct w83627ehf_data {
 	unsigned long last_updated;	/* In jiffies */
 
 	/* Register values */
+	u8 bank;		/* current register bank */
 	u8 in_num;		/* number of in inputs we have */
 	u8 in[10];		/* Register value */
 	u8 in_max[10];		/* Register value */
@@ -347,21 +348,19 @@ struct w83627ehf_sio_data {
 	enum kinds kind;
 };
 
-/* Registers 0x50-0x5f are banked */
+/*
+ * On older chips, only registers 0x50-0x5f are banked.
+ * On more recent chips, all registers are banked.
+ * Assume that is the case and set the bank number for each access.
+ * Cache the bank number so it only needs to be set if it changes.
+ */
 static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
 {
-	if ((reg & 0x00f0) == 0x50) {
-		outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
-		outb_p(reg >> 8, data->addr + DATA_REG_OFFSET);
-	}
-}
-
-/* Not strictly necessary, but play it safe for now */
-static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg)
-{
-	if (reg & 0xff00) {
+	u8 bank = reg >> 8;
+	if (data->bank != bank) {
 		outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
-		outb_p(0, data->addr + DATA_REG_OFFSET);
+		outb_p(bank, data->addr + DATA_REG_OFFSET);
+		data->bank = bank;
 	}
 }
 
@@ -379,10 +378,8 @@ static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
 		       data->addr + ADDR_REG_OFFSET);
 		res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
 	}
-	w83627ehf_reset_bank(data, reg);
 
 	mutex_unlock(&data->lock);
-
 	return res;
 }
 
@@ -401,7 +398,6 @@ static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
 		       data->addr + ADDR_REG_OFFSET);
 	}
 	outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
-	w83627ehf_reset_bank(data, reg);
 
 	mutex_unlock(&data->lock);
 	return 0;
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [lm-sensors] [PATCH v5 04/11] hwmon: (w83627ehf) Improve support
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
@ 2011-03-04 17:57   ` Guenter Roeck
  -1 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:57 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

Add support for 4th temperature sensor on W83677HG-B.
Display temperature labels on W83677HG-B to report temperature sources.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 Documentation/hwmon/w83627ehf |   19 +++--
 drivers/hwmon/w83627ehf.c     |  155 ++++++++++++++++++++++++++++++++--------
 2 files changed, 136 insertions(+), 38 deletions(-)

diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf
index 13d5561..0643019 100644
--- a/Documentation/hwmon/w83627ehf
+++ b/Documentation/hwmon/w83627ehf
@@ -39,16 +39,21 @@ This driver implements support for the Winbond W83627EHF, W83627EHG,
 W83627DHG, W83627DHG-P, W83667HG and W83667HG-B super I/O chips.
 We will refer to them collectively as Winbond chips.
 
-The chips implement three temperature sensors, five fan rotation
-speed sensors, ten analog voltage sensors (only nine for the 627DHG), one
-VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG and 667HG), alarms
-with beep warnings (control unimplemented), and some automatic fan
+The chips implement three temperature sensors (up to four for 667HG-B),
+five fan rotation speed sensors, ten analog voltage sensors (only nine for the
+627DHG), one VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG and 667HG),
+alarms with beep warnings (control unimplemented), and some automatic fan
 regulation strategies (plus manual fan control mode).
 
+The temperature sensor sources on W82677HG-B are configurable. temp4 is only
+reported if its temperature source differs from the temperature sources of the
+other three temperature sensors. The configured source for each of the
+temperature sensors is reported in tempX_label.
+
 Temperatures are measured in degrees Celsius and measurement resolution is 1
-degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
-the temperature gets higher than high limit; it stays on until the temperature
-falls below the hysteresis value.
+degC for temp1 and temp4, and 0.5 degC for temp2 and temp3. An alarm is
+triggered when the temperature gets higher than high limit; it stays on until
+the temperature falls below the hysteresis value.
 
 Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
 triggered if the rotation speed has dropped below a programmable limit. Fan
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 5a627b9..d10fe70 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -39,7 +39,7 @@
     w83627dhg    9      5       4       3      0xa020 0xc1    0x5ca3
     w83627dhg-p  9      5       4       3      0xb070 0xc1    0x5ca3
     w83667hg     9      5       3       3      0xa510 0xc1    0x5ca3
-    w83667hg-b   9      5       3       3      0xb350 0xc1    0x5ca3
+    w83667hg-b   9      5       3       4      0xb350 0xc1    0x5ca3
 */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -164,10 +164,10 @@ static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
 #define W83627EHF_REG_IN(nr)		((nr < 7) ? (0x20 + (nr)) : \
 					 (0x550 + (nr) - 7))
 
-static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250 };
-static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253 };
-static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255 };
-static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252 };
+static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250, 0x7e };
+static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253, 0 };
+static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255, 0 };
+static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 };
 
 /* Fan clock dividers are spread over the following five registers */
 #define W83627EHF_REG_FANDIV1		0x47
@@ -213,6 +213,19 @@ static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
 static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
 static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c };
 
+static const char *const w83667hg_b_temp_label[] = {
+	"SYSTIN",
+	"CPUTIN",
+	"AUXTIN",
+	"AMDTSI",
+	"PECI Agent 1",
+	"PECI Agent 2",
+	"PECI Agent 3",
+	"PECI Agent 4"
+};
+
+#define NUM_REG_TEMP	4
+
 static inline int is_word_sized(u16 reg)
 {
 	return (((reg & 0xff00) = 0x100
@@ -294,6 +307,9 @@ struct w83627ehf_data {
 	struct device *hwmon_dev;
 	struct mutex lock;
 
+	u8 temp_src[NUM_REG_TEMP];
+	const char * const *temp_label;
+
 	const u8 *REG_FAN_START_OUTPUT;
 	const u8 *REG_FAN_STOP_OUTPUT;
 	const u8 *REG_FAN_MAX_OUTPUT;
@@ -314,9 +330,9 @@ struct w83627ehf_data {
 	u8 fan_div[5];
 	u8 has_fan;		/* some fan inputs can be disabled */
 	u8 temp_type[3];
-	s16 temp[3];
-	s16 temp_max[3];
-	s16 temp_max_hyst[3];
+	s16 temp[4];
+	s16 temp_max[4];
+	s16 temp_max_hyst[4];
 	u32 alarms;
 
 	u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
@@ -339,7 +355,7 @@ struct w83627ehf_data {
 	u8 vid;
 	u8 vrm;
 
-	u8 temp3_disable;
+	u8 have_temp;
 	u8 in6_skip;
 };
 
@@ -577,12 +593,18 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 		}
 
 		/* Measured temperatures and limits */
-		for (i = 0; i < 3; i++) {
-			data->temp[i] = w83627ehf_read_value(data,
-					W83627EHF_REG_TEMP[i]);
-			data->temp_max[i] = w83627ehf_read_value(data,
-					    W83627EHF_REG_TEMP_OVER[i]);
-			data->temp_max_hyst[i] = w83627ehf_read_value(data,
+		for (i = 0; i < NUM_REG_TEMP; i++) {
+			if (!(data->have_temp & (1 << i)))
+				continue;
+			data->temp[i]
+			  = w83627ehf_read_value(data, W83627EHF_REG_TEMP[i]);
+			if (i > 2)
+				break;
+			data->temp_max[i]
+			  = w83627ehf_read_value(data,
+						 W83627EHF_REG_TEMP_OVER[i]);
+			data->temp_max_hyst[i]
+			  = w83627ehf_read_value(data,
 						 W83627EHF_REG_TEMP_HYST[i]);
 		}
 
@@ -844,6 +866,15 @@ static struct sensor_device_attribute sda_fan_div[] = {
 	SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
 };
 
+static ssize_t
+show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
+}
+
 #define show_temp_reg(REG, reg) \
 static ssize_t \
 show_##reg(struct device *dev, struct device_attribute *attr, \
@@ -897,6 +928,14 @@ static struct sensor_device_attribute sda_temp_input[] = {
 	SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
 	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
 	SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
+	SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3),
+};
+
+static struct sensor_device_attribute sda_temp_label[] = {
+	SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0),
+	SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
+	SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
+	SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
 };
 
 static struct sensor_device_attribute sda_temp_max[] = {
@@ -1328,10 +1367,13 @@ static void w83627ehf_device_remove_files(struct device *dev)
 		device_remove_file(dev, &sda_target_temp[i].dev_attr);
 		device_remove_file(dev, &sda_tolerance[i].dev_attr);
 	}
-	for (i = 0; i < 3; i++) {
-		if ((i = 2) && data->temp3_disable)
+	for (i = 0; i < NUM_REG_TEMP; i++) {
+		if (!(data->have_temp & (1 << i)))
 			continue;
 		device_remove_file(dev, &sda_temp_input[i].dev_attr);
+		device_remove_file(dev, &sda_temp_label[i].dev_attr);
+		if (i > 2)
+			break;
 		device_remove_file(dev, &sda_temp_max[i].dev_attr);
 		device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
 		device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
@@ -1354,12 +1396,14 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
 		w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
 				      tmp | 0x01);
 
-	/* Enable temp2 and temp3 if needed */
-	for (i = 1; i < 3; i++) {
+	/* Enable temperature sensors if needed */
+	for (i = 0; i < NUM_REG_TEMP; i++) {
+		if (!(data->have_temp & (1 << i)))
+			continue;
+		if (!W83627EHF_REG_TEMP_CONFIG[i])
+			continue;
 		tmp = w83627ehf_read_value(data,
 					   W83627EHF_REG_TEMP_CONFIG[i]);
-		if ((i = 2) && data->temp3_disable)
-			continue;
 		if (tmp & 0x01)
 			w83627ehf_write_value(data,
 					      W83627EHF_REG_TEMP_CONFIG[i],
@@ -1417,11 +1461,52 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	data->pwm_num = (sio_data->kind = w83667hg
 			 || sio_data->kind = w83667hg_b) ? 3 : 4;
 
+	data->have_temp = 0x07;
 	/* Check temp3 configuration bit for 667HG */
-	if (sio_data->kind = w83667hg || sio_data->kind = w83667hg_b) {
-		data->temp3_disable = w83627ehf_read_value(data,
-					W83627EHF_REG_TEMP_CONFIG[2]) & 0x01;
-		data->in6_skip = !data->temp3_disable;
+	if (sio_data->kind = w83667hg) {
+		u8 reg;
+
+		reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
+		if (reg & 0x01)
+			data->have_temp &= ~(1 << 2);
+		else
+			data->in6_skip = 1; /* Either temp3 or in6 */
+	} else if (sio_data->kind = w83667hg_b) {
+		u8 reg;
+
+		reg = w83627ehf_read_value(data, 0x4a);
+		data->temp_src[0] = reg >> 5;
+		reg = w83627ehf_read_value(data, 0x49);
+		data->temp_src[1] = reg & 0x07;
+		data->temp_src[2] = (reg >> 4)  & 0x07;
+
+		/*
+		 * W83667HG-B has another temperature register at 0x7e.
+		 * The temperature source is selected with register 0x7d.
+		 * Support it if the source differs from already reported
+		 * sources.
+		 */
+		reg = w83627ehf_read_value(data, 0x7d);
+		reg &= 0x07;
+		if (reg != data->temp_src[0] && reg != data->temp_src[1]
+		    && reg != data->temp_src[2]) {
+			data->temp_src[3] = reg;
+			data->have_temp |= 1 << 3;
+		}
+
+		/*
+		 * Chip supports either AUXTIN or VIN3. Try to find out which
+		 * one.
+		 */
+		reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
+		if (data->temp_src[2] = 2 && (reg & 0x01))
+			data->have_temp &= ~(1 << 2);
+
+		if ((data->temp_src[2] = 2 && (data->have_temp & (1 << 2)))
+		    || (data->temp_src[3] = 2 && (data->have_temp & (1 << 3))))
+			data->in6_skip = 1;
+
+		data->temp_label = w83667hg_b_temp_label;
 	}
 
 	data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
@@ -1584,13 +1669,21 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 		}
 	}
 
-	for (i = 0; i < 3; i++) {
-		if ((i = 2) && data->temp3_disable)
+	for (i = 0; i < NUM_REG_TEMP; i++) {
+		if (!(data->have_temp & (1 << i)))
 			continue;
-		if ((err = device_create_file(dev,
-				&sda_temp_input[i].dev_attr))
-			|| (err = device_create_file(dev,
-				&sda_temp_max[i].dev_attr))
+		err = device_create_file(dev, &sda_temp_input[i].dev_attr);
+		if (err)
+			goto exit_remove;
+		if (data->temp_label) {
+			err = device_create_file(dev,
+						 &sda_temp_label[i].dev_attr);
+			if (err)
+				goto exit_remove;
+		}
+		if (i > 2)
+			break;
+		if ((err = device_create_file(dev, &sda_temp_max[i].dev_attr))
 			|| (err = device_create_file(dev,
 				&sda_temp_max_hyst[i].dev_attr))
 			|| (err = device_create_file(dev,
-- 
1.7.3.1


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 04/11] hwmon: (w83627ehf) Improve support for W83667HG-B
@ 2011-03-04 17:57   ` Guenter Roeck
  0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:57 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

Add support for 4th temperature sensor on W83677HG-B.
Display temperature labels on W83677HG-B to report temperature sources.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 Documentation/hwmon/w83627ehf |   19 +++--
 drivers/hwmon/w83627ehf.c     |  155 ++++++++++++++++++++++++++++++++--------
 2 files changed, 136 insertions(+), 38 deletions(-)

diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf
index 13d5561..0643019 100644
--- a/Documentation/hwmon/w83627ehf
+++ b/Documentation/hwmon/w83627ehf
@@ -39,16 +39,21 @@ This driver implements support for the Winbond W83627EHF, W83627EHG,
 W83627DHG, W83627DHG-P, W83667HG and W83667HG-B super I/O chips.
 We will refer to them collectively as Winbond chips.
 
-The chips implement three temperature sensors, five fan rotation
-speed sensors, ten analog voltage sensors (only nine for the 627DHG), one
-VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG and 667HG), alarms
-with beep warnings (control unimplemented), and some automatic fan
+The chips implement three temperature sensors (up to four for 667HG-B),
+five fan rotation speed sensors, ten analog voltage sensors (only nine for the
+627DHG), one VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG and 667HG),
+alarms with beep warnings (control unimplemented), and some automatic fan
 regulation strategies (plus manual fan control mode).
 
+The temperature sensor sources on W82677HG-B are configurable. temp4 is only
+reported if its temperature source differs from the temperature sources of the
+other three temperature sensors. The configured source for each of the
+temperature sensors is reported in tempX_label.
+
 Temperatures are measured in degrees Celsius and measurement resolution is 1
-degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
-the temperature gets higher than high limit; it stays on until the temperature
-falls below the hysteresis value.
+degC for temp1 and temp4, and 0.5 degC for temp2 and temp3. An alarm is
+triggered when the temperature gets higher than high limit; it stays on until
+the temperature falls below the hysteresis value.
 
 Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
 triggered if the rotation speed has dropped below a programmable limit. Fan
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 5a627b9..d10fe70 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -39,7 +39,7 @@
     w83627dhg    9      5       4       3      0xa020 0xc1    0x5ca3
     w83627dhg-p  9      5       4       3      0xb070 0xc1    0x5ca3
     w83667hg     9      5       3       3      0xa510 0xc1    0x5ca3
-    w83667hg-b   9      5       3       3      0xb350 0xc1    0x5ca3
+    w83667hg-b   9      5       3       4      0xb350 0xc1    0x5ca3
 */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -164,10 +164,10 @@ static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
 #define W83627EHF_REG_IN(nr)		((nr < 7) ? (0x20 + (nr)) : \
 					 (0x550 + (nr) - 7))
 
-static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250 };
-static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253 };
-static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255 };
-static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252 };
+static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250, 0x7e };
+static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253, 0 };
+static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255, 0 };
+static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 };
 
 /* Fan clock dividers are spread over the following five registers */
 #define W83627EHF_REG_FANDIV1		0x47
@@ -213,6 +213,19 @@ static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
 static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
 static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c };
 
+static const char *const w83667hg_b_temp_label[] = {
+	"SYSTIN",
+	"CPUTIN",
+	"AUXTIN",
+	"AMDTSI",
+	"PECI Agent 1",
+	"PECI Agent 2",
+	"PECI Agent 3",
+	"PECI Agent 4"
+};
+
+#define NUM_REG_TEMP	4
+
 static inline int is_word_sized(u16 reg)
 {
 	return (((reg & 0xff00) == 0x100
@@ -294,6 +307,9 @@ struct w83627ehf_data {
 	struct device *hwmon_dev;
 	struct mutex lock;
 
+	u8 temp_src[NUM_REG_TEMP];
+	const char * const *temp_label;
+
 	const u8 *REG_FAN_START_OUTPUT;
 	const u8 *REG_FAN_STOP_OUTPUT;
 	const u8 *REG_FAN_MAX_OUTPUT;
@@ -314,9 +330,9 @@ struct w83627ehf_data {
 	u8 fan_div[5];
 	u8 has_fan;		/* some fan inputs can be disabled */
 	u8 temp_type[3];
-	s16 temp[3];
-	s16 temp_max[3];
-	s16 temp_max_hyst[3];
+	s16 temp[4];
+	s16 temp_max[4];
+	s16 temp_max_hyst[4];
 	u32 alarms;
 
 	u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
@@ -339,7 +355,7 @@ struct w83627ehf_data {
 	u8 vid;
 	u8 vrm;
 
-	u8 temp3_disable;
+	u8 have_temp;
 	u8 in6_skip;
 };
 
@@ -577,12 +593,18 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 		}
 
 		/* Measured temperatures and limits */
-		for (i = 0; i < 3; i++) {
-			data->temp[i] = w83627ehf_read_value(data,
-					W83627EHF_REG_TEMP[i]);
-			data->temp_max[i] = w83627ehf_read_value(data,
-					    W83627EHF_REG_TEMP_OVER[i]);
-			data->temp_max_hyst[i] = w83627ehf_read_value(data,
+		for (i = 0; i < NUM_REG_TEMP; i++) {
+			if (!(data->have_temp & (1 << i)))
+				continue;
+			data->temp[i]
+			  = w83627ehf_read_value(data, W83627EHF_REG_TEMP[i]);
+			if (i > 2)
+				break;
+			data->temp_max[i]
+			  = w83627ehf_read_value(data,
+						 W83627EHF_REG_TEMP_OVER[i]);
+			data->temp_max_hyst[i]
+			  = w83627ehf_read_value(data,
 						 W83627EHF_REG_TEMP_HYST[i]);
 		}
 
@@ -844,6 +866,15 @@ static struct sensor_device_attribute sda_fan_div[] = {
 	SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
 };
 
+static ssize_t
+show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
+}
+
 #define show_temp_reg(REG, reg) \
 static ssize_t \
 show_##reg(struct device *dev, struct device_attribute *attr, \
@@ -897,6 +928,14 @@ static struct sensor_device_attribute sda_temp_input[] = {
 	SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
 	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
 	SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
+	SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3),
+};
+
+static struct sensor_device_attribute sda_temp_label[] = {
+	SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0),
+	SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
+	SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
+	SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
 };
 
 static struct sensor_device_attribute sda_temp_max[] = {
@@ -1328,10 +1367,13 @@ static void w83627ehf_device_remove_files(struct device *dev)
 		device_remove_file(dev, &sda_target_temp[i].dev_attr);
 		device_remove_file(dev, &sda_tolerance[i].dev_attr);
 	}
-	for (i = 0; i < 3; i++) {
-		if ((i == 2) && data->temp3_disable)
+	for (i = 0; i < NUM_REG_TEMP; i++) {
+		if (!(data->have_temp & (1 << i)))
 			continue;
 		device_remove_file(dev, &sda_temp_input[i].dev_attr);
+		device_remove_file(dev, &sda_temp_label[i].dev_attr);
+		if (i > 2)
+			break;
 		device_remove_file(dev, &sda_temp_max[i].dev_attr);
 		device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
 		device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
@@ -1354,12 +1396,14 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
 		w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
 				      tmp | 0x01);
 
-	/* Enable temp2 and temp3 if needed */
-	for (i = 1; i < 3; i++) {
+	/* Enable temperature sensors if needed */
+	for (i = 0; i < NUM_REG_TEMP; i++) {
+		if (!(data->have_temp & (1 << i)))
+			continue;
+		if (!W83627EHF_REG_TEMP_CONFIG[i])
+			continue;
 		tmp = w83627ehf_read_value(data,
 					   W83627EHF_REG_TEMP_CONFIG[i]);
-		if ((i == 2) && data->temp3_disable)
-			continue;
 		if (tmp & 0x01)
 			w83627ehf_write_value(data,
 					      W83627EHF_REG_TEMP_CONFIG[i],
@@ -1417,11 +1461,52 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	data->pwm_num = (sio_data->kind == w83667hg
 			 || sio_data->kind == w83667hg_b) ? 3 : 4;
 
+	data->have_temp = 0x07;
 	/* Check temp3 configuration bit for 667HG */
-	if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
-		data->temp3_disable = w83627ehf_read_value(data,
-					W83627EHF_REG_TEMP_CONFIG[2]) & 0x01;
-		data->in6_skip = !data->temp3_disable;
+	if (sio_data->kind == w83667hg) {
+		u8 reg;
+
+		reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
+		if (reg & 0x01)
+			data->have_temp &= ~(1 << 2);
+		else
+			data->in6_skip = 1; /* Either temp3 or in6 */
+	} else if (sio_data->kind == w83667hg_b) {
+		u8 reg;
+
+		reg = w83627ehf_read_value(data, 0x4a);
+		data->temp_src[0] = reg >> 5;
+		reg = w83627ehf_read_value(data, 0x49);
+		data->temp_src[1] = reg & 0x07;
+		data->temp_src[2] = (reg >> 4)  & 0x07;
+
+		/*
+		 * W83667HG-B has another temperature register at 0x7e.
+		 * The temperature source is selected with register 0x7d.
+		 * Support it if the source differs from already reported
+		 * sources.
+		 */
+		reg = w83627ehf_read_value(data, 0x7d);
+		reg &= 0x07;
+		if (reg != data->temp_src[0] && reg != data->temp_src[1]
+		    && reg != data->temp_src[2]) {
+			data->temp_src[3] = reg;
+			data->have_temp |= 1 << 3;
+		}
+
+		/*
+		 * Chip supports either AUXTIN or VIN3. Try to find out which
+		 * one.
+		 */
+		reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
+		if (data->temp_src[2] == 2 && (reg & 0x01))
+			data->have_temp &= ~(1 << 2);
+
+		if ((data->temp_src[2] == 2 && (data->have_temp & (1 << 2)))
+		    || (data->temp_src[3] == 2 && (data->have_temp & (1 << 3))))
+			data->in6_skip = 1;
+
+		data->temp_label = w83667hg_b_temp_label;
 	}
 
 	data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
@@ -1584,13 +1669,21 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 		}
 	}
 
-	for (i = 0; i < 3; i++) {
-		if ((i == 2) && data->temp3_disable)
+	for (i = 0; i < NUM_REG_TEMP; i++) {
+		if (!(data->have_temp & (1 << i)))
 			continue;
-		if ((err = device_create_file(dev,
-				&sda_temp_input[i].dev_attr))
-			|| (err = device_create_file(dev,
-				&sda_temp_max[i].dev_attr))
+		err = device_create_file(dev, &sda_temp_input[i].dev_attr);
+		if (err)
+			goto exit_remove;
+		if (data->temp_label) {
+			err = device_create_file(dev,
+						 &sda_temp_label[i].dev_attr);
+			if (err)
+				goto exit_remove;
+		}
+		if (i > 2)
+			break;
+		if ((err = device_create_file(dev, &sda_temp_max[i].dev_attr))
 			|| (err = device_create_file(dev,
 				&sda_temp_max_hyst[i].dev_attr))
 			|| (err = device_create_file(dev,
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [lm-sensors] [PATCH v5 05/11] hwmon: (w83627ehf) Remove references
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
@ 2011-03-04 17:58   ` Guenter Roeck
  -1 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:58 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 Documentation/hwmon/w83627ehf |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf
index 0643019..b634e98 100644
--- a/Documentation/hwmon/w83627ehf
+++ b/Documentation/hwmon/w83627ehf
@@ -5,13 +5,11 @@ Supported chips:
   * Winbond W83627EHF/EHG (ISA access ONLY)
     Prefix: 'w83627ehf'
     Addresses scanned: ISA address retrieved from Super I/O registers
-    Datasheet:
-        http://www.nuvoton.com.tw/NR/rdonlyres/A6A258F0-F0C9-4F97-81C0-C4D29E7E943E/0/W83627EHF.pdf
+    Datasheet: not available
   * Winbond W83627DHG
     Prefix: 'w83627dhg'
     Addresses scanned: ISA address retrieved from Super I/O registers
-    Datasheet:
-        http://www.nuvoton.com.tw/NR/rdonlyres/7885623D-A487-4CF9-A47F-30C5F73D6FE6/0/W83627DHG.pdf
+    Datasheet: not available
   * Winbond W83627DHG-P
     Prefix: 'w83627dhg'
     Addresses scanned: ISA address retrieved from Super I/O registers
-- 
1.7.3.1


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 05/11] hwmon: (w83627ehf) Remove references to datasheets which no longer exist
@ 2011-03-04 17:58   ` Guenter Roeck
  0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:58 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 Documentation/hwmon/w83627ehf |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf
index 0643019..b634e98 100644
--- a/Documentation/hwmon/w83627ehf
+++ b/Documentation/hwmon/w83627ehf
@@ -5,13 +5,11 @@ Supported chips:
   * Winbond W83627EHF/EHG (ISA access ONLY)
     Prefix: 'w83627ehf'
     Addresses scanned: ISA address retrieved from Super I/O registers
-    Datasheet:
-        http://www.nuvoton.com.tw/NR/rdonlyres/A6A258F0-F0C9-4F97-81C0-C4D29E7E943E/0/W83627EHF.pdf
+    Datasheet: not available
   * Winbond W83627DHG
     Prefix: 'w83627dhg'
     Addresses scanned: ISA address retrieved from Super I/O registers
-    Datasheet:
-        http://www.nuvoton.com.tw/NR/rdonlyres/7885623D-A487-4CF9-A47F-30C5F73D6FE6/0/W83627DHG.pdf
+    Datasheet: not available
   * Winbond W83627DHG-P
     Prefix: 'w83627dhg'
     Addresses scanned: ISA address retrieved from Super I/O registers
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [lm-sensors] [PATCH v5 06/11] hwmon: (w83627ehf) Convert register
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
@ 2011-03-04 17:58   ` Guenter Roeck
  -1 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:58 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

For newer chips, several registers are banked and thus need to be 16 bit.
Also, register addresses change.

To prepare for those chips, convert affected register arrays to 16 bit,
and change access to those registers to array pointers in struct w83627ehf_data.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/w83627ehf.c |   60 +++++++++++++++++++++++++++------------------
 1 files changed, 36 insertions(+), 24 deletions(-)

diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index d10fe70..2420f1c 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -196,22 +196,23 @@ static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
 static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
 
 /* FAN Duty Cycle, be used to control */
-static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
-static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
+static const u16 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
+static const u16 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
 static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
 
 /* Advanced Fan control, some values are common for all fans */
-static const u8 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 };
-static const u8 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
-static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 };
+static const u16 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 };
+static const u16 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
+static const u16 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 };
 
-static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[]
+static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[]
 						= { 0xff, 0x67, 0xff, 0x69 };
-static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
+static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
 						= { 0xff, 0x68, 0xff, 0x6a };
 
-static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
-static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c };
+static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
+static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[]
+						= { 0x68, 0x6a, 0x6c };
 
 static const char *const w83667hg_b_temp_label[] = {
 	"SYSTIN",
@@ -310,10 +311,15 @@ struct w83627ehf_data {
 	u8 temp_src[NUM_REG_TEMP];
 	const char * const *temp_label;
 
-	const u8 *REG_FAN_START_OUTPUT;
-	const u8 *REG_FAN_STOP_OUTPUT;
-	const u8 *REG_FAN_MAX_OUTPUT;
-	const u8 *REG_FAN_STEP_OUTPUT;
+	const u16 *REG_PWM;
+	const u16 *REG_TARGET;
+	const u16 *REG_FAN;
+	const u16 *REG_FAN_MIN;
+	const u16 *REG_FAN_START_OUTPUT;
+	const u16 *REG_FAN_STOP_OUTPUT;
+	const u16 *REG_FAN_STOP_TIME;
+	const u16 *REG_FAN_MAX_OUTPUT;
+	const u16 *REG_FAN_STEP_OUTPUT;
 
 	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
@@ -524,9 +530,9 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 				continue;
 
 			data->fan[i] = w83627ehf_read_value(data,
-				       W83627EHF_REG_FAN[i]);
+				       data->REG_FAN[i]);
 			data->fan_min[i] = w83627ehf_read_value(data,
-					   W83627EHF_REG_FAN_MIN[i]);
+					   data->REG_FAN_MIN[i]);
 
 			/* If we failed to measure the fan speed and clock
 			   divider can be increased, let's try that for next
@@ -543,7 +549,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 				if (data->fan_min[i] >= 2
 				 && data->fan_min[i] != 255)
 					w83627ehf_write_value(data,
-						W83627EHF_REG_FAN_MIN[i],
+						data->REG_FAN_MIN[i],
 						(data->fan_min[i] /= 2));
 			}
 		}
@@ -566,13 +572,13 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 				((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
 				& 3) + 1;
 			data->pwm[i] = w83627ehf_read_value(data,
-						W83627EHF_REG_PWM[i]);
+							    data->REG_PWM[i]);
 			data->fan_start_output[i] = w83627ehf_read_value(data,
-					W83627EHF_REG_FAN_START_OUTPUT[i]);
+					data->REG_FAN_START_OUTPUT[i]);
 			data->fan_stop_output[i] = w83627ehf_read_value(data,
-					W83627EHF_REG_FAN_STOP_OUTPUT[i]);
+					data->REG_FAN_STOP_OUTPUT[i]);
 			data->fan_stop_time[i] = w83627ehf_read_value(data,
-					W83627EHF_REG_FAN_STOP_TIME[i]);
+					data->REG_FAN_STOP_TIME[i]);
 
 			if (data->REG_FAN_MAX_OUTPUT[i] != 0xff)
 				data->fan_max_output[i] @@ -586,7 +592,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 
 			data->target_temp[i]  				w83627ehf_read_value(data,
-					W83627EHF_REG_TARGET[i]) &
+					data->REG_TARGET[i]) &
 					(data->pwm_mode[i] = 1 ? 0x7f : 0xff);
 			data->tolerance[i] = (tolerance >> (i = 1 ? 4 : 0))
 									& 0x0f;
@@ -822,7 +828,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 		/* Give the chip time to sample a new speed value */
 		data->last_updated = jiffies;
 	}
-	w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
+	w83627ehf_write_value(data, data->REG_FAN_MIN[nr],
 			      data->fan_min[nr]);
 	mutex_unlock(&data->update_lock);
 
@@ -1029,7 +1035,7 @@ store_pwm(struct device *dev, struct device_attribute *attr,
 
 	mutex_lock(&data->update_lock);
 	data->pwm[nr] = val;
-	w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
+	w83627ehf_write_value(data, data->REG_PWM[nr], val);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -1094,7 +1100,7 @@ store_target_temp(struct device *dev, struct device_attribute *attr,
 
 	mutex_lock(&data->update_lock);
 	data->target_temp[nr] = val;
-	w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
+	w83627ehf_write_value(data, data->REG_TARGET[nr], val);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -1509,8 +1515,14 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 		data->temp_label = w83667hg_b_temp_label;
 	}
 
+	data->REG_PWM = W83627EHF_REG_PWM;
+	data->REG_TARGET = W83627EHF_REG_TARGET;
+	data->REG_FAN = W83627EHF_REG_FAN;
+	data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
 	data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
 	data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
+	data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
+	data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
 	if (sio_data->kind = w83667hg_b) {
 		data->REG_FAN_MAX_OUTPUT  		  W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
-- 
1.7.3.1


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 06/11] hwmon: (w83627ehf) Convert register arrays to 16 bit, and convert access to pointers
@ 2011-03-04 17:58   ` Guenter Roeck
  0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:58 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

For newer chips, several registers are banked and thus need to be 16 bit.
Also, register addresses change.

To prepare for those chips, convert affected register arrays to 16 bit,
and change access to those registers to array pointers in struct w83627ehf_data.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/w83627ehf.c |   60 +++++++++++++++++++++++++++------------------
 1 files changed, 36 insertions(+), 24 deletions(-)

diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index d10fe70..2420f1c 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -196,22 +196,23 @@ static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
 static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
 
 /* FAN Duty Cycle, be used to control */
-static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
-static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
+static const u16 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
+static const u16 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
 static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
 
 /* Advanced Fan control, some values are common for all fans */
-static const u8 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 };
-static const u8 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
-static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 };
+static const u16 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 };
+static const u16 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
+static const u16 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 };
 
-static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[]
+static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[]
 						= { 0xff, 0x67, 0xff, 0x69 };
-static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
+static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
 						= { 0xff, 0x68, 0xff, 0x6a };
 
-static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
-static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c };
+static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
+static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[]
+						= { 0x68, 0x6a, 0x6c };
 
 static const char *const w83667hg_b_temp_label[] = {
 	"SYSTIN",
@@ -310,10 +311,15 @@ struct w83627ehf_data {
 	u8 temp_src[NUM_REG_TEMP];
 	const char * const *temp_label;
 
-	const u8 *REG_FAN_START_OUTPUT;
-	const u8 *REG_FAN_STOP_OUTPUT;
-	const u8 *REG_FAN_MAX_OUTPUT;
-	const u8 *REG_FAN_STEP_OUTPUT;
+	const u16 *REG_PWM;
+	const u16 *REG_TARGET;
+	const u16 *REG_FAN;
+	const u16 *REG_FAN_MIN;
+	const u16 *REG_FAN_START_OUTPUT;
+	const u16 *REG_FAN_STOP_OUTPUT;
+	const u16 *REG_FAN_STOP_TIME;
+	const u16 *REG_FAN_MAX_OUTPUT;
+	const u16 *REG_FAN_STEP_OUTPUT;
 
 	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
@@ -524,9 +530,9 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 				continue;
 
 			data->fan[i] = w83627ehf_read_value(data,
-				       W83627EHF_REG_FAN[i]);
+				       data->REG_FAN[i]);
 			data->fan_min[i] = w83627ehf_read_value(data,
-					   W83627EHF_REG_FAN_MIN[i]);
+					   data->REG_FAN_MIN[i]);
 
 			/* If we failed to measure the fan speed and clock
 			   divider can be increased, let's try that for next
@@ -543,7 +549,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 				if (data->fan_min[i] >= 2
 				 && data->fan_min[i] != 255)
 					w83627ehf_write_value(data,
-						W83627EHF_REG_FAN_MIN[i],
+						data->REG_FAN_MIN[i],
 						(data->fan_min[i] /= 2));
 			}
 		}
@@ -566,13 +572,13 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 				((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
 				& 3) + 1;
 			data->pwm[i] = w83627ehf_read_value(data,
-						W83627EHF_REG_PWM[i]);
+							    data->REG_PWM[i]);
 			data->fan_start_output[i] = w83627ehf_read_value(data,
-					W83627EHF_REG_FAN_START_OUTPUT[i]);
+					data->REG_FAN_START_OUTPUT[i]);
 			data->fan_stop_output[i] = w83627ehf_read_value(data,
-					W83627EHF_REG_FAN_STOP_OUTPUT[i]);
+					data->REG_FAN_STOP_OUTPUT[i]);
 			data->fan_stop_time[i] = w83627ehf_read_value(data,
-					W83627EHF_REG_FAN_STOP_TIME[i]);
+					data->REG_FAN_STOP_TIME[i]);
 
 			if (data->REG_FAN_MAX_OUTPUT[i] != 0xff)
 				data->fan_max_output[i] =
@@ -586,7 +592,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 
 			data->target_temp[i] =
 				w83627ehf_read_value(data,
-					W83627EHF_REG_TARGET[i]) &
+					data->REG_TARGET[i]) &
 					(data->pwm_mode[i] == 1 ? 0x7f : 0xff);
 			data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
 									& 0x0f;
@@ -822,7 +828,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 		/* Give the chip time to sample a new speed value */
 		data->last_updated = jiffies;
 	}
-	w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
+	w83627ehf_write_value(data, data->REG_FAN_MIN[nr],
 			      data->fan_min[nr]);
 	mutex_unlock(&data->update_lock);
 
@@ -1029,7 +1035,7 @@ store_pwm(struct device *dev, struct device_attribute *attr,
 
 	mutex_lock(&data->update_lock);
 	data->pwm[nr] = val;
-	w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
+	w83627ehf_write_value(data, data->REG_PWM[nr], val);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -1094,7 +1100,7 @@ store_target_temp(struct device *dev, struct device_attribute *attr,
 
 	mutex_lock(&data->update_lock);
 	data->target_temp[nr] = val;
-	w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
+	w83627ehf_write_value(data, data->REG_TARGET[nr], val);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -1509,8 +1515,14 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 		data->temp_label = w83667hg_b_temp_label;
 	}
 
+	data->REG_PWM = W83627EHF_REG_PWM;
+	data->REG_TARGET = W83627EHF_REG_TARGET;
+	data->REG_FAN = W83627EHF_REG_FAN;
+	data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
 	data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
 	data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
+	data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
+	data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
 	if (sio_data->kind == w83667hg_b) {
 		data->REG_FAN_MAX_OUTPUT =
 		  W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [lm-sensors] [PATCH v5 07/11] hwmon: (w83627ehf) Permit enabling
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
@ 2011-03-04 17:58   ` Guenter Roeck
  -1 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:58 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

If SmartFan IV mode was configured at startup, it should be possible
to re-enable it later on.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/w83627ehf.c |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 2420f1c..2f17f99 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -346,7 +346,10 @@ struct w83627ehf_data {
 			     2->thermal cruise mode (also called SmartFan I)
 			     3->fan speed cruise mode
 			     4->variable thermal cruise (also called
-				SmartFan III) */
+				SmartFan III)
+			     5->enhanced variable thermal cruise (also called
+				SmartFan IV) */
+	u8 pwm_enable_orig[4];	/* original value of pwm_enable */
 	u8 pwm_num;		/* number of pwm */
 	u8 pwm[4];
 	u8 target_temp[4];
@@ -1055,7 +1058,7 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
 	if (err < 0)
 		return err;
 
-	if (!val || (val > 4))
+	if (!val || (val > 4 && val != data->pwm_enable_orig[nr]))
 		return -EINVAL;
 	mutex_lock(&data->update_lock);
 	reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
@@ -1617,6 +1620,11 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	/* Read fan clock dividers immediately */
 	w83627ehf_update_fan_div(data);
 
+	/* Read pwm data to save original values */
+	w83627ehf_update_pwm_common(dev, data);
+	for (i = 0; i < data->pwm_num; i++)
+		data->pwm_enable_orig[i] = data->pwm_enable[i];
+
 	/* Register sysfs hooks */
 	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) {
 		err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr);
-- 
1.7.3.1


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 07/11] hwmon: (w83627ehf) Permit enabling SmartFan IV mode if configured at startup
@ 2011-03-04 17:58   ` Guenter Roeck
  0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:58 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

If SmartFan IV mode was configured at startup, it should be possible
to re-enable it later on.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/w83627ehf.c |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 2420f1c..2f17f99 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -346,7 +346,10 @@ struct w83627ehf_data {
 			     2->thermal cruise mode (also called SmartFan I)
 			     3->fan speed cruise mode
 			     4->variable thermal cruise (also called
-				SmartFan III) */
+				SmartFan III)
+			     5->enhanced variable thermal cruise (also called
+				SmartFan IV) */
+	u8 pwm_enable_orig[4];	/* original value of pwm_enable */
 	u8 pwm_num;		/* number of pwm */
 	u8 pwm[4];
 	u8 target_temp[4];
@@ -1055,7 +1058,7 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
 	if (err < 0)
 		return err;
 
-	if (!val || (val > 4))
+	if (!val || (val > 4 && val != data->pwm_enable_orig[nr]))
 		return -EINVAL;
 	mutex_lock(&data->update_lock);
 	reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
@@ -1617,6 +1620,11 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	/* Read fan clock dividers immediately */
 	w83627ehf_update_fan_div(data);
 
+	/* Read pwm data to save original values */
+	w83627ehf_update_pwm_common(dev, data);
+	for (i = 0; i < data->pwm_num; i++)
+		data->pwm_enable_orig[i] = data->pwm_enable[i];
+
 	/* Register sysfs hooks */
 	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) {
 		err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr);
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [lm-sensors] [PATCH v5 08/11] hwmon: (w83627ehf) Add support for
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
@ 2011-03-04 17:58   ` Guenter Roeck
  -1 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:58 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

This patch adds support for NCT6775F and NCT6776F to the w83627ehf driver.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
Tested-by: Ian Dobson <i.dobson@planet-ian.com> (for NCT6776F)
---
 Documentation/hwmon/w83627ehf |   59 +++-
 drivers/hwmon/w83627ehf.c     |  791 +++++++++++++++++++++++++++++++++-------
 2 files changed, 694 insertions(+), 156 deletions(-)

diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf
index b634e98..76ffef9 100644
--- a/Documentation/hwmon/w83627ehf
+++ b/Documentation/hwmon/w83627ehf
@@ -22,6 +22,14 @@ Supported chips:
     Prefix: 'w83667hg'
     Addresses scanned: ISA address retrieved from Super I/O registers
     Datasheet: Available from Nuvoton upon request
+  * Nuvoton NCT6775F/W83667HG-I
+    Prefix: 'nct6775'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet: Available from Nuvoton upon request
+  * Nuvoton NCT6776F
+    Prefix: 'nct6776'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet: Available from Nuvoton upon request
 
 Authors:
         Jean Delvare <khali@linux-fr.org>
@@ -34,24 +42,28 @@ Description
 -----------
 
 This driver implements support for the Winbond W83627EHF, W83627EHG,
-W83627DHG, W83627DHG-P, W83667HG and W83667HG-B super I/O chips.
-We will refer to them collectively as Winbond chips.
-
-The chips implement three temperature sensors (up to four for 667HG-B),
-five fan rotation speed sensors, ten analog voltage sensors (only nine for the
-627DHG), one VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG and 667HG),
-alarms with beep warnings (control unimplemented), and some automatic fan
-regulation strategies (plus manual fan control mode).
-
-The temperature sensor sources on W82677HG-B are configurable. temp4 is only
-reported if its temperature source differs from the temperature sources of the
-other three temperature sensors. The configured source for each of the
-temperature sensors is reported in tempX_label.
+W83627DHG, W83627DHG-P, W83667HG, W83667HG-B, W83667HG-I (NCT6775F),
+and NCT6776F super I/O chips. We will refer to them collectively as
+Winbond chips.
+
+The chips implement three temperature sensors (up to four for 667HG-B, and nine
+for NCT6775F and NCT6776F), five fan rotation speed sensors, ten analog voltage
+sensors (only nine for the 627DHG), one VID (6 pins for the 627EHF/EHG, 8 pins
+for the 627DHG and 667HG), alarms with beep warnings (control unimplemented),
+and some automatic fan regulation strategies (plus manual fan control mode).
+
+The temperature sensor sources on W82677HG-B, NCT6775F, and NCT6776F are
+configurable. temp4 and higher attributes are only reported if its temperature
+source differs from the temperature sources of the already reported temperature
+sensors. The configured source for each of the temperature sensors is provided
+in tempX_label.
 
 Temperatures are measured in degrees Celsius and measurement resolution is 1
-degC for temp1 and temp4, and 0.5 degC for temp2 and temp3. An alarm is
-triggered when the temperature gets higher than high limit; it stays on until
-the temperature falls below the hysteresis value.
+degC for temp1 and and 0.5 degC for temp2 and temp3. For temp4 and higher,
+resolution is 1 degC for W83667HG-B and 0.0 degC for NCT6775F and NCT6776F.
+An alarm is triggered when the temperature gets higher than high limit;
+it stays on until the temperature falls below the hysteresis value.
+Alarms are only supported for temp1, temp2, and temp3.
 
 Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
 triggered if the rotation speed has dropped below a programmable limit. Fan
@@ -83,7 +95,8 @@ prog  -> pwm4 (not on 667HG and 667HG-B; the programmable setting is not
 
 name - this is a standard hwmon device entry. For the W83627EHF and W83627EHG,
        it is set to "w83627ehf", for the W83627DHG it is set to "w83627dhg",
-       and for the W83667HG it is set to "w83667hg".
+       for the W83667HG and W83667HG-B it is set to "w83667hg", for NCT6775F it
+       is set to "nct6775", and for NCT6776F it is set to "nct6776".
 
 pwm[1-4] - this file stores PWM duty cycle or DC value (fan speed) in range:
 	   0 (stop) to 255 (full)
@@ -93,6 +106,18 @@ pwm[1-4]_enable - this file controls mode of fan/temperature control:
 	* 2 "Thermal Cruise" mode
 	* 3 "Fan Speed Cruise" mode
 	* 4 "Smart Fan III" mode
+	* 5 "Smart Fan IV" mode
+
+	SmartFan III mode is not supported on NCT6776F.
+
+	SmartFan IV mode is configurable only if it was configured at system
+	startup, and is only supported for W83677HG-B, NCT6775F, and NCT6776F.
+	SmartFan IV operational parameters can not be configured at this time,
+	and the various pwm attributes are not used in SmartFan IV mode.
+	The attributes can be written to, which is useful if you plan to
+	configure the system for a different pwm mode. However, the information
+	returned when reading pwm attributes is unrelated to SmartFan IV
+	operation.
 
 pwm[1-4]_mode - controls if output is PWM or DC level
         * 0 DC output (0 - 12v)
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 2f17f99..b3b4f2b 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -6,6 +6,7 @@
 			Rudolf Marek <r.marek@assembler.cz>
 			David Hubbard <david.c.hubbard@gmail.com>
 			Daniel J Blueman <daniel.blueman@gmail.com>
+    Copyright (C) 2010  Sheng-Yuan Huang (Nuvoton) (PS00)
 
     Shamelessly ripped from the w83627hf driver
     Copyright (C) 2003  Mark Studebaker
@@ -40,6 +41,8 @@
     w83627dhg-p  9      5       4       3      0xb070 0xc1    0x5ca3
     w83667hg     9      5       3       3      0xa510 0xc1    0x5ca3
     w83667hg-b   9      5       3       4      0xb350 0xc1    0x5ca3
+    nct6775f     9      4       3       9      0xb470 0xc1    0x5ca3
+    nct6776f     9      5       3       9      0xC330 0xc1    0x5ca3
 */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -58,7 +61,8 @@
 #include <linux/io.h>
 #include "lm75.h"
 
-enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b };
+enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b, nct6775,
+	nct6776 };
 
 /* used to set data->name = w83627ehf_device_names[data->sio_kind] */
 static const char * const w83627ehf_device_names[] = {
@@ -67,6 +71,8 @@ static const char * const w83627ehf_device_names[] = {
 	"w83627dhg",
 	"w83667hg",
 	"w83667hg",
+	"nct6775",
+	"nct6776",
 };
 
 static unsigned short force_id;
@@ -96,6 +102,8 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
 #define SIO_W83627DHG_P_ID	0xb070
 #define SIO_W83667HG_ID		0xa510
 #define SIO_W83667HG_B_ID	0xb350
+#define SIO_NCT6775_ID		0xb470
+#define SIO_NCT6776_ID		0xc330
 #define SIO_ID_MASK		0xFFF0
 
 static inline void
@@ -176,6 +184,10 @@ static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 };
 #define W83627EHF_REG_DIODE		0x59
 #define W83627EHF_REG_SMI_OVT		0x4C
 
+/* NCT6775F has its own fan divider registers */
+#define NCT6775_REG_FANDIV1		0x506
+#define NCT6775_REG_FANDIV2		0x507
+
 #define W83627EHF_REG_ALARM1		0x459
 #define W83627EHF_REG_ALARM2		0x45A
 #define W83627EHF_REG_ALARM3		0x45B
@@ -214,6 +226,28 @@ static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
 static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[]
 						= { 0x68, 0x6a, 0x6c };
 
+static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301 };
+static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302 };
+static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = { 0x105, 0x205, 0x305 };
+static const u16 NCT6775_REG_FAN_START_OUTPUT[] = { 0x106, 0x206, 0x306 };
+static const u16 NCT6775_REG_FAN_STOP_TIME[] = { 0x107, 0x207, 0x307 };
+static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309 };
+static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
+static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
+static const u16 NCT6776_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
+static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642};
+
+static const u16 NCT6775_REG_TEMP[]
+	= { 0x27, 0x150, 0x250, 0x73, 0x75, 0x77, 0x62b, 0x62c, 0x62d };
+static const u16 NCT6775_REG_TEMP_CONFIG[]
+	= { 0, 0x152, 0x252, 0, 0, 0, 0x628, 0x629, 0x62A };
+static const u16 NCT6775_REG_TEMP_HYST[]
+	= { 0x3a, 0x153, 0x253, 0, 0, 0, 0x673, 0x678, 0x67D };
+static const u16 NCT6775_REG_TEMP_OVER[]
+	= { 0x39, 0x155, 0x255, 0, 0, 0, 0x672, 0x677, 0x67C };
+static const u16 NCT6775_REG_TEMP_SOURCE[]
+	= { 0x621, 0x622, 0x623, 0x100, 0x200, 0x300, 0x624, 0x625, 0x626 };
+
 static const char *const w83667hg_b_temp_label[] = {
 	"SYSTIN",
 	"CPUTIN",
@@ -225,15 +259,71 @@ static const char *const w83667hg_b_temp_label[] = {
 	"PECI Agent 4"
 };
 
-#define NUM_REG_TEMP	4
+static const char *const nct6775_temp_label[] = {
+	"",
+	"SYSTIN",
+	"CPUTIN",
+	"AUXTIN",
+	"AMD SB-TSI",
+	"PECI Agent 0",
+	"PECI Agent 1",
+	"PECI Agent 2",
+	"PECI Agent 3",
+	"PECI Agent 4",
+	"PECI Agent 5",
+	"PECI Agent 6",
+	"PECI Agent 7",
+	"PCH_CHIP_CPU_MAX_TEMP",
+	"PCH_CHIP_TEMP",
+	"PCH_CPU_TEMP",
+	"PCH_MCH_TEMP",
+	"PCH_DIM0_TEMP",
+	"PCH_DIM1_TEMP",
+	"PCH_DIM2_TEMP",
+	"PCH_DIM3_TEMP"
+};
+
+static const char *const nct6776_temp_label[] = {
+	"",
+	"SYSTIN",
+	"CPUTIN",
+	"AUXTIN",
+	"SMBUSMASTER 0",
+	"SMBUSMASTER 1",
+	"SMBUSMASTER 2",
+	"SMBUSMASTER 3",
+	"SMBUSMASTER 4",
+	"SMBUSMASTER 5",
+	"SMBUSMASTER 6",
+	"SMBUSMASTER 7",
+	"PECI Agent 0",
+	"PECI Agent 1",
+	"PCH_CHIP_CPU_MAX_TEMP",
+	"PCH_CHIP_TEMP",
+	"PCH_CPU_TEMP",
+	"PCH_MCH_TEMP",
+	"PCH_DIM0_TEMP",
+	"PCH_DIM1_TEMP",
+	"PCH_DIM2_TEMP",
+	"PCH_DIM3_TEMP",
+	"BYTE_TEMP"
+};
+
+#define NUM_REG_TEMP	ARRAY_SIZE(NCT6775_REG_TEMP)
 
 static inline int is_word_sized(u16 reg)
 {
-	return (((reg & 0xff00) = 0x100
+	return ((((reg & 0xff00) = 0x100
 	      || (reg & 0xff00) = 0x200)
 	     && ((reg & 0x00ff) = 0x50
 	      || (reg & 0x00ff) = 0x53
-	      || (reg & 0x00ff) = 0x55));
+	      || (reg & 0x00ff) = 0x55))
+	     || (reg & 0xfff0) = 0x630
+	     || reg = 0x640 || reg = 0x642
+	     || ((reg & 0xfff0) = 0x650
+		 && (reg & 0x000f) >= 0x06)
+	     || reg = 0x73 || reg = 0x75 || reg = 0x77
+		);
 }
 
 /*
@@ -253,11 +343,20 @@ static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
 }
 
 static inline unsigned int
-fan_from_reg(u8 reg, unsigned int div)
+fan_from_reg(int reg, u16 val, unsigned int div)
 {
-	if (reg = 0 || reg = 255)
+	if (val = 0)
 		return 0;
-	return 1350000U / (reg * div);
+	if (is_word_sized(reg)) {
+		if ((val & 0xff1f) = 0xff1f)
+			return 0;
+		val = (val & 0x1f) | ((val & 0xff00) >> 3);
+	} else {
+		if (val = 255 || div = 0)
+			return 0;
+		val *= div;
+	}
+	return 1350000U / val;
 }
 
 static inline unsigned int
@@ -274,7 +373,7 @@ temp_from_reg(u16 reg, s16 regval)
 	return regval * 1000;
 }
 
-static inline s16
+static inline u16
 temp_to_reg(u16 reg, long temp)
 {
 	if (is_word_sized(reg))
@@ -308,6 +407,10 @@ struct w83627ehf_data {
 	struct device *hwmon_dev;
 	struct mutex lock;
 
+	u16 reg_temp[NUM_REG_TEMP];
+	u16 reg_temp_over[NUM_REG_TEMP];
+	u16 reg_temp_hyst[NUM_REG_TEMP];
+	u16 reg_temp_config[NUM_REG_TEMP];
 	u8 temp_src[NUM_REG_TEMP];
 	const char * const *temp_label;
 
@@ -331,14 +434,15 @@ struct w83627ehf_data {
 	u8 in[10];		/* Register value */
 	u8 in_max[10];		/* Register value */
 	u8 in_min[10];		/* Register value */
-	u8 fan[5];
-	u8 fan_min[5];
+	u16 fan[5];
+	u16 fan_min[5];
 	u8 fan_div[5];
 	u8 has_fan;		/* some fan inputs can be disabled */
+	u8 has_fan_min;		/* some fans don't have min register */
 	u8 temp_type[3];
-	s16 temp[4];
-	s16 temp_max[4];
-	s16 temp_max_hyst[4];
+	s16 temp[9];
+	s16 temp_max[9];
+	s16 temp_max_hyst[9];
 	u32 alarms;
 
 	u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
@@ -364,7 +468,7 @@ struct w83627ehf_data {
 	u8 vid;
 	u8 vrm;
 
-	u8 have_temp;
+	u16 have_temp;
 	u8 in6_skip;
 };
 
@@ -429,6 +533,34 @@ static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
 }
 
 /* This function assumes that the caller holds data->update_lock */
+static void nct6775_write_fan_div(struct w83627ehf_data *data, int nr)
+{
+	u8 reg;
+
+	switch (nr) {
+	case 0:
+		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
+		    | (data->fan_div[0] & 0x7);
+		w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
+		break;
+	case 1:
+		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
+		    | ((data->fan_div[1] << 4) & 0x70);
+		w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
+	case 2:
+		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
+		    | (data->fan_div[2] & 0x7);
+		w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
+		break;
+	case 3:
+		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
+		    | ((data->fan_div[3] << 4) & 0x70);
+		w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
+		break;
+	}
+}
+
+/* This function assumes that the caller holds data->update_lock */
 static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
 {
 	u8 reg;
@@ -479,6 +611,32 @@ static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
 	}
 }
 
+static void w83627ehf_write_fan_div_common(struct device *dev,
+					   struct w83627ehf_data *data, int nr)
+{
+	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+
+	if (sio_data->kind = nct6776)
+		; /* no dividers, do nothing */
+	else if (sio_data->kind = nct6775)
+		nct6775_write_fan_div(data, nr);
+	else
+		w83627ehf_write_fan_div(data, nr);
+}
+
+static void nct6775_update_fan_div(struct w83627ehf_data *data)
+{
+	u8 i;
+
+	i = w83627ehf_read_value(data, NCT6775_REG_FANDIV1);
+	data->fan_div[0] = i & 0x7;
+	data->fan_div[1] = (i & 0x70) >> 4;
+	i = w83627ehf_read_value(data, NCT6775_REG_FANDIV2);
+	data->fan_div[2] = i & 0x7;
+	if (data->has_fan & (1<<3))
+		data->fan_div[3] = (i & 0x70) >> 4;
+}
+
 static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
 {
 	int i;
@@ -504,10 +662,79 @@ static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
 	}
 }
 
+static void w83627ehf_update_fan_div_common(struct device *dev,
+					    struct w83627ehf_data *data)
+{
+	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+
+	if (sio_data->kind = nct6776)
+		; /* no dividers, do nothing */
+	else if (sio_data->kind = nct6775)
+		nct6775_update_fan_div(data);
+	else
+		w83627ehf_update_fan_div(data);
+}
+
+static void nct6775_update_pwm(struct w83627ehf_data *data)
+{
+	int i;
+	int pwmcfg, fanmodecfg;
+
+	for (i = 0; i < data->pwm_num; i++) {
+		pwmcfg = w83627ehf_read_value(data,
+					      W83627EHF_REG_PWM_ENABLE[i]);
+		fanmodecfg = w83627ehf_read_value(data,
+						  NCT6775_REG_FAN_MODE[i]);
+		data->pwm_mode[i] +		  ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
+		data->pwm_enable[i] = ((fanmodecfg >> 4) & 7) + 1;
+		data->tolerance[i] = fanmodecfg & 0x0f;
+		data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
+	}
+}
+
+static void w83627ehf_update_pwm(struct w83627ehf_data *data)
+{
+	int i;
+	int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
+
+	for (i = 0; i < data->pwm_num; i++) {
+		if (!(data->has_fan & (1 << i)))
+			continue;
+
+		/* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
+		if (i != 1) {
+			pwmcfg = w83627ehf_read_value(data,
+					W83627EHF_REG_PWM_ENABLE[i]);
+			tolerance = w83627ehf_read_value(data,
+					W83627EHF_REG_TOLERANCE[i]);
+		}
+		data->pwm_mode[i] +			((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
+		data->pwm_enable[i] = ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
+				       & 3) + 1;
+		data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
+
+		data->tolerance[i] = (tolerance >> (i = 1 ? 4 : 0)) & 0x0f;
+	}
+}
+
+static void w83627ehf_update_pwm_common(struct device *dev,
+					struct w83627ehf_data *data)
+{
+	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+
+	if (sio_data->kind = nct6775 || sio_data->kind = nct6776)
+		nct6775_update_pwm(data);
+	else
+		w83627ehf_update_pwm(data);
+}
+
 static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 {
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
-	int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
+	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+
 	int i;
 
 	mutex_lock(&data->update_lock);
@@ -515,7 +742,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 	if (time_after(jiffies, data->last_updated + HZ + HZ/2)
 	 || !data->valid) {
 		/* Fan clock dividers */
-		w83627ehf_update_fan_div(data);
+		w83627ehf_update_fan_div_common(dev, data);
 
 		/* Measured voltages and limits */
 		for (i = 0; i < data->in_num; i++) {
@@ -533,23 +760,29 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 				continue;
 
 			data->fan[i] = w83627ehf_read_value(data,
-				       data->REG_FAN[i]);
-			data->fan_min[i] = w83627ehf_read_value(data,
+							    data->REG_FAN[i]);
+
+			if (data->has_fan_min & (1 << i))
+				data->fan_min[i] = w83627ehf_read_value(data,
 					   data->REG_FAN_MIN[i]);
 
 			/* If we failed to measure the fan speed and clock
 			   divider can be increased, let's try that for next
 			   time */
-			if (data->fan[i] = 0xff
-			 && data->fan_div[i] < 0x07) {
+			if (!is_word_sized(data->REG_FAN[i])
+			    && (data->fan[i] = 0xff
+				|| (sio_data->kind = nct6775
+				    && data->fan[i] = 0x00))
+			    && data->fan_div[i] < 0x07) {
 				dev_dbg(dev, "Increasing fan%d "
 					"clock divider from %u to %u\n",
 					i + 1, div_from_reg(data->fan_div[i]),
 					div_from_reg(data->fan_div[i] + 1));
 				data->fan_div[i]++;
-				w83627ehf_write_fan_div(data, i);
+				w83627ehf_write_fan_div_common(dev, data, i);
 				/* Preserve min limit if possible */
-				if (data->fan_min[i] >= 2
+				if ((data->has_fan_min & (1 << i))
+				 && data->fan_min[i] >= 2
 				 && data->fan_min[i] != 255)
 					w83627ehf_write_value(data,
 						data->REG_FAN_MIN[i],
@@ -557,64 +790,54 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 			}
 		}
 
+		w83627ehf_update_pwm_common(dev, data);
+
 		for (i = 0; i < data->pwm_num; i++) {
 			if (!(data->has_fan & (1 << i)))
 				continue;
 
-			/* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
-			if (i != 1) {
-				pwmcfg = w83627ehf_read_value(data,
-						W83627EHF_REG_PWM_ENABLE[i]);
-				tolerance = w83627ehf_read_value(data,
-						W83627EHF_REG_TOLERANCE[i]);
-			}
-			data->pwm_mode[i] -				((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
-				? 0 : 1;
-			data->pwm_enable[i] -				((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
-				& 3) + 1;
-			data->pwm[i] = w83627ehf_read_value(data,
-							    data->REG_PWM[i]);
-			data->fan_start_output[i] = w83627ehf_read_value(data,
-					data->REG_FAN_START_OUTPUT[i]);
-			data->fan_stop_output[i] = w83627ehf_read_value(data,
-					data->REG_FAN_STOP_OUTPUT[i]);
-			data->fan_stop_time[i] = w83627ehf_read_value(data,
-					data->REG_FAN_STOP_TIME[i]);
-
-			if (data->REG_FAN_MAX_OUTPUT[i] != 0xff)
+			data->fan_start_output[i] +			  w83627ehf_read_value(data,
+					       data->REG_FAN_START_OUTPUT[i]);
+			data->fan_stop_output[i] +			  w83627ehf_read_value(data,
+					       data->REG_FAN_STOP_OUTPUT[i]);
+			data->fan_stop_time[i] +			  w83627ehf_read_value(data,
+					       data->REG_FAN_STOP_TIME[i]);
+
+			if (data->REG_FAN_MAX_OUTPUT &&
+			    data->REG_FAN_MAX_OUTPUT[i] != 0xff)
 				data->fan_max_output[i]  				  w83627ehf_read_value(data,
-					       data->REG_FAN_MAX_OUTPUT[i]);
+						data->REG_FAN_MAX_OUTPUT[i]);
 
-			if (data->REG_FAN_STEP_OUTPUT[i] != 0xff)
+			if (data->REG_FAN_STEP_OUTPUT &&
+			    data->REG_FAN_STEP_OUTPUT[i] != 0xff)
 				data->fan_step_output[i]  				  w83627ehf_read_value(data,
-					       data->REG_FAN_STEP_OUTPUT[i]);
+						data->REG_FAN_STEP_OUTPUT[i]);
 
 			data->target_temp[i]  				w83627ehf_read_value(data,
 					data->REG_TARGET[i]) &
 					(data->pwm_mode[i] = 1 ? 0x7f : 0xff);
-			data->tolerance[i] = (tolerance >> (i = 1 ? 4 : 0))
-									& 0x0f;
 		}
 
 		/* Measured temperatures and limits */
 		for (i = 0; i < NUM_REG_TEMP; i++) {
 			if (!(data->have_temp & (1 << i)))
 				continue;
-			data->temp[i]
-			  = w83627ehf_read_value(data, W83627EHF_REG_TEMP[i]);
-			if (i > 2)
-				break;
-			data->temp_max[i]
-			  = w83627ehf_read_value(data,
-						 W83627EHF_REG_TEMP_OVER[i]);
-			data->temp_max_hyst[i]
-			  = w83627ehf_read_value(data,
-						 W83627EHF_REG_TEMP_HYST[i]);
+			data->temp[i] = w83627ehf_read_value(data,
+						data->reg_temp[i]);
+			if (data->reg_temp_over[i])
+				data->temp_max[i]
+				  = w83627ehf_read_value(data,
+						data->reg_temp_over[i]);
+			if (data->reg_temp_hyst[i])
+				data->temp_max_hyst[i]
+				  = w83627ehf_read_value(data,
+						data->reg_temp_hyst[i]);
 		}
 
 		data->alarms = w83627ehf_read_value(data,
@@ -736,21 +959,29 @@ static struct sensor_device_attribute sda_in_max[] = {
 	SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
 };
 
-#define show_fan_reg(reg) \
-static ssize_t \
-show_##reg(struct device *dev, struct device_attribute *attr, \
-	   char *buf) \
-{ \
-	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = \
-		to_sensor_dev_attr(attr); \
-	int nr = sensor_attr->index; \
-	return sprintf(buf, "%d\n", \
-		       fan_from_reg(data->reg[nr], \
-				    div_from_reg(data->fan_div[nr]))); \
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%d\n",
+		       fan_from_reg(data->REG_FAN[nr],
+				    data->fan[nr],
+				    div_from_reg(data->fan_div[nr])));
+}
+
+static ssize_t
+show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%d\n",
+		       fan_from_reg(data->REG_FAN_MIN[nr],
+				    data->fan_min[nr],
+				    div_from_reg(data->fan_div[nr])));
 }
-show_fan_reg(fan);
-show_fan_reg(fan_min);
 
 static ssize_t
 show_fan_div(struct device *dev, struct device_attribute *attr,
@@ -779,6 +1010,18 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 		return err;
 
 	mutex_lock(&data->update_lock);
+	if (is_word_sized(data->REG_FAN_MIN[nr])) {
+		if (!val) {
+			val = 0xff1f;
+		} else {
+			if (val > 1350000U)
+				val = 135000U;
+			val = 1350000U / val;
+			val = (val & 0x1f) | ((val << 3) & 0xff00);
+		}
+		data->fan_min[nr] = val;
+		goto done;	/* Leave fan divider alone */
+	}
 	if (!val) {
 		/* No min limit, alarm disabled */
 		data->fan_min[nr] = 255;
@@ -790,14 +1033,16 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 		data->fan_min[nr] = 254;
 		new_div = 7; /* 128 = (1 << 7) */
 		dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
-			 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
+			 "minimum\n", nr + 1, val,
+			 fan_from_reg(data->REG_FAN_MIN[nr], 254, 128));
 	} else if (!reg) {
 		/* Speed above this value cannot possibly be represented,
 		   even with the lowest divider (1) */
 		data->fan_min[nr] = 1;
 		new_div = 0; /* 1 = (1 << 0) */
 		dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
-			 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
+			 "maximum\n", nr + 1, val,
+			 fan_from_reg(data->REG_FAN_MIN[nr], 1, 1));
 	} else {
 		/* Automatically pick the best divider, i.e. the one such
 		   that the min limit will correspond to a register value
@@ -827,10 +1072,11 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 			nr + 1, div_from_reg(data->fan_div[nr]),
 			div_from_reg(new_div));
 		data->fan_div[nr] = new_div;
-		w83627ehf_write_fan_div(data, nr);
+		w83627ehf_write_fan_div_common(dev, data, nr);
 		/* Give the chip time to sample a new speed value */
 		data->last_updated = jiffies;
 	}
+done:
 	w83627ehf_write_value(data, data->REG_FAN_MIN[nr],
 			      data->fan_min[nr]);
 	mutex_unlock(&data->update_lock);
@@ -884,7 +1130,7 @@ show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
 	return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
 }
 
-#define show_temp_reg(REG, reg) \
+#define show_temp_reg(addr, reg) \
 static ssize_t \
 show_##reg(struct device *dev, struct device_attribute *attr, \
 	   char *buf) \
@@ -894,13 +1140,13 @@ show_##reg(struct device *dev, struct device_attribute *attr, \
 		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", \
-		       temp_from_reg(W83627EHF_REG_##REG[nr], data->reg[nr])); \
+		       temp_from_reg(data->addr[nr], data->reg[nr])); \
 }
-show_temp_reg(TEMP, temp);
-show_temp_reg(TEMP_OVER, temp_max);
-show_temp_reg(TEMP_HYST, temp_max_hyst);
+show_temp_reg(reg_temp, temp);
+show_temp_reg(reg_temp_over, temp_max);
+show_temp_reg(reg_temp_hyst, temp_max_hyst);
 
-#define store_temp_reg(REG, reg) \
+#define store_temp_reg(addr, reg) \
 static ssize_t \
 store_##reg(struct device *dev, struct device_attribute *attr, \
 	    const char *buf, size_t count) \
@@ -915,14 +1161,14 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
 	if (err < 0) \
 		return err; \
 	mutex_lock(&data->update_lock); \
-	data->reg[nr] = temp_to_reg(W83627EHF_REG_TEMP_##REG[nr], val); \
-	w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
+	data->reg[nr] = temp_to_reg(data->addr[nr], val); \
+	w83627ehf_write_value(data, data->addr[nr], \
 			      data->reg[nr]); \
 	mutex_unlock(&data->update_lock); \
 	return count; \
 }
-store_temp_reg(OVER, temp_max);
-store_temp_reg(HYST, temp_max_hyst);
+store_temp_reg(reg_temp_over, temp_max);
+store_temp_reg(reg_temp_hyst, temp_max_hyst);
 
 static ssize_t
 show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
@@ -938,6 +1184,11 @@ static struct sensor_device_attribute sda_temp_input[] = {
 	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
 	SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
 	SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3),
+	SENSOR_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4),
+	SENSOR_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5),
+	SENSOR_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6),
+	SENSOR_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7),
+	SENSOR_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8),
 };
 
 static struct sensor_device_attribute sda_temp_label[] = {
@@ -945,6 +1196,11 @@ static struct sensor_device_attribute sda_temp_label[] = {
 	SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
 	SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
 	SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
+	SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4),
+	SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5),
+	SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6),
+	SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7),
+	SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8),
 };
 
 static struct sensor_device_attribute sda_temp_max[] = {
@@ -954,6 +1210,18 @@ static struct sensor_device_attribute sda_temp_max[] = {
 		    store_temp_max, 1),
 	SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
 		    store_temp_max, 2),
+	SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 3),
+	SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 4),
+	SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 5),
+	SENSOR_ATTR(temp7_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 6),
+	SENSOR_ATTR(temp8_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 7),
+	SENSOR_ATTR(temp9_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 8),
 };
 
 static struct sensor_device_attribute sda_temp_max_hyst[] = {
@@ -963,6 +1231,18 @@ static struct sensor_device_attribute sda_temp_max_hyst[] = {
 		    store_temp_max_hyst, 1),
 	SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
 		    store_temp_max_hyst, 2),
+	SENSOR_ATTR(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 3),
+	SENSOR_ATTR(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 4),
+	SENSOR_ATTR(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 5),
+	SENSOR_ATTR(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 6),
+	SENSOR_ATTR(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 7),
+	SENSOR_ATTR(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 8),
 };
 
 static struct sensor_device_attribute sda_temp_alarm[] = {
@@ -1048,6 +1328,7 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
 			const char *buf, size_t count)
 {
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	struct w83627ehf_sio_data *sio_data = dev->platform_data;
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	unsigned long val;
@@ -1060,12 +1341,25 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
 
 	if (!val || (val > 4 && val != data->pwm_enable_orig[nr]))
 		return -EINVAL;
+	/* SmartFan III mode is not supported on NCT6776F */
+	if (sio_data->kind = nct6776 && val = 4)
+		return -EINVAL;
+
 	mutex_lock(&data->update_lock);
-	reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
 	data->pwm_enable[nr] = val;
-	reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
-	reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
-	w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
+	if (sio_data->kind = nct6775 || sio_data->kind = nct6776) {
+		reg = w83627ehf_read_value(data,
+					   NCT6775_REG_FAN_MODE[nr]);
+		reg &= 0x0f;
+		reg |= (val - 1) << 4;
+		w83627ehf_write_value(data,
+				      NCT6775_REG_FAN_MODE[nr], reg);
+	} else {
+		reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
+		reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
+		reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
+		w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
+	}
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -1113,6 +1407,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
 			const char *buf, size_t count)
 {
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	struct w83627ehf_sio_data *sio_data = dev->platform_data;
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	u16 reg;
@@ -1127,13 +1422,22 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
 	val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
 
 	mutex_lock(&data->update_lock);
-	reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
-	data->tolerance[nr] = val;
-	if (nr = 1)
-		reg = (reg & 0x0f) | (val << 4);
-	else
+	if (sio_data->kind = nct6775 || sio_data->kind = nct6776) {
+		/* Limit tolerance further for NCT6776F */
+		if (sio_data->kind = nct6776 && val > 7)
+			val = 7;
+		reg = w83627ehf_read_value(data, NCT6775_REG_FAN_MODE[nr]);
 		reg = (reg & 0xf0) | val;
-	w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
+		w83627ehf_write_value(data, NCT6775_REG_FAN_MODE[nr], reg);
+	} else {
+		reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
+		if (nr = 1)
+			reg = (reg & 0x0f) | (val << 4);
+		else
+			reg = (reg & 0xf0) | val;
+		w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
+	}
+	data->tolerance[nr] = val;
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -1350,7 +1654,8 @@ static void w83627ehf_device_remove_files(struct device *dev)
 	for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
 		struct sensor_device_attribute *attr  		  &sda_sf3_max_step_arrays[i];
-		if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
+		if (data->REG_FAN_STEP_OUTPUT &&
+		    data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
 			device_remove_file(dev, &attr->dev_attr);
 	}
 	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
@@ -1381,10 +1686,10 @@ static void w83627ehf_device_remove_files(struct device *dev)
 			continue;
 		device_remove_file(dev, &sda_temp_input[i].dev_attr);
 		device_remove_file(dev, &sda_temp_label[i].dev_attr);
-		if (i > 2)
-			break;
 		device_remove_file(dev, &sda_temp_max[i].dev_attr);
 		device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
+		if (i > 2)
+			continue;
 		device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
 		device_remove_file(dev, &sda_temp_type[i].dev_attr);
 	}
@@ -1409,13 +1714,13 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
 	for (i = 0; i < NUM_REG_TEMP; i++) {
 		if (!(data->have_temp & (1 << i)))
 			continue;
-		if (!W83627EHF_REG_TEMP_CONFIG[i])
+		if (!data->reg_temp_config[i])
 			continue;
 		tmp = w83627ehf_read_value(data,
-					   W83627EHF_REG_TEMP_CONFIG[i]);
+					   data->reg_temp_config[i]);
 		if (tmp & 0x01)
 			w83627ehf_write_value(data,
-					      W83627EHF_REG_TEMP_CONFIG[i],
+					      data->reg_temp_config[i],
 					      tmp & 0xfe);
 	}
 
@@ -1434,13 +1739,39 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
 	}
 }
 
+static void w82627ehf_swap_tempreg(struct w83627ehf_data *data,
+				   int r1, int r2)
+{
+	u16 tmp;
+
+	tmp = data->temp_src[r1];
+	data->temp_src[r1] = data->temp_src[r2];
+	data->temp_src[r2] = tmp;
+
+	tmp = data->reg_temp[r1];
+	data->reg_temp[r1] = data->reg_temp[r2];
+	data->reg_temp[r2] = tmp;
+
+	tmp = data->reg_temp_over[r1];
+	data->reg_temp_over[r1] = data->reg_temp_over[r2];
+	data->reg_temp_over[r2] = tmp;
+
+	tmp = data->reg_temp_hyst[r1];
+	data->reg_temp_hyst[r1] = data->reg_temp_hyst[r2];
+	data->reg_temp_hyst[r2] = tmp;
+
+	tmp = data->reg_temp_config[r1];
+	data->reg_temp_config[r1] = data->reg_temp_config[r2];
+	data->reg_temp_config[r2] = tmp;
+}
+
 static int __devinit w83627ehf_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct w83627ehf_sio_data *sio_data = dev->platform_data;
 	struct w83627ehf_data *data;
 	struct resource *res;
-	u8 fan4pin, fan5pin, en_vrm10;
+	u8 fan3pin, fan4pin, fan4min, fan5pin, en_vrm10;
 	int i, err = 0;
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1466,9 +1797,11 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 
 	/* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
 	data->in_num = (sio_data->kind = w83627ehf) ? 10 : 9;
-	/* 667HG has 3 pwms */
+	/* 667HG, NCT6775F, and NCT6776F have 3 pwms */
 	data->pwm_num = (sio_data->kind = w83667hg
-			 || sio_data->kind = w83667hg_b) ? 3 : 4;
+			 || sio_data->kind = w83667hg_b
+			 || sio_data->kind = nct6775
+			 || sio_data->kind = nct6776) ? 3 : 4;
 
 	data->have_temp = 0x07;
 	/* Check temp3 configuration bit for 667HG */
@@ -1479,15 +1812,98 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 		if (reg & 0x01)
 			data->have_temp &= ~(1 << 2);
 		else
-			data->in6_skip = 1; /* Either temp3 or in6 */
+			data->in6_skip = 1;	/* either temp3 or in6 */
+	}
+
+	/* Deal with temperature register setup first. */
+	if (sio_data->kind = nct6775 || sio_data->kind = nct6776) {
+		int mask = 0;
+
+		/*
+		 * Display temperature sensor output only if it monitors
+		 * a source other than one already reported. Always display
+		 * first three temperature registers, though.
+		 */
+		for (i = 0; i < NUM_REG_TEMP; i++) {
+			u8 src;
+
+			data->reg_temp[i] = NCT6775_REG_TEMP[i];
+			data->reg_temp_over[i] = NCT6775_REG_TEMP_OVER[i];
+			data->reg_temp_hyst[i] = NCT6775_REG_TEMP_HYST[i];
+			data->reg_temp_config[i] = NCT6775_REG_TEMP_CONFIG[i];
+
+			src = w83627ehf_read_value(data,
+						   NCT6775_REG_TEMP_SOURCE[i]);
+			src &= 0x1f;
+			if (src && !(mask & (1 << src))) {
+				data->have_temp |= 1 << i;
+				mask |= 1 << src;
+			}
+
+			data->temp_src[i] = src;
+
+			/*
+			 * Now do some register swapping if index 0..2 don't
+			 * point to SYSTIN(1), CPUIN(2), and AUXIN(3).
+			 * Idea is to have the first three attributes
+			 * report SYSTIN, CPUIN, and AUXIN if possible
+			 * without overriding the basic system configuration.
+			 */
+			if (i > 0 && data->temp_src[0] != 1
+			    && data->temp_src[i] = 1)
+				w82627ehf_swap_tempreg(data, 0, i);
+			if (i > 1 && data->temp_src[1] != 2
+			    && data->temp_src[i] = 2)
+				w82627ehf_swap_tempreg(data, 1, i);
+			if (i > 2 && data->temp_src[2] != 3
+			    && data->temp_src[i] = 3)
+				w82627ehf_swap_tempreg(data, 2, i);
+		}
+		if (sio_data->kind = nct6776) {
+			/*
+			 * On NCT6776, AUXTIN and VIN3 pins are shared.
+			 * Only way to detect it is to check if AUXTIN is used
+			 * as a temperature source, and if that source is
+			 * enabled.
+			 *
+			 * If that is the case, disable in6, which reports VIN3.
+			 * Otherwise disable temp3.
+			 */
+			if (data->temp_src[2] = 3) {
+				u8 reg;
+
+				if (data->reg_temp_config[2])
+					reg = w83627ehf_read_value(data,
+						data->reg_temp_config[2]);
+				else
+					reg = 0; /* Assume AUXTIN is used */
+
+				if (reg & 0x01)
+					data->have_temp &= ~(1 << 2);
+				else
+					data->in6_skip = 1;
+			}
+		}
+
+		data->temp_label = nct6776_temp_label;
 	} else if (sio_data->kind = w83667hg_b) {
 		u8 reg;
 
+		/*
+		 * Temperature sources are selected with bank 0, registers 0x49
+		 * and 0x4a.
+		 */
+		for (i = 0; i < ARRAY_SIZE(W83627EHF_REG_TEMP); i++) {
+			data->reg_temp[i] = W83627EHF_REG_TEMP[i];
+			data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
+			data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
+			data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
+		}
 		reg = w83627ehf_read_value(data, 0x4a);
 		data->temp_src[0] = reg >> 5;
 		reg = w83627ehf_read_value(data, 0x49);
 		data->temp_src[1] = reg & 0x07;
-		data->temp_src[2] = (reg >> 4)  & 0x07;
+		data->temp_src[2] = (reg >> 4) & 0x07;
 
 		/*
 		 * W83667HG-B has another temperature register at 0x7e.
@@ -1516,22 +1932,54 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 			data->in6_skip = 1;
 
 		data->temp_label = w83667hg_b_temp_label;
+	} else {
+		/* Temperature sources are fixed */
+		for (i = 0; i < 3; i++) {
+			data->reg_temp[i] = W83627EHF_REG_TEMP[i];
+			data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
+			data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
+			data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
+		}
 	}
 
-	data->REG_PWM = W83627EHF_REG_PWM;
-	data->REG_TARGET = W83627EHF_REG_TARGET;
-	data->REG_FAN = W83627EHF_REG_FAN;
-	data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
-	data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
-	data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
-	data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
-	data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
-	if (sio_data->kind = w83667hg_b) {
+	if (sio_data->kind = nct6775) {
+		data->REG_PWM = NCT6775_REG_PWM;
+		data->REG_TARGET = NCT6775_REG_TARGET;
+		data->REG_FAN = W83627EHF_REG_FAN;
+		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
+		data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
+		data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
+		data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
+		data->REG_FAN_MAX_OUTPUT = NCT6775_REG_FAN_MAX_OUTPUT;
+		data->REG_FAN_STEP_OUTPUT = NCT6775_REG_FAN_STEP_OUTPUT;
+	} else if (sio_data->kind = nct6776) {
+		data->REG_PWM = NCT6775_REG_PWM;
+		data->REG_TARGET = NCT6775_REG_TARGET;
+		data->REG_FAN = NCT6776_REG_FAN;
+		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+		data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
+		data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
+		data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
+	} else if (sio_data->kind = w83667hg_b) {
+		data->REG_PWM = W83627EHF_REG_PWM;
+		data->REG_TARGET = W83627EHF_REG_TARGET;
+		data->REG_FAN = W83627EHF_REG_FAN;
+		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
+		data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
+		data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
+		data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
 		data->REG_FAN_MAX_OUTPUT  		  W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
 		data->REG_FAN_STEP_OUTPUT  		  W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
 	} else {
+		data->REG_PWM = W83627EHF_REG_PWM;
+		data->REG_TARGET = W83627EHF_REG_TARGET;
+		data->REG_FAN = W83627EHF_REG_FAN;
+		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
+		data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
+		data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
+		data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
 		data->REG_FAN_MAX_OUTPUT  		  W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
 		data->REG_FAN_STEP_OUTPUT @@ -1544,7 +1992,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	data->vrm = vid_which_vrm();
 	superio_enter(sio_data->sioreg);
 	/* Read VID value */
-	if (sio_data->kind = w83667hg || sio_data->kind = w83667hg_b) {
+	if (sio_data->kind = w83667hg || sio_data->kind = w83667hg_b ||
+	    sio_data->kind = nct6775 || sio_data->kind = nct6776) {
 		/* W83667HG has different pins for VID input and output, so
 		we can get the VID input values directly at logical device D
 		0xe3. */
@@ -1595,12 +2044,27 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	}
 
 	/* fan4 and fan5 share some pins with the GPIO and serial flash */
-	if (sio_data->kind = w83667hg || sio_data->kind = w83667hg_b) {
-		fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
+	if (sio_data->kind = nct6775) {
+		/* On NCT6775, fan4 shares pins with the fdc interface */
+		fan3pin = 1;
+		fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
+		fan4min = 0;
+		fan5pin = 0;
+	} else if (sio_data->kind = nct6776) {
+		fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
+		fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01);
+		fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02);
+		fan4min = fan4pin;
+	} else if (sio_data->kind = w83667hg || sio_data->kind = w83667hg_b) {
+		fan3pin = 1;
 		fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
+		fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
+		fan4min = fan4pin;
 	} else {
-		fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
+		fan3pin = 1;
 		fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
+		fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
+		fan4min = fan4pin;
 	}
 	superio_exit(sio_data->sioreg);
 
@@ -1610,15 +2074,36 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	   connected fan5 as input unless they are emitting log 1, which
 	   is not the default. */
 
-	data->has_fan = 0x07; /* fan1, fan2 and fan3 */
-	i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
-	if ((i & (1 << 2)) && fan4pin)
-		data->has_fan |= (1 << 3);
-	if (!(i & (1 << 1)) && fan5pin)
-		data->has_fan |= (1 << 4);
+	data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
+
+	data->has_fan |= (fan3pin << 2);
+	data->has_fan_min |= (fan3pin << 2);
+
+	/*
+	 * NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1 register
+	 */
+	if (sio_data->kind = nct6775 || sio_data->kind = nct6776) {
+		data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
+		data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
+	} else {
+		i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
+		if ((i & (1 << 2)) && fan4pin) {
+			data->has_fan |= (1 << 3);
+			data->has_fan_min |= (1 << 3);
+		}
+		if (!(i & (1 << 1)) && fan5pin) {
+			data->has_fan |= (1 << 4);
+			data->has_fan_min |= (1 << 4);
+		}
+	}
 
 	/* Read fan clock dividers immediately */
-	w83627ehf_update_fan_div(data);
+	w83627ehf_update_fan_div_common(dev, data);
+
+	/* Read pwm data to save original values */
+	w83627ehf_update_pwm_common(dev, data);
+	for (i = 0; i < data->pwm_num; i++)
+		data->pwm_enable_orig[i] = data->pwm_enable[i];
 
 	/* Read pwm data to save original values */
 	w83627ehf_update_pwm_common(dev, data);
@@ -1635,7 +2120,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
 		struct sensor_device_attribute *attr  		  &sda_sf3_max_step_arrays[i];
-		if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
+		if (data->REG_FAN_STEP_OUTPUT &&
+		    data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
 			err = device_create_file(dev, &attr->dev_attr);
 			if (err)
 				goto exit_remove;
@@ -1668,12 +2154,20 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 			if ((err = device_create_file(dev,
 					&sda_fan_input[i].dev_attr))
 				|| (err = device_create_file(dev,
-					&sda_fan_alarm[i].dev_attr))
-				|| (err = device_create_file(dev,
-					&sda_fan_div[i].dev_attr))
-				|| (err = device_create_file(dev,
-					&sda_fan_min[i].dev_attr)))
+					&sda_fan_alarm[i].dev_attr)))
 				goto exit_remove;
+			if (sio_data->kind != nct6776) {
+				err = device_create_file(dev,
+						&sda_fan_div[i].dev_attr);
+				if (err)
+					goto exit_remove;
+			}
+			if (data->has_fan_min & (1 << i)) {
+				err = device_create_file(dev,
+						&sda_fan_min[i].dev_attr);
+				if (err)
+					goto exit_remove;
+			}
 			if (i < data->pwm_num &&
 				((err = device_create_file(dev,
 					&sda_pwm[i].dev_attr))
@@ -1701,12 +2195,21 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 			if (err)
 				goto exit_remove;
 		}
+		if (data->reg_temp_over[i]) {
+			err = device_create_file(dev,
+				&sda_temp_max[i].dev_attr);
+			if (err)
+				goto exit_remove;
+		}
+		if (data->reg_temp_hyst[i]) {
+			err = device_create_file(dev,
+				&sda_temp_max_hyst[i].dev_attr);
+			if (err)
+				goto exit_remove;
+		}
 		if (i > 2)
-			break;
-		if ((err = device_create_file(dev, &sda_temp_max[i].dev_attr))
-			|| (err = device_create_file(dev,
-				&sda_temp_max_hyst[i].dev_attr))
-			|| (err = device_create_file(dev,
+			continue;
+		if ((err = device_create_file(dev,
 				&sda_temp_alarm[i].dev_attr))
 			|| (err = device_create_file(dev,
 				&sda_temp_type[i].dev_attr)))
@@ -1767,6 +2270,8 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
 	static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
 	static const char __initdata sio_name_W83667HG[] = "W83667HG";
 	static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
+	static const char __initdata sio_name_NCT6775[] = "NCT6775F";
+	static const char __initdata sio_name_NCT6776[] = "NCT6776F";
 
 	u16 val;
 	const char *sio_name;
@@ -1803,6 +2308,14 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
 		sio_data->kind = w83667hg_b;
 		sio_name = sio_name_W83667HG_B;
 		break;
+	case SIO_NCT6775_ID:
+		sio_data->kind = nct6775;
+		sio_name = sio_name_NCT6775;
+		break;
+	case SIO_NCT6776_ID:
+		sio_data->kind = nct6776;
+		sio_name = sio_name_NCT6776;
+		break;
 	default:
 		if (val != 0xffff)
 			pr_debug("unsupported chip ID: 0x%04x\n", val);
-- 
1.7.3.1


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 08/11] hwmon: (w83627ehf) Add support for Nuvoton NCT6775F and NCT6776F
@ 2011-03-04 17:58   ` Guenter Roeck
  0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:58 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

This patch adds support for NCT6775F and NCT6776F to the w83627ehf driver.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
Tested-by: Ian Dobson <i.dobson@planet-ian.com> (for NCT6776F)
---
 Documentation/hwmon/w83627ehf |   59 +++-
 drivers/hwmon/w83627ehf.c     |  791 +++++++++++++++++++++++++++++++++-------
 2 files changed, 694 insertions(+), 156 deletions(-)

diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf
index b634e98..76ffef9 100644
--- a/Documentation/hwmon/w83627ehf
+++ b/Documentation/hwmon/w83627ehf
@@ -22,6 +22,14 @@ Supported chips:
     Prefix: 'w83667hg'
     Addresses scanned: ISA address retrieved from Super I/O registers
     Datasheet: Available from Nuvoton upon request
+  * Nuvoton NCT6775F/W83667HG-I
+    Prefix: 'nct6775'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet: Available from Nuvoton upon request
+  * Nuvoton NCT6776F
+    Prefix: 'nct6776'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet: Available from Nuvoton upon request
 
 Authors:
         Jean Delvare <khali@linux-fr.org>
@@ -34,24 +42,28 @@ Description
 -----------
 
 This driver implements support for the Winbond W83627EHF, W83627EHG,
-W83627DHG, W83627DHG-P, W83667HG and W83667HG-B super I/O chips.
-We will refer to them collectively as Winbond chips.
-
-The chips implement three temperature sensors (up to four for 667HG-B),
-five fan rotation speed sensors, ten analog voltage sensors (only nine for the
-627DHG), one VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG and 667HG),
-alarms with beep warnings (control unimplemented), and some automatic fan
-regulation strategies (plus manual fan control mode).
-
-The temperature sensor sources on W82677HG-B are configurable. temp4 is only
-reported if its temperature source differs from the temperature sources of the
-other three temperature sensors. The configured source for each of the
-temperature sensors is reported in tempX_label.
+W83627DHG, W83627DHG-P, W83667HG, W83667HG-B, W83667HG-I (NCT6775F),
+and NCT6776F super I/O chips. We will refer to them collectively as
+Winbond chips.
+
+The chips implement three temperature sensors (up to four for 667HG-B, and nine
+for NCT6775F and NCT6776F), five fan rotation speed sensors, ten analog voltage
+sensors (only nine for the 627DHG), one VID (6 pins for the 627EHF/EHG, 8 pins
+for the 627DHG and 667HG), alarms with beep warnings (control unimplemented),
+and some automatic fan regulation strategies (plus manual fan control mode).
+
+The temperature sensor sources on W82677HG-B, NCT6775F, and NCT6776F are
+configurable. temp4 and higher attributes are only reported if its temperature
+source differs from the temperature sources of the already reported temperature
+sensors. The configured source for each of the temperature sensors is provided
+in tempX_label.
 
 Temperatures are measured in degrees Celsius and measurement resolution is 1
-degC for temp1 and temp4, and 0.5 degC for temp2 and temp3. An alarm is
-triggered when the temperature gets higher than high limit; it stays on until
-the temperature falls below the hysteresis value.
+degC for temp1 and and 0.5 degC for temp2 and temp3. For temp4 and higher,
+resolution is 1 degC for W83667HG-B and 0.0 degC for NCT6775F and NCT6776F.
+An alarm is triggered when the temperature gets higher than high limit;
+it stays on until the temperature falls below the hysteresis value.
+Alarms are only supported for temp1, temp2, and temp3.
 
 Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
 triggered if the rotation speed has dropped below a programmable limit. Fan
@@ -83,7 +95,8 @@ prog  -> pwm4 (not on 667HG and 667HG-B; the programmable setting is not
 
 name - this is a standard hwmon device entry. For the W83627EHF and W83627EHG,
        it is set to "w83627ehf", for the W83627DHG it is set to "w83627dhg",
-       and for the W83667HG it is set to "w83667hg".
+       for the W83667HG and W83667HG-B it is set to "w83667hg", for NCT6775F it
+       is set to "nct6775", and for NCT6776F it is set to "nct6776".
 
 pwm[1-4] - this file stores PWM duty cycle or DC value (fan speed) in range:
 	   0 (stop) to 255 (full)
@@ -93,6 +106,18 @@ pwm[1-4]_enable - this file controls mode of fan/temperature control:
 	* 2 "Thermal Cruise" mode
 	* 3 "Fan Speed Cruise" mode
 	* 4 "Smart Fan III" mode
+	* 5 "Smart Fan IV" mode
+
+	SmartFan III mode is not supported on NCT6776F.
+
+	SmartFan IV mode is configurable only if it was configured at system
+	startup, and is only supported for W83677HG-B, NCT6775F, and NCT6776F.
+	SmartFan IV operational parameters can not be configured at this time,
+	and the various pwm attributes are not used in SmartFan IV mode.
+	The attributes can be written to, which is useful if you plan to
+	configure the system for a different pwm mode. However, the information
+	returned when reading pwm attributes is unrelated to SmartFan IV
+	operation.
 
 pwm[1-4]_mode - controls if output is PWM or DC level
         * 0 DC output (0 - 12v)
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 2f17f99..b3b4f2b 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -6,6 +6,7 @@
 			Rudolf Marek <r.marek@assembler.cz>
 			David Hubbard <david.c.hubbard@gmail.com>
 			Daniel J Blueman <daniel.blueman@gmail.com>
+    Copyright (C) 2010  Sheng-Yuan Huang (Nuvoton) (PS00)
 
     Shamelessly ripped from the w83627hf driver
     Copyright (C) 2003  Mark Studebaker
@@ -40,6 +41,8 @@
     w83627dhg-p  9      5       4       3      0xb070 0xc1    0x5ca3
     w83667hg     9      5       3       3      0xa510 0xc1    0x5ca3
     w83667hg-b   9      5       3       4      0xb350 0xc1    0x5ca3
+    nct6775f     9      4       3       9      0xb470 0xc1    0x5ca3
+    nct6776f     9      5       3       9      0xC330 0xc1    0x5ca3
 */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -58,7 +61,8 @@
 #include <linux/io.h>
 #include "lm75.h"
 
-enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b };
+enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b, nct6775,
+	nct6776 };
 
 /* used to set data->name = w83627ehf_device_names[data->sio_kind] */
 static const char * const w83627ehf_device_names[] = {
@@ -67,6 +71,8 @@ static const char * const w83627ehf_device_names[] = {
 	"w83627dhg",
 	"w83667hg",
 	"w83667hg",
+	"nct6775",
+	"nct6776",
 };
 
 static unsigned short force_id;
@@ -96,6 +102,8 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
 #define SIO_W83627DHG_P_ID	0xb070
 #define SIO_W83667HG_ID		0xa510
 #define SIO_W83667HG_B_ID	0xb350
+#define SIO_NCT6775_ID		0xb470
+#define SIO_NCT6776_ID		0xc330
 #define SIO_ID_MASK		0xFFF0
 
 static inline void
@@ -176,6 +184,10 @@ static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 };
 #define W83627EHF_REG_DIODE		0x59
 #define W83627EHF_REG_SMI_OVT		0x4C
 
+/* NCT6775F has its own fan divider registers */
+#define NCT6775_REG_FANDIV1		0x506
+#define NCT6775_REG_FANDIV2		0x507
+
 #define W83627EHF_REG_ALARM1		0x459
 #define W83627EHF_REG_ALARM2		0x45A
 #define W83627EHF_REG_ALARM3		0x45B
@@ -214,6 +226,28 @@ static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
 static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[]
 						= { 0x68, 0x6a, 0x6c };
 
+static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301 };
+static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302 };
+static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = { 0x105, 0x205, 0x305 };
+static const u16 NCT6775_REG_FAN_START_OUTPUT[] = { 0x106, 0x206, 0x306 };
+static const u16 NCT6775_REG_FAN_STOP_TIME[] = { 0x107, 0x207, 0x307 };
+static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309 };
+static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
+static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
+static const u16 NCT6776_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
+static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642};
+
+static const u16 NCT6775_REG_TEMP[]
+	= { 0x27, 0x150, 0x250, 0x73, 0x75, 0x77, 0x62b, 0x62c, 0x62d };
+static const u16 NCT6775_REG_TEMP_CONFIG[]
+	= { 0, 0x152, 0x252, 0, 0, 0, 0x628, 0x629, 0x62A };
+static const u16 NCT6775_REG_TEMP_HYST[]
+	= { 0x3a, 0x153, 0x253, 0, 0, 0, 0x673, 0x678, 0x67D };
+static const u16 NCT6775_REG_TEMP_OVER[]
+	= { 0x39, 0x155, 0x255, 0, 0, 0, 0x672, 0x677, 0x67C };
+static const u16 NCT6775_REG_TEMP_SOURCE[]
+	= { 0x621, 0x622, 0x623, 0x100, 0x200, 0x300, 0x624, 0x625, 0x626 };
+
 static const char *const w83667hg_b_temp_label[] = {
 	"SYSTIN",
 	"CPUTIN",
@@ -225,15 +259,71 @@ static const char *const w83667hg_b_temp_label[] = {
 	"PECI Agent 4"
 };
 
-#define NUM_REG_TEMP	4
+static const char *const nct6775_temp_label[] = {
+	"",
+	"SYSTIN",
+	"CPUTIN",
+	"AUXTIN",
+	"AMD SB-TSI",
+	"PECI Agent 0",
+	"PECI Agent 1",
+	"PECI Agent 2",
+	"PECI Agent 3",
+	"PECI Agent 4",
+	"PECI Agent 5",
+	"PECI Agent 6",
+	"PECI Agent 7",
+	"PCH_CHIP_CPU_MAX_TEMP",
+	"PCH_CHIP_TEMP",
+	"PCH_CPU_TEMP",
+	"PCH_MCH_TEMP",
+	"PCH_DIM0_TEMP",
+	"PCH_DIM1_TEMP",
+	"PCH_DIM2_TEMP",
+	"PCH_DIM3_TEMP"
+};
+
+static const char *const nct6776_temp_label[] = {
+	"",
+	"SYSTIN",
+	"CPUTIN",
+	"AUXTIN",
+	"SMBUSMASTER 0",
+	"SMBUSMASTER 1",
+	"SMBUSMASTER 2",
+	"SMBUSMASTER 3",
+	"SMBUSMASTER 4",
+	"SMBUSMASTER 5",
+	"SMBUSMASTER 6",
+	"SMBUSMASTER 7",
+	"PECI Agent 0",
+	"PECI Agent 1",
+	"PCH_CHIP_CPU_MAX_TEMP",
+	"PCH_CHIP_TEMP",
+	"PCH_CPU_TEMP",
+	"PCH_MCH_TEMP",
+	"PCH_DIM0_TEMP",
+	"PCH_DIM1_TEMP",
+	"PCH_DIM2_TEMP",
+	"PCH_DIM3_TEMP",
+	"BYTE_TEMP"
+};
+
+#define NUM_REG_TEMP	ARRAY_SIZE(NCT6775_REG_TEMP)
 
 static inline int is_word_sized(u16 reg)
 {
-	return (((reg & 0xff00) == 0x100
+	return ((((reg & 0xff00) == 0x100
 	      || (reg & 0xff00) == 0x200)
 	     && ((reg & 0x00ff) == 0x50
 	      || (reg & 0x00ff) == 0x53
-	      || (reg & 0x00ff) == 0x55));
+	      || (reg & 0x00ff) == 0x55))
+	     || (reg & 0xfff0) == 0x630
+	     || reg == 0x640 || reg == 0x642
+	     || ((reg & 0xfff0) == 0x650
+		 && (reg & 0x000f) >= 0x06)
+	     || reg == 0x73 || reg == 0x75 || reg == 0x77
+		);
 }
 
 /*
@@ -253,11 +343,20 @@ static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
 }
 
 static inline unsigned int
-fan_from_reg(u8 reg, unsigned int div)
+fan_from_reg(int reg, u16 val, unsigned int div)
 {
-	if (reg == 0 || reg == 255)
+	if (val == 0)
 		return 0;
-	return 1350000U / (reg * div);
+	if (is_word_sized(reg)) {
+		if ((val & 0xff1f) == 0xff1f)
+			return 0;
+		val = (val & 0x1f) | ((val & 0xff00) >> 3);
+	} else {
+		if (val == 255 || div == 0)
+			return 0;
+		val *= div;
+	}
+	return 1350000U / val;
 }
 
 static inline unsigned int
@@ -274,7 +373,7 @@ temp_from_reg(u16 reg, s16 regval)
 	return regval * 1000;
 }
 
-static inline s16
+static inline u16
 temp_to_reg(u16 reg, long temp)
 {
 	if (is_word_sized(reg))
@@ -308,6 +407,10 @@ struct w83627ehf_data {
 	struct device *hwmon_dev;
 	struct mutex lock;
 
+	u16 reg_temp[NUM_REG_TEMP];
+	u16 reg_temp_over[NUM_REG_TEMP];
+	u16 reg_temp_hyst[NUM_REG_TEMP];
+	u16 reg_temp_config[NUM_REG_TEMP];
 	u8 temp_src[NUM_REG_TEMP];
 	const char * const *temp_label;
 
@@ -331,14 +434,15 @@ struct w83627ehf_data {
 	u8 in[10];		/* Register value */
 	u8 in_max[10];		/* Register value */
 	u8 in_min[10];		/* Register value */
-	u8 fan[5];
-	u8 fan_min[5];
+	u16 fan[5];
+	u16 fan_min[5];
 	u8 fan_div[5];
 	u8 has_fan;		/* some fan inputs can be disabled */
+	u8 has_fan_min;		/* some fans don't have min register */
 	u8 temp_type[3];
-	s16 temp[4];
-	s16 temp_max[4];
-	s16 temp_max_hyst[4];
+	s16 temp[9];
+	s16 temp_max[9];
+	s16 temp_max_hyst[9];
 	u32 alarms;
 
 	u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
@@ -364,7 +468,7 @@ struct w83627ehf_data {
 	u8 vid;
 	u8 vrm;
 
-	u8 have_temp;
+	u16 have_temp;
 	u8 in6_skip;
 };
 
@@ -429,6 +533,34 @@ static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
 }
 
 /* This function assumes that the caller holds data->update_lock */
+static void nct6775_write_fan_div(struct w83627ehf_data *data, int nr)
+{
+	u8 reg;
+
+	switch (nr) {
+	case 0:
+		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
+		    | (data->fan_div[0] & 0x7);
+		w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
+		break;
+	case 1:
+		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
+		    | ((data->fan_div[1] << 4) & 0x70);
+		w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
+	case 2:
+		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
+		    | (data->fan_div[2] & 0x7);
+		w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
+		break;
+	case 3:
+		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
+		    | ((data->fan_div[3] << 4) & 0x70);
+		w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
+		break;
+	}
+}
+
+/* This function assumes that the caller holds data->update_lock */
 static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
 {
 	u8 reg;
@@ -479,6 +611,32 @@ static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
 	}
 }
 
+static void w83627ehf_write_fan_div_common(struct device *dev,
+					   struct w83627ehf_data *data, int nr)
+{
+	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+
+	if (sio_data->kind == nct6776)
+		; /* no dividers, do nothing */
+	else if (sio_data->kind == nct6775)
+		nct6775_write_fan_div(data, nr);
+	else
+		w83627ehf_write_fan_div(data, nr);
+}
+
+static void nct6775_update_fan_div(struct w83627ehf_data *data)
+{
+	u8 i;
+
+	i = w83627ehf_read_value(data, NCT6775_REG_FANDIV1);
+	data->fan_div[0] = i & 0x7;
+	data->fan_div[1] = (i & 0x70) >> 4;
+	i = w83627ehf_read_value(data, NCT6775_REG_FANDIV2);
+	data->fan_div[2] = i & 0x7;
+	if (data->has_fan & (1<<3))
+		data->fan_div[3] = (i & 0x70) >> 4;
+}
+
 static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
 {
 	int i;
@@ -504,10 +662,79 @@ static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
 	}
 }
 
+static void w83627ehf_update_fan_div_common(struct device *dev,
+					    struct w83627ehf_data *data)
+{
+	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+
+	if (sio_data->kind == nct6776)
+		; /* no dividers, do nothing */
+	else if (sio_data->kind == nct6775)
+		nct6775_update_fan_div(data);
+	else
+		w83627ehf_update_fan_div(data);
+}
+
+static void nct6775_update_pwm(struct w83627ehf_data *data)
+{
+	int i;
+	int pwmcfg, fanmodecfg;
+
+	for (i = 0; i < data->pwm_num; i++) {
+		pwmcfg = w83627ehf_read_value(data,
+					      W83627EHF_REG_PWM_ENABLE[i]);
+		fanmodecfg = w83627ehf_read_value(data,
+						  NCT6775_REG_FAN_MODE[i]);
+		data->pwm_mode[i] =
+		  ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
+		data->pwm_enable[i] = ((fanmodecfg >> 4) & 7) + 1;
+		data->tolerance[i] = fanmodecfg & 0x0f;
+		data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
+	}
+}
+
+static void w83627ehf_update_pwm(struct w83627ehf_data *data)
+{
+	int i;
+	int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
+
+	for (i = 0; i < data->pwm_num; i++) {
+		if (!(data->has_fan & (1 << i)))
+			continue;
+
+		/* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
+		if (i != 1) {
+			pwmcfg = w83627ehf_read_value(data,
+					W83627EHF_REG_PWM_ENABLE[i]);
+			tolerance = w83627ehf_read_value(data,
+					W83627EHF_REG_TOLERANCE[i]);
+		}
+		data->pwm_mode[i] =
+			((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
+		data->pwm_enable[i] = ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
+				       & 3) + 1;
+		data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
+
+		data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0)) & 0x0f;
+	}
+}
+
+static void w83627ehf_update_pwm_common(struct device *dev,
+					struct w83627ehf_data *data)
+{
+	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+
+	if (sio_data->kind == nct6775 || sio_data->kind == nct6776)
+		nct6775_update_pwm(data);
+	else
+		w83627ehf_update_pwm(data);
+}
+
 static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 {
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
-	int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
+	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+
 	int i;
 
 	mutex_lock(&data->update_lock);
@@ -515,7 +742,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 	if (time_after(jiffies, data->last_updated + HZ + HZ/2)
 	 || !data->valid) {
 		/* Fan clock dividers */
-		w83627ehf_update_fan_div(data);
+		w83627ehf_update_fan_div_common(dev, data);
 
 		/* Measured voltages and limits */
 		for (i = 0; i < data->in_num; i++) {
@@ -533,23 +760,29 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 				continue;
 
 			data->fan[i] = w83627ehf_read_value(data,
-				       data->REG_FAN[i]);
-			data->fan_min[i] = w83627ehf_read_value(data,
+							    data->REG_FAN[i]);
+
+			if (data->has_fan_min & (1 << i))
+				data->fan_min[i] = w83627ehf_read_value(data,
 					   data->REG_FAN_MIN[i]);
 
 			/* If we failed to measure the fan speed and clock
 			   divider can be increased, let's try that for next
 			   time */
-			if (data->fan[i] == 0xff
-			 && data->fan_div[i] < 0x07) {
+			if (!is_word_sized(data->REG_FAN[i])
+			    && (data->fan[i] == 0xff
+				|| (sio_data->kind == nct6775
+				    && data->fan[i] == 0x00))
+			    && data->fan_div[i] < 0x07) {
 				dev_dbg(dev, "Increasing fan%d "
 					"clock divider from %u to %u\n",
 					i + 1, div_from_reg(data->fan_div[i]),
 					div_from_reg(data->fan_div[i] + 1));
 				data->fan_div[i]++;
-				w83627ehf_write_fan_div(data, i);
+				w83627ehf_write_fan_div_common(dev, data, i);
 				/* Preserve min limit if possible */
-				if (data->fan_min[i] >= 2
+				if ((data->has_fan_min & (1 << i))
+				 && data->fan_min[i] >= 2
 				 && data->fan_min[i] != 255)
 					w83627ehf_write_value(data,
 						data->REG_FAN_MIN[i],
@@ -557,64 +790,54 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 			}
 		}
 
+		w83627ehf_update_pwm_common(dev, data);
+
 		for (i = 0; i < data->pwm_num; i++) {
 			if (!(data->has_fan & (1 << i)))
 				continue;
 
-			/* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
-			if (i != 1) {
-				pwmcfg = w83627ehf_read_value(data,
-						W83627EHF_REG_PWM_ENABLE[i]);
-				tolerance = w83627ehf_read_value(data,
-						W83627EHF_REG_TOLERANCE[i]);
-			}
-			data->pwm_mode[i] =
-				((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
-				? 0 : 1;
-			data->pwm_enable[i] =
-				((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
-				& 3) + 1;
-			data->pwm[i] = w83627ehf_read_value(data,
-							    data->REG_PWM[i]);
-			data->fan_start_output[i] = w83627ehf_read_value(data,
-					data->REG_FAN_START_OUTPUT[i]);
-			data->fan_stop_output[i] = w83627ehf_read_value(data,
-					data->REG_FAN_STOP_OUTPUT[i]);
-			data->fan_stop_time[i] = w83627ehf_read_value(data,
-					data->REG_FAN_STOP_TIME[i]);
-
-			if (data->REG_FAN_MAX_OUTPUT[i] != 0xff)
+			data->fan_start_output[i] =
+			  w83627ehf_read_value(data,
+					       data->REG_FAN_START_OUTPUT[i]);
+			data->fan_stop_output[i] =
+			  w83627ehf_read_value(data,
+					       data->REG_FAN_STOP_OUTPUT[i]);
+			data->fan_stop_time[i] =
+			  w83627ehf_read_value(data,
+					       data->REG_FAN_STOP_TIME[i]);
+
+			if (data->REG_FAN_MAX_OUTPUT &&
+			    data->REG_FAN_MAX_OUTPUT[i] != 0xff)
 				data->fan_max_output[i] =
 				  w83627ehf_read_value(data,
-					       data->REG_FAN_MAX_OUTPUT[i]);
+						data->REG_FAN_MAX_OUTPUT[i]);
 
-			if (data->REG_FAN_STEP_OUTPUT[i] != 0xff)
+			if (data->REG_FAN_STEP_OUTPUT &&
+			    data->REG_FAN_STEP_OUTPUT[i] != 0xff)
 				data->fan_step_output[i] =
 				  w83627ehf_read_value(data,
-					       data->REG_FAN_STEP_OUTPUT[i]);
+						data->REG_FAN_STEP_OUTPUT[i]);
 
 			data->target_temp[i] =
 				w83627ehf_read_value(data,
 					data->REG_TARGET[i]) &
 					(data->pwm_mode[i] == 1 ? 0x7f : 0xff);
-			data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
-									& 0x0f;
 		}
 
 		/* Measured temperatures and limits */
 		for (i = 0; i < NUM_REG_TEMP; i++) {
 			if (!(data->have_temp & (1 << i)))
 				continue;
-			data->temp[i]
-			  = w83627ehf_read_value(data, W83627EHF_REG_TEMP[i]);
-			if (i > 2)
-				break;
-			data->temp_max[i]
-			  = w83627ehf_read_value(data,
-						 W83627EHF_REG_TEMP_OVER[i]);
-			data->temp_max_hyst[i]
-			  = w83627ehf_read_value(data,
-						 W83627EHF_REG_TEMP_HYST[i]);
+			data->temp[i] = w83627ehf_read_value(data,
+						data->reg_temp[i]);
+			if (data->reg_temp_over[i])
+				data->temp_max[i]
+				  = w83627ehf_read_value(data,
+						data->reg_temp_over[i]);
+			if (data->reg_temp_hyst[i])
+				data->temp_max_hyst[i]
+				  = w83627ehf_read_value(data,
+						data->reg_temp_hyst[i]);
 		}
 
 		data->alarms = w83627ehf_read_value(data,
@@ -736,21 +959,29 @@ static struct sensor_device_attribute sda_in_max[] = {
 	SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
 };
 
-#define show_fan_reg(reg) \
-static ssize_t \
-show_##reg(struct device *dev, struct device_attribute *attr, \
-	   char *buf) \
-{ \
-	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
-	struct sensor_device_attribute *sensor_attr = \
-		to_sensor_dev_attr(attr); \
-	int nr = sensor_attr->index; \
-	return sprintf(buf, "%d\n", \
-		       fan_from_reg(data->reg[nr], \
-				    div_from_reg(data->fan_div[nr]))); \
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%d\n",
+		       fan_from_reg(data->REG_FAN[nr],
+				    data->fan[nr],
+				    div_from_reg(data->fan_div[nr])));
+}
+
+static ssize_t
+show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%d\n",
+		       fan_from_reg(data->REG_FAN_MIN[nr],
+				    data->fan_min[nr],
+				    div_from_reg(data->fan_div[nr])));
 }
-show_fan_reg(fan);
-show_fan_reg(fan_min);
 
 static ssize_t
 show_fan_div(struct device *dev, struct device_attribute *attr,
@@ -779,6 +1010,18 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 		return err;
 
 	mutex_lock(&data->update_lock);
+	if (is_word_sized(data->REG_FAN_MIN[nr])) {
+		if (!val) {
+			val = 0xff1f;
+		} else {
+			if (val > 1350000U)
+				val = 135000U;
+			val = 1350000U / val;
+			val = (val & 0x1f) | ((val << 3) & 0xff00);
+		}
+		data->fan_min[nr] = val;
+		goto done;	/* Leave fan divider alone */
+	}
 	if (!val) {
 		/* No min limit, alarm disabled */
 		data->fan_min[nr] = 255;
@@ -790,14 +1033,16 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 		data->fan_min[nr] = 254;
 		new_div = 7; /* 128 == (1 << 7) */
 		dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
-			 "minimum\n", nr + 1, val, fan_from_reg(254, 128));
+			 "minimum\n", nr + 1, val,
+			 fan_from_reg(data->REG_FAN_MIN[nr], 254, 128));
 	} else if (!reg) {
 		/* Speed above this value cannot possibly be represented,
 		   even with the lowest divider (1) */
 		data->fan_min[nr] = 1;
 		new_div = 0; /* 1 == (1 << 0) */
 		dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
-			 "maximum\n", nr + 1, val, fan_from_reg(1, 1));
+			 "maximum\n", nr + 1, val,
+			 fan_from_reg(data->REG_FAN_MIN[nr], 1, 1));
 	} else {
 		/* Automatically pick the best divider, i.e. the one such
 		   that the min limit will correspond to a register value
@@ -827,10 +1072,11 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 			nr + 1, div_from_reg(data->fan_div[nr]),
 			div_from_reg(new_div));
 		data->fan_div[nr] = new_div;
-		w83627ehf_write_fan_div(data, nr);
+		w83627ehf_write_fan_div_common(dev, data, nr);
 		/* Give the chip time to sample a new speed value */
 		data->last_updated = jiffies;
 	}
+done:
 	w83627ehf_write_value(data, data->REG_FAN_MIN[nr],
 			      data->fan_min[nr]);
 	mutex_unlock(&data->update_lock);
@@ -884,7 +1130,7 @@ show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
 	return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
 }
 
-#define show_temp_reg(REG, reg) \
+#define show_temp_reg(addr, reg) \
 static ssize_t \
 show_##reg(struct device *dev, struct device_attribute *attr, \
 	   char *buf) \
@@ -894,13 +1140,13 @@ show_##reg(struct device *dev, struct device_attribute *attr, \
 		to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	return sprintf(buf, "%d\n", \
-		       temp_from_reg(W83627EHF_REG_##REG[nr], data->reg[nr])); \
+		       temp_from_reg(data->addr[nr], data->reg[nr])); \
 }
-show_temp_reg(TEMP, temp);
-show_temp_reg(TEMP_OVER, temp_max);
-show_temp_reg(TEMP_HYST, temp_max_hyst);
+show_temp_reg(reg_temp, temp);
+show_temp_reg(reg_temp_over, temp_max);
+show_temp_reg(reg_temp_hyst, temp_max_hyst);
 
-#define store_temp_reg(REG, reg) \
+#define store_temp_reg(addr, reg) \
 static ssize_t \
 store_##reg(struct device *dev, struct device_attribute *attr, \
 	    const char *buf, size_t count) \
@@ -915,14 +1161,14 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
 	if (err < 0) \
 		return err; \
 	mutex_lock(&data->update_lock); \
-	data->reg[nr] = temp_to_reg(W83627EHF_REG_TEMP_##REG[nr], val); \
-	w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
+	data->reg[nr] = temp_to_reg(data->addr[nr], val); \
+	w83627ehf_write_value(data, data->addr[nr], \
 			      data->reg[nr]); \
 	mutex_unlock(&data->update_lock); \
 	return count; \
 }
-store_temp_reg(OVER, temp_max);
-store_temp_reg(HYST, temp_max_hyst);
+store_temp_reg(reg_temp_over, temp_max);
+store_temp_reg(reg_temp_hyst, temp_max_hyst);
 
 static ssize_t
 show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
@@ -938,6 +1184,11 @@ static struct sensor_device_attribute sda_temp_input[] = {
 	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
 	SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
 	SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3),
+	SENSOR_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4),
+	SENSOR_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5),
+	SENSOR_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6),
+	SENSOR_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7),
+	SENSOR_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8),
 };
 
 static struct sensor_device_attribute sda_temp_label[] = {
@@ -945,6 +1196,11 @@ static struct sensor_device_attribute sda_temp_label[] = {
 	SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
 	SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
 	SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
+	SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4),
+	SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5),
+	SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6),
+	SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7),
+	SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8),
 };
 
 static struct sensor_device_attribute sda_temp_max[] = {
@@ -954,6 +1210,18 @@ static struct sensor_device_attribute sda_temp_max[] = {
 		    store_temp_max, 1),
 	SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
 		    store_temp_max, 2),
+	SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 3),
+	SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 4),
+	SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 5),
+	SENSOR_ATTR(temp7_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 6),
+	SENSOR_ATTR(temp8_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 7),
+	SENSOR_ATTR(temp9_max, S_IRUGO | S_IWUSR, show_temp_max,
+		    store_temp_max, 8),
 };
 
 static struct sensor_device_attribute sda_temp_max_hyst[] = {
@@ -963,6 +1231,18 @@ static struct sensor_device_attribute sda_temp_max_hyst[] = {
 		    store_temp_max_hyst, 1),
 	SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
 		    store_temp_max_hyst, 2),
+	SENSOR_ATTR(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 3),
+	SENSOR_ATTR(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 4),
+	SENSOR_ATTR(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 5),
+	SENSOR_ATTR(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 6),
+	SENSOR_ATTR(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 7),
+	SENSOR_ATTR(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+		    store_temp_max_hyst, 8),
 };
 
 static struct sensor_device_attribute sda_temp_alarm[] = {
@@ -1048,6 +1328,7 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
 			const char *buf, size_t count)
 {
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	struct w83627ehf_sio_data *sio_data = dev->platform_data;
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	unsigned long val;
@@ -1060,12 +1341,25 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
 
 	if (!val || (val > 4 && val != data->pwm_enable_orig[nr]))
 		return -EINVAL;
+	/* SmartFan III mode is not supported on NCT6776F */
+	if (sio_data->kind == nct6776 && val == 4)
+		return -EINVAL;
+
 	mutex_lock(&data->update_lock);
-	reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
 	data->pwm_enable[nr] = val;
-	reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
-	reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
-	w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
+	if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
+		reg = w83627ehf_read_value(data,
+					   NCT6775_REG_FAN_MODE[nr]);
+		reg &= 0x0f;
+		reg |= (val - 1) << 4;
+		w83627ehf_write_value(data,
+				      NCT6775_REG_FAN_MODE[nr], reg);
+	} else {
+		reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
+		reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
+		reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
+		w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
+	}
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -1113,6 +1407,7 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
 			const char *buf, size_t count)
 {
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	struct w83627ehf_sio_data *sio_data = dev->platform_data;
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	u16 reg;
@@ -1127,13 +1422,22 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
 	val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
 
 	mutex_lock(&data->update_lock);
-	reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
-	data->tolerance[nr] = val;
-	if (nr == 1)
-		reg = (reg & 0x0f) | (val << 4);
-	else
+	if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
+		/* Limit tolerance further for NCT6776F */
+		if (sio_data->kind == nct6776 && val > 7)
+			val = 7;
+		reg = w83627ehf_read_value(data, NCT6775_REG_FAN_MODE[nr]);
 		reg = (reg & 0xf0) | val;
-	w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
+		w83627ehf_write_value(data, NCT6775_REG_FAN_MODE[nr], reg);
+	} else {
+		reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
+		if (nr == 1)
+			reg = (reg & 0x0f) | (val << 4);
+		else
+			reg = (reg & 0xf0) | val;
+		w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
+	}
+	data->tolerance[nr] = val;
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -1350,7 +1654,8 @@ static void w83627ehf_device_remove_files(struct device *dev)
 	for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
 		struct sensor_device_attribute *attr =
 		  &sda_sf3_max_step_arrays[i];
-		if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
+		if (data->REG_FAN_STEP_OUTPUT &&
+		    data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
 			device_remove_file(dev, &attr->dev_attr);
 	}
 	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
@@ -1381,10 +1686,10 @@ static void w83627ehf_device_remove_files(struct device *dev)
 			continue;
 		device_remove_file(dev, &sda_temp_input[i].dev_attr);
 		device_remove_file(dev, &sda_temp_label[i].dev_attr);
-		if (i > 2)
-			break;
 		device_remove_file(dev, &sda_temp_max[i].dev_attr);
 		device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
+		if (i > 2)
+			continue;
 		device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
 		device_remove_file(dev, &sda_temp_type[i].dev_attr);
 	}
@@ -1409,13 +1714,13 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
 	for (i = 0; i < NUM_REG_TEMP; i++) {
 		if (!(data->have_temp & (1 << i)))
 			continue;
-		if (!W83627EHF_REG_TEMP_CONFIG[i])
+		if (!data->reg_temp_config[i])
 			continue;
 		tmp = w83627ehf_read_value(data,
-					   W83627EHF_REG_TEMP_CONFIG[i]);
+					   data->reg_temp_config[i]);
 		if (tmp & 0x01)
 			w83627ehf_write_value(data,
-					      W83627EHF_REG_TEMP_CONFIG[i],
+					      data->reg_temp_config[i],
 					      tmp & 0xfe);
 	}
 
@@ -1434,13 +1739,39 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
 	}
 }
 
+static void w82627ehf_swap_tempreg(struct w83627ehf_data *data,
+				   int r1, int r2)
+{
+	u16 tmp;
+
+	tmp = data->temp_src[r1];
+	data->temp_src[r1] = data->temp_src[r2];
+	data->temp_src[r2] = tmp;
+
+	tmp = data->reg_temp[r1];
+	data->reg_temp[r1] = data->reg_temp[r2];
+	data->reg_temp[r2] = tmp;
+
+	tmp = data->reg_temp_over[r1];
+	data->reg_temp_over[r1] = data->reg_temp_over[r2];
+	data->reg_temp_over[r2] = tmp;
+
+	tmp = data->reg_temp_hyst[r1];
+	data->reg_temp_hyst[r1] = data->reg_temp_hyst[r2];
+	data->reg_temp_hyst[r2] = tmp;
+
+	tmp = data->reg_temp_config[r1];
+	data->reg_temp_config[r1] = data->reg_temp_config[r2];
+	data->reg_temp_config[r2] = tmp;
+}
+
 static int __devinit w83627ehf_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct w83627ehf_sio_data *sio_data = dev->platform_data;
 	struct w83627ehf_data *data;
 	struct resource *res;
-	u8 fan4pin, fan5pin, en_vrm10;
+	u8 fan3pin, fan4pin, fan4min, fan5pin, en_vrm10;
 	int i, err = 0;
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1466,9 +1797,11 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 
 	/* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
 	data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
-	/* 667HG has 3 pwms */
+	/* 667HG, NCT6775F, and NCT6776F have 3 pwms */
 	data->pwm_num = (sio_data->kind == w83667hg
-			 || sio_data->kind == w83667hg_b) ? 3 : 4;
+			 || sio_data->kind == w83667hg_b
+			 || sio_data->kind == nct6775
+			 || sio_data->kind == nct6776) ? 3 : 4;
 
 	data->have_temp = 0x07;
 	/* Check temp3 configuration bit for 667HG */
@@ -1479,15 +1812,98 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 		if (reg & 0x01)
 			data->have_temp &= ~(1 << 2);
 		else
-			data->in6_skip = 1; /* Either temp3 or in6 */
+			data->in6_skip = 1;	/* either temp3 or in6 */
+	}
+
+	/* Deal with temperature register setup first. */
+	if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
+		int mask = 0;
+
+		/*
+		 * Display temperature sensor output only if it monitors
+		 * a source other than one already reported. Always display
+		 * first three temperature registers, though.
+		 */
+		for (i = 0; i < NUM_REG_TEMP; i++) {
+			u8 src;
+
+			data->reg_temp[i] = NCT6775_REG_TEMP[i];
+			data->reg_temp_over[i] = NCT6775_REG_TEMP_OVER[i];
+			data->reg_temp_hyst[i] = NCT6775_REG_TEMP_HYST[i];
+			data->reg_temp_config[i] = NCT6775_REG_TEMP_CONFIG[i];
+
+			src = w83627ehf_read_value(data,
+						   NCT6775_REG_TEMP_SOURCE[i]);
+			src &= 0x1f;
+			if (src && !(mask & (1 << src))) {
+				data->have_temp |= 1 << i;
+				mask |= 1 << src;
+			}
+
+			data->temp_src[i] = src;
+
+			/*
+			 * Now do some register swapping if index 0..2 don't
+			 * point to SYSTIN(1), CPUIN(2), and AUXIN(3).
+			 * Idea is to have the first three attributes
+			 * report SYSTIN, CPUIN, and AUXIN if possible
+			 * without overriding the basic system configuration.
+			 */
+			if (i > 0 && data->temp_src[0] != 1
+			    && data->temp_src[i] == 1)
+				w82627ehf_swap_tempreg(data, 0, i);
+			if (i > 1 && data->temp_src[1] != 2
+			    && data->temp_src[i] == 2)
+				w82627ehf_swap_tempreg(data, 1, i);
+			if (i > 2 && data->temp_src[2] != 3
+			    && data->temp_src[i] == 3)
+				w82627ehf_swap_tempreg(data, 2, i);
+		}
+		if (sio_data->kind == nct6776) {
+			/*
+			 * On NCT6776, AUXTIN and VIN3 pins are shared.
+			 * Only way to detect it is to check if AUXTIN is used
+			 * as a temperature source, and if that source is
+			 * enabled.
+			 *
+			 * If that is the case, disable in6, which reports VIN3.
+			 * Otherwise disable temp3.
+			 */
+			if (data->temp_src[2] == 3) {
+				u8 reg;
+
+				if (data->reg_temp_config[2])
+					reg = w83627ehf_read_value(data,
+						data->reg_temp_config[2]);
+				else
+					reg = 0; /* Assume AUXTIN is used */
+
+				if (reg & 0x01)
+					data->have_temp &= ~(1 << 2);
+				else
+					data->in6_skip = 1;
+			}
+		}
+
+		data->temp_label = nct6776_temp_label;
 	} else if (sio_data->kind == w83667hg_b) {
 		u8 reg;
 
+		/*
+		 * Temperature sources are selected with bank 0, registers 0x49
+		 * and 0x4a.
+		 */
+		for (i = 0; i < ARRAY_SIZE(W83627EHF_REG_TEMP); i++) {
+			data->reg_temp[i] = W83627EHF_REG_TEMP[i];
+			data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
+			data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
+			data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
+		}
 		reg = w83627ehf_read_value(data, 0x4a);
 		data->temp_src[0] = reg >> 5;
 		reg = w83627ehf_read_value(data, 0x49);
 		data->temp_src[1] = reg & 0x07;
-		data->temp_src[2] = (reg >> 4)  & 0x07;
+		data->temp_src[2] = (reg >> 4) & 0x07;
 
 		/*
 		 * W83667HG-B has another temperature register at 0x7e.
@@ -1516,22 +1932,54 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 			data->in6_skip = 1;
 
 		data->temp_label = w83667hg_b_temp_label;
+	} else {
+		/* Temperature sources are fixed */
+		for (i = 0; i < 3; i++) {
+			data->reg_temp[i] = W83627EHF_REG_TEMP[i];
+			data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
+			data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
+			data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
+		}
 	}
 
-	data->REG_PWM = W83627EHF_REG_PWM;
-	data->REG_TARGET = W83627EHF_REG_TARGET;
-	data->REG_FAN = W83627EHF_REG_FAN;
-	data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
-	data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
-	data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
-	data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
-	data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
-	if (sio_data->kind == w83667hg_b) {
+	if (sio_data->kind == nct6775) {
+		data->REG_PWM = NCT6775_REG_PWM;
+		data->REG_TARGET = NCT6775_REG_TARGET;
+		data->REG_FAN = W83627EHF_REG_FAN;
+		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
+		data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
+		data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
+		data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
+		data->REG_FAN_MAX_OUTPUT = NCT6775_REG_FAN_MAX_OUTPUT;
+		data->REG_FAN_STEP_OUTPUT = NCT6775_REG_FAN_STEP_OUTPUT;
+	} else if (sio_data->kind == nct6776) {
+		data->REG_PWM = NCT6775_REG_PWM;
+		data->REG_TARGET = NCT6775_REG_TARGET;
+		data->REG_FAN = NCT6776_REG_FAN;
+		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+		data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
+		data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
+		data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
+	} else if (sio_data->kind == w83667hg_b) {
+		data->REG_PWM = W83627EHF_REG_PWM;
+		data->REG_TARGET = W83627EHF_REG_TARGET;
+		data->REG_FAN = W83627EHF_REG_FAN;
+		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
+		data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
+		data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
+		data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
 		data->REG_FAN_MAX_OUTPUT =
 		  W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
 		data->REG_FAN_STEP_OUTPUT =
 		  W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
 	} else {
+		data->REG_PWM = W83627EHF_REG_PWM;
+		data->REG_TARGET = W83627EHF_REG_TARGET;
+		data->REG_FAN = W83627EHF_REG_FAN;
+		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
+		data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
+		data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
+		data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
 		data->REG_FAN_MAX_OUTPUT =
 		  W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
 		data->REG_FAN_STEP_OUTPUT =
@@ -1544,7 +1992,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	data->vrm = vid_which_vrm();
 	superio_enter(sio_data->sioreg);
 	/* Read VID value */
-	if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
+	if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b ||
+	    sio_data->kind == nct6775 || sio_data->kind == nct6776) {
 		/* W83667HG has different pins for VID input and output, so
 		we can get the VID input values directly at logical device D
 		0xe3. */
@@ -1595,12 +2044,27 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	}
 
 	/* fan4 and fan5 share some pins with the GPIO and serial flash */
-	if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
-		fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
+	if (sio_data->kind == nct6775) {
+		/* On NCT6775, fan4 shares pins with the fdc interface */
+		fan3pin = 1;
+		fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
+		fan4min = 0;
+		fan5pin = 0;
+	} else if (sio_data->kind == nct6776) {
+		fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
+		fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01);
+		fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02);
+		fan4min = fan4pin;
+	} else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
+		fan3pin = 1;
 		fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
+		fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
+		fan4min = fan4pin;
 	} else {
-		fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
+		fan3pin = 1;
 		fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
+		fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
+		fan4min = fan4pin;
 	}
 	superio_exit(sio_data->sioreg);
 
@@ -1610,15 +2074,36 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	   connected fan5 as input unless they are emitting log 1, which
 	   is not the default. */
 
-	data->has_fan = 0x07; /* fan1, fan2 and fan3 */
-	i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
-	if ((i & (1 << 2)) && fan4pin)
-		data->has_fan |= (1 << 3);
-	if (!(i & (1 << 1)) && fan5pin)
-		data->has_fan |= (1 << 4);
+	data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
+
+	data->has_fan |= (fan3pin << 2);
+	data->has_fan_min |= (fan3pin << 2);
+
+	/*
+	 * NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1 register
+	 */
+	if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
+		data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
+		data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
+	} else {
+		i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
+		if ((i & (1 << 2)) && fan4pin) {
+			data->has_fan |= (1 << 3);
+			data->has_fan_min |= (1 << 3);
+		}
+		if (!(i & (1 << 1)) && fan5pin) {
+			data->has_fan |= (1 << 4);
+			data->has_fan_min |= (1 << 4);
+		}
+	}
 
 	/* Read fan clock dividers immediately */
-	w83627ehf_update_fan_div(data);
+	w83627ehf_update_fan_div_common(dev, data);
+
+	/* Read pwm data to save original values */
+	w83627ehf_update_pwm_common(dev, data);
+	for (i = 0; i < data->pwm_num; i++)
+		data->pwm_enable_orig[i] = data->pwm_enable[i];
 
 	/* Read pwm data to save original values */
 	w83627ehf_update_pwm_common(dev, data);
@@ -1635,7 +2120,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
 		struct sensor_device_attribute *attr =
 		  &sda_sf3_max_step_arrays[i];
-		if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
+		if (data->REG_FAN_STEP_OUTPUT &&
+		    data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
 			err = device_create_file(dev, &attr->dev_attr);
 			if (err)
 				goto exit_remove;
@@ -1668,12 +2154,20 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 			if ((err = device_create_file(dev,
 					&sda_fan_input[i].dev_attr))
 				|| (err = device_create_file(dev,
-					&sda_fan_alarm[i].dev_attr))
-				|| (err = device_create_file(dev,
-					&sda_fan_div[i].dev_attr))
-				|| (err = device_create_file(dev,
-					&sda_fan_min[i].dev_attr)))
+					&sda_fan_alarm[i].dev_attr)))
 				goto exit_remove;
+			if (sio_data->kind != nct6776) {
+				err = device_create_file(dev,
+						&sda_fan_div[i].dev_attr);
+				if (err)
+					goto exit_remove;
+			}
+			if (data->has_fan_min & (1 << i)) {
+				err = device_create_file(dev,
+						&sda_fan_min[i].dev_attr);
+				if (err)
+					goto exit_remove;
+			}
 			if (i < data->pwm_num &&
 				((err = device_create_file(dev,
 					&sda_pwm[i].dev_attr))
@@ -1701,12 +2195,21 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 			if (err)
 				goto exit_remove;
 		}
+		if (data->reg_temp_over[i]) {
+			err = device_create_file(dev,
+				&sda_temp_max[i].dev_attr);
+			if (err)
+				goto exit_remove;
+		}
+		if (data->reg_temp_hyst[i]) {
+			err = device_create_file(dev,
+				&sda_temp_max_hyst[i].dev_attr);
+			if (err)
+				goto exit_remove;
+		}
 		if (i > 2)
-			break;
-		if ((err = device_create_file(dev, &sda_temp_max[i].dev_attr))
-			|| (err = device_create_file(dev,
-				&sda_temp_max_hyst[i].dev_attr))
-			|| (err = device_create_file(dev,
+			continue;
+		if ((err = device_create_file(dev,
 				&sda_temp_alarm[i].dev_attr))
 			|| (err = device_create_file(dev,
 				&sda_temp_type[i].dev_attr)))
@@ -1767,6 +2270,8 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
 	static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
 	static const char __initdata sio_name_W83667HG[] = "W83667HG";
 	static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
+	static const char __initdata sio_name_NCT6775[] = "NCT6775F";
+	static const char __initdata sio_name_NCT6776[] = "NCT6776F";
 
 	u16 val;
 	const char *sio_name;
@@ -1803,6 +2308,14 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
 		sio_data->kind = w83667hg_b;
 		sio_name = sio_name_W83667HG_B;
 		break;
+	case SIO_NCT6775_ID:
+		sio_data->kind = nct6775;
+		sio_name = sio_name_NCT6775;
+		break;
+	case SIO_NCT6776_ID:
+		sio_data->kind = nct6776;
+		sio_name = sio_name_NCT6776;
+		break;
 	default:
 		if (val != 0xffff)
 			pr_debug("unsupported chip ID: 0x%04x\n", val);
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [lm-sensors] [PATCH v5 09/11] hwmon: (w83627ehf) Use 16 bit fan
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
@ 2011-03-04 17:58   ` Guenter Roeck
  -1 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:58 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

Some of the chips supported by this driver have 13 bit or 16 bit fan count
registers. This patch improves support for those registers, specifically for
NCT6775F. With the changes in this patch, fan speed is reported correctly even
if the fan divider is set to a low value, which results in a fan speed reading
above 0xff.

With this patch, the width of fan count registers is no longer used to determine
if the chip has fan divider register(s) or not. A dedicated flag is used instead
to determine if this is the case.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/w83627ehf.c |   86 +++++++++++++++++++++++++++++++--------------
 1 files changed, 59 insertions(+), 27 deletions(-)

diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index b3b4f2b..df6e502 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -234,7 +234,7 @@ static const u16 NCT6775_REG_FAN_STOP_TIME[] = { 0x107, 0x207, 0x307 };
 static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309 };
 static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
 static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
-static const u16 NCT6776_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
+static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
 static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642};
 
 static const u16 NCT6775_REG_TEMP[]
@@ -342,21 +342,36 @@ static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
 						(msec + 200) / 400), 1, 255);
 }
 
-static inline unsigned int
-fan_from_reg(int reg, u16 val, unsigned int div)
+static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
 {
-	if (val = 0)
+	if (reg = 0 || reg = 255)
 		return 0;
-	if (is_word_sized(reg)) {
-		if ((val & 0xff1f) = 0xff1f)
-			return 0;
-		val = (val & 0x1f) | ((val & 0xff00) >> 3);
-	} else {
-		if (val = 255 || div = 0)
-			return 0;
-		val *= div;
-	}
-	return 1350000U / val;
+	return 1350000U / (reg << divreg);
+}
+
+static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
+{
+	if ((reg & 0xff1f) = 0xff1f)
+		return 0;
+
+	reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
+
+	if (reg = 0)
+		return 0;
+
+	return 1350000U / reg;
+}
+
+static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
+{
+	if (reg = 0 || reg = 0xffff)
+		return 0;
+
+	/*
+	 * Even though the registers are 16 bit wide, the fan divisor
+	 * still applies.
+	 */
+	return 1350000U / (reg << divreg);
 }
 
 static inline unsigned int
@@ -424,6 +439,9 @@ struct w83627ehf_data {
 	const u16 *REG_FAN_MAX_OUTPUT;
 	const u16 *REG_FAN_STEP_OUTPUT;
 
+	unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
+	unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
+
 	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
@@ -439,6 +457,7 @@ struct w83627ehf_data {
 	u8 fan_div[5];
 	u8 has_fan;		/* some fan inputs can be disabled */
 	u8 has_fan_min;		/* some fans don't have min register */
+	bool has_fan_div;
 	u8 temp_type[3];
 	s16 temp[9];
 	s16 temp_max[9];
@@ -769,8 +788,8 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 			/* If we failed to measure the fan speed and clock
 			   divider can be increased, let's try that for next
 			   time */
-			if (!is_word_sized(data->REG_FAN[i])
-			    && (data->fan[i] = 0xff
+			if (data->has_fan_div
+			    && (data->fan[i] >= 0xff
 				|| (sio_data->kind = nct6775
 				    && data->fan[i] = 0x00))
 			    && data->fan_div[i] < 0x07) {
@@ -966,9 +985,7 @@ show_fan(struct device *dev, struct device_attribute *attr, char *buf)
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	return sprintf(buf, "%d\n",
-		       fan_from_reg(data->REG_FAN[nr],
-				    data->fan[nr],
-				    div_from_reg(data->fan_div[nr])));
+		       data->fan_from_reg(data->fan[nr], data->fan_div[nr]));
 }
 
 static ssize_t
@@ -978,9 +995,8 @@ show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	return sprintf(buf, "%d\n",
-		       fan_from_reg(data->REG_FAN_MIN[nr],
-				    data->fan_min[nr],
-				    div_from_reg(data->fan_div[nr])));
+		       data->fan_from_reg_min(data->fan_min[nr],
+					      data->fan_div[nr]));
 }
 
 static ssize_t
@@ -1010,7 +1026,11 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 		return err;
 
 	mutex_lock(&data->update_lock);
-	if (is_word_sized(data->REG_FAN_MIN[nr])) {
+	if (!data->has_fan_div) {
+		/*
+		 * Only NCT6776F for now, so we know that this is a 13 bit
+		 * register
+		 */
 		if (!val) {
 			val = 0xff1f;
 		} else {
@@ -1034,7 +1054,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 		new_div = 7; /* 128 = (1 << 7) */
 		dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
 			 "minimum\n", nr + 1, val,
-			 fan_from_reg(data->REG_FAN_MIN[nr], 254, 128));
+			 data->fan_from_reg_min(254, 7));
 	} else if (!reg) {
 		/* Speed above this value cannot possibly be represented,
 		   even with the lowest divider (1) */
@@ -1042,7 +1062,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 		new_div = 0; /* 1 = (1 << 0) */
 		dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
 			 "maximum\n", nr + 1, val,
-			 fan_from_reg(data->REG_FAN_MIN[nr], 1, 1));
+			 data->fan_from_reg_min(1, 0));
 	} else {
 		/* Automatically pick the best divider, i.e. the one such
 		   that the min limit will correspond to a register value
@@ -1943,9 +1963,12 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	}
 
 	if (sio_data->kind = nct6775) {
+		data->has_fan_div = true;
+		data->fan_from_reg = fan_from_reg16;
+		data->fan_from_reg_min = fan_from_reg8;
 		data->REG_PWM = NCT6775_REG_PWM;
 		data->REG_TARGET = NCT6775_REG_TARGET;
-		data->REG_FAN = W83627EHF_REG_FAN;
+		data->REG_FAN = NCT6775_REG_FAN;
 		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
 		data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
 		data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
@@ -1953,14 +1976,20 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 		data->REG_FAN_MAX_OUTPUT = NCT6775_REG_FAN_MAX_OUTPUT;
 		data->REG_FAN_STEP_OUTPUT = NCT6775_REG_FAN_STEP_OUTPUT;
 	} else if (sio_data->kind = nct6776) {
+		data->has_fan_div = false;
+		data->fan_from_reg = fan_from_reg13;
+		data->fan_from_reg_min = fan_from_reg13;
 		data->REG_PWM = NCT6775_REG_PWM;
 		data->REG_TARGET = NCT6775_REG_TARGET;
-		data->REG_FAN = NCT6776_REG_FAN;
+		data->REG_FAN = NCT6775_REG_FAN;
 		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
 		data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
 		data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
 		data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
 	} else if (sio_data->kind = w83667hg_b) {
+		data->has_fan_div = true;
+		data->fan_from_reg = fan_from_reg8;
+		data->fan_from_reg_min = fan_from_reg8;
 		data->REG_PWM = W83627EHF_REG_PWM;
 		data->REG_TARGET = W83627EHF_REG_TARGET;
 		data->REG_FAN = W83627EHF_REG_FAN;
@@ -1973,6 +2002,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 		data->REG_FAN_STEP_OUTPUT  		  W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
 	} else {
+		data->has_fan_div = true;
+		data->fan_from_reg = fan_from_reg8;
+		data->fan_from_reg_min = fan_from_reg8;
 		data->REG_PWM = W83627EHF_REG_PWM;
 		data->REG_TARGET = W83627EHF_REG_TARGET;
 		data->REG_FAN = W83627EHF_REG_FAN;
-- 
1.7.3.1


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 09/11] hwmon: (w83627ehf) Use 16 bit fan count registers if supported
@ 2011-03-04 17:58   ` Guenter Roeck
  0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:58 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

Some of the chips supported by this driver have 13 bit or 16 bit fan count
registers. This patch improves support for those registers, specifically for
NCT6775F. With the changes in this patch, fan speed is reported correctly even
if the fan divider is set to a low value, which results in a fan speed reading
above 0xff.

With this patch, the width of fan count registers is no longer used to determine
if the chip has fan divider register(s) or not. A dedicated flag is used instead
to determine if this is the case.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/w83627ehf.c |   86 +++++++++++++++++++++++++++++++--------------
 1 files changed, 59 insertions(+), 27 deletions(-)

diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index b3b4f2b..df6e502 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -234,7 +234,7 @@ static const u16 NCT6775_REG_FAN_STOP_TIME[] = { 0x107, 0x207, 0x307 };
 static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309 };
 static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
 static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
-static const u16 NCT6776_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
+static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
 static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642};
 
 static const u16 NCT6775_REG_TEMP[]
@@ -342,21 +342,36 @@ static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
 						(msec + 200) / 400), 1, 255);
 }
 
-static inline unsigned int
-fan_from_reg(int reg, u16 val, unsigned int div)
+static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
 {
-	if (val == 0)
+	if (reg == 0 || reg == 255)
 		return 0;
-	if (is_word_sized(reg)) {
-		if ((val & 0xff1f) == 0xff1f)
-			return 0;
-		val = (val & 0x1f) | ((val & 0xff00) >> 3);
-	} else {
-		if (val == 255 || div == 0)
-			return 0;
-		val *= div;
-	}
-	return 1350000U / val;
+	return 1350000U / (reg << divreg);
+}
+
+static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
+{
+	if ((reg & 0xff1f) == 0xff1f)
+		return 0;
+
+	reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
+
+	if (reg == 0)
+		return 0;
+
+	return 1350000U / reg;
+}
+
+static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
+{
+	if (reg == 0 || reg == 0xffff)
+		return 0;
+
+	/*
+	 * Even though the registers are 16 bit wide, the fan divisor
+	 * still applies.
+	 */
+	return 1350000U / (reg << divreg);
 }
 
 static inline unsigned int
@@ -424,6 +439,9 @@ struct w83627ehf_data {
 	const u16 *REG_FAN_MAX_OUTPUT;
 	const u16 *REG_FAN_STEP_OUTPUT;
 
+	unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
+	unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
+
 	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
@@ -439,6 +457,7 @@ struct w83627ehf_data {
 	u8 fan_div[5];
 	u8 has_fan;		/* some fan inputs can be disabled */
 	u8 has_fan_min;		/* some fans don't have min register */
+	bool has_fan_div;
 	u8 temp_type[3];
 	s16 temp[9];
 	s16 temp_max[9];
@@ -769,8 +788,8 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 			/* If we failed to measure the fan speed and clock
 			   divider can be increased, let's try that for next
 			   time */
-			if (!is_word_sized(data->REG_FAN[i])
-			    && (data->fan[i] == 0xff
+			if (data->has_fan_div
+			    && (data->fan[i] >= 0xff
 				|| (sio_data->kind == nct6775
 				    && data->fan[i] == 0x00))
 			    && data->fan_div[i] < 0x07) {
@@ -966,9 +985,7 @@ show_fan(struct device *dev, struct device_attribute *attr, char *buf)
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	return sprintf(buf, "%d\n",
-		       fan_from_reg(data->REG_FAN[nr],
-				    data->fan[nr],
-				    div_from_reg(data->fan_div[nr])));
+		       data->fan_from_reg(data->fan[nr], data->fan_div[nr]));
 }
 
 static ssize_t
@@ -978,9 +995,8 @@ show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	return sprintf(buf, "%d\n",
-		       fan_from_reg(data->REG_FAN_MIN[nr],
-				    data->fan_min[nr],
-				    div_from_reg(data->fan_div[nr])));
+		       data->fan_from_reg_min(data->fan_min[nr],
+					      data->fan_div[nr]));
 }
 
 static ssize_t
@@ -1010,7 +1026,11 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 		return err;
 
 	mutex_lock(&data->update_lock);
-	if (is_word_sized(data->REG_FAN_MIN[nr])) {
+	if (!data->has_fan_div) {
+		/*
+		 * Only NCT6776F for now, so we know that this is a 13 bit
+		 * register
+		 */
 		if (!val) {
 			val = 0xff1f;
 		} else {
@@ -1034,7 +1054,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 		new_div = 7; /* 128 == (1 << 7) */
 		dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
 			 "minimum\n", nr + 1, val,
-			 fan_from_reg(data->REG_FAN_MIN[nr], 254, 128));
+			 data->fan_from_reg_min(254, 7));
 	} else if (!reg) {
 		/* Speed above this value cannot possibly be represented,
 		   even with the lowest divider (1) */
@@ -1042,7 +1062,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 		new_div = 0; /* 1 == (1 << 0) */
 		dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
 			 "maximum\n", nr + 1, val,
-			 fan_from_reg(data->REG_FAN_MIN[nr], 1, 1));
+			 data->fan_from_reg_min(1, 0));
 	} else {
 		/* Automatically pick the best divider, i.e. the one such
 		   that the min limit will correspond to a register value
@@ -1943,9 +1963,12 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 	}
 
 	if (sio_data->kind == nct6775) {
+		data->has_fan_div = true;
+		data->fan_from_reg = fan_from_reg16;
+		data->fan_from_reg_min = fan_from_reg8;
 		data->REG_PWM = NCT6775_REG_PWM;
 		data->REG_TARGET = NCT6775_REG_TARGET;
-		data->REG_FAN = W83627EHF_REG_FAN;
+		data->REG_FAN = NCT6775_REG_FAN;
 		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
 		data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
 		data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
@@ -1953,14 +1976,20 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 		data->REG_FAN_MAX_OUTPUT = NCT6775_REG_FAN_MAX_OUTPUT;
 		data->REG_FAN_STEP_OUTPUT = NCT6775_REG_FAN_STEP_OUTPUT;
 	} else if (sio_data->kind == nct6776) {
+		data->has_fan_div = false;
+		data->fan_from_reg = fan_from_reg13;
+		data->fan_from_reg_min = fan_from_reg13;
 		data->REG_PWM = NCT6775_REG_PWM;
 		data->REG_TARGET = NCT6775_REG_TARGET;
-		data->REG_FAN = NCT6776_REG_FAN;
+		data->REG_FAN = NCT6775_REG_FAN;
 		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
 		data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
 		data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
 		data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
 	} else if (sio_data->kind == w83667hg_b) {
+		data->has_fan_div = true;
+		data->fan_from_reg = fan_from_reg8;
+		data->fan_from_reg_min = fan_from_reg8;
 		data->REG_PWM = W83627EHF_REG_PWM;
 		data->REG_TARGET = W83627EHF_REG_TARGET;
 		data->REG_FAN = W83627EHF_REG_FAN;
@@ -1973,6 +2002,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
 		data->REG_FAN_STEP_OUTPUT =
 		  W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
 	} else {
+		data->has_fan_div = true;
+		data->fan_from_reg = fan_from_reg8;
+		data->fan_from_reg_min = fan_from_reg8;
 		data->REG_PWM = W83627EHF_REG_PWM;
 		data->REG_TARGET = W83627EHF_REG_TARGET;
 		data->REG_FAN = W83627EHF_REG_FAN;
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [lm-sensors] [PATCH v5 10/11] hwmon: (w83627ehf) Store rpm instead
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
@ 2011-03-04 17:58   ` Guenter Roeck
  -1 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:58 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

Since the fan speed value can be above 0xff, we can no longer use
that value to determine if the fan speed reading is valid. This
makes it difficult to manipulate the stored fan speed register value.

If we store rpm instead of the fan speed register value, we do not
need to correct it if the fan divisor value is changed, and the above
mentioned problem no longer exists.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/w83627ehf.c |   27 +++++++++------------------
 1 files changed, 9 insertions(+), 18 deletions(-)

diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index df6e502..460292b 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -452,7 +452,7 @@ struct w83627ehf_data {
 	u8 in[10];		/* Register value */
 	u8 in_max[10];		/* Register value */
 	u8 in_min[10];		/* Register value */
-	u16 fan[5];
+	unsigned int rpm[5];
 	u16 fan_min[5];
 	u8 fan_div[5];
 	u8 has_fan;		/* some fan inputs can be disabled */
@@ -775,11 +775,14 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 
 		/* Measured fan speeds and limits */
 		for (i = 0; i < 5; i++) {
+			u16 reg;
+
 			if (!(data->has_fan & (1 << i)))
 				continue;
 
-			data->fan[i] = w83627ehf_read_value(data,
-							    data->REG_FAN[i]);
+			reg = w83627ehf_read_value(data, data->REG_FAN[i]);
+			data->rpm[i] = data->fan_from_reg(reg,
+							  data->fan_div[i]);
 
 			if (data->has_fan_min & (1 << i))
 				data->fan_min[i] = w83627ehf_read_value(data,
@@ -789,9 +792,8 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 			   divider can be increased, let's try that for next
 			   time */
 			if (data->has_fan_div
-			    && (data->fan[i] >= 0xff
-				|| (sio_data->kind = nct6775
-				    && data->fan[i] = 0x00))
+			    && (reg >= 0xff || (sio_data->kind = nct6775
+						&& reg = 0x00))
 			    && data->fan_div[i] < 0x07) {
 				dev_dbg(dev, "Increasing fan%d "
 					"clock divider from %u to %u\n",
@@ -984,8 +986,7 @@ show_fan(struct device *dev, struct device_attribute *attr, char *buf)
 	struct w83627ehf_data *data = w83627ehf_update_device(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	return sprintf(buf, "%d\n",
-		       data->fan_from_reg(data->fan[nr], data->fan_div[nr]));
+	return sprintf(buf, "%d\n", data->rpm[nr]);
 }
 
 static ssize_t
@@ -1078,16 +1079,6 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 	/* Write both the fan clock divider (if it changed) and the new
 	   fan min (unconditionally) */
 	if (new_div != data->fan_div[nr]) {
-		/* Preserve the fan speed reading */
-		if (data->fan[nr] != 0xff) {
-			if (new_div > data->fan_div[nr])
-				data->fan[nr] >>= new_div - data->fan_div[nr];
-			else if (data->fan[nr] & 0x80)
-				data->fan[nr] = 0xff;
-			else
-				data->fan[nr] <<= data->fan_div[nr] - new_div;
-		}
-
 		dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
 			nr + 1, div_from_reg(data->fan_div[nr]),
 			div_from_reg(new_div));
-- 
1.7.3.1


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 10/11] hwmon: (w83627ehf) Store rpm instead of raw fan speed data
@ 2011-03-04 17:58   ` Guenter Roeck
  0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:58 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

Since the fan speed value can be above 0xff, we can no longer use
that value to determine if the fan speed reading is valid. This
makes it difficult to manipulate the stored fan speed register value.

If we store rpm instead of the fan speed register value, we do not
need to correct it if the fan divisor value is changed, and the above
mentioned problem no longer exists.

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/w83627ehf.c |   27 +++++++++------------------
 1 files changed, 9 insertions(+), 18 deletions(-)

diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index df6e502..460292b 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -452,7 +452,7 @@ struct w83627ehf_data {
 	u8 in[10];		/* Register value */
 	u8 in_max[10];		/* Register value */
 	u8 in_min[10];		/* Register value */
-	u16 fan[5];
+	unsigned int rpm[5];
 	u16 fan_min[5];
 	u8 fan_div[5];
 	u8 has_fan;		/* some fan inputs can be disabled */
@@ -775,11 +775,14 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 
 		/* Measured fan speeds and limits */
 		for (i = 0; i < 5; i++) {
+			u16 reg;
+
 			if (!(data->has_fan & (1 << i)))
 				continue;
 
-			data->fan[i] = w83627ehf_read_value(data,
-							    data->REG_FAN[i]);
+			reg = w83627ehf_read_value(data, data->REG_FAN[i]);
+			data->rpm[i] = data->fan_from_reg(reg,
+							  data->fan_div[i]);
 
 			if (data->has_fan_min & (1 << i))
 				data->fan_min[i] = w83627ehf_read_value(data,
@@ -789,9 +792,8 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 			   divider can be increased, let's try that for next
 			   time */
 			if (data->has_fan_div
-			    && (data->fan[i] >= 0xff
-				|| (sio_data->kind == nct6775
-				    && data->fan[i] == 0x00))
+			    && (reg >= 0xff || (sio_data->kind == nct6775
+						&& reg == 0x00))
 			    && data->fan_div[i] < 0x07) {
 				dev_dbg(dev, "Increasing fan%d "
 					"clock divider from %u to %u\n",
@@ -984,8 +986,7 @@ show_fan(struct device *dev, struct device_attribute *attr, char *buf)
 	struct w83627ehf_data *data = w83627ehf_update_device(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	return sprintf(buf, "%d\n",
-		       data->fan_from_reg(data->fan[nr], data->fan_div[nr]));
+	return sprintf(buf, "%d\n", data->rpm[nr]);
 }
 
 static ssize_t
@@ -1078,16 +1079,6 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
 	/* Write both the fan clock divider (if it changed) and the new
 	   fan min (unconditionally) */
 	if (new_div != data->fan_div[nr]) {
-		/* Preserve the fan speed reading */
-		if (data->fan[nr] != 0xff) {
-			if (new_div > data->fan_div[nr])
-				data->fan[nr] >>= new_div - data->fan_div[nr];
-			else if (data->fan[nr] & 0x80)
-				data->fan[nr] = 0xff;
-			else
-				data->fan[nr] <<= data->fan_div[nr] - new_div;
-		}
-
 		dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
 			nr + 1, div_from_reg(data->fan_div[nr]),
 			div_from_reg(new_div));
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [lm-sensors] [PATCH v5 11/11] hwmon: (w83627ehf) Update Kconfig for
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
@ 2011-03-04 17:58   ` Guenter Roeck
  -1 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:58 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/Kconfig |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 297bc9a..c100802 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1083,7 +1083,7 @@ config SENSORS_W83627HF
 	  will be called w83627hf.
 
 config SENSORS_W83627EHF
-	tristate "Winbond W83627EHF/EHG/DHG, W83667HG"
+	tristate "Winbond W83627EHF/EHG/DHG, W83667HG, NCT6775F, NCT6776F"
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the hardware
@@ -1094,7 +1094,8 @@ config SENSORS_W83627EHF
 	  chip suited for specific Intel processors that use PECI such as
 	  the Core 2 Duo.
 
-	  This driver also supports the W83667HG chip.
+	  This driver also supports Nuvoton W83667HG, W83667HG-B, NCT6775F
+	  (also known as W83667HG-I), and NCT6776F.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called w83627ehf.
-- 
1.7.3.1


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 11/11] hwmon: (w83627ehf) Update Kconfig for W83677HG-B, NCT6775F and NCT6776F
@ 2011-03-04 17:58   ` Guenter Roeck
  0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 17:58 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Ian Dobson, Andy Lutomirski, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel, Guenter Roeck

Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
---
 drivers/hwmon/Kconfig |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 297bc9a..c100802 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1083,7 +1083,7 @@ config SENSORS_W83627HF
 	  will be called w83627hf.
 
 config SENSORS_W83627EHF
-	tristate "Winbond W83627EHF/EHG/DHG, W83667HG"
+	tristate "Winbond W83627EHF/EHG/DHG, W83667HG, NCT6775F, NCT6776F"
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the hardware
@@ -1094,7 +1094,8 @@ config SENSORS_W83627EHF
 	  chip suited for specific Intel processors that use PECI such as
 	  the Core 2 Duo.
 
-	  This driver also supports the W83667HG chip.
+	  This driver also supports Nuvoton W83667HG, W83667HG-B, NCT6775F
+	  (also known as W83667HG-I), and NCT6776F.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called w83627ehf.
-- 
1.7.3.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [lm-sensors] [PATCH v5 00/11] hwmon: (w83627ehf) Add support
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
@ 2011-03-04 18:50   ` Andrew Lutomirski
  -1 siblings, 0 replies; 36+ messages in thread
From: Andrew Lutomirski @ 2011-03-04 18:50 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Jean Delvare, Ian Dobson, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel

On Fri, Mar 4, 2011 at 12:57 PM, Guenter Roeck
<guenter.roeck@ericsson.com> wrote:
> The following patch series adds support for NCT6775F and NCT6776F to the
> w83627ehf driver. It also includes some cleanup and adds support for
> the fourth temperature sensor on W83677HG-B.
>
> No code changes since v4. Resubmitting and widening audience in the hope that
> someone may find the time to review the changes prior to the next commit window.

I'm not sure my review is worth much, but the driver seems to work.  I've tested
fan speed measurement, changing pwm2_enable to 1, changing the fan speed,
and changing back to 5.  Everything looks good.

The only weird thing I noticed is that, the first time I ran sensors, I got:
fan2:                    0 RPM  (min =    0 RPM, div = 64)
and thereafter I get
fan2:                  136 RPM  (min =    0 RPM, div = 64)  ALARM

I suspect (although I haven't checked) that sensors is just reading
div after it's already changed to 64.

Thanks,
Andy

>
> v5:
> - Update Kconfig to reference W83667HG, NCT6775F, and NCT6776F.
>
> v4:
> - Store rpm instead of raw fan speed readings
> - For NCT6775F, increase fan divisor if the fan speed reads 0
>  [ On NCT6775F, fan speed readings can return 0 instead of 0xff if the
>    fan divisor value is too low ]
> - Separate changes into more patches to simplify review
>
> v3:
> - Documentation: Remove references to datasheets which no longer exist
> - Documentation: Add information about limits of SmartFan IV support.
> - SmartFan III mode is not supported on NCT6776F, so remove related attributes
>  and refuse to configure it.
> - (additional patch) Improve support for chips with 16-bit fan count registers
>
> v2:
> - W83677HG-B does share the AUXTIN/VIN3 pin, so we can not skip this check.
> - Cosmetic changes to fix a couple of checkpatch errors and to undo some
>  unnecessary formatting changes in patch 5.
> - Patch 1 introduced a bug in temp_to_reg which was fixed in a later patch.
>  Modified code to not introduce the bug in the first place.
> - Two dev_dbg messages were changed to dev_info for testing. Changed back
>  to dev_dbg.
>
> The patched driver can be downloaded as stand-alone driver from
>        http://www.roeck-us.net/linux/drivers/w83627ehf/
>

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F
@ 2011-03-04 18:50   ` Andrew Lutomirski
  0 siblings, 0 replies; 36+ messages in thread
From: Andrew Lutomirski @ 2011-03-04 18:50 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Jean Delvare, Ian Dobson, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel

On Fri, Mar 4, 2011 at 12:57 PM, Guenter Roeck
<guenter.roeck@ericsson.com> wrote:
> The following patch series adds support for NCT6775F and NCT6776F to the
> w83627ehf driver. It also includes some cleanup and adds support for
> the fourth temperature sensor on W83677HG-B.
>
> No code changes since v4. Resubmitting and widening audience in the hope that
> someone may find the time to review the changes prior to the next commit window.

I'm not sure my review is worth much, but the driver seems to work.  I've tested
fan speed measurement, changing pwm2_enable to 1, changing the fan speed,
and changing back to 5.  Everything looks good.

The only weird thing I noticed is that, the first time I ran sensors, I got:
fan2:                    0 RPM  (min =    0 RPM, div = 64)
and thereafter I get
fan2:                  136 RPM  (min =    0 RPM, div = 64)  ALARM

I suspect (although I haven't checked) that sensors is just reading
div after it's already changed to 64.

Thanks,
Andy

>
> v5:
> - Update Kconfig to reference W83667HG, NCT6775F, and NCT6776F.
>
> v4:
> - Store rpm instead of raw fan speed readings
> - For NCT6775F, increase fan divisor if the fan speed reads 0
>  [ On NCT6775F, fan speed readings can return 0 instead of 0xff if the
>    fan divisor value is too low ]
> - Separate changes into more patches to simplify review
>
> v3:
> - Documentation: Remove references to datasheets which no longer exist
> - Documentation: Add information about limits of SmartFan IV support.
> - SmartFan III mode is not supported on NCT6776F, so remove related attributes
>  and refuse to configure it.
> - (additional patch) Improve support for chips with 16-bit fan count registers
>
> v2:
> - W83677HG-B does share the AUXTIN/VIN3 pin, so we can not skip this check.
> - Cosmetic changes to fix a couple of checkpatch errors and to undo some
>  unnecessary formatting changes in patch 5.
> - Patch 1 introduced a bug in temp_to_reg which was fixed in a later patch.
>  Modified code to not introduce the bug in the first place.
> - Two dev_dbg messages were changed to dev_info for testing. Changed back
>  to dev_dbg.
>
> The patched driver can be downloaded as stand-alone driver from
>        http://www.roeck-us.net/linux/drivers/w83627ehf/
>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [lm-sensors] [PATCH v5 00/11] hwmon: (w83627ehf) Add support
  2011-03-04 18:50   ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Andrew Lutomirski
@ 2011-03-04 18:53     ` Andrew Lutomirski
  -1 siblings, 0 replies; 36+ messages in thread
From: Andrew Lutomirski @ 2011-03-04 18:53 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Jean Delvare, Ian Dobson, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel

On Fri, Mar 4, 2011 at 1:50 PM, Andrew Lutomirski <luto@mit.edu> wrote:
> On Fri, Mar 4, 2011 at 12:57 PM, Guenter Roeck
> <guenter.roeck@ericsson.com> wrote:
>> The following patch series adds support for NCT6775F and NCT6776F to the
>> w83627ehf driver. It also includes some cleanup and adds support for
>> the fourth temperature sensor on W83677HG-B.
>>
>> No code changes since v4. Resubmitting and widening audience in the hope that
>> someone may find the time to review the changes prior to the next commit window.
>
> I'm not sure my review is worth much, but the driver seems to work.  I've tested
> fan speed measurement, changing pwm2_enable to 1, changing the fan speed,
> and changing back to 5.  Everything looks good.
>
> The only weird thing I noticed is that, the first time I ran sensors, I got:
> fan2:                    0 RPM  (min =    0 RPM, div = 64)
> and thereafter I get
> fan2:                  136 RPM  (min =    0 RPM, div = 64)  ALARM
>
> I suspect (although I haven't checked) that sensors is just reading
> div after it's already changed to 64.

I'll add one more weird thing on my NCT6775F.

[root@midnight w83627ehf.656]# echo 3200 >fan2_min
[root@midnight w83627ehf.656]# cat fan2_div
8
[root@midnight w83627ehf.656]# cat fan2_input
133
[root@midnight w83627ehf.656]# cat fan2_div
16
[root@midnight w83627ehf.656]# cat fan2_input
133
[root@midnight w83627ehf.656]# cat fan2_div
32
[root@midnight w83627ehf.656]# cat fan2_input
133
[root@midnight w83627ehf.656]# cat fan2_div
64
[root@midnight w83627ehf.656]# cat fan2_input
132
[root@midnight w83627ehf.656]# cat fan2_div
64

I waited a second or two between commands.

Does this mean that 16-bit mode works but the driver doesn't realize it works?

--Andy

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F
@ 2011-03-04 18:53     ` Andrew Lutomirski
  0 siblings, 0 replies; 36+ messages in thread
From: Andrew Lutomirski @ 2011-03-04 18:53 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Jean Delvare, Ian Dobson, Randy Dunlap, binximeng, lmsensors,
	andrea.rizzolo, jeff.sadowski, lm-sensors, linux-doc,
	linux-kernel

On Fri, Mar 4, 2011 at 1:50 PM, Andrew Lutomirski <luto@mit.edu> wrote:
> On Fri, Mar 4, 2011 at 12:57 PM, Guenter Roeck
> <guenter.roeck@ericsson.com> wrote:
>> The following patch series adds support for NCT6775F and NCT6776F to the
>> w83627ehf driver. It also includes some cleanup and adds support for
>> the fourth temperature sensor on W83677HG-B.
>>
>> No code changes since v4. Resubmitting and widening audience in the hope that
>> someone may find the time to review the changes prior to the next commit window.
>
> I'm not sure my review is worth much, but the driver seems to work.  I've tested
> fan speed measurement, changing pwm2_enable to 1, changing the fan speed,
> and changing back to 5.  Everything looks good.
>
> The only weird thing I noticed is that, the first time I ran sensors, I got:
> fan2:                    0 RPM  (min =    0 RPM, div = 64)
> and thereafter I get
> fan2:                  136 RPM  (min =    0 RPM, div = 64)  ALARM
>
> I suspect (although I haven't checked) that sensors is just reading
> div after it's already changed to 64.

I'll add one more weird thing on my NCT6775F.

[root@midnight w83627ehf.656]# echo 3200 >fan2_min
[root@midnight w83627ehf.656]# cat fan2_div
8
[root@midnight w83627ehf.656]# cat fan2_input
133
[root@midnight w83627ehf.656]# cat fan2_div
16
[root@midnight w83627ehf.656]# cat fan2_input
133
[root@midnight w83627ehf.656]# cat fan2_div
32
[root@midnight w83627ehf.656]# cat fan2_input
133
[root@midnight w83627ehf.656]# cat fan2_div
64
[root@midnight w83627ehf.656]# cat fan2_input
132
[root@midnight w83627ehf.656]# cat fan2_div
64

I waited a second or two between commands.

Does this mean that 16-bit mode works but the driver doesn't realize it works?

--Andy

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [lm-sensors] [PATCH v5 00/11] hwmon: (w83627ehf) Add support
  2011-03-04 18:53     ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Andrew Lutomirski
@ 2011-03-04 19:56       ` Guenter Roeck
  -1 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 19:56 UTC (permalink / raw)
  To: Andrew Lutomirski
  Cc: Jean Delvare, Ian Dobson, Randy Dunlap, binximeng@gmail.com,
	lmsensors@tapanitarvainen.fi, andrea.rizzolo@gmail.com,
	jeff.sadowski@gmail.com, lm-sensors@lm-sensors.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org

On Fri, 2011-03-04 at 13:53 -0500, Andrew Lutomirski wrote:
> On Fri, Mar 4, 2011 at 1:50 PM, Andrew Lutomirski <luto@mit.edu> wrote:
> > On Fri, Mar 4, 2011 at 12:57 PM, Guenter Roeck
> > <guenter.roeck@ericsson.com> wrote:
> >> The following patch series adds support for NCT6775F and NCT6776F to the
> >> w83627ehf driver. It also includes some cleanup and adds support for
> >> the fourth temperature sensor on W83677HG-B.
> >>
> >> No code changes since v4. Resubmitting and widening audience in the hope that
> >> someone may find the time to review the changes prior to the next commit window.
> >
> > I'm not sure my review is worth much, but the driver seems to work.  I've tested
> > fan speed measurement, changing pwm2_enable to 1, changing the fan speed,
> > and changing back to 5.  Everything looks good.
> >
> > The only weird thing I noticed is that, the first time I ran sensors, I got:
> > fan2:                    0 RPM  (min =    0 RPM, div = 64)
> > and thereafter I get
> > fan2:                  136 RPM  (min =    0 RPM, div = 64)  ALARM
> >
> > I suspect (although I haven't checked) that sensors is just reading
> > div after it's already changed to 64.
> 
> I'll add one more weird thing on my NCT6775F.
> 
> [root@midnight w83627ehf.656]# echo 3200 >fan2_min
> [root@midnight w83627ehf.656]# cat fan2_div
> 8
> [root@midnight w83627ehf.656]# cat fan2_input
> 133
> [root@midnight w83627ehf.656]# cat fan2_div
> 16
> [root@midnight w83627ehf.656]# cat fan2_input
> 133
> [root@midnight w83627ehf.656]# cat fan2_div
> 32
> [root@midnight w83627ehf.656]# cat fan2_input
> 133
> [root@midnight w83627ehf.656]# cat fan2_div
> 64
> [root@midnight w83627ehf.656]# cat fan2_input
> 132
> [root@midnight w83627ehf.656]# cat fan2_div
> 64

This is actually as expected. rpm calculation is
	rpm = 1350000 / (rpm_reg * div)
In your case, this translates to
	rpm_reg * div ~ 8500
so for div < 64, the value of rpm_reg is larger than 255. If this
happens, the driver automatically increases fan_div until rpm_reg is
smaller than 255.

Reason for this is that while the chip has a 16 bit rpm register, the
min speed register is still only 8 bit wide. Plus, at least some
versions of NCT6775F report an rpm of 0 if the divisor is set too low.

Thanks,
Guenter



_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F
@ 2011-03-04 19:56       ` Guenter Roeck
  0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 19:56 UTC (permalink / raw)
  To: Andrew Lutomirski
  Cc: Jean Delvare, Ian Dobson, Randy Dunlap, binximeng@gmail.com,
	lmsensors@tapanitarvainen.fi, andrea.rizzolo@gmail.com,
	jeff.sadowski@gmail.com, lm-sensors@lm-sensors.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org

On Fri, 2011-03-04 at 13:53 -0500, Andrew Lutomirski wrote:
> On Fri, Mar 4, 2011 at 1:50 PM, Andrew Lutomirski <luto@mit.edu> wrote:
> > On Fri, Mar 4, 2011 at 12:57 PM, Guenter Roeck
> > <guenter.roeck@ericsson.com> wrote:
> >> The following patch series adds support for NCT6775F and NCT6776F to the
> >> w83627ehf driver. It also includes some cleanup and adds support for
> >> the fourth temperature sensor on W83677HG-B.
> >>
> >> No code changes since v4. Resubmitting and widening audience in the hope that
> >> someone may find the time to review the changes prior to the next commit window.
> >
> > I'm not sure my review is worth much, but the driver seems to work.  I've tested
> > fan speed measurement, changing pwm2_enable to 1, changing the fan speed,
> > and changing back to 5.  Everything looks good.
> >
> > The only weird thing I noticed is that, the first time I ran sensors, I got:
> > fan2:                    0 RPM  (min =    0 RPM, div = 64)
> > and thereafter I get
> > fan2:                  136 RPM  (min =    0 RPM, div = 64)  ALARM
> >
> > I suspect (although I haven't checked) that sensors is just reading
> > div after it's already changed to 64.
> 
> I'll add one more weird thing on my NCT6775F.
> 
> [root@midnight w83627ehf.656]# echo 3200 >fan2_min
> [root@midnight w83627ehf.656]# cat fan2_div
> 8
> [root@midnight w83627ehf.656]# cat fan2_input
> 133
> [root@midnight w83627ehf.656]# cat fan2_div
> 16
> [root@midnight w83627ehf.656]# cat fan2_input
> 133
> [root@midnight w83627ehf.656]# cat fan2_div
> 32
> [root@midnight w83627ehf.656]# cat fan2_input
> 133
> [root@midnight w83627ehf.656]# cat fan2_div
> 64
> [root@midnight w83627ehf.656]# cat fan2_input
> 132
> [root@midnight w83627ehf.656]# cat fan2_div
> 64

This is actually as expected. rpm calculation is
	rpm = 1350000 / (rpm_reg * div)
In your case, this translates to
	rpm_reg * div ~ 8500
so for div < 64, the value of rpm_reg is larger than 255. If this
happens, the driver automatically increases fan_div until rpm_reg is
smaller than 255.

Reason for this is that while the chip has a 16 bit rpm register, the
min speed register is still only 8 bit wide. Plus, at least some
versions of NCT6775F report an rpm of 0 if the divisor is set too low.

Thanks,
Guenter



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [lm-sensors] [PATCH v5 00/11] hwmon: (w83627ehf) Add support
  2011-03-04 18:50   ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Andrew Lutomirski
@ 2011-03-04 19:59     ` Guenter Roeck
  -1 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 19:59 UTC (permalink / raw)
  To: Andrew Lutomirski
  Cc: Jean Delvare, Ian Dobson, Randy Dunlap, binximeng@gmail.com,
	lmsensors@tapanitarvainen.fi, andrea.rizzolo@gmail.com,
	jeff.sadowski@gmail.com, lm-sensors@lm-sensors.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org

On Fri, 2011-03-04 at 13:50 -0500, Andrew Lutomirski wrote:
> On Fri, Mar 4, 2011 at 12:57 PM, Guenter Roeck
> <guenter.roeck@ericsson.com> wrote:
> > The following patch series adds support for NCT6775F and NCT6776F to the
> > w83627ehf driver. It also includes some cleanup and adds support for
> > the fourth temperature sensor on W83677HG-B.
> >
> > No code changes since v4. Resubmitting and widening audience in the hope that
> > someone may find the time to review the changes prior to the next commit window.
> 
> I'm not sure my review is worth much, but the driver seems to work.  I've tested
> fan speed measurement, changing pwm2_enable to 1, changing the fan speed,
> and changing back to 5.  Everything looks good.
> 
> The only weird thing I noticed is that, the first time I ran sensors, I got:
> fan2:                    0 RPM  (min =    0 RPM, div = 64)
> and thereafter I get
> fan2:                  136 RPM  (min =    0 RPM, div = 64)  ALARM
> 
> I suspect (although I haven't checked) that sensors is just reading
> div after it's already changed to 64.
> 
The driver reads rpm, finds it to be zero, and increases div as result
(NCT6775F may report zero rpm if div is too low). That explains the
first reading.

What I don't understand is the alarm you get with the 2nd reading. Any
idea where this might come from ? Is it sticky, or do you see it only
once ?

Thanks,
Guenter



_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F
@ 2011-03-04 19:59     ` Guenter Roeck
  0 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-04 19:59 UTC (permalink / raw)
  To: Andrew Lutomirski
  Cc: Jean Delvare, Ian Dobson, Randy Dunlap, binximeng@gmail.com,
	lmsensors@tapanitarvainen.fi, andrea.rizzolo@gmail.com,
	jeff.sadowski@gmail.com, lm-sensors@lm-sensors.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org

On Fri, 2011-03-04 at 13:50 -0500, Andrew Lutomirski wrote:
> On Fri, Mar 4, 2011 at 12:57 PM, Guenter Roeck
> <guenter.roeck@ericsson.com> wrote:
> > The following patch series adds support for NCT6775F and NCT6776F to the
> > w83627ehf driver. It also includes some cleanup and adds support for
> > the fourth temperature sensor on W83677HG-B.
> >
> > No code changes since v4. Resubmitting and widening audience in the hope that
> > someone may find the time to review the changes prior to the next commit window.
> 
> I'm not sure my review is worth much, but the driver seems to work.  I've tested
> fan speed measurement, changing pwm2_enable to 1, changing the fan speed,
> and changing back to 5.  Everything looks good.
> 
> The only weird thing I noticed is that, the first time I ran sensors, I got:
> fan2:                    0 RPM  (min =    0 RPM, div = 64)
> and thereafter I get
> fan2:                  136 RPM  (min =    0 RPM, div = 64)  ALARM
> 
> I suspect (although I haven't checked) that sensors is just reading
> div after it's already changed to 64.
> 
The driver reads rpm, finds it to be zero, and increases div as result
(NCT6775F may report zero rpm if div is too low). That explains the
first reading.

What I don't understand is the alarm you get with the 2nd reading. Any
idea where this might come from ? Is it sticky, or do you see it only
once ?

Thanks,
Guenter



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [lm-sensors] [PATCH v5 00/11] hwmon: (w83627ehf) Add support
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
                   ` (12 preceding siblings ...)
  (?)
@ 2011-03-16  9:49 ` Michiel
  -1 siblings, 0 replies; 36+ messages in thread
From: Michiel @ 2011-03-16  9:49 UTC (permalink / raw)
  To: lm-sensors

Hi,

I installed the stand alone module you created for the nct6775f and
basic functionality seems OK. Although the voltage sensor readings seem
a bit nonsensical. This is on an ASRock 870iCafe motherboard.
( http://www.asrock.com/mb/overview.asp?Model‡0iCafe )

It has 2 4pin fan connectors and 1 3pin connector. I'm still trying to
configure those for use with fancontrol. But I'm not there yet..

Thanks for all time and hard work you punt in to lm-sensors ! :-)
 
> k10temp-pci-00c3
> Adapter: PCI adapter
> temp1:       +17.5��C  (high = +70.0��C)                  
> 
> nct6775-isa-0290
> Adapter: ISA adapter
> in0:         +0.99 V  (min =  +0.00 V, max =  +1.74 V)   
> in1:         +1.85 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> in2:         +3.41 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> in3:         +3.41 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> in4:         +0.06 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> in5:         +1.67 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> in6:         +1.70 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> in7:         +3.44 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> in8:         +3.39 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> fan1:       1095 RPM  (min =    0 RPM, div = 8)  ALARM
> fan2:       1095 RPM  (min =    0 RPM, div = 8)  ALARM
> fan3:       1180 RPM  (min =    0 RPM, div = 8)  ALARM
> SYSTIN:      +30.0��C  (high =  +0.0��C, hyst =  +0.0��C)  ALARM  sensor = thermistor
> CPUTIN:      +26.5��C  (high = +80.0��C, hyst = +75.0��C)  sensor = thermistor
> AUXTIN:      -12.5��C  (high = +80.0��C, hyst = +75.0��C)  sensor = thermistor
> cpu0_vid:   +0.375 V




_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [lm-sensors] [PATCH v5 00/11] hwmon: (w83627ehf) Add support
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
                   ` (13 preceding siblings ...)
  (?)
@ 2011-03-16 15:20 ` Guenter Roeck
  -1 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-03-16 15:20 UTC (permalink / raw)
  To: lm-sensors

On Wed, Mar 16, 2011 at 05:49:20AM -0400, Michiel wrote:
> Hi,
> 
> I installed the stand alone module you created for the nct6775f and
> basic functionality seems OK. Although the voltage sensor readings seem
> a bit nonsensical. This is on an ASRock 870iCafe motherboard.
> ( http://www.asrock.com/mb/overview.asp?Model‡0iCafe )
> 
Thanks for testing.

The voltage values are not surprising; you'll have to figure out actual voltages
and add scaling factors to sensors3.conf.

> It has 2 4pin fan connectors and 1 3pin connector. I'm still trying to
> configure those for use with fancontrol. But I'm not there yet..
> 
> Thanks for all time and hard work you punt in to lm-sensors ! :-)
>  
> > k10temp-pci-00c3
> > Adapter: PCI adapter
> > temp1:       +17.5��C  (high = +70.0��C)                  
> > 
> > nct6775-isa-0290
> > Adapter: ISA adapter
> > in0:         +0.99 V  (min =  +0.00 V, max =  +1.74 V)   
> > in1:         +1.85 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> > in2:         +3.41 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> > in3:         +3.41 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> > in4:         +0.06 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> > in5:         +1.67 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> > in6:         +1.70 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> > in7:         +3.44 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> > in8:         +3.39 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
> > fan1:       1095 RPM  (min =    0 RPM, div = 8)  ALARM
> > fan2:       1095 RPM  (min =    0 RPM, div = 8)  ALARM
> > fan3:       1180 RPM  (min =    0 RPM, div = 8)  ALARM
> > SYSTIN:      +30.0��C  (high =  +0.0��C, hyst =  +0.0��C)  ALARM  sensor = thermistor
> > CPUTIN:      +26.5��C  (high = +80.0��C, hyst = +75.0��C)  sensor = thermistor
> > AUXTIN:      -12.5��C  (high = +80.0��C, hyst = +75.0��C)  sensor = thermistor

Must be pretty cold where you live ;).

Guenter

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [lm-sensors] [PATCH v5 00/11] hwmon: (w83627ehf) Add support
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
                   ` (14 preceding siblings ...)
  (?)
@ 2011-04-06  0:33 ` Michael D Powell
  -1 siblings, 0 replies; 36+ messages in thread
From: Michael D Powell @ 2011-04-06  0:33 UTC (permalink / raw)
  To: lm-sensors


Perhaps I'm missing something obvious or simple, but I always get fan
RPM of zero from lm sensors and can't seem to debug it.  Thanks in
advance for developing support for the
nct6775f.

Here's my setup:

Intel DH57DD board with core i5-750 cpu
bios JGIBX10J.86A 1219.2132 (bios date 12/19/2010)
3 4-pin fans plugged into the motherboard
bios setup reports positive fan rpm values that seem reasonable
at least one of the fans runs very fast after a reset for a second or
so, then they all slow down to < 1000 rpm.  Even under heavy CPU load,
the fans don't seem to speed up much if at all, but the system is pretty
well vented and doesn't overheat.

Kernel module installed from http://roeck-us.net/linux/drivers/w83627ehf
on 2011/04/04 and manually built and installed using that Makefile.
kernel 2.6.32-5-amd64 (Debian 2.6.32-31)
Debian squeeze
sensors version 3.1.2 with libsensors version 3.1.2

No overrides set when loading the module (just "modprobe w83627ehf"). 
No overrides for nct6775 in /etc/sensors3.conf.  On previous
versions of the driver which did not support nct6775f, I used
force_id=0xa510 to get some temperature value output.  But all fan RPMs
were zero using that module and id value too.

Since the fan divisor is read-only now, I have not been able to change
it.  It is already 128 anyway--see below.  

output of "sensors"

$ sensors
coretemp-isa-0000
Adapter: ISA adapter
Core 0:      +32.0°C  (high = +84.0°C, crit = +100.0°C)  

coretemp-isa-0001
Adapter: ISA adapter
Core 1:      +29.0°C  (high = +84.0°C, crit = +100.0°C)  

coretemp-isa-0002
Adapter: ISA adapter
Core 2:      +33.0°C  (high = +84.0°C, crit = +100.0°C)  

coretemp-isa-0003
Adapter: ISA adapter
Core 3:      +30.0°C  (high = +84.0°C, crit = +100.0°C)  

nct6775-isa-0680
Adapter: ISA adapter
in0:         +0.87 V  (min =  +0.00 V, max =  +1.74 V)   
in1:         +0.77 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
in2:         +3.34 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
in3:         +3.34 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
in4:         +1.26 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
in5:         +0.75 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
in6:         +1.06 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
in7:         +3.30 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
in8:         +3.26 V  (min =  +0.00 V, max =  +0.00 V)   ALARM
fan1:          0 RPM  (min =    0 RPM, div = 128)  ALARM
fan2:          0 RPM  (min =    0 RPM, div = 128)  ALARM
fan3:          0 RPM  (min =    0 RPM, div = 128)  ALARM
fan4:          0 RPM  (div = 128)  ALARM
SYSTIN:      +31.0°C  (high =  +0.0°C, hyst =  +0.0°C)  ALARM  sensor diode
CPUTIN:      +45.0°C  (high = +80.0°C, hyst = +75.0°C)  sensor = diode
AUXTIN:      +23.0°C  (high = +80.0°C, hyst = +75.0°C)  sensor thermistor
cpu0_vid:   +1.500 V

Output of pwmconfig:# pwmconfig 
# pwmconfig revision 5770 (2009-09-16)
This program will search your sensors for pulse width modulation (pwm)
controls, and test each one to see if it controls a fan on
your motherboard. Note that many motherboards do not have pwm
circuitry installed, even if your sensor chip supports pwm.

We will attempt to briefly stop each fan using the pwm controls.
The program will attempt to restore each fan to full speed
after testing. However, it is ** very important ** that you
physically verify that the fans have been to full speed
after the program has completed.

Found the following devices:
   hwmon0/device is coretemp
   hwmon1/device is coretemp
   hwmon2/device is coretemp
   hwmon3/device is coretemp
   hwmon4/device is nct6775

Found the following PWM controls:
   hwmon4/device/pwm1
   hwmon4/device/pwm2
   hwmon4/device/pwm3

Giving the fans some time to reach full speed...
Found the following fan sensors:
   hwmon4/device/fan1_input     current speed: 0 ... skipping!
   hwmon4/device/fan2_input     current speed: 0 ... skipping!
   hwmon4/device/fan3_input     current speed: 0 ... skipping!
   hwmon4/device/fan4_input     current speed: 0 ... skipping!

I can manually write "0" or "1" to
/sys/devices/platform/w83627ehf.1664/pwm1_mode, but it has no effect on
anything. pwm[1-3] all have value 255.

Any thoughts or other info I can provide?  Thanks.

__________________________________________________________________
Michael D. Powell

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [lm-sensors] [PATCH v5 00/11] hwmon: (w83627ehf) Add support
  2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
                   ` (15 preceding siblings ...)
  (?)
@ 2011-04-06  0:47 ` Guenter Roeck
  -1 siblings, 0 replies; 36+ messages in thread
From: Guenter Roeck @ 2011-04-06  0:47 UTC (permalink / raw)
  To: lm-sensors

On Tue, Apr 05, 2011 at 08:33:52PM -0400, Michael D Powell wrote:
> 
> Perhaps I'm missing something obvious or simple, but I always get fan
> RPM of zero from lm sensors and can't seem to debug it.  Thanks in
> advance for developing support for the
> nct6775f.
> 
> Here's my setup:
> 
> Intel DH57DD board with core i5-750 cpu

I suspect you have the same problem I have with the DH57JG board: That Intel 
does not use the fan control from the NCT6775F, but their own fan control
implementation in one of the Intel support chips. See if you can find
the technical documentation of your board (should be somewhere on the Intel
web site) and check if it mentions anything about fan control.

Thanks,
Guenter

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2011-04-06  0:47 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-03-04 17:57 [lm-sensors] [PATCH v5 00/11] hwmon: (w83627ehf) Add support for Guenter Roeck
2011-03-04 17:57 ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
2011-03-04 17:57 ` [lm-sensors] [PATCH v5 01/11] hwmon: (w83627ehf) Unify temperature Guenter Roeck
2011-03-04 17:57   ` [PATCH v5 01/11] hwmon: (w83627ehf) Unify temperature register access, and use strict string conversions Guenter Roeck
2011-03-04 17:57 ` [lm-sensors] [PATCH v5 02/11] hwmon: (w83627ehf) Fixed most Guenter Roeck
2011-03-04 17:57   ` [PATCH v5 02/11] hwmon: (w83627ehf) Fixed most checkpatch warnings and errors Guenter Roeck
2011-03-04 17:57 ` [lm-sensors] [PATCH v5 03/11] hwmon: (w83627ehf) Optimize Guenter Roeck
2011-03-04 17:57   ` [PATCH v5 03/11] hwmon: (w83627ehf) Optimize multi-bank register access Guenter Roeck
2011-03-04 17:57 ` [lm-sensors] [PATCH v5 04/11] hwmon: (w83627ehf) Improve support Guenter Roeck
2011-03-04 17:57   ` [PATCH v5 04/11] hwmon: (w83627ehf) Improve support for W83667HG-B Guenter Roeck
2011-03-04 17:58 ` [lm-sensors] [PATCH v5 05/11] hwmon: (w83627ehf) Remove references Guenter Roeck
2011-03-04 17:58   ` [PATCH v5 05/11] hwmon: (w83627ehf) Remove references to datasheets which no longer exist Guenter Roeck
2011-03-04 17:58 ` [lm-sensors] [PATCH v5 06/11] hwmon: (w83627ehf) Convert register Guenter Roeck
2011-03-04 17:58   ` [PATCH v5 06/11] hwmon: (w83627ehf) Convert register arrays to 16 bit, and convert access to pointers Guenter Roeck
2011-03-04 17:58 ` [lm-sensors] [PATCH v5 07/11] hwmon: (w83627ehf) Permit enabling Guenter Roeck
2011-03-04 17:58   ` [PATCH v5 07/11] hwmon: (w83627ehf) Permit enabling SmartFan IV mode if configured at startup Guenter Roeck
2011-03-04 17:58 ` [lm-sensors] [PATCH v5 08/11] hwmon: (w83627ehf) Add support for Guenter Roeck
2011-03-04 17:58   ` [PATCH v5 08/11] hwmon: (w83627ehf) Add support for Nuvoton NCT6775F and NCT6776F Guenter Roeck
2011-03-04 17:58 ` [lm-sensors] [PATCH v5 09/11] hwmon: (w83627ehf) Use 16 bit fan Guenter Roeck
2011-03-04 17:58   ` [PATCH v5 09/11] hwmon: (w83627ehf) Use 16 bit fan count registers if supported Guenter Roeck
2011-03-04 17:58 ` [lm-sensors] [PATCH v5 10/11] hwmon: (w83627ehf) Store rpm instead Guenter Roeck
2011-03-04 17:58   ` [PATCH v5 10/11] hwmon: (w83627ehf) Store rpm instead of raw fan speed data Guenter Roeck
2011-03-04 17:58 ` [lm-sensors] [PATCH v5 11/11] hwmon: (w83627ehf) Update Kconfig for Guenter Roeck
2011-03-04 17:58   ` [PATCH v5 11/11] hwmon: (w83627ehf) Update Kconfig for W83677HG-B, NCT6775F and NCT6776F Guenter Roeck
2011-03-04 18:50 ` [lm-sensors] [PATCH v5 00/11] hwmon: (w83627ehf) Add support Andrew Lutomirski
2011-03-04 18:50   ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Andrew Lutomirski
2011-03-04 18:53   ` [lm-sensors] [PATCH v5 00/11] hwmon: (w83627ehf) Add support Andrew Lutomirski
2011-03-04 18:53     ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Andrew Lutomirski
2011-03-04 19:56     ` [lm-sensors] [PATCH v5 00/11] hwmon: (w83627ehf) Add support Guenter Roeck
2011-03-04 19:56       ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
2011-03-04 19:59   ` [lm-sensors] [PATCH v5 00/11] hwmon: (w83627ehf) Add support Guenter Roeck
2011-03-04 19:59     ` [PATCH v5 00/11] hwmon: (w83627ehf) Add support for NCT6775F and NCT6776F Guenter Roeck
2011-03-16  9:49 ` [lm-sensors] [PATCH v5 00/11] hwmon: (w83627ehf) Add support Michiel
2011-03-16 15:20 ` Guenter Roeck
2011-04-06  0:33 ` Michael D Powell
2011-04-06  0:47 ` Guenter Roeck

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.