diff options
Diffstat (limited to 'drivers/thermal')
-rw-r--r-- | drivers/thermal/thermal.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal.c index cf56af4b7e02..6098787341f3 100644 --- a/drivers/thermal/thermal.c +++ b/drivers/thermal/thermal.c | |||
@@ -295,6 +295,164 @@ thermal_cooling_device_trip_point_show(struct device *dev, | |||
295 | 295 | ||
296 | /* Device management */ | 296 | /* Device management */ |
297 | 297 | ||
298 | #if defined(CONFIG_HWMON) || \ | ||
299 | (defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE)) | ||
300 | /* hwmon sys I/F */ | ||
301 | #include <linux/hwmon.h> | ||
302 | static LIST_HEAD(thermal_hwmon_list); | ||
303 | |||
304 | static ssize_t | ||
305 | name_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
306 | { | ||
307 | struct thermal_hwmon_device *hwmon = dev->driver_data; | ||
308 | return sprintf(buf, "%s\n", hwmon->type); | ||
309 | } | ||
310 | static DEVICE_ATTR(name, 0444, name_show, NULL); | ||
311 | |||
312 | static ssize_t | ||
313 | temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
314 | { | ||
315 | struct thermal_hwmon_attr *hwmon_attr | ||
316 | = container_of(attr, struct thermal_hwmon_attr, attr); | ||
317 | struct thermal_zone_device *tz | ||
318 | = container_of(hwmon_attr, struct thermal_zone_device, | ||
319 | temp_input); | ||
320 | |||
321 | return tz->ops->get_temp(tz, buf); | ||
322 | } | ||
323 | |||
324 | static ssize_t | ||
325 | temp_crit_show(struct device *dev, struct device_attribute *attr, | ||
326 | char *buf) | ||
327 | { | ||
328 | struct thermal_hwmon_attr *hwmon_attr | ||
329 | = container_of(attr, struct thermal_hwmon_attr, attr); | ||
330 | struct thermal_zone_device *tz | ||
331 | = container_of(hwmon_attr, struct thermal_zone_device, | ||
332 | temp_crit); | ||
333 | |||
334 | return tz->ops->get_trip_temp(tz, 0, buf); | ||
335 | } | ||
336 | |||
337 | |||
338 | static int | ||
339 | thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) | ||
340 | { | ||
341 | struct thermal_hwmon_device *hwmon; | ||
342 | int new_hwmon_device = 1; | ||
343 | int result; | ||
344 | |||
345 | mutex_lock(&thermal_list_lock); | ||
346 | list_for_each_entry(hwmon, &thermal_hwmon_list, node) | ||
347 | if (!strcmp(hwmon->type, tz->type)) { | ||
348 | new_hwmon_device = 0; | ||
349 | mutex_unlock(&thermal_list_lock); | ||
350 | goto register_sys_interface; | ||
351 | } | ||
352 | mutex_unlock(&thermal_list_lock); | ||
353 | |||
354 | hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL); | ||
355 | if (!hwmon) | ||
356 | return -ENOMEM; | ||
357 | |||
358 | INIT_LIST_HEAD(&hwmon->tz_list); | ||
359 | strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH); | ||
360 | hwmon->device = hwmon_device_register(NULL); | ||
361 | if (IS_ERR(hwmon->device)) { | ||
362 | result = PTR_ERR(hwmon->device); | ||
363 | goto free_mem; | ||
364 | } | ||
365 | hwmon->device->driver_data = hwmon; | ||
366 | result = device_create_file(hwmon->device, &dev_attr_name); | ||
367 | if (result) | ||
368 | goto unregister_hwmon_device; | ||
369 | |||
370 | register_sys_interface: | ||
371 | tz->hwmon = hwmon; | ||
372 | hwmon->count++; | ||
373 | |||
374 | snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH, | ||
375 | "temp%d_input", hwmon->count); | ||
376 | tz->temp_input.attr.attr.name = tz->temp_input.name; | ||
377 | tz->temp_input.attr.attr.mode = 0444; | ||
378 | tz->temp_input.attr.show = temp_input_show; | ||
379 | result = device_create_file(hwmon->device, &tz->temp_input.attr); | ||
380 | if (result) | ||
381 | goto unregister_hwmon_device; | ||
382 | |||
383 | if (tz->ops->get_crit_temp) { | ||
384 | unsigned long temperature; | ||
385 | if (!tz->ops->get_crit_temp(tz, &temperature)) { | ||
386 | snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH, | ||
387 | "temp%d_crit", hwmon->count); | ||
388 | tz->temp_crit.attr.attr.name = tz->temp_crit.name; | ||
389 | tz->temp_crit.attr.attr.mode = 0444; | ||
390 | tz->temp_crit.attr.show = temp_crit_show; | ||
391 | result = device_create_file(hwmon->device, | ||
392 | &tz->temp_crit.attr); | ||
393 | if (result) | ||
394 | goto unregister_hwmon_device; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | mutex_lock(&thermal_list_lock); | ||
399 | if (new_hwmon_device) | ||
400 | list_add_tail(&hwmon->node, &thermal_hwmon_list); | ||
401 | list_add_tail(&tz->hwmon_node, &hwmon->tz_list); | ||
402 | mutex_unlock(&thermal_list_lock); | ||
403 | |||
404 | return 0; | ||
405 | |||
406 | unregister_hwmon_device: | ||
407 | device_remove_file(hwmon->device, &tz->temp_crit.attr); | ||
408 | device_remove_file(hwmon->device, &tz->temp_input.attr); | ||
409 | if (new_hwmon_device) { | ||
410 | device_remove_file(hwmon->device, &dev_attr_name); | ||
411 | hwmon_device_unregister(hwmon->device); | ||
412 | } | ||
413 | free_mem: | ||
414 | if (new_hwmon_device) | ||
415 | kfree(hwmon); | ||
416 | |||
417 | return result; | ||
418 | } | ||
419 | |||
420 | static void | ||
421 | thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) | ||
422 | { | ||
423 | struct thermal_hwmon_device *hwmon = tz->hwmon; | ||
424 | |||
425 | tz->hwmon = NULL; | ||
426 | device_remove_file(hwmon->device, &tz->temp_input.attr); | ||
427 | device_remove_file(hwmon->device, &tz->temp_crit.attr); | ||
428 | |||
429 | mutex_lock(&thermal_list_lock); | ||
430 | list_del(&tz->hwmon_node); | ||
431 | if (!list_empty(&hwmon->tz_list)) { | ||
432 | mutex_unlock(&thermal_list_lock); | ||
433 | return; | ||
434 | } | ||
435 | list_del(&hwmon->node); | ||
436 | mutex_unlock(&thermal_list_lock); | ||
437 | |||
438 | device_remove_file(hwmon->device, &dev_attr_name); | ||
439 | hwmon_device_unregister(hwmon->device); | ||
440 | kfree(hwmon); | ||
441 | } | ||
442 | #else | ||
443 | static int | ||
444 | thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) | ||
445 | { | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static void | ||
450 | thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) | ||
451 | { | ||
452 | } | ||
453 | #endif | ||
454 | |||
455 | |||
298 | /** | 456 | /** |
299 | * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone | 457 | * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone |
300 | * @tz: thermal zone device | 458 | * @tz: thermal zone device |
@@ -642,6 +800,10 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, | |||
642 | goto unregister; | 800 | goto unregister; |
643 | } | 801 | } |
644 | 802 | ||
803 | result = thermal_add_hwmon_sysfs(tz); | ||
804 | if (result) | ||
805 | goto unregister; | ||
806 | |||
645 | mutex_lock(&thermal_list_lock); | 807 | mutex_lock(&thermal_list_lock); |
646 | list_add_tail(&tz->node, &thermal_tz_list); | 808 | list_add_tail(&tz->node, &thermal_tz_list); |
647 | if (ops->bind) | 809 | if (ops->bind) |
@@ -700,6 +862,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) | |||
700 | for (count = 0; count < tz->trips; count++) | 862 | for (count = 0; count < tz->trips; count++) |
701 | TRIP_POINT_ATTR_REMOVE(&tz->device, count); | 863 | TRIP_POINT_ATTR_REMOVE(&tz->device, count); |
702 | 864 | ||
865 | thermal_remove_hwmon_sysfs(tz); | ||
703 | release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); | 866 | release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); |
704 | idr_destroy(&tz->idr); | 867 | idr_destroy(&tz->idr); |
705 | mutex_destroy(&tz->lock); | 868 | mutex_destroy(&tz->lock); |