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>
This commit is contained in:
Marc Hulsman 2008-08-06 22:41:04 +02:00 committed by Jean Delvare
parent 05a5e47768
commit ad02ad85cf
2 changed files with 23 additions and 7 deletions

View file

@ -22,6 +22,7 @@ Credits:
Additional contributors: Additional contributors:
Sven Anders <anders@anduras.de> Sven Anders <anders@anduras.de>
Marc Hulsman <m.hulsman@tudelft.nl>
Module Parameters 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 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 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 readings can be divided by a programmable divider (1, 2, 4, 8, 16,
and 1, 2, 4, 8, 16, 32, 64 or 128 for fan 4/5) to give the readings more 32, 64 or 128 for all fans) to give the readings more range or accuracy.
range or accuracy.
Voltage sensors (also known as IN sensors) report their values in millivolts. Voltage sensors (also known as IN sensors) report their values in millivolts.
An alarm is triggered if the voltage has crossed a programmable minimum An alarm is triggered if the voltage has crossed a programmable minimum

View file

@ -233,11 +233,9 @@ static u8 fan_to_reg(long rpm, int div)
static u8 div_to_reg(int nr, long val) static u8 div_to_reg(int nr, long val)
{ {
int i; int i;
int max;
/* first three fan's divisor max out at 8, rest max out at 128 */ /* fan divisors max out at 128 */
max = (nr < 3) ? 8 : 128; val = SENSORS_LIMIT(val, 1, 128) >> 1;
val = SENSORS_LIMIT(val, 1, max) >> 1;
for (i = 0; i < 7; i++) { for (i = 0; i < 7; i++) {
if (val == 0) if (val == 0)
break; break;
@ -530,6 +528,7 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr,
unsigned long min; unsigned long min;
u8 tmp_fan_div; u8 tmp_fan_div;
u8 fan_div_reg; u8 fan_div_reg;
u8 vbat_reg;
int indx = 0; int indx = 0;
u8 keep_mask = 0; u8 keep_mask = 0;
u8 new_shift = 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], w83791d_write(client, W83791D_REG_FAN_DIV[indx],
fan_div_reg | tmp_fan_div); 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 */ /* Restore fan_min */
data->fan_min[nr] = fan_to_reg(min, DIV_FROM_REG(data->fan_div[nr])); 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]); 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); struct w83791d_data *data = i2c_get_clientdata(client);
int i, j; int i, j;
u8 reg_array_tmp[3]; u8 reg_array_tmp[3];
u8 vbat_reg;
mutex_lock(&data->update_lock); 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[3] = reg_array_tmp[2] & 0x07;
data->fan_div[4] = (reg_array_tmp[2] >> 4) & 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 */ /* Update the first temperature sensor */
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
data->temp1[i] = w83791d_read(client, data->temp1[i] = w83791d_read(client,