diff options
author | Guenter Roeck <linux@roeck-us.net> | 2012-01-16 16:51:46 -0500 |
---|---|---|
committer | Jean Delvare <khali@endymion.delvare> | 2012-01-16 16:51:46 -0500 |
commit | 94e55df48a230162edc641e55c28d058f5b6cb76 (patch) | |
tree | 19b93afcb7e23289cf2cc82c7aaa114f6f54a158 | |
parent | e872c91e726e7f7f74817cf9a81a138bf0d0a583 (diff) |
hwmon: (lm63) Add support for writing the external critical temperature
On LM64, the external critical temperature limit is always writable. On LM96163,
it is writable if the chip is configured for it. Add conditional support for
writing the register dependent on chip type and configuration.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
-rw-r--r-- | drivers/hwmon/lm63.c | 55 |
1 files changed, 44 insertions, 11 deletions
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 24a96f89d206..a9e6212ed54a 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c | |||
@@ -117,6 +117,9 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; | |||
117 | (val) >= 127000 ? 127 : \ | 117 | (val) >= 127000 ? 127 : \ |
118 | (val) < 0 ? ((val) - 500) / 1000 : \ | 118 | (val) < 0 ? ((val) - 500) / 1000 : \ |
119 | ((val) + 500) / 1000) | 119 | ((val) + 500) / 1000) |
120 | #define TEMP8U_TO_REG(val) ((val) <= 0 ? 0 : \ | ||
121 | (val) >= 255000 ? 255 : \ | ||
122 | ((val) + 500) / 1000) | ||
120 | #define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) | 123 | #define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) |
121 | #define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ | 124 | #define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ |
122 | (val) >= 127875 ? 0x7FE0 : \ | 125 | (val) >= 127875 ? 0x7FE0 : \ |
@@ -313,22 +316,33 @@ static ssize_t show_remote_temp8(struct device *dev, | |||
313 | + data->temp2_offset); | 316 | + data->temp2_offset); |
314 | } | 317 | } |
315 | 318 | ||
316 | static ssize_t set_local_temp8(struct device *dev, | 319 | static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, |
317 | struct device_attribute *dummy, | 320 | const char *buf, size_t count) |
318 | const char *buf, size_t count) | ||
319 | { | 321 | { |
322 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
320 | struct i2c_client *client = to_i2c_client(dev); | 323 | struct i2c_client *client = to_i2c_client(dev); |
321 | struct lm63_data *data = i2c_get_clientdata(client); | 324 | struct lm63_data *data = i2c_get_clientdata(client); |
325 | int nr = attr->index; | ||
326 | int reg = nr == 2 ? LM63_REG_REMOTE_TCRIT : LM63_REG_LOCAL_HIGH; | ||
322 | long val; | 327 | long val; |
323 | int err; | 328 | int err; |
329 | int temp; | ||
324 | 330 | ||
325 | err = kstrtol(buf, 10, &val); | 331 | err = kstrtol(buf, 10, &val); |
326 | if (err) | 332 | if (err) |
327 | return err; | 333 | return err; |
328 | 334 | ||
329 | mutex_lock(&data->update_lock); | 335 | mutex_lock(&data->update_lock); |
330 | data->temp8[1] = TEMP8_TO_REG(val); | 336 | if (nr == 2) { |
331 | i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]); | 337 | if (data->remote_unsigned) |
338 | temp = TEMP8U_TO_REG(val - data->temp2_offset); | ||
339 | else | ||
340 | temp = TEMP8_TO_REG(val - data->temp2_offset); | ||
341 | } else { | ||
342 | temp = TEMP8_TO_REG(val); | ||
343 | } | ||
344 | data->temp8[nr] = temp; | ||
345 | i2c_smbus_write_byte_data(client, reg, temp); | ||
332 | mutex_unlock(&data->update_lock); | 346 | mutex_unlock(&data->update_lock); |
333 | return count; | 347 | return count; |
334 | } | 348 | } |
@@ -461,7 +475,7 @@ static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); | |||
461 | 475 | ||
462 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0); | 476 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0); |
463 | static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8, | 477 | static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8, |
464 | set_local_temp8, 1); | 478 | set_temp8, 1); |
465 | 479 | ||
466 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); | 480 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); |
467 | static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, | 481 | static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, |
@@ -470,12 +484,8 @@ static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, | |||
470 | set_temp11, 2); | 484 | set_temp11, 2); |
471 | static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11, | 485 | static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11, |
472 | set_temp11, 3); | 486 | set_temp11, 3); |
473 | /* | ||
474 | * On LM63, temp2_crit can be set only once, which should be job | ||
475 | * of the bootloader. | ||
476 | */ | ||
477 | static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8, | 487 | static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8, |
478 | NULL, 2); | 488 | set_temp8, 2); |
479 | static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, | 489 | static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, |
480 | set_temp2_crit_hyst); | 490 | set_temp2_crit_hyst); |
481 | 491 | ||
@@ -510,7 +520,30 @@ static struct attribute *lm63_attributes[] = { | |||
510 | NULL | 520 | NULL |
511 | }; | 521 | }; |
512 | 522 | ||
523 | /* | ||
524 | * On LM63, temp2_crit can be set only once, which should be job | ||
525 | * of the bootloader. | ||
526 | * On LM64, temp2_crit can always be set. | ||
527 | * On LM96163, temp2_crit can be set if bit 1 of the configuration | ||
528 | * register is true. | ||
529 | */ | ||
530 | static umode_t lm63_attribute_mode(struct kobject *kobj, | ||
531 | struct attribute *attr, int index) | ||
532 | { | ||
533 | struct device *dev = container_of(kobj, struct device, kobj); | ||
534 | struct i2c_client *client = to_i2c_client(dev); | ||
535 | struct lm63_data *data = i2c_get_clientdata(client); | ||
536 | |||
537 | if (attr == &sensor_dev_attr_temp2_crit.dev_attr.attr | ||
538 | && (data->kind == lm64 || | ||
539 | (data->kind == lm96163 && (data->config & 0x02)))) | ||
540 | return attr->mode | S_IWUSR; | ||
541 | |||
542 | return attr->mode; | ||
543 | } | ||
544 | |||
513 | static const struct attribute_group lm63_group = { | 545 | static const struct attribute_group lm63_group = { |
546 | .is_visible = lm63_attribute_mode, | ||
514 | .attrs = lm63_attributes, | 547 | .attrs = lm63_attributes, |
515 | }; | 548 | }; |
516 | 549 | ||