hwmon: (lm63) Let the user adjust the lookup table

Make the automatic fan speed control lookup table writable. This lets
the user tweak the fan speed / temperature response curve.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
Acked-by: Guenter Roeck <guenter.roeck@ericsson.com>
Tested-by: Guenter Roeck <guenter.roeck@ericsson.com>
This commit is contained in:
Jean Delvare 2012-03-23 10:02:19 +01:00 committed by Jean Delvare
parent 817c6cc546
commit af2ef4fc04
1 changed files with 76 additions and 42 deletions

View File

@ -205,6 +205,15 @@ static inline int lut_temp_from_reg(struct lm63_data *data, int nr)
return data->temp8[nr] * (data->lut_temp_highres ? 500 : 1000); return data->temp8[nr] * (data->lut_temp_highres ? 500 : 1000);
} }
static inline int lut_temp_to_reg(struct lm63_data *data, long val)
{
val -= data->temp2_offset;
if (data->lut_temp_highres)
return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127500), 500);
else
return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127000), 1000);
}
/* /*
* Update the lookup table register cache. * Update the lookup table register cache.
* client->update_lock must be held when calling this function. * client->update_lock must be held when calling this function.
@ -387,13 +396,16 @@ static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr,
return sprintf(buf, "%d\n", pwm); return sprintf(buf, "%d\n", pwm);
} }
static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, static ssize_t set_pwm1(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client); struct lm63_data *data = i2c_get_clientdata(client);
int nr = attr->index;
unsigned long val; unsigned long val;
int err; int err;
u8 reg;
if (!(data->config_fan & 0x20)) /* register is read-only */ if (!(data->config_fan & 0x20)) /* register is read-only */
return -EPERM; return -EPERM;
@ -402,11 +414,13 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
if (err) if (err)
return err; return err;
reg = nr ? LM63_REG_LUT_PWM(nr - 1) : LM63_REG_PWM_VALUE;
val = SENSORS_LIMIT(val, 0, 255); val = SENSORS_LIMIT(val, 0, 255);
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
data->pwm1[0] = data->pwm_highres ? val : data->pwm1[nr] = data->pwm_highres ? val :
(val * data->pwm1_freq * 2 + 127) / 255; (val * data->pwm1_freq * 2 + 127) / 255;
i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1[0]); i2c_smbus_write_byte_data(client, reg, data->pwm1[nr]);
mutex_unlock(&data->update_lock); mutex_unlock(&data->update_lock);
return count; return count;
} }
@ -495,23 +509,31 @@ static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client); struct lm63_data *data = i2c_get_clientdata(client);
int nr = attr->index; int nr = attr->index;
int reg = nr == 2 ? LM63_REG_REMOTE_TCRIT : LM63_REG_LOCAL_HIGH;
long val; long val;
int err; int err;
int temp; int temp;
u8 reg;
err = kstrtol(buf, 10, &val); err = kstrtol(buf, 10, &val);
if (err) if (err)
return err; return err;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
if (nr == 2) { switch (nr) {
case 2:
reg = LM63_REG_REMOTE_TCRIT;
if (data->remote_unsigned) if (data->remote_unsigned)
temp = TEMP8U_TO_REG(val - data->temp2_offset); temp = TEMP8U_TO_REG(val - data->temp2_offset);
else else
temp = TEMP8_TO_REG(val - data->temp2_offset); temp = TEMP8_TO_REG(val - data->temp2_offset);
} else { break;
case 1:
reg = LM63_REG_LOCAL_HIGH;
temp = TEMP8_TO_REG(val); temp = TEMP8_TO_REG(val);
break;
default: /* lookup table */
reg = LM63_REG_LUT_TEMP(nr - 3);
temp = lut_temp_to_reg(data, val);
} }
data->temp8[nr] = temp; data->temp8[nr] = temp;
i2c_smbus_write_byte_data(client, reg, temp); i2c_smbus_write_byte_data(client, reg, temp);
@ -743,64 +765,76 @@ static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0); static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0);
static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
show_pwm1_enable, set_pwm1_enable); show_pwm1_enable, set_pwm1_enable);
static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO, show_pwm1, NULL, 1); static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IRUGO, show_pwm1, set_pwm1, 1);
show_lut_temp, NULL, 3); static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 3);
static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp_hyst, S_IRUGO, static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 3); show_lut_temp_hyst, NULL, 3);
static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO, show_pwm1, NULL, 2); static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO, show_pwm1, set_pwm1, 2);
show_lut_temp, NULL, 4); static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 4);
static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp_hyst, S_IRUGO, static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 4); show_lut_temp_hyst, NULL, 4);
static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO, show_pwm1, NULL, 3); static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IWUSR | S_IRUGO,
static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IRUGO, show_pwm1, set_pwm1, 3);
show_lut_temp, NULL, 5); static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 5);
static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp_hyst, S_IRUGO, static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 5); show_lut_temp_hyst, NULL, 5);
static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO, show_pwm1, NULL, 4); static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IWUSR | S_IRUGO,
static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IRUGO, show_pwm1, set_pwm1, 4);
show_lut_temp, NULL, 6); static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 6);
static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp_hyst, S_IRUGO, static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 6); show_lut_temp_hyst, NULL, 6);
static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm1, NULL, 5); static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IWUSR | S_IRUGO,
static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IRUGO, show_pwm1, set_pwm1, 5);
show_lut_temp, NULL, 7); static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 7);
static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp_hyst, S_IRUGO, static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 7); show_lut_temp_hyst, NULL, 7);
static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IRUGO, show_pwm1, NULL, 6); static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IWUSR | S_IRUGO,
static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IRUGO, show_pwm1, set_pwm1, 6);
show_lut_temp, NULL, 8); static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 8);
static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp_hyst, S_IRUGO, static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 8); show_lut_temp_hyst, NULL, 8);
static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IRUGO, show_pwm1, NULL, 7); static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IWUSR | S_IRUGO,
static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IRUGO, show_pwm1, set_pwm1, 7);
show_lut_temp, NULL, 9); static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 9);
static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp_hyst, S_IRUGO, static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 9); show_lut_temp_hyst, NULL, 9);
static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IRUGO, show_pwm1, NULL, 8); static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IWUSR | S_IRUGO,
static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IRUGO, show_pwm1, set_pwm1, 8);
show_lut_temp, NULL, 10); static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 10);
static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp_hyst, S_IRUGO, static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 10); show_lut_temp_hyst, NULL, 10);
static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, S_IRUGO, show_pwm1, NULL, 9); static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, S_IWUSR | S_IRUGO,
static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, S_IRUGO, show_pwm1, set_pwm1, 9);
show_lut_temp, NULL, 11); static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 11);
static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp_hyst, S_IRUGO, static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 11); show_lut_temp_hyst, NULL, 11);
static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, S_IRUGO, show_pwm1, NULL, 10); static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, S_IWUSR | S_IRUGO,
static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, S_IRUGO, show_pwm1, set_pwm1, 10);
show_lut_temp, NULL, 12); static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 12);
static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp_hyst, S_IRUGO, static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 12); show_lut_temp_hyst, NULL, 12);
static SENSOR_DEVICE_ATTR(pwm1_auto_point11_pwm, S_IRUGO, show_pwm1, NULL, 11); static SENSOR_DEVICE_ATTR(pwm1_auto_point11_pwm, S_IWUSR | S_IRUGO,
static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp, S_IRUGO, show_pwm1, set_pwm1, 11);
show_lut_temp, NULL, 13); static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 13);
static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp_hyst, S_IRUGO, static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 13); show_lut_temp_hyst, NULL, 13);
static SENSOR_DEVICE_ATTR(pwm1_auto_point12_pwm, S_IRUGO, show_pwm1, NULL, 12); static SENSOR_DEVICE_ATTR(pwm1_auto_point12_pwm, S_IWUSR | S_IRUGO,
static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp, S_IRUGO, show_pwm1, set_pwm1, 12);
show_lut_temp, NULL, 14); static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 14);
static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp_hyst, S_IRUGO, static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 14); show_lut_temp_hyst, NULL, 14);