hwmon: (w83791d) Use fan divisor bits from vbat register

Update w83791d with fan bits in vbat mon register (7.48 of the
datasheet). This change allows all fans to have a divisor of 128, 
and fixes a problem with incorrectly reported fan speeds. 

Signed-off-by: Marc Hulsman <m.hulsman@tudelft.nl>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index e4e91c9..daa7d12 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -233,11 +233,9 @@
 static u8 div_to_reg(int nr, long val)
 {
 	int i;
-	int max;
 
-	/* first three fan's divisor max out at 8, rest max out at 128 */
-	max = (nr < 3) ? 8 : 128;
-	val = SENSORS_LIMIT(val, 1, max) >> 1;
+	/* fan divisors max out at 128 */
+	val = SENSORS_LIMIT(val, 1, 128) >> 1;
 	for (i = 0; i < 7; i++) {
 		if (val == 0)
 			break;
@@ -530,6 +528,7 @@
 	unsigned long min;
 	u8 tmp_fan_div;
 	u8 fan_div_reg;
+	u8 vbat_reg;
 	int indx = 0;
 	u8 keep_mask = 0;
 	u8 new_shift = 0;
@@ -581,6 +580,16 @@
 	w83791d_write(client, W83791D_REG_FAN_DIV[indx],
 				fan_div_reg | tmp_fan_div);
 
+	/* Bit 2 of fans 0-2 is stored in the vbat register (bits 5-7) */
+	if (nr < 3) {
+		keep_mask = ~(1 << (nr + 5));
+		vbat_reg = w83791d_read(client, W83791D_REG_VBAT)
+				& keep_mask;
+		tmp_fan_div = (data->fan_div[nr] << (3 + nr)) & ~keep_mask;
+		w83791d_write(client, W83791D_REG_VBAT,
+				vbat_reg | tmp_fan_div);
+	}
+
 	/* Restore fan_min */
 	data->fan_min[nr] = fan_to_reg(min, DIV_FROM_REG(data->fan_div[nr]));
 	w83791d_write(client, W83791D_REG_FAN_MIN[nr], data->fan_min[nr]);
@@ -1182,6 +1191,7 @@
 	struct w83791d_data *data = i2c_get_clientdata(client);
 	int i, j;
 	u8 reg_array_tmp[3];
+	u8 vbat_reg;
 
 	mutex_lock(&data->update_lock);
 
@@ -1219,6 +1229,12 @@
 		data->fan_div[3] = reg_array_tmp[2] & 0x07;
 		data->fan_div[4] = (reg_array_tmp[2] >> 4) & 0x07;
 
+		/* The fan divisor for fans 0-2 get bit 2 from
+		   bits 5-7 respectively of vbat register */
+		vbat_reg = w83791d_read(client, W83791D_REG_VBAT);
+		for (i = 0; i < 3; i++)
+			data->fan_div[i] |= (vbat_reg >> (3 + i)) & 0x04;
+
 		/* Update the first temperature sensor */
 		for (i = 0; i < 3; i++) {
 			data->temp1[i] = w83791d_read(client,