diff options
author | Guenter Roeck <guenter.roeck@ericsson.com> | 2011-02-07 18:08:54 -0500 |
---|---|---|
committer | Guenter Roeck <guenter.roeck@ericsson.com> | 2011-03-15 01:39:14 -0400 |
commit | d36cf32c9a6c4ffea8f2108a05defb55800f9215 (patch) | |
tree | 7d663ef2b91947314d6b39d1af83ec6c4c5d823c /drivers/hwmon | |
parent | 83cc8985b82dff2ef85987a8481a92aab1b33323 (diff) |
hwmon: (w83627ehf) Improve support for W83667HG-B
Add support for 4th temperature sensor on W83677HG-B.
Display temperature labels on W83677HG-B to report temperature sources.
Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
Acked-by: Ian Dobson <i.dobson@planet-ian.com>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/w83627ehf.c | 155 |
1 files changed, 124 insertions, 31 deletions
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 5a627b9db3e8..d10fe706c856 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c | |||
@@ -39,7 +39,7 @@ | |||
39 | w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 | 39 | w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 |
40 | w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3 | 40 | w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3 |
41 | w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 | 41 | w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 |
42 | w83667hg-b 9 5 3 3 0xb350 0xc1 0x5ca3 | 42 | w83667hg-b 9 5 3 4 0xb350 0xc1 0x5ca3 |
43 | */ | 43 | */ |
44 | 44 | ||
45 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 45 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
@@ -164,10 +164,10 @@ static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; | |||
164 | #define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ | 164 | #define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ |
165 | (0x550 + (nr) - 7)) | 165 | (0x550 + (nr) - 7)) |
166 | 166 | ||
167 | static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250 }; | 167 | static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250, 0x7e }; |
168 | static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253 }; | 168 | static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253, 0 }; |
169 | static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255 }; | 169 | static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255, 0 }; |
170 | static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252 }; | 170 | static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 }; |
171 | 171 | ||
172 | /* Fan clock dividers are spread over the following five registers */ | 172 | /* Fan clock dividers are spread over the following five registers */ |
173 | #define W83627EHF_REG_FANDIV1 0x47 | 173 | #define W83627EHF_REG_FANDIV1 0x47 |
@@ -213,6 +213,19 @@ static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[] | |||
213 | static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b }; | 213 | static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b }; |
214 | static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c }; | 214 | static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c }; |
215 | 215 | ||
216 | static const char *const w83667hg_b_temp_label[] = { | ||
217 | "SYSTIN", | ||
218 | "CPUTIN", | ||
219 | "AUXTIN", | ||
220 | "AMDTSI", | ||
221 | "PECI Agent 1", | ||
222 | "PECI Agent 2", | ||
223 | "PECI Agent 3", | ||
224 | "PECI Agent 4" | ||
225 | }; | ||
226 | |||
227 | #define NUM_REG_TEMP 4 | ||
228 | |||
216 | static inline int is_word_sized(u16 reg) | 229 | static inline int is_word_sized(u16 reg) |
217 | { | 230 | { |
218 | return (((reg & 0xff00) == 0x100 | 231 | return (((reg & 0xff00) == 0x100 |
@@ -294,6 +307,9 @@ struct w83627ehf_data { | |||
294 | struct device *hwmon_dev; | 307 | struct device *hwmon_dev; |
295 | struct mutex lock; | 308 | struct mutex lock; |
296 | 309 | ||
310 | u8 temp_src[NUM_REG_TEMP]; | ||
311 | const char * const *temp_label; | ||
312 | |||
297 | const u8 *REG_FAN_START_OUTPUT; | 313 | const u8 *REG_FAN_START_OUTPUT; |
298 | const u8 *REG_FAN_STOP_OUTPUT; | 314 | const u8 *REG_FAN_STOP_OUTPUT; |
299 | const u8 *REG_FAN_MAX_OUTPUT; | 315 | const u8 *REG_FAN_MAX_OUTPUT; |
@@ -314,9 +330,9 @@ struct w83627ehf_data { | |||
314 | u8 fan_div[5]; | 330 | u8 fan_div[5]; |
315 | u8 has_fan; /* some fan inputs can be disabled */ | 331 | u8 has_fan; /* some fan inputs can be disabled */ |
316 | u8 temp_type[3]; | 332 | u8 temp_type[3]; |
317 | s16 temp[3]; | 333 | s16 temp[4]; |
318 | s16 temp_max[3]; | 334 | s16 temp_max[4]; |
319 | s16 temp_max_hyst[3]; | 335 | s16 temp_max_hyst[4]; |
320 | u32 alarms; | 336 | u32 alarms; |
321 | 337 | ||
322 | u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ | 338 | u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ |
@@ -339,7 +355,7 @@ struct w83627ehf_data { | |||
339 | u8 vid; | 355 | u8 vid; |
340 | u8 vrm; | 356 | u8 vrm; |
341 | 357 | ||
342 | u8 temp3_disable; | 358 | u8 have_temp; |
343 | u8 in6_skip; | 359 | u8 in6_skip; |
344 | }; | 360 | }; |
345 | 361 | ||
@@ -577,12 +593,18 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | |||
577 | } | 593 | } |
578 | 594 | ||
579 | /* Measured temperatures and limits */ | 595 | /* Measured temperatures and limits */ |
580 | for (i = 0; i < 3; i++) { | 596 | for (i = 0; i < NUM_REG_TEMP; i++) { |
581 | data->temp[i] = w83627ehf_read_value(data, | 597 | if (!(data->have_temp & (1 << i))) |
582 | W83627EHF_REG_TEMP[i]); | 598 | continue; |
583 | data->temp_max[i] = w83627ehf_read_value(data, | 599 | data->temp[i] |
584 | W83627EHF_REG_TEMP_OVER[i]); | 600 | = w83627ehf_read_value(data, W83627EHF_REG_TEMP[i]); |
585 | data->temp_max_hyst[i] = w83627ehf_read_value(data, | 601 | if (i > 2) |
602 | break; | ||
603 | data->temp_max[i] | ||
604 | = w83627ehf_read_value(data, | ||
605 | W83627EHF_REG_TEMP_OVER[i]); | ||
606 | data->temp_max_hyst[i] | ||
607 | = w83627ehf_read_value(data, | ||
586 | W83627EHF_REG_TEMP_HYST[i]); | 608 | W83627EHF_REG_TEMP_HYST[i]); |
587 | } | 609 | } |
588 | 610 | ||
@@ -844,6 +866,15 @@ static struct sensor_device_attribute sda_fan_div[] = { | |||
844 | SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4), | 866 | SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4), |
845 | }; | 867 | }; |
846 | 868 | ||
869 | static ssize_t | ||
870 | show_temp_label(struct device *dev, struct device_attribute *attr, char *buf) | ||
871 | { | ||
872 | struct w83627ehf_data *data = w83627ehf_update_device(dev); | ||
873 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
874 | int nr = sensor_attr->index; | ||
875 | return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]); | ||
876 | } | ||
877 | |||
847 | #define show_temp_reg(REG, reg) \ | 878 | #define show_temp_reg(REG, reg) \ |
848 | static ssize_t \ | 879 | static ssize_t \ |
849 | show_##reg(struct device *dev, struct device_attribute *attr, \ | 880 | show_##reg(struct device *dev, struct device_attribute *attr, \ |
@@ -897,6 +928,14 @@ static struct sensor_device_attribute sda_temp_input[] = { | |||
897 | SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0), | 928 | SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0), |
898 | SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1), | 929 | SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1), |
899 | SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2), | 930 | SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2), |
931 | SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3), | ||
932 | }; | ||
933 | |||
934 | static struct sensor_device_attribute sda_temp_label[] = { | ||
935 | SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0), | ||
936 | SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1), | ||
937 | SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2), | ||
938 | SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3), | ||
900 | }; | 939 | }; |
901 | 940 | ||
902 | static struct sensor_device_attribute sda_temp_max[] = { | 941 | static struct sensor_device_attribute sda_temp_max[] = { |
@@ -1328,10 +1367,13 @@ static void w83627ehf_device_remove_files(struct device *dev) | |||
1328 | device_remove_file(dev, &sda_target_temp[i].dev_attr); | 1367 | device_remove_file(dev, &sda_target_temp[i].dev_attr); |
1329 | device_remove_file(dev, &sda_tolerance[i].dev_attr); | 1368 | device_remove_file(dev, &sda_tolerance[i].dev_attr); |
1330 | } | 1369 | } |
1331 | for (i = 0; i < 3; i++) { | 1370 | for (i = 0; i < NUM_REG_TEMP; i++) { |
1332 | if ((i == 2) && data->temp3_disable) | 1371 | if (!(data->have_temp & (1 << i))) |
1333 | continue; | 1372 | continue; |
1334 | device_remove_file(dev, &sda_temp_input[i].dev_attr); | 1373 | device_remove_file(dev, &sda_temp_input[i].dev_attr); |
1374 | device_remove_file(dev, &sda_temp_label[i].dev_attr); | ||
1375 | if (i > 2) | ||
1376 | break; | ||
1335 | device_remove_file(dev, &sda_temp_max[i].dev_attr); | 1377 | device_remove_file(dev, &sda_temp_max[i].dev_attr); |
1336 | device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr); | 1378 | device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr); |
1337 | device_remove_file(dev, &sda_temp_alarm[i].dev_attr); | 1379 | device_remove_file(dev, &sda_temp_alarm[i].dev_attr); |
@@ -1354,12 +1396,14 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data) | |||
1354 | w83627ehf_write_value(data, W83627EHF_REG_CONFIG, | 1396 | w83627ehf_write_value(data, W83627EHF_REG_CONFIG, |
1355 | tmp | 0x01); | 1397 | tmp | 0x01); |
1356 | 1398 | ||
1357 | /* Enable temp2 and temp3 if needed */ | 1399 | /* Enable temperature sensors if needed */ |
1358 | for (i = 1; i < 3; i++) { | 1400 | for (i = 0; i < NUM_REG_TEMP; i++) { |
1401 | if (!(data->have_temp & (1 << i))) | ||
1402 | continue; | ||
1403 | if (!W83627EHF_REG_TEMP_CONFIG[i]) | ||
1404 | continue; | ||
1359 | tmp = w83627ehf_read_value(data, | 1405 | tmp = w83627ehf_read_value(data, |
1360 | W83627EHF_REG_TEMP_CONFIG[i]); | 1406 | W83627EHF_REG_TEMP_CONFIG[i]); |
1361 | if ((i == 2) && data->temp3_disable) | ||
1362 | continue; | ||
1363 | if (tmp & 0x01) | 1407 | if (tmp & 0x01) |
1364 | w83627ehf_write_value(data, | 1408 | w83627ehf_write_value(data, |
1365 | W83627EHF_REG_TEMP_CONFIG[i], | 1409 | W83627EHF_REG_TEMP_CONFIG[i], |
@@ -1417,11 +1461,52 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1417 | data->pwm_num = (sio_data->kind == w83667hg | 1461 | data->pwm_num = (sio_data->kind == w83667hg |
1418 | || sio_data->kind == w83667hg_b) ? 3 : 4; | 1462 | || sio_data->kind == w83667hg_b) ? 3 : 4; |
1419 | 1463 | ||
1464 | data->have_temp = 0x07; | ||
1420 | /* Check temp3 configuration bit for 667HG */ | 1465 | /* Check temp3 configuration bit for 667HG */ |
1421 | if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) { | 1466 | if (sio_data->kind == w83667hg) { |
1422 | data->temp3_disable = w83627ehf_read_value(data, | 1467 | u8 reg; |
1423 | W83627EHF_REG_TEMP_CONFIG[2]) & 0x01; | 1468 | |
1424 | data->in6_skip = !data->temp3_disable; | 1469 | reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]); |
1470 | if (reg & 0x01) | ||
1471 | data->have_temp &= ~(1 << 2); | ||
1472 | else | ||
1473 | data->in6_skip = 1; /* Either temp3 or in6 */ | ||
1474 | } else if (sio_data->kind == w83667hg_b) { | ||
1475 | u8 reg; | ||
1476 | |||
1477 | reg = w83627ehf_read_value(data, 0x4a); | ||
1478 | data->temp_src[0] = reg >> 5; | ||
1479 | reg = w83627ehf_read_value(data, 0x49); | ||
1480 | data->temp_src[1] = reg & 0x07; | ||
1481 | data->temp_src[2] = (reg >> 4) & 0x07; | ||
1482 | |||
1483 | /* | ||
1484 | * W83667HG-B has another temperature register at 0x7e. | ||
1485 | * The temperature source is selected with register 0x7d. | ||
1486 | * Support it if the source differs from already reported | ||
1487 | * sources. | ||
1488 | */ | ||
1489 | reg = w83627ehf_read_value(data, 0x7d); | ||
1490 | reg &= 0x07; | ||
1491 | if (reg != data->temp_src[0] && reg != data->temp_src[1] | ||
1492 | && reg != data->temp_src[2]) { | ||
1493 | data->temp_src[3] = reg; | ||
1494 | data->have_temp |= 1 << 3; | ||
1495 | } | ||
1496 | |||
1497 | /* | ||
1498 | * Chip supports either AUXTIN or VIN3. Try to find out which | ||
1499 | * one. | ||
1500 | */ | ||
1501 | reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]); | ||
1502 | if (data->temp_src[2] == 2 && (reg & 0x01)) | ||
1503 | data->have_temp &= ~(1 << 2); | ||
1504 | |||
1505 | if ((data->temp_src[2] == 2 && (data->have_temp & (1 << 2))) | ||
1506 | || (data->temp_src[3] == 2 && (data->have_temp & (1 << 3)))) | ||
1507 | data->in6_skip = 1; | ||
1508 | |||
1509 | data->temp_label = w83667hg_b_temp_label; | ||
1425 | } | 1510 | } |
1426 | 1511 | ||
1427 | data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT; | 1512 | data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT; |
@@ -1584,13 +1669,21 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1584 | } | 1669 | } |
1585 | } | 1670 | } |
1586 | 1671 | ||
1587 | for (i = 0; i < 3; i++) { | 1672 | for (i = 0; i < NUM_REG_TEMP; i++) { |
1588 | if ((i == 2) && data->temp3_disable) | 1673 | if (!(data->have_temp & (1 << i))) |
1589 | continue; | 1674 | continue; |
1590 | if ((err = device_create_file(dev, | 1675 | err = device_create_file(dev, &sda_temp_input[i].dev_attr); |
1591 | &sda_temp_input[i].dev_attr)) | 1676 | if (err) |
1592 | || (err = device_create_file(dev, | 1677 | goto exit_remove; |
1593 | &sda_temp_max[i].dev_attr)) | 1678 | if (data->temp_label) { |
1679 | err = device_create_file(dev, | ||
1680 | &sda_temp_label[i].dev_attr); | ||
1681 | if (err) | ||
1682 | goto exit_remove; | ||
1683 | } | ||
1684 | if (i > 2) | ||
1685 | break; | ||
1686 | if ((err = device_create_file(dev, &sda_temp_max[i].dev_attr)) | ||
1594 | || (err = device_create_file(dev, | 1687 | || (err = device_create_file(dev, |
1595 | &sda_temp_max_hyst[i].dev_attr)) | 1688 | &sda_temp_max_hyst[i].dev_attr)) |
1596 | || (err = device_create_file(dev, | 1689 | || (err = device_create_file(dev, |