aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/thermal
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2011-07-28 16:48:42 -0400
committerLen Brown <len.brown@intel.com>2011-08-02 14:51:57 -0400
commit31f5396ad3bde23c8416e8d23ba425e27f413314 (patch)
tree923ec07b9afff6cf952cbc2bd5f26bf490793c6f /drivers/thermal
parent0d97d7a494d43be77f57e688369be0aae33d1ade (diff)
thermal: make THERMAL_HWMON implementation fully internal
THERMAL_HWMON is implemented inside the thermal_sys driver and has no effect on drivers implementing thermal zones, so they shouldn't see anything related to it in <linux/thermal.h>. Making the THERMAL_HWMON implementation fully internal has two advantages beyond the cleaner design: * This avoids rebuilding all thermal drivers if the THERMAL_HWMON implementation changes, or if CONFIG_THERMAL_HWMON gets enabled or disabled. * This avoids breaking the thermal kABI in these cases too, which should make distributions happy. The only drawback I can see is slightly higher memory fragmentation, as the number of kzalloc() calls will increase by one per thermal zone. But I doubt it will be a problem in practice, as I've never seen a system with more than two thermal zones. Signed-off-by: Jean Delvare <khali@linux-fr.org> Cc: Rene Herman <rene.herman@gmail.com> Acked-by: Guenter Roeck <guenter.roeck@ericsson.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/thermal')
-rw-r--r--drivers/thermal/thermal_sys.c117
1 files changed, 92 insertions, 25 deletions
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index b6353d61fac..708f8e92771 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -420,6 +420,29 @@ thermal_cooling_device_trip_point_show(struct device *dev,
420 420
421/* hwmon sys I/F */ 421/* hwmon sys I/F */
422#include <linux/hwmon.h> 422#include <linux/hwmon.h>
423
424/* thermal zone devices with the same type share one hwmon device */
425struct thermal_hwmon_device {
426 char type[THERMAL_NAME_LENGTH];
427 struct device *device;
428 int count;
429 struct list_head tz_list;
430 struct list_head node;
431};
432
433struct thermal_hwmon_attr {
434 struct device_attribute attr;
435 char name[16];
436};
437
438/* one temperature input for each thermal zone */
439struct thermal_hwmon_temp {
440 struct list_head hwmon_node;
441 struct thermal_zone_device *tz;
442 struct thermal_hwmon_attr temp_input; /* hwmon sys attr */
443 struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */
444};
445
423static LIST_HEAD(thermal_hwmon_list); 446static LIST_HEAD(thermal_hwmon_list);
424 447
425static ssize_t 448static ssize_t
@@ -437,9 +460,10 @@ temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
437 int ret; 460 int ret;
438 struct thermal_hwmon_attr *hwmon_attr 461 struct thermal_hwmon_attr *hwmon_attr
439 = container_of(attr, struct thermal_hwmon_attr, attr); 462 = container_of(attr, struct thermal_hwmon_attr, attr);
440 struct thermal_zone_device *tz 463 struct thermal_hwmon_temp *temp
441 = container_of(hwmon_attr, struct thermal_zone_device, 464 = container_of(hwmon_attr, struct thermal_hwmon_temp,
442 temp_input); 465 temp_input);
466 struct thermal_zone_device *tz = temp->tz;
443 467
444 ret = tz->ops->get_temp(tz, &temperature); 468 ret = tz->ops->get_temp(tz, &temperature);
445 469
@@ -455,9 +479,10 @@ temp_crit_show(struct device *dev, struct device_attribute *attr,
455{ 479{
456 struct thermal_hwmon_attr *hwmon_attr 480 struct thermal_hwmon_attr *hwmon_attr
457 = container_of(attr, struct thermal_hwmon_attr, attr); 481 = container_of(attr, struct thermal_hwmon_attr, attr);
458 struct thermal_zone_device *tz 482 struct thermal_hwmon_temp *temp
459 = container_of(hwmon_attr, struct thermal_zone_device, 483 = container_of(hwmon_attr, struct thermal_hwmon_temp,
460 temp_crit); 484 temp_crit);
485 struct thermal_zone_device *tz = temp->tz;
461 long temperature; 486 long temperature;
462 int ret; 487 int ret;
463 488
@@ -485,10 +510,29 @@ thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
485 return NULL; 510 return NULL;
486} 511}
487 512
513/* Find the temperature input matching a given thermal zone */
514static struct thermal_hwmon_temp *
515thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
516 const struct thermal_zone_device *tz)
517{
518 struct thermal_hwmon_temp *temp;
519
520 mutex_lock(&thermal_list_lock);
521 list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
522 if (temp->tz == tz) {
523 mutex_unlock(&thermal_list_lock);
524 return temp;
525 }
526 mutex_unlock(&thermal_list_lock);
527
528 return NULL;
529}
530
488static int 531static int
489thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) 532thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
490{ 533{
491 struct thermal_hwmon_device *hwmon; 534 struct thermal_hwmon_device *hwmon;
535 struct thermal_hwmon_temp *temp;
492 int new_hwmon_device = 1; 536 int new_hwmon_device = 1;
493 int result; 537 int result;
494 538
@@ -515,30 +559,36 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
515 goto free_mem; 559 goto free_mem;
516 560
517 register_sys_interface: 561 register_sys_interface:
518 tz->hwmon = hwmon; 562 temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
563 if (!temp) {
564 result = -ENOMEM;
565 goto unregister_name;
566 }
567
568 temp->tz = tz;
519 hwmon->count++; 569 hwmon->count++;
520 570
521 snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH, 571 snprintf(temp->temp_input.name, THERMAL_NAME_LENGTH,
522 "temp%d_input", hwmon->count); 572 "temp%d_input", hwmon->count);
523 tz->temp_input.attr.attr.name = tz->temp_input.name; 573 temp->temp_input.attr.attr.name = temp->temp_input.name;
524 tz->temp_input.attr.attr.mode = 0444; 574 temp->temp_input.attr.attr.mode = 0444;
525 tz->temp_input.attr.show = temp_input_show; 575 temp->temp_input.attr.show = temp_input_show;
526 sysfs_attr_init(&tz->temp_input.attr.attr); 576 sysfs_attr_init(&temp->temp_input.attr.attr);
527 result = device_create_file(hwmon->device, &tz->temp_input.attr); 577 result = device_create_file(hwmon->device, &temp->temp_input.attr);
528 if (result) 578 if (result)
529 goto unregister_name; 579 goto free_temp_mem;
530 580
531 if (tz->ops->get_crit_temp) { 581 if (tz->ops->get_crit_temp) {
532 unsigned long temperature; 582 unsigned long temperature;
533 if (!tz->ops->get_crit_temp(tz, &temperature)) { 583 if (!tz->ops->get_crit_temp(tz, &temperature)) {
534 snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH, 584 snprintf(temp->temp_crit.name, THERMAL_NAME_LENGTH,
535 "temp%d_crit", hwmon->count); 585 "temp%d_crit", hwmon->count);
536 tz->temp_crit.attr.attr.name = tz->temp_crit.name; 586 temp->temp_crit.attr.attr.name = temp->temp_crit.name;
537 tz->temp_crit.attr.attr.mode = 0444; 587 temp->temp_crit.attr.attr.mode = 0444;
538 tz->temp_crit.attr.show = temp_crit_show; 588 temp->temp_crit.attr.show = temp_crit_show;
539 sysfs_attr_init(&tz->temp_crit.attr.attr); 589 sysfs_attr_init(&temp->temp_crit.attr.attr);
540 result = device_create_file(hwmon->device, 590 result = device_create_file(hwmon->device,
541 &tz->temp_crit.attr); 591 &temp->temp_crit.attr);
542 if (result) 592 if (result)
543 goto unregister_input; 593 goto unregister_input;
544 } 594 }
@@ -547,13 +597,15 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
547 mutex_lock(&thermal_list_lock); 597 mutex_lock(&thermal_list_lock);
548 if (new_hwmon_device) 598 if (new_hwmon_device)
549 list_add_tail(&hwmon->node, &thermal_hwmon_list); 599 list_add_tail(&hwmon->node, &thermal_hwmon_list);
550 list_add_tail(&tz->hwmon_node, &hwmon->tz_list); 600 list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
551 mutex_unlock(&thermal_list_lock); 601 mutex_unlock(&thermal_list_lock);
552 602
553 return 0; 603 return 0;
554 604
555 unregister_input: 605 unregister_input:
556 device_remove_file(hwmon->device, &tz->temp_input.attr); 606 device_remove_file(hwmon->device, &temp->temp_input.attr);
607 free_temp_mem:
608 kfree(temp);
557 unregister_name: 609 unregister_name:
558 if (new_hwmon_device) { 610 if (new_hwmon_device) {
559 device_remove_file(hwmon->device, &dev_attr_name); 611 device_remove_file(hwmon->device, &dev_attr_name);
@@ -569,15 +621,30 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
569static void 621static void
570thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) 622thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
571{ 623{
572 struct thermal_hwmon_device *hwmon = tz->hwmon; 624 struct thermal_hwmon_device *hwmon;
625 struct thermal_hwmon_temp *temp;
626
627 hwmon = thermal_hwmon_lookup_by_type(tz);
628 if (unlikely(!hwmon)) {
629 /* Should never happen... */
630 dev_dbg(&tz->device, "hwmon device lookup failed!\n");
631 return;
632 }
633
634 temp = thermal_hwmon_lookup_temp(hwmon, tz);
635 if (unlikely(!temp)) {
636 /* Should never happen... */
637 dev_dbg(&tz->device, "temperature input lookup failed!\n");
638 return;
639 }
573 640
574 tz->hwmon = NULL; 641 device_remove_file(hwmon->device, &temp->temp_input.attr);
575 device_remove_file(hwmon->device, &tz->temp_input.attr);
576 if (tz->ops->get_crit_temp) 642 if (tz->ops->get_crit_temp)
577 device_remove_file(hwmon->device, &tz->temp_crit.attr); 643 device_remove_file(hwmon->device, &temp->temp_crit.attr);
578 644
579 mutex_lock(&thermal_list_lock); 645 mutex_lock(&thermal_list_lock);
580 list_del(&tz->hwmon_node); 646 list_del(&temp->hwmon_node);
647 kfree(temp);
581 if (!list_empty(&hwmon->tz_list)) { 648 if (!list_empty(&hwmon->tz_list)) {
582 mutex_unlock(&thermal_list_lock); 649 mutex_unlock(&thermal_list_lock);
583 return; 650 return;