diff options
| -rw-r--r-- | drivers/hwmon/smsc47m1.c | 198 |
1 files changed, 95 insertions, 103 deletions
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index 7c16c1c80ef1..1e21c8cc948f 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <linux/jiffies.h> | 32 | #include <linux/jiffies.h> |
| 33 | #include <linux/platform_device.h> | 33 | #include <linux/platform_device.h> |
| 34 | #include <linux/hwmon.h> | 34 | #include <linux/hwmon.h> |
| 35 | #include <linux/hwmon-sysfs.h> | ||
| 35 | #include <linux/err.h> | 36 | #include <linux/err.h> |
| 36 | #include <linux/init.h> | 37 | #include <linux/init.h> |
| 37 | #include <linux/mutex.h> | 38 | #include <linux/mutex.h> |
| @@ -157,11 +158,12 @@ static struct platform_driver smsc47m1_driver = { | |||
| 157 | .remove = __devexit_p(smsc47m1_remove), | 158 | .remove = __devexit_p(smsc47m1_remove), |
| 158 | }; | 159 | }; |
| 159 | 160 | ||
| 160 | /* nr is 0 or 1 in the callback functions below */ | 161 | static ssize_t get_fan(struct device *dev, struct device_attribute |
| 161 | 162 | *devattr, char *buf) | |
| 162 | static ssize_t get_fan(struct device *dev, char *buf, int nr) | ||
| 163 | { | 163 | { |
| 164 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
| 164 | struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); | 165 | struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
| 166 | int nr = attr->index; | ||
| 165 | /* This chip (stupidly) stops monitoring fan speed if PWM is | 167 | /* This chip (stupidly) stops monitoring fan speed if PWM is |
| 166 | enabled and duty cycle is 0%. This is fine if the monitoring | 168 | enabled and duty cycle is 0%. This is fine if the monitoring |
| 167 | and control concern the same fan, but troublesome if they are | 169 | and control concern the same fan, but troublesome if they are |
| @@ -173,42 +175,54 @@ static ssize_t get_fan(struct device *dev, char *buf, int nr) | |||
| 173 | return sprintf(buf, "%d\n", rpm); | 175 | return sprintf(buf, "%d\n", rpm); |
| 174 | } | 176 | } |
| 175 | 177 | ||
| 176 | static ssize_t get_fan_min(struct device *dev, char *buf, int nr) | 178 | static ssize_t get_fan_min(struct device *dev, struct device_attribute |
| 179 | *devattr, char *buf) | ||
| 177 | { | 180 | { |
| 181 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
| 178 | struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); | 182 | struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
| 183 | int nr = attr->index; | ||
| 179 | int rpm = MIN_FROM_REG(data->fan_preload[nr], | 184 | int rpm = MIN_FROM_REG(data->fan_preload[nr], |
| 180 | DIV_FROM_REG(data->fan_div[nr])); | 185 | DIV_FROM_REG(data->fan_div[nr])); |
| 181 | return sprintf(buf, "%d\n", rpm); | 186 | return sprintf(buf, "%d\n", rpm); |
| 182 | } | 187 | } |
| 183 | 188 | ||
| 184 | static ssize_t get_fan_div(struct device *dev, char *buf, int nr) | 189 | static ssize_t get_fan_div(struct device *dev, struct device_attribute |
| 190 | *devattr, char *buf) | ||
| 185 | { | 191 | { |
| 192 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
| 186 | struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); | 193 | struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
| 187 | return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); | 194 | return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index])); |
| 188 | } | 195 | } |
| 189 | 196 | ||
| 190 | static ssize_t get_pwm(struct device *dev, char *buf, int nr) | 197 | static ssize_t get_pwm(struct device *dev, struct device_attribute |
| 198 | *devattr, char *buf) | ||
| 191 | { | 199 | { |
| 200 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
| 192 | struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); | 201 | struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
| 193 | return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); | 202 | return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[attr->index])); |
| 194 | } | 203 | } |
| 195 | 204 | ||
| 196 | static ssize_t get_pwm_en(struct device *dev, char *buf, int nr) | 205 | static ssize_t get_pwm_en(struct device *dev, struct device_attribute |
| 206 | *devattr, char *buf) | ||
| 197 | { | 207 | { |
| 208 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
| 198 | struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); | 209 | struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
| 199 | return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[nr])); | 210 | return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[attr->index])); |
| 200 | } | 211 | } |
| 201 | 212 | ||
| 202 | static ssize_t get_alarms(struct device *dev, struct device_attribute *attr, char *buf) | 213 | static ssize_t get_alarms(struct device *dev, struct device_attribute |
| 214 | *devattr, char *buf) | ||
| 203 | { | 215 | { |
| 204 | struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); | 216 | struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
| 205 | return sprintf(buf, "%d\n", data->alarms); | 217 | return sprintf(buf, "%d\n", data->alarms); |
| 206 | } | 218 | } |
| 207 | 219 | ||
| 208 | static ssize_t set_fan_min(struct device *dev, const char *buf, | 220 | static ssize_t set_fan_min(struct device *dev, struct device_attribute |
| 209 | size_t count, int nr) | 221 | *devattr, const char *buf, size_t count) |
| 210 | { | 222 | { |
| 223 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
| 211 | struct smsc47m1_data *data = dev_get_drvdata(dev); | 224 | struct smsc47m1_data *data = dev_get_drvdata(dev); |
| 225 | int nr = attr->index; | ||
| 212 | long rpmdiv, val = simple_strtol(buf, NULL, 10); | 226 | long rpmdiv, val = simple_strtol(buf, NULL, 10); |
| 213 | 227 | ||
| 214 | mutex_lock(&data->update_lock); | 228 | mutex_lock(&data->update_lock); |
| @@ -231,11 +245,12 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, | |||
| 231 | determined in part by the fan clock divider. This follows the principle | 245 | determined in part by the fan clock divider. This follows the principle |
| 232 | of least surprise; the user doesn't expect the fan minimum to change just | 246 | of least surprise; the user doesn't expect the fan minimum to change just |
| 233 | because the divider changed. */ | 247 | because the divider changed. */ |
| 234 | static ssize_t set_fan_div(struct device *dev, const char *buf, | 248 | static ssize_t set_fan_div(struct device *dev, struct device_attribute |
| 235 | size_t count, int nr) | 249 | *devattr, const char *buf, size_t count) |
| 236 | { | 250 | { |
| 251 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
| 237 | struct smsc47m1_data *data = dev_get_drvdata(dev); | 252 | struct smsc47m1_data *data = dev_get_drvdata(dev); |
| 238 | 253 | int nr = attr->index; | |
| 239 | long new_div = simple_strtol(buf, NULL, 10), tmp; | 254 | long new_div = simple_strtol(buf, NULL, 10), tmp; |
| 240 | u8 old_div = DIV_FROM_REG(data->fan_div[nr]); | 255 | u8 old_div = DIV_FROM_REG(data->fan_div[nr]); |
| 241 | 256 | ||
| @@ -279,11 +294,12 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, | |||
| 279 | return count; | 294 | return count; |
| 280 | } | 295 | } |
| 281 | 296 | ||
| 282 | static ssize_t set_pwm(struct device *dev, const char *buf, | 297 | static ssize_t set_pwm(struct device *dev, struct device_attribute |
| 283 | size_t count, int nr) | 298 | *devattr, const char *buf, size_t count) |
| 284 | { | 299 | { |
| 300 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
| 285 | struct smsc47m1_data *data = dev_get_drvdata(dev); | 301 | struct smsc47m1_data *data = dev_get_drvdata(dev); |
| 286 | 302 | int nr = attr->index; | |
| 287 | long val = simple_strtol(buf, NULL, 10); | 303 | long val = simple_strtol(buf, NULL, 10); |
| 288 | 304 | ||
| 289 | if (val < 0 || val > 255) | 305 | if (val < 0 || val > 255) |
| @@ -299,11 +315,12 @@ static ssize_t set_pwm(struct device *dev, const char *buf, | |||
| 299 | return count; | 315 | return count; |
| 300 | } | 316 | } |
| 301 | 317 | ||
| 302 | static ssize_t set_pwm_en(struct device *dev, const char *buf, | 318 | static ssize_t set_pwm_en(struct device *dev, struct device_attribute |
| 303 | size_t count, int nr) | 319 | *devattr, const char *buf, size_t count) |
| 304 | { | 320 | { |
| 321 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
| 305 | struct smsc47m1_data *data = dev_get_drvdata(dev); | 322 | struct smsc47m1_data *data = dev_get_drvdata(dev); |
| 306 | 323 | int nr = attr->index; | |
| 307 | long val = simple_strtol(buf, NULL, 10); | 324 | long val = simple_strtol(buf, NULL, 10); |
| 308 | 325 | ||
| 309 | if (val != 0 && val != 1) | 326 | if (val != 0 && val != 1) |
| @@ -320,56 +337,16 @@ static ssize_t set_pwm_en(struct device *dev, const char *buf, | |||
| 320 | } | 337 | } |
| 321 | 338 | ||
| 322 | #define fan_present(offset) \ | 339 | #define fan_present(offset) \ |
| 323 | static ssize_t get_fan##offset (struct device *dev, struct device_attribute *attr, char *buf) \ | 340 | static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan, \ |
| 324 | { \ | 341 | NULL, offset - 1); \ |
| 325 | return get_fan(dev, buf, offset - 1); \ | 342 | static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ |
| 326 | } \ | 343 | get_fan_min, set_fan_min, offset - 1); \ |
| 327 | static ssize_t get_fan##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ | 344 | static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ |
| 328 | { \ | 345 | get_fan_div, set_fan_div, offset - 1); \ |
| 329 | return get_fan_min(dev, buf, offset - 1); \ | 346 | static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ |
| 330 | } \ | 347 | get_pwm, set_pwm, offset - 1); \ |
| 331 | static ssize_t set_fan##offset##_min (struct device *dev, struct device_attribute *attr, \ | 348 | static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ |
| 332 | const char *buf, size_t count) \ | 349 | get_pwm_en, set_pwm_en, offset - 1) |
| 333 | { \ | ||
| 334 | return set_fan_min(dev, buf, count, offset - 1); \ | ||
| 335 | } \ | ||
| 336 | static ssize_t get_fan##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ | ||
| 337 | { \ | ||
| 338 | return get_fan_div(dev, buf, offset - 1); \ | ||
| 339 | } \ | ||
| 340 | static ssize_t set_fan##offset##_div (struct device *dev, struct device_attribute *attr, \ | ||
| 341 | const char *buf, size_t count) \ | ||
| 342 | { \ | ||
| 343 | return set_fan_div(dev, buf, count, offset - 1); \ | ||
| 344 | } \ | ||
| 345 | static ssize_t get_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf) \ | ||
| 346 | { \ | ||
| 347 | return get_pwm(dev, buf, offset - 1); \ | ||
| 348 | } \ | ||
| 349 | static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr, \ | ||
| 350 | const char *buf, size_t count) \ | ||
| 351 | { \ | ||
| 352 | return set_pwm(dev, buf, count, offset - 1); \ | ||
| 353 | } \ | ||
| 354 | static ssize_t get_pwm##offset##_en (struct device *dev, struct device_attribute *attr, char *buf) \ | ||
| 355 | { \ | ||
| 356 | return get_pwm_en(dev, buf, offset - 1); \ | ||
| 357 | } \ | ||
| 358 | static ssize_t set_pwm##offset##_en (struct device *dev, struct device_attribute *attr, \ | ||
| 359 | const char *buf, size_t count) \ | ||
| 360 | { \ | ||
| 361 | return set_pwm_en(dev, buf, count, offset - 1); \ | ||
| 362 | } \ | ||
| 363 | static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset, \ | ||
| 364 | NULL); \ | ||
| 365 | static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ | ||
| 366 | get_fan##offset##_min, set_fan##offset##_min); \ | ||
| 367 | static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ | ||
| 368 | get_fan##offset##_div, set_fan##offset##_div); \ | ||
| 369 | static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ | ||
| 370 | get_pwm##offset, set_pwm##offset); \ | ||
| 371 | static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ | ||
| 372 | get_pwm##offset##_en, set_pwm##offset##_en); | ||
| 373 | 350 | ||
| 374 | fan_present(1); | 351 | fan_present(1); |
| 375 | fan_present(2); | 352 | fan_present(2); |
| @@ -390,22 +367,22 @@ static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | |||
| 390 | setup so we create them individually. It is still convenient to define a | 367 | setup so we create them individually. It is still convenient to define a |
| 391 | group to remove them all at once. */ | 368 | group to remove them all at once. */ |
| 392 | static struct attribute *smsc47m1_attributes[] = { | 369 | static struct attribute *smsc47m1_attributes[] = { |
| 393 | &dev_attr_fan1_input.attr, | 370 | &sensor_dev_attr_fan1_input.dev_attr.attr, |
| 394 | &dev_attr_fan1_min.attr, | 371 | &sensor_dev_attr_fan1_min.dev_attr.attr, |
| 395 | &dev_attr_fan1_div.attr, | 372 | &sensor_dev_attr_fan1_div.dev_attr.attr, |
| 396 | &dev_attr_fan2_input.attr, | 373 | &sensor_dev_attr_fan2_input.dev_attr.attr, |
| 397 | &dev_attr_fan2_min.attr, | 374 | &sensor_dev_attr_fan2_min.dev_attr.attr, |
| 398 | &dev_attr_fan2_div.attr, | 375 | &sensor_dev_attr_fan2_div.dev_attr.attr, |
| 399 | &dev_attr_fan3_input.attr, | 376 | &sensor_dev_attr_fan3_input.dev_attr.attr, |
| 400 | &dev_attr_fan3_min.attr, | 377 | &sensor_dev_attr_fan3_min.dev_attr.attr, |
| 401 | &dev_attr_fan3_div.attr, | 378 | &sensor_dev_attr_fan3_div.dev_attr.attr, |
| 402 | 379 | ||
| 403 | &dev_attr_pwm1.attr, | 380 | &sensor_dev_attr_pwm1.dev_attr.attr, |
| 404 | &dev_attr_pwm1_enable.attr, | 381 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, |
| 405 | &dev_attr_pwm2.attr, | 382 | &sensor_dev_attr_pwm2.dev_attr.attr, |
| 406 | &dev_attr_pwm2_enable.attr, | 383 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, |
| 407 | &dev_attr_pwm3.attr, | 384 | &sensor_dev_attr_pwm3.dev_attr.attr, |
| 408 | &dev_attr_pwm3_enable.attr, | 385 | &sensor_dev_attr_pwm3_enable.dev_attr.attr, |
| 409 | 386 | ||
| 410 | &dev_attr_alarms.attr, | 387 | &dev_attr_alarms.attr, |
| 411 | &dev_attr_name.attr, | 388 | &dev_attr_name.attr, |
| @@ -547,46 +524,61 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev) | |||
| 547 | 524 | ||
| 548 | /* Register sysfs hooks */ | 525 | /* Register sysfs hooks */ |
| 549 | if (fan1) { | 526 | if (fan1) { |
| 550 | if ((err = device_create_file(dev, &dev_attr_fan1_input)) | 527 | if ((err = device_create_file(dev, |
| 551 | || (err = device_create_file(dev, &dev_attr_fan1_min)) | 528 | &sensor_dev_attr_fan1_input.dev_attr)) |
| 552 | || (err = device_create_file(dev, &dev_attr_fan1_div))) | 529 | || (err = device_create_file(dev, |
| 530 | &sensor_dev_attr_fan1_min.dev_attr)) | ||
| 531 | || (err = device_create_file(dev, | ||
| 532 | &sensor_dev_attr_fan1_div.dev_attr))) | ||
| 553 | goto error_remove_files; | 533 | goto error_remove_files; |
| 554 | } else | 534 | } else |
| 555 | dev_dbg(dev, "Fan 1 not enabled by hardware, skipping\n"); | 535 | dev_dbg(dev, "Fan 1 not enabled by hardware, skipping\n"); |
| 556 | 536 | ||
| 557 | if (fan2) { | 537 | if (fan2) { |
| 558 | if ((err = device_create_file(dev, &dev_attr_fan2_input)) | 538 | if ((err = device_create_file(dev, |
| 559 | || (err = device_create_file(dev, &dev_attr_fan2_min)) | 539 | &sensor_dev_attr_fan2_input.dev_attr)) |
| 560 | || (err = device_create_file(dev, &dev_attr_fan2_div))) | 540 | || (err = device_create_file(dev, |
| 541 | &sensor_dev_attr_fan2_min.dev_attr)) | ||
| 542 | || (err = device_create_file(dev, | ||
| 543 | &sensor_dev_attr_fan2_div.dev_attr))) | ||
| 561 | goto error_remove_files; | 544 | goto error_remove_files; |
| 562 | } else | 545 | } else |
| 563 | dev_dbg(dev, "Fan 2 not enabled by hardware, skipping\n"); | 546 | dev_dbg(dev, "Fan 2 not enabled by hardware, skipping\n"); |
| 564 | 547 | ||
| 565 | if (fan3) { | 548 | if (fan3) { |
| 566 | if ((err = device_create_file(dev, &dev_attr_fan3_input)) | 549 | if ((err = device_create_file(dev, |
| 567 | || (err = device_create_file(dev, &dev_attr_fan3_min)) | 550 | &sensor_dev_attr_fan3_input.dev_attr)) |
| 568 | || (err = device_create_file(dev, &dev_attr_fan3_div))) | 551 | || (err = device_create_file(dev, |
| 552 | &sensor_dev_attr_fan3_min.dev_attr)) | ||
| 553 | || (err = device_create_file(dev, | ||
| 554 | &sensor_dev_attr_fan3_div.dev_attr))) | ||
| 569 | goto error_remove_files; | 555 | goto error_remove_files; |
| 570 | } else | 556 | } else |
| 571 | dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n"); | 557 | dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n"); |
| 572 | 558 | ||
| 573 | if (pwm1) { | 559 | if (pwm1) { |
| 574 | if ((err = device_create_file(dev, &dev_attr_pwm1)) | 560 | if ((err = device_create_file(dev, |
| 575 | || (err = device_create_file(dev, &dev_attr_pwm1_enable))) | 561 | &sensor_dev_attr_pwm1.dev_attr)) |
| 562 | || (err = device_create_file(dev, | ||
| 563 | &sensor_dev_attr_pwm1_enable.dev_attr))) | ||
| 576 | goto error_remove_files; | 564 | goto error_remove_files; |
| 577 | } else | 565 | } else |
| 578 | dev_dbg(dev, "PWM 1 not enabled by hardware, skipping\n"); | 566 | dev_dbg(dev, "PWM 1 not enabled by hardware, skipping\n"); |
| 579 | 567 | ||
| 580 | if (pwm2) { | 568 | if (pwm2) { |
| 581 | if ((err = device_create_file(dev, &dev_attr_pwm2)) | 569 | if ((err = device_create_file(dev, |
| 582 | || (err = device_create_file(dev, &dev_attr_pwm2_enable))) | 570 | &sensor_dev_attr_pwm2.dev_attr)) |
| 571 | || (err = device_create_file(dev, | ||
| 572 | &sensor_dev_attr_pwm2_enable.dev_attr))) | ||
| 583 | goto error_remove_files; | 573 | goto error_remove_files; |
| 584 | } else | 574 | } else |
| 585 | dev_dbg(dev, "PWM 2 not enabled by hardware, skipping\n"); | 575 | dev_dbg(dev, "PWM 2 not enabled by hardware, skipping\n"); |
| 586 | 576 | ||
| 587 | if (pwm3) { | 577 | if (pwm3) { |
| 588 | if ((err = device_create_file(dev, &dev_attr_pwm3)) | 578 | if ((err = device_create_file(dev, |
| 589 | || (err = device_create_file(dev, &dev_attr_pwm3_enable))) | 579 | &sensor_dev_attr_pwm3.dev_attr)) |
| 580 | || (err = device_create_file(dev, | ||
| 581 | &sensor_dev_attr_pwm3_enable.dev_attr))) | ||
| 590 | goto error_remove_files; | 582 | goto error_remove_files; |
| 591 | } else | 583 | } else |
| 592 | dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n"); | 584 | dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n"); |
