From: Cumulus Networks <support@xxxxxxxxxxxxxxxxxxx> The driver only fills the most significant 8 bits of the fan tach count (11 bit value). Fixing the driver to use all of 11 bits for more accuracy. --- drivers/hwmon/max6620.c | 105 ++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 59 deletions(-) diff --git a/drivers/hwmon/max6620.c b/drivers/hwmon/max6620.c index 3c337c7b0f4d..2cd3b0beb6b4 100644 --- a/drivers/hwmon/max6620.c +++ b/drivers/hwmon/max6620.c @@ -46,6 +46,8 @@ /* clock: The clock frequency of the chip the driver should assume */ static int clock = 8192; +static u32 sr = 2; +static u32 np = 2; module_param(clock, int, S_IRUGO); @@ -213,22 +215,22 @@ static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, cha struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct max6620_data *data = max6620_update_device(dev); - int rpm; - - /* - * Calculation details: - * - * Each tachometer counts over an interval given by the "count" - * register (0.25, 0.5, 1 or 2 seconds). This module assumes - * that the fans produce two pulses per revolution (this seems - * to be the most common). - */ - if(data->tach[attr->index] == 0 || data->tach[attr->index] == 255) { + struct i2c_client *client = to_i2c_client(dev); + u32 rpm = 0; + u32 tach = 0; + u32 tach1 = 0; + u32 tach2 = 0; + + tach1 = i2c_smbus_read_byte_data(client, tach_reg[attr->index]); + tach1 = (tach1 << 3) & 0x7f8; + tach2 = i2c_smbus_read_byte_data(client, tach_reg[attr->index] + 1); + tach2 = (tach2 >> 5) & 0x7; + tach = tach1 | tach2; + if (tach == 0) { rpm = 0; } else { - rpm = ((clock / (data->tach[attr->index] << 3)) * 30 * DIV_FROM_REG(data->fandyn[attr->index])); + rpm = (60 * DIV_FROM_REG(data->fandyn[attr->index]) * clock)/(tach * np); } - return sprintf(buf, "%d\n", rpm); } @@ -236,22 +238,21 @@ static ssize_t get_target(struct device *dev, struct device_attribute *devattr, struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct max6620_data *data = max6620_update_device(dev); - int kscale, ktach, rpm; - - /* - * Use the datasheet equation: - * - * FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)] - * - * then multiply by 60 to give rpm. - */ - - kscale = DIV_FROM_REG(data->fandyn[attr->index]); - ktach = data->target[attr->index]; - if(ktach == 0) { + struct i2c_client *client = to_i2c_client(dev); + u32 rpm; + u32 target; + u32 target1; + u32 target2; + + target1 = i2c_smbus_read_byte_data(client, target_reg[attr->index]); + target1 = (target1 << 3) & 0x7f8; + target2 = i2c_smbus_read_byte_data(client, target_reg[attr->index] + 1); + target2 = (target2 >> 5) & 0x7; + target = target1 | target2; + if (target == 0) { rpm = 0; } else { - rpm = ((60 * kscale * clock) / (ktach << 3)); + rpm = (60 * DIV_FROM_REG(data->fandyn[attr->index]) * clock)/(target * np); } return sprintf(buf, "%d\n", rpm); } @@ -261,9 +262,11 @@ static ssize_t set_target(struct device *dev, struct device_attribute *devattr, struct i2c_client *client = to_i2c_client(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct max6620_data *data = i2c_get_clientdata(client); - int kscale, ktach; - unsigned long rpm; + u32 rpm; int err; + u32 target; + u32 target1; + u32 target2; err = kstrtoul(buf, 10, &rpm); if (err) @@ -271,25 +274,13 @@ static ssize_t set_target(struct device *dev, struct device_attribute *devattr, rpm = SENSORS_LIMIT(rpm, FAN_RPM_MIN, FAN_RPM_MAX); - /* - * Divide the required speed by 60 to get from rpm to rps, then - * use the datasheet equation: - * - * KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1 - */ - mutex_lock(&data->update_lock); - kscale = DIV_FROM_REG(data->fandyn[attr->index]); - ktach = ((60 * kscale * clock) / rpm); - if (ktach < 0) - ktach = 0; - if (ktach > 255) - ktach = 255; - data->target[attr->index] = ktach; - - i2c_smbus_write_byte_data(client, target_reg[attr->index], data->target[attr->index]); - i2c_smbus_write_byte_data(client, target_reg[attr->index]+0x01, 0x00); + target = (60 * DIV_FROM_REG(data->fandyn[attr->index]) * clock)/(rpm * np); + target1 = (target >> 3) & 0xff; + target2 = (target << 5) & 0xe0; + i2c_smbus_write_byte_data(client, target_reg[attr->index], target1); + i2c_smbus_write_byte_data(client, target_reg[attr->index] + 1, target2); mutex_unlock(&data->update_lock); @@ -609,8 +600,11 @@ static int max6620_init_client(struct i2c_client *client) { } - - if (i2c_smbus_write_byte_data(client, MAX6620_REG_CONFIG, config)) { + /* + * Set bit 4, disable other fans from going full speed on a fail + * failure. + */ + if (i2c_smbus_write_byte_data(client, MAX6620_REG_CONFIG, config | 0x10)) { dev_err(&client->dev, "Config write error, aborting.\n"); return err; } @@ -618,28 +612,21 @@ static int max6620_init_client(struct i2c_client *client) { data->config = config; for (i = 0; i < 4; i++) { data->fancfg[i] = i2c_smbus_read_byte_data(client, config_reg[i]); - data->fancfg[i] |= 0x80; // enable TACH monitoring + data->fancfg[i] |= 0xa8; // enable TACH monitoring i2c_smbus_write_byte_data(client, config_reg[i], data->fancfg[i]); data->fandyn[i] = i2c_smbus_read_byte_data(client, dyn_reg[i]); - data-> fandyn[i] |= 0x1C; + /* 2 counts (001) and Rate change 100 (0.125 secs) */ + data-> fandyn[i] = 0x30; i2c_smbus_write_byte_data(client, dyn_reg[i], data->fandyn[i]); data->tach[i] = i2c_smbus_read_byte_data(client, tach_reg[i]); data->volt[i] = i2c_smbus_read_byte_data(client, volt_reg[i]); data->target[i] = i2c_smbus_read_byte_data(client, target_reg[i]); data->dac[i] = i2c_smbus_read_byte_data(client, dac_reg[i]); - - } - - - return 0; } - - - static struct max6620_data *max6620_update_device(struct device *dev) { int i; @@ -678,7 +665,7 @@ static struct max6620_data *max6620_update_device(struct device *dev) return data; } -module_i2c_driver(max6620_driver); +// module_i2c_driver(max6620_driver); static int __init max6620_init(void) { -- 2.32.0