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 236f9f29c62..3b8b81984ad 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -328,6 +328,12 @@ static struct sensor_device_attribute fan_min[] = { SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 2), }; +#define FAN_UNIT_ATTRS(X) \ + &fan_input[X].dev_attr.attr, \ + &fan_status[X].dev_attr.attr, \ + &fan_div[X].dev_attr.attr, \ + &fan_min[X].dev_attr.attr + static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); @@ -360,6 +366,19 @@ static struct sensor_device_attribute pwm[] = { SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2), }; +static struct attribute * pc8736x_fan_attr_array[] = { + FAN_UNIT_ATTRS(0), + FAN_UNIT_ATTRS(1), + FAN_UNIT_ATTRS(2), + &pwm[0].dev_attr.attr, + &pwm[1].dev_attr.attr, + &pwm[2].dev_attr.attr, + NULL +}; +static const struct attribute_group pc8736x_fan_group = { + .attrs = pc8736x_fan_attr_array, +}; + static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); @@ -472,6 +491,61 @@ static struct sensor_device_attribute in_max[] = { SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10), }; +#define VIN_UNIT_ATTRS(X) \ + &in_input[X].dev_attr.attr, \ + &in_status[X].dev_attr.attr, \ + &in_min[X].dev_attr.attr, \ + &in_max[X].dev_attr.attr + +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); + +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", data->vrm); +} +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pc87360_data *data = i2c_get_clientdata(client); + data->vrm = simple_strtoul(buf, NULL, 10); + return count; +} +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); + +static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", data->in_alarms); +} +static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL); + +static struct attribute *pc8736x_vin_attr_array[] = { + VIN_UNIT_ATTRS(0), + VIN_UNIT_ATTRS(1), + VIN_UNIT_ATTRS(2), + VIN_UNIT_ATTRS(3), + VIN_UNIT_ATTRS(4), + VIN_UNIT_ATTRS(5), + VIN_UNIT_ATTRS(6), + VIN_UNIT_ATTRS(7), + VIN_UNIT_ATTRS(8), + VIN_UNIT_ATTRS(9), + VIN_UNIT_ATTRS(10), + &dev_attr_cpu0_vid.attr, + &dev_attr_vrm.attr, + &dev_attr_alarms_in.attr, + NULL +}; +static const struct attribute_group pc8736x_vin_group = { + .attrs = pc8736x_vin_attr_array, +}; + static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); @@ -590,33 +664,22 @@ static struct sensor_device_attribute therm_crit[] = { show_therm_crit, set_therm_crit, 2+11), }; -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); -} -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); - -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", data->vrm); -} -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct pc87360_data *data = i2c_get_clientdata(client); - data->vrm = simple_strtoul(buf, NULL, 10); - return count; -} -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); - -static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", data->in_alarms); -} -static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL); +#define THERM_UNIT_ATTRS(X) \ + &therm_input[X].dev_attr.attr, \ + &therm_status[X].dev_attr.attr, \ + &therm_min[X].dev_attr.attr, \ + &therm_max[X].dev_attr.attr, \ + &therm_crit[X].dev_attr.attr + +static struct attribute * pc8736x_therm_attr_array[] = { + THERM_UNIT_ATTRS(0), + THERM_UNIT_ATTRS(1), + THERM_UNIT_ATTRS(2), + NULL +}; +static const struct attribute_group pc8736x_therm_group = { + .attrs = pc8736x_therm_attr_array, +}; static ssize_t show_temp_input(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -736,6 +799,25 @@ static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *att } static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL); +#define TEMP_UNIT_ATTRS(X) \ + &temp_input[X].dev_attr.attr, \ + &temp_status[X].dev_attr.attr, \ + &temp_min[X].dev_attr.attr, \ + &temp_max[X].dev_attr.attr, \ + &temp_crit[X].dev_attr.attr + +static struct attribute * pc8736x_temp_attr_array[] = { + TEMP_UNIT_ATTRS(0), + TEMP_UNIT_ATTRS(1), + TEMP_UNIT_ATTRS(2), + /* include the few miscellaneous atts here */ + &dev_attr_alarms_temp.attr, + NULL +}; +static const struct attribute_group pc8736x_temp_group = { + .attrs = pc8736x_temp_attr_array, +}; + /* * Device detection, registration and update */ @@ -936,60 +1018,69 @@ static int pc87360_detect(struct i2c_adapter *adapter) pc87360_init_client(client, use_thermistors); } - /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + /* Register all-or-nothing sysfs groups */ + + if (data->innr && + (err = sysfs_create_group(&client->dev.kobj, + &pc8736x_vin_group))) goto ERROR3; - } - if (data->innr) { - for (i = 0; i < 11; i++) { - device_create_file(dev, &in_input[i].dev_attr); - device_create_file(dev, &in_min[i].dev_attr); - device_create_file(dev, &in_max[i].dev_attr); - device_create_file(dev, &in_status[i].dev_attr); - } - device_create_file(dev, &dev_attr_cpu0_vid); - device_create_file(dev, &dev_attr_vrm); - device_create_file(dev, &dev_attr_alarms_in); - } + if (data->innr == 14 && + (err = sysfs_create_group(&client->dev.kobj, + &pc8736x_therm_group))) + goto ERROR3; + + /* create device attr-files for varying sysfs groups */ if (data->tempnr) { for (i = 0; i < data->tempnr; i++) { - device_create_file(dev, &temp_input[i].dev_attr); - device_create_file(dev, &temp_min[i].dev_attr); - device_create_file(dev, &temp_max[i].dev_attr); - device_create_file(dev, &temp_crit[i].dev_attr); - device_create_file(dev, &temp_status[i].dev_attr); - } - device_create_file(dev, &dev_attr_alarms_temp); - } - - if (data->innr == 14) { - for (i = 0; i < 3; i++) { - device_create_file(dev, &therm_input[i].dev_attr); - device_create_file(dev, &therm_min[i].dev_attr); - device_create_file(dev, &therm_max[i].dev_attr); - device_create_file(dev, &therm_crit[i].dev_attr); - device_create_file(dev, &therm_status[i].dev_attr); + if ((err = device_create_file(dev, + &temp_input[i].dev_attr)) + || (err = device_create_file(dev, + &temp_min[i].dev_attr)) + || (err = device_create_file(dev, + &temp_max[i].dev_attr)) + || (err = device_create_file(dev, + &temp_crit[i].dev_attr)) + || (err = device_create_file(dev, + &temp_status[i].dev_attr))) + goto ERROR3; } + if ((err = device_create_file(dev, &dev_attr_alarms_temp))) + goto ERROR3; } for (i = 0; i < data->fannr; i++) { - if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { - device_create_file(dev, &fan_input[i].dev_attr); - device_create_file(dev, &fan_min[i].dev_attr); - device_create_file(dev, &fan_div[i].dev_attr); - device_create_file(dev, &fan_status[i].dev_attr); - } - if (FAN_CONFIG_CONTROL(data->fan_conf, i)) - device_create_file(dev, &pwm[i].dev_attr); + if (FAN_CONFIG_MONITOR(data->fan_conf, i) + && ((err = device_create_file(dev, + &fan_input[i].dev_attr)) + || (err = device_create_file(dev, + &fan_min[i].dev_attr)) + || (err = device_create_file(dev, + &fan_div[i].dev_attr)) + || (err = device_create_file(dev, + &fan_status[i].dev_attr)))) + goto ERROR3; + + if (FAN_CONFIG_CONTROL(data->fan_conf, i) + && (err = device_create_file(dev, &pwm[i].dev_attr))) + goto ERROR3; } + data->class_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto ERROR3; + } return 0; ERROR3: + /* can still remove groups whose members were added individually */ + sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group); + sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group); + sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group); + sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group); + i2c_detach_client(client); ERROR2: for (i = 0; i < 3; i++) { @@ -1009,6 +1100,11 @@ static int pc87360_detach_client(struct i2c_client *client) hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group); + sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group); + sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group); + sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group); + if ((i = i2c_detach_client(client))) return i; |