diff options
author | Rudolf Marek <r.marek@sh.cvut.cz> | 2006-03-23 10:25:22 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-06-22 14:10:31 -0400 |
commit | cf0676fe42c8e14c4c7ed5895e2fe5d17f779b43 (patch) | |
tree | ff201260e2a0979471c60ca440e6eedbe87ee27f /drivers | |
parent | 43cb7ebee2f478d3f987ad773d4e6b07fc23c631 (diff) |
[PATCH] w83627ehf: Add voltage inputs support
Add the voltage measuring support to W83627EHF. The code is based
on the patch provided by Yuan Mu from Winbond.
Signed-off-by: Yuan Mu <Ymu@winbond.com.tw>
Signed-off-by: Rudolf Marek <r.marek@sh.cvut.cz>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hwmon/w83627ehf.c | 124 |
1 files changed, 120 insertions, 4 deletions
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index b6bd5685fd38..08bbeaf64e94 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c | |||
@@ -30,10 +30,7 @@ | |||
30 | Supports the following chips: | 30 | Supports the following chips: |
31 | 31 | ||
32 | Chip #vin #fan #pwm #temp chip_id man_id | 32 | Chip #vin #fan #pwm #temp chip_id man_id |
33 | w83627ehf - 5 - 3 0x88 0x5ca3 | 33 | w83627ehf 10 5 - 3 0x88 0x5ca3 |
34 | |||
35 | This is a preliminary version of the driver, only supporting the | ||
36 | fan and temperature inputs. The chip does much more than that. | ||
37 | */ | 34 | */ |
38 | 35 | ||
39 | #include <linux/module.h> | 36 | #include <linux/module.h> |
@@ -121,6 +118,14 @@ superio_exit(void) | |||
121 | static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; | 118 | static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; |
122 | static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; | 119 | static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; |
123 | 120 | ||
121 | /* The W83627EHF registers for nr=7,8,9 are in bank 5 */ | ||
122 | #define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ | ||
123 | (0x554 + (((nr) - 7) * 2))) | ||
124 | #define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ | ||
125 | (0x555 + (((nr) - 7) * 2))) | ||
126 | #define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ | ||
127 | (0x550 + (nr) - 7)) | ||
128 | |||
124 | #define W83627EHF_REG_TEMP1 0x27 | 129 | #define W83627EHF_REG_TEMP1 0x27 |
125 | #define W83627EHF_REG_TEMP1_HYST 0x3a | 130 | #define W83627EHF_REG_TEMP1_HYST 0x3a |
126 | #define W83627EHF_REG_TEMP1_OVER 0x39 | 131 | #define W83627EHF_REG_TEMP1_OVER 0x39 |
@@ -172,6 +177,20 @@ temp1_to_reg(int temp) | |||
172 | return (temp + 500) / 1000; | 177 | return (temp + 500) / 1000; |
173 | } | 178 | } |
174 | 179 | ||
180 | /* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */ | ||
181 | |||
182 | static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 }; | ||
183 | |||
184 | static inline long in_from_reg(u8 reg, u8 nr) | ||
185 | { | ||
186 | return reg * scale_in[nr]; | ||
187 | } | ||
188 | |||
189 | static inline u8 in_to_reg(u32 val, u8 nr) | ||
190 | { | ||
191 | return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255); | ||
192 | } | ||
193 | |||
175 | /* | 194 | /* |
176 | * Data structures and manipulation thereof | 195 | * Data structures and manipulation thereof |
177 | */ | 196 | */ |
@@ -186,6 +205,9 @@ struct w83627ehf_data { | |||
186 | unsigned long last_updated; /* In jiffies */ | 205 | unsigned long last_updated; /* In jiffies */ |
187 | 206 | ||
188 | /* Register values */ | 207 | /* Register values */ |
208 | u8 in[10]; /* Register value */ | ||
209 | u8 in_max[10]; /* Register value */ | ||
210 | u8 in_min[10]; /* Register value */ | ||
189 | u8 fan[5]; | 211 | u8 fan[5]; |
190 | u8 fan_min[5]; | 212 | u8 fan_min[5]; |
191 | u8 fan_div[5]; | 213 | u8 fan_div[5]; |
@@ -349,6 +371,16 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | |||
349 | data->fan_div[3] |= (i >> 5) & 0x04; | 371 | data->fan_div[3] |= (i >> 5) & 0x04; |
350 | } | 372 | } |
351 | 373 | ||
374 | /* Measured voltages and limits */ | ||
375 | for (i = 0; i < 10; i++) { | ||
376 | data->in[i] = w83627ehf_read_value(client, | ||
377 | W83627EHF_REG_IN(i)); | ||
378 | data->in_min[i] = w83627ehf_read_value(client, | ||
379 | W83627EHF_REG_IN_MIN(i)); | ||
380 | data->in_max[i] = w83627ehf_read_value(client, | ||
381 | W83627EHF_REG_IN_MAX(i)); | ||
382 | } | ||
383 | |||
352 | /* Measured fan speeds and limits */ | 384 | /* Measured fan speeds and limits */ |
353 | for (i = 0; i < 5; i++) { | 385 | for (i = 0; i < 5; i++) { |
354 | if (!(data->has_fan & (1 << i))) | 386 | if (!(data->has_fan & (1 << i))) |
@@ -406,6 +438,87 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | |||
406 | /* | 438 | /* |
407 | * Sysfs callback functions | 439 | * Sysfs callback functions |
408 | */ | 440 | */ |
441 | #define show_in_reg(reg) \ | ||
442 | static ssize_t \ | ||
443 | show_##reg(struct device *dev, struct device_attribute *attr, \ | ||
444 | char *buf) \ | ||
445 | { \ | ||
446 | struct w83627ehf_data *data = w83627ehf_update_device(dev); \ | ||
447 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ | ||
448 | int nr = sensor_attr->index; \ | ||
449 | return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \ | ||
450 | } | ||
451 | show_in_reg(in) | ||
452 | show_in_reg(in_min) | ||
453 | show_in_reg(in_max) | ||
454 | |||
455 | #define store_in_reg(REG, reg) \ | ||
456 | static ssize_t \ | ||
457 | store_in_##reg (struct device *dev, struct device_attribute *attr, \ | ||
458 | const char *buf, size_t count) \ | ||
459 | { \ | ||
460 | struct i2c_client *client = to_i2c_client(dev); \ | ||
461 | struct w83627ehf_data *data = i2c_get_clientdata(client); \ | ||
462 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ | ||
463 | int nr = sensor_attr->index; \ | ||
464 | u32 val = simple_strtoul(buf, NULL, 10); \ | ||
465 | \ | ||
466 | mutex_lock(&data->update_lock); \ | ||
467 | data->in_##reg[nr] = in_to_reg(val, nr); \ | ||
468 | w83627ehf_write_value(client, W83627EHF_REG_IN_##REG(nr), \ | ||
469 | data->in_##reg[nr]); \ | ||
470 | mutex_unlock(&data->update_lock); \ | ||
471 | return count; \ | ||
472 | } | ||
473 | |||
474 | store_in_reg(MIN, min) | ||
475 | store_in_reg(MAX, max) | ||
476 | |||
477 | static struct sensor_device_attribute sda_in_input[] = { | ||
478 | SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), | ||
479 | SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), | ||
480 | SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), | ||
481 | SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3), | ||
482 | SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4), | ||
483 | SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5), | ||
484 | SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6), | ||
485 | SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7), | ||
486 | SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8), | ||
487 | SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9), | ||
488 | }; | ||
489 | |||
490 | static struct sensor_device_attribute sda_in_min[] = { | ||
491 | SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0), | ||
492 | SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1), | ||
493 | SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2), | ||
494 | SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3), | ||
495 | SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4), | ||
496 | SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5), | ||
497 | SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6), | ||
498 | SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7), | ||
499 | SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8), | ||
500 | SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9), | ||
501 | }; | ||
502 | |||
503 | static struct sensor_device_attribute sda_in_max[] = { | ||
504 | SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0), | ||
505 | SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1), | ||
506 | SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2), | ||
507 | SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3), | ||
508 | SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4), | ||
509 | SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5), | ||
510 | SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6), | ||
511 | SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7), | ||
512 | SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8), | ||
513 | SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9), | ||
514 | }; | ||
515 | |||
516 | static void device_create_file_in(struct device *dev, int i) | ||
517 | { | ||
518 | device_create_file(dev, &sda_in_input[i].dev_attr); | ||
519 | device_create_file(dev, &sda_in_min[i].dev_attr); | ||
520 | device_create_file(dev, &sda_in_max[i].dev_attr); | ||
521 | } | ||
409 | 522 | ||
410 | #define show_fan_reg(reg) \ | 523 | #define show_fan_reg(reg) \ |
411 | static ssize_t \ | 524 | static ssize_t \ |
@@ -705,6 +818,9 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) | |||
705 | goto exit_detach; | 818 | goto exit_detach; |
706 | } | 819 | } |
707 | 820 | ||
821 | for (i = 0; i < 10; i++) | ||
822 | device_create_file_in(dev, i); | ||
823 | |||
708 | for (i = 0; i < 5; i++) { | 824 | for (i = 0; i < 5; i++) { |
709 | if (data->has_fan & (1 << i)) | 825 | if (data->has_fan & (1 << i)) |
710 | device_create_file_fan(dev, i); | 826 | device_create_file_fan(dev, i); |