hwmon: (w83791d) Use fan divisor bits from vbat register
Marc Hulsman [Wed, 6 Aug 2008 20:41:04 +0000 (22:41 +0200)]
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>

Documentation/hwmon/w83791d
drivers/hwmon/w83791d.c

index f153b2f..a67d3b7 100644 (file)
@@ -22,6 +22,7 @@ Credits:
 
 Additional contributors:
     Sven Anders <anders@anduras.de>
+    Marc Hulsman <m.hulsman@tudelft.nl>
 
 Module Parameters
 -----------------
@@ -67,9 +68,8 @@ 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
-readings can be divided by a programmable divider (1, 2, 4, 8 for fan 1/2/3
-and 1, 2, 4, 8, 16, 32, 64 or 128 for fan 4/5) to give the readings more
-range or accuracy.
+readings can be divided by a programmable divider (1, 2, 4, 8, 16,
+32, 64 or 128 for all fans) to give the readings more range or accuracy.
 
 Voltage sensors (also known as IN sensors) report their values in millivolts.
 An alarm is triggered if the voltage has crossed a programmable minimum
index e4e91c9..daa7d12 100644 (file)
@@ -233,11 +233,9 @@ static u8 fan_to_reg(long rpm, int div)
 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 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr,
        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 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr,
        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 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
        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 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
                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,