diff options
Diffstat (limited to 'drivers/hwmon/pc87360.c')
-rw-r--r-- | drivers/hwmon/pc87360.c | 230 |
1 files changed, 163 insertions, 67 deletions
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index 236f9f29c624..3b8b81984ad4 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c | |||
@@ -328,6 +328,12 @@ static struct sensor_device_attribute fan_min[] = { | |||
328 | SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 2), | 328 | SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 2), |
329 | }; | 329 | }; |
330 | 330 | ||
331 | #define FAN_UNIT_ATTRS(X) \ | ||
332 | &fan_input[X].dev_attr.attr, \ | ||
333 | &fan_status[X].dev_attr.attr, \ | ||
334 | &fan_div[X].dev_attr.attr, \ | ||
335 | &fan_min[X].dev_attr.attr | ||
336 | |||
331 | static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf) | 337 | static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf) |
332 | { | 338 | { |
333 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 339 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
@@ -360,6 +366,19 @@ static struct sensor_device_attribute pwm[] = { | |||
360 | SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2), | 366 | SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2), |
361 | }; | 367 | }; |
362 | 368 | ||
369 | static struct attribute * pc8736x_fan_attr_array[] = { | ||
370 | FAN_UNIT_ATTRS(0), | ||
371 | FAN_UNIT_ATTRS(1), | ||
372 | FAN_UNIT_ATTRS(2), | ||
373 | &pwm[0].dev_attr.attr, | ||
374 | &pwm[1].dev_attr.attr, | ||
375 | &pwm[2].dev_attr.attr, | ||
376 | NULL | ||
377 | }; | ||
378 | static const struct attribute_group pc8736x_fan_group = { | ||
379 | .attrs = pc8736x_fan_attr_array, | ||
380 | }; | ||
381 | |||
363 | static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf) | 382 | static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf) |
364 | { | 383 | { |
365 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 384 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
@@ -472,6 +491,61 @@ static struct sensor_device_attribute in_max[] = { | |||
472 | SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10), | 491 | SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10), |
473 | }; | 492 | }; |
474 | 493 | ||
494 | #define VIN_UNIT_ATTRS(X) \ | ||
495 | &in_input[X].dev_attr.attr, \ | ||
496 | &in_status[X].dev_attr.attr, \ | ||
497 | &in_min[X].dev_attr.attr, \ | ||
498 | &in_max[X].dev_attr.attr | ||
499 | |||
500 | static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) | ||
501 | { | ||
502 | struct pc87360_data *data = pc87360_update_device(dev); | ||
503 | return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); | ||
504 | } | ||
505 | static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); | ||
506 | |||
507 | static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) | ||
508 | { | ||
509 | struct pc87360_data *data = pc87360_update_device(dev); | ||
510 | return sprintf(buf, "%u\n", data->vrm); | ||
511 | } | ||
512 | static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
513 | { | ||
514 | struct i2c_client *client = to_i2c_client(dev); | ||
515 | struct pc87360_data *data = i2c_get_clientdata(client); | ||
516 | data->vrm = simple_strtoul(buf, NULL, 10); | ||
517 | return count; | ||
518 | } | ||
519 | static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); | ||
520 | |||
521 | static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf) | ||
522 | { | ||
523 | struct pc87360_data *data = pc87360_update_device(dev); | ||
524 | return sprintf(buf, "%u\n", data->in_alarms); | ||
525 | } | ||
526 | static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL); | ||
527 | |||
528 | static struct attribute *pc8736x_vin_attr_array[] = { | ||
529 | VIN_UNIT_ATTRS(0), | ||
530 | VIN_UNIT_ATTRS(1), | ||
531 | VIN_UNIT_ATTRS(2), | ||
532 | VIN_UNIT_ATTRS(3), | ||
533 | VIN_UNIT_ATTRS(4), | ||
534 | VIN_UNIT_ATTRS(5), | ||
535 | VIN_UNIT_ATTRS(6), | ||
536 | VIN_UNIT_ATTRS(7), | ||
537 | VIN_UNIT_ATTRS(8), | ||
538 | VIN_UNIT_ATTRS(9), | ||
539 | VIN_UNIT_ATTRS(10), | ||
540 | &dev_attr_cpu0_vid.attr, | ||
541 | &dev_attr_vrm.attr, | ||
542 | &dev_attr_alarms_in.attr, | ||
543 | NULL | ||
544 | }; | ||
545 | static const struct attribute_group pc8736x_vin_group = { | ||
546 | .attrs = pc8736x_vin_attr_array, | ||
547 | }; | ||
548 | |||
475 | static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf) | 549 | static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf) |
476 | { | 550 | { |
477 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 551 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
@@ -590,33 +664,22 @@ static struct sensor_device_attribute therm_crit[] = { | |||
590 | show_therm_crit, set_therm_crit, 2+11), | 664 | show_therm_crit, set_therm_crit, 2+11), |
591 | }; | 665 | }; |
592 | 666 | ||
593 | static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) | 667 | #define THERM_UNIT_ATTRS(X) \ |
594 | { | 668 | &therm_input[X].dev_attr.attr, \ |
595 | struct pc87360_data *data = pc87360_update_device(dev); | 669 | &therm_status[X].dev_attr.attr, \ |
596 | return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); | 670 | &therm_min[X].dev_attr.attr, \ |
597 | } | 671 | &therm_max[X].dev_attr.attr, \ |
598 | static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); | 672 | &therm_crit[X].dev_attr.attr |
599 | 673 | ||
600 | static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) | 674 | static struct attribute * pc8736x_therm_attr_array[] = { |
601 | { | 675 | THERM_UNIT_ATTRS(0), |
602 | struct pc87360_data *data = pc87360_update_device(dev); | 676 | THERM_UNIT_ATTRS(1), |
603 | return sprintf(buf, "%u\n", data->vrm); | 677 | THERM_UNIT_ATTRS(2), |
604 | } | 678 | NULL |
605 | static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 679 | }; |
606 | { | 680 | static const struct attribute_group pc8736x_therm_group = { |
607 | struct i2c_client *client = to_i2c_client(dev); | 681 | .attrs = pc8736x_therm_attr_array, |
608 | struct pc87360_data *data = i2c_get_clientdata(client); | 682 | }; |
609 | data->vrm = simple_strtoul(buf, NULL, 10); | ||
610 | return count; | ||
611 | } | ||
612 | static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); | ||
613 | |||
614 | static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf) | ||
615 | { | ||
616 | struct pc87360_data *data = pc87360_update_device(dev); | ||
617 | return sprintf(buf, "%u\n", data->in_alarms); | ||
618 | } | ||
619 | static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL); | ||
620 | 683 | ||
621 | static ssize_t show_temp_input(struct device *dev, struct device_attribute *devattr, char *buf) | 684 | static ssize_t show_temp_input(struct device *dev, struct device_attribute *devattr, char *buf) |
622 | { | 685 | { |
@@ -736,6 +799,25 @@ static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *att | |||
736 | } | 799 | } |
737 | static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL); | 800 | static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL); |
738 | 801 | ||
802 | #define TEMP_UNIT_ATTRS(X) \ | ||
803 | &temp_input[X].dev_attr.attr, \ | ||
804 | &temp_status[X].dev_attr.attr, \ | ||
805 | &temp_min[X].dev_attr.attr, \ | ||
806 | &temp_max[X].dev_attr.attr, \ | ||
807 | &temp_crit[X].dev_attr.attr | ||
808 | |||
809 | static struct attribute * pc8736x_temp_attr_array[] = { | ||
810 | TEMP_UNIT_ATTRS(0), | ||
811 | TEMP_UNIT_ATTRS(1), | ||
812 | TEMP_UNIT_ATTRS(2), | ||
813 | /* include the few miscellaneous atts here */ | ||
814 | &dev_attr_alarms_temp.attr, | ||
815 | NULL | ||
816 | }; | ||
817 | static const struct attribute_group pc8736x_temp_group = { | ||
818 | .attrs = pc8736x_temp_attr_array, | ||
819 | }; | ||
820 | |||
739 | /* | 821 | /* |
740 | * Device detection, registration and update | 822 | * Device detection, registration and update |
741 | */ | 823 | */ |
@@ -936,60 +1018,69 @@ static int pc87360_detect(struct i2c_adapter *adapter) | |||
936 | pc87360_init_client(client, use_thermistors); | 1018 | pc87360_init_client(client, use_thermistors); |
937 | } | 1019 | } |
938 | 1020 | ||
939 | /* Register sysfs hooks */ | 1021 | /* Register all-or-nothing sysfs groups */ |
940 | data->class_dev = hwmon_device_register(&client->dev); | 1022 | |
941 | if (IS_ERR(data->class_dev)) { | 1023 | if (data->innr && |
942 | err = PTR_ERR(data->class_dev); | 1024 | (err = sysfs_create_group(&client->dev.kobj, |
1025 | &pc8736x_vin_group))) | ||
943 | goto ERROR3; | 1026 | goto ERROR3; |
944 | } | ||
945 | 1027 | ||
946 | if (data->innr) { | 1028 | if (data->innr == 14 && |
947 | for (i = 0; i < 11; i++) { | 1029 | (err = sysfs_create_group(&client->dev.kobj, |
948 | device_create_file(dev, &in_input[i].dev_attr); | 1030 | &pc8736x_therm_group))) |
949 | device_create_file(dev, &in_min[i].dev_attr); | 1031 | goto ERROR3; |
950 | device_create_file(dev, &in_max[i].dev_attr); | 1032 | |
951 | device_create_file(dev, &in_status[i].dev_attr); | 1033 | /* create device attr-files for varying sysfs groups */ |
952 | } | ||
953 | device_create_file(dev, &dev_attr_cpu0_vid); | ||
954 | device_create_file(dev, &dev_attr_vrm); | ||
955 | device_create_file(dev, &dev_attr_alarms_in); | ||
956 | } | ||
957 | 1034 | ||
958 | if (data->tempnr) { | 1035 | if (data->tempnr) { |
959 | for (i = 0; i < data->tempnr; i++) { | 1036 | for (i = 0; i < data->tempnr; i++) { |
960 | device_create_file(dev, &temp_input[i].dev_attr); | 1037 | if ((err = device_create_file(dev, |
961 | device_create_file(dev, &temp_min[i].dev_attr); | 1038 | &temp_input[i].dev_attr)) |
962 | device_create_file(dev, &temp_max[i].dev_attr); | 1039 | || (err = device_create_file(dev, |
963 | device_create_file(dev, &temp_crit[i].dev_attr); | 1040 | &temp_min[i].dev_attr)) |
964 | device_create_file(dev, &temp_status[i].dev_attr); | 1041 | || (err = device_create_file(dev, |
965 | } | 1042 | &temp_max[i].dev_attr)) |
966 | device_create_file(dev, &dev_attr_alarms_temp); | 1043 | || (err = device_create_file(dev, |
967 | } | 1044 | &temp_crit[i].dev_attr)) |
968 | 1045 | || (err = device_create_file(dev, | |
969 | if (data->innr == 14) { | 1046 | &temp_status[i].dev_attr))) |
970 | for (i = 0; i < 3; i++) { | 1047 | goto ERROR3; |
971 | device_create_file(dev, &therm_input[i].dev_attr); | ||
972 | device_create_file(dev, &therm_min[i].dev_attr); | ||
973 | device_create_file(dev, &therm_max[i].dev_attr); | ||
974 | device_create_file(dev, &therm_crit[i].dev_attr); | ||
975 | device_create_file(dev, &therm_status[i].dev_attr); | ||
976 | } | 1048 | } |
1049 | if ((err = device_create_file(dev, &dev_attr_alarms_temp))) | ||
1050 | goto ERROR3; | ||
977 | } | 1051 | } |
978 | 1052 | ||
979 | for (i = 0; i < data->fannr; i++) { | 1053 | for (i = 0; i < data->fannr; i++) { |
980 | if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { | 1054 | if (FAN_CONFIG_MONITOR(data->fan_conf, i) |
981 | device_create_file(dev, &fan_input[i].dev_attr); | 1055 | && ((err = device_create_file(dev, |
982 | device_create_file(dev, &fan_min[i].dev_attr); | 1056 | &fan_input[i].dev_attr)) |
983 | device_create_file(dev, &fan_div[i].dev_attr); | 1057 | || (err = device_create_file(dev, |
984 | device_create_file(dev, &fan_status[i].dev_attr); | 1058 | &fan_min[i].dev_attr)) |
985 | } | 1059 | || (err = device_create_file(dev, |
986 | if (FAN_CONFIG_CONTROL(data->fan_conf, i)) | 1060 | &fan_div[i].dev_attr)) |
987 | device_create_file(dev, &pwm[i].dev_attr); | 1061 | || (err = device_create_file(dev, |
1062 | &fan_status[i].dev_attr)))) | ||
1063 | goto ERROR3; | ||
1064 | |||
1065 | if (FAN_CONFIG_CONTROL(data->fan_conf, i) | ||
1066 | && (err = device_create_file(dev, &pwm[i].dev_attr))) | ||
1067 | goto ERROR3; | ||
988 | } | 1068 | } |
989 | 1069 | ||
1070 | data->class_dev = hwmon_device_register(&client->dev); | ||
1071 | if (IS_ERR(data->class_dev)) { | ||
1072 | err = PTR_ERR(data->class_dev); | ||
1073 | goto ERROR3; | ||
1074 | } | ||
990 | return 0; | 1075 | return 0; |
991 | 1076 | ||
992 | ERROR3: | 1077 | ERROR3: |
1078 | /* can still remove groups whose members were added individually */ | ||
1079 | sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group); | ||
1080 | sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group); | ||
1081 | sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group); | ||
1082 | sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group); | ||
1083 | |||
993 | i2c_detach_client(client); | 1084 | i2c_detach_client(client); |
994 | ERROR2: | 1085 | ERROR2: |
995 | for (i = 0; i < 3; i++) { | 1086 | for (i = 0; i < 3; i++) { |
@@ -1009,6 +1100,11 @@ static int pc87360_detach_client(struct i2c_client *client) | |||
1009 | 1100 | ||
1010 | hwmon_device_unregister(data->class_dev); | 1101 | hwmon_device_unregister(data->class_dev); |
1011 | 1102 | ||
1103 | sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group); | ||
1104 | sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group); | ||
1105 | sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group); | ||
1106 | sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group); | ||
1107 | |||
1012 | if ((i = i2c_detach_client(client))) | 1108 | if ((i = i2c_detach_client(client))) |
1013 | return i; | 1109 | return i; |
1014 | 1110 | ||