thermal: fix generic thermal I/F for hwmon
Zhang, Rui [Wed, 27 Feb 2008 00:37:50 +0000 (08:37 +0800)]
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>

Documentation/thermal/sysfs-api.txt
drivers/thermal/Kconfig
drivers/thermal/thermal.c

index ba9c2da..d9f28be 100644 (file)
@@ -143,10 +143,10 @@ type                              Strings which represent the thermal zone type.
                                This is given by thermal zone driver as part of registration.
                                Eg: "ACPI thermal zone" indicates it's a ACPI thermal device
                                RO
-                               Optional
+                               Required
 
 temp                           Current temperature as reported by thermal zone (sensor)
-                               Unit: degree Celsius
+                               Unit: millidegree Celsius
                                RO
                                Required
 
@@ -163,7 +163,7 @@ mode                                One of the predefined values in [kernel, user]
                                          charge of the thermal management.
 
 trip_point_[0-*]_temp          The temperature above which trip point will be fired
-                               Unit: degree Celsius
+                               Unit: millidegree Celsius
                                RO
                                Optional
 
@@ -193,7 +193,7 @@ type                                String which represents the type of device
                                eg. For memory controller device on intel_menlow platform:
                                this should be "Memory controller"
                                RO
-                               Optional
+                               Required
 
 max_state                      The maximum permissible cooling state of this cooling device.
                                RO
@@ -219,16 +219,16 @@ the sys I/F structure will be built like this:
 
 |thermal_zone1:
        |-----type:                     ACPI thermal zone
-       |-----temp:                     37
+       |-----temp:                     37000
        |-----mode:                     kernel
-       |-----trip_point_0_temp:        100
+       |-----trip_point_0_temp:        100000
        |-----trip_point_0_type:        critical
-       |-----trip_point_1_temp:        80
+       |-----trip_point_1_temp:        80000
        |-----trip_point_1_type:        passive
-       |-----trip_point_2_temp:        70
-       |-----trip_point_2_type:        active[0]
-       |-----trip_point_3_temp:        60
-       |-----trip_point_3_type:        active[1]
+       |-----trip_point_2_temp:        70000
+       |-----trip_point_2_type:        active0
+       |-----trip_point_3_temp:        60000
+       |-----trip_point_3_type:        active1
        |-----cdev0:                    --->/sys/class/thermal/cooling_device0
        |-----cdev0_trip_point:         1       /* cdev0 can be used for passive */
        |-----cdev1:                    --->/sys/class/thermal/cooling_device3
index 69f19f2..3ab313e 100644 (file)
@@ -4,6 +4,7 @@
 
 menuconfig THERMAL
        bool "Generic Thermal sysfs driver"
+       select HWMON
        default y
        help
          Generic Thermal Sysfs driver offers a generic mechanism for
index 8b86e53..41bd4c8 100644 (file)
 #include <linux/idr.h>
 #include <linux/thermal.h>
 #include <linux/spinlock.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 
-MODULE_AUTHOR("Zhang Rui")
+MODULE_AUTHOR("Zhang Rui");
 MODULE_DESCRIPTION("Generic thermal management sysfs support");
 MODULE_LICENSE("GPL");
 
@@ -56,6 +58,9 @@ static LIST_HEAD(thermal_tz_list);
 static LIST_HEAD(thermal_cdev_list);
 static DEFINE_MUTEX(thermal_list_lock);
 
+static struct device *thermal_hwmon;
+#define MAX_THERMAL_ZONES      10
+
 static int get_idr(struct idr *idr, struct mutex *lock, int *id)
 {
        int err;
@@ -87,7 +92,67 @@ static void release_idr(struct idr *idr, struct mutex *lock, int id)
                mutex_unlock(lock);
 }
 
-/* sys I/F for thermal zone */
+/* hwmon sys I/F*/
+static ssize_t
+name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "thermal_sys_class\n");
+}
+
+static ssize_t
+temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct thermal_zone_device *tz;
+       struct sensor_device_attribute *sensor_attr
+                                               = to_sensor_dev_attr(attr);
+
+       list_for_each_entry(tz, &thermal_tz_list, node)
+               if (tz->id == sensor_attr->index)
+                       return tz->ops->get_temp(tz, buf);
+
+       return -ENODEV;
+}
+
+static ssize_t
+temp_crit_show(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct thermal_zone_device *tz;
+       struct sensor_device_attribute *sensor_attr
+                                               = to_sensor_dev_attr(attr);
+
+       list_for_each_entry(tz, &thermal_tz_list, node)
+               if (tz->id == sensor_attr->index)
+                       return tz->ops->get_trip_temp(tz, 0, buf);
+
+       return -ENODEV;
+}
+
+static DEVICE_ATTR(name, 0444, name_show, NULL);
+static struct sensor_device_attribute sensor_attrs[] = {
+       SENSOR_ATTR(temp1_input, 0444, temp_input_show, NULL, 0),
+       SENSOR_ATTR(temp1_crit, 0444, temp_crit_show, NULL, 0),
+       SENSOR_ATTR(temp2_input, 0444, temp_input_show, NULL, 1),
+       SENSOR_ATTR(temp2_crit, 0444, temp_crit_show, NULL, 1),
+       SENSOR_ATTR(temp3_input, 0444, temp_input_show, NULL, 2),
+       SENSOR_ATTR(temp3_crit, 0444, temp_crit_show, NULL, 2),
+       SENSOR_ATTR(temp4_input, 0444, temp_input_show, NULL, 3),
+       SENSOR_ATTR(temp4_crit, 0444, temp_crit_show, NULL, 3),
+       SENSOR_ATTR(temp5_input, 0444, temp_input_show, NULL, 4),
+       SENSOR_ATTR(temp5_crit, 0444, temp_crit_show, NULL, 4),
+       SENSOR_ATTR(temp6_input, 0444, temp_input_show, NULL, 5),
+       SENSOR_ATTR(temp6_crit, 0444, temp_crit_show, NULL, 5),
+       SENSOR_ATTR(temp7_input, 0444, temp_input_show, NULL, 6),
+       SENSOR_ATTR(temp7_crit, 0444, temp_crit_show, NULL, 6),
+       SENSOR_ATTR(temp8_input, 0444, temp_input_show, NULL, 7),
+       SENSOR_ATTR(temp8_crit, 0444, temp_crit_show, NULL, 7),
+       SENSOR_ATTR(temp9_input, 0444, temp_input_show, NULL, 8),
+       SENSOR_ATTR(temp9_crit, 0444, temp_crit_show, NULL, 8),
+       SENSOR_ATTR(temp10_input, 0444, temp_input_show, NULL, 9),
+       SENSOR_ATTR(temp10_crit, 0444, temp_crit_show, NULL, 9),
+};
+
+/* thermal zone sys I/F */
 
 #define to_thermal_zone(_dev) \
        container_of(_dev, struct thermal_zone_device, device)
@@ -214,7 +279,7 @@ do {        \
        device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]);    \
 } while (0)
 
-/* sys I/F for cooling device */
+/* cooling device sys I/F */
 #define to_cooling_device(_dev)        \
        container_of(_dev, struct thermal_cooling_device, device)
 
@@ -447,6 +512,9 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
        struct thermal_zone_device *pos;
        int result;
 
+       if (!type)
+               return ERR_PTR(-EINVAL);
+
        if (strlen(type) >= THERMAL_NAME_LENGTH)
                return ERR_PTR(-EINVAL);
 
@@ -477,11 +545,9 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
        }
 
        /* sys I/F */
-       if (type) {
-               result = device_create_file(&cdev->device, &dev_attr_cdev_type);
-               if (result)
-                       goto unregister;
-       }
+       result = device_create_file(&cdev->device, &dev_attr_cdev_type);
+       if (result)
+               goto unregister;
 
        result = device_create_file(&cdev->device, &dev_attr_max_state);
        if (result)
@@ -547,8 +613,8 @@ void thermal_cooling_device_unregister(struct
                tz->ops->unbind(tz, cdev);
        }
        mutex_unlock(&thermal_list_lock);
-       if (cdev->type[0])
-               device_remove_file(&cdev->device, &dev_attr_cdev_type);
+
+       device_remove_file(&cdev->device, &dev_attr_cdev_type);
        device_remove_file(&cdev->device, &dev_attr_max_state);
        device_remove_file(&cdev->device, &dev_attr_cur_state);
 
@@ -580,6 +646,9 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
        int result;
        int count;
 
+       if (!type)
+               return ERR_PTR(-EINVAL);
+
        if (strlen(type) >= THERMAL_NAME_LENGTH)
                return ERR_PTR(-EINVAL);
 
@@ -601,6 +670,13 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
                kfree(tz);
                return ERR_PTR(result);
        }
+       if (tz->id >= MAX_THERMAL_ZONES) {
+               printk(KERN_ERR PREFIX
+                       "Too many thermal zones\n");
+               release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
+               kfree(tz);
+               return ERR_PTR(-EINVAL);
+       }
 
        strcpy(tz->type, type);
        tz->ops = ops;
@@ -615,13 +691,28 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
                return ERR_PTR(result);
        }
 
-       /* sys I/F */
-       if (type) {
-               result = device_create_file(&tz->device, &dev_attr_type);
-               if (result)
-                       goto unregister;
+       /* hwmon sys I/F */
+       result = device_create_file(thermal_hwmon,
+                                       &sensor_attrs[tz->id * 2].dev_attr);
+       if (result)
+               goto unregister;
+
+       if (trips > 0) {
+               char buf[40];
+               result = tz->ops->get_trip_type(tz, 0, buf);
+               if (result > 0 && !strcmp(buf, "critical\n")) {
+                       result = device_create_file(thermal_hwmon,
+                                       &sensor_attrs[tz->id * 2 + 1].dev_attr);
+                       if (result)
+                               goto unregister;
+               }
        }
 
+       /* sys I/F */
+       result = device_create_file(&tz->device, &dev_attr_type);
+       if (result)
+               goto unregister;
+
        result = device_create_file(&tz->device, &dev_attr_temp);
        if (result)
                goto unregister;
@@ -687,8 +778,17 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
                    tz->ops->unbind(tz, cdev);
        mutex_unlock(&thermal_list_lock);
 
-       if (tz->type[0])
-               device_remove_file(&tz->device, &dev_attr_type);
+       device_remove_file(thermal_hwmon,
+                               &sensor_attrs[tz->id * 2].dev_attr);
+       if (tz->trips > 0) {
+               char buf[40];
+               if (tz->ops->get_trip_type(tz, 0, buf) > 0)
+                       if (!strcmp(buf, "critical\n"))
+                               device_remove_file(thermal_hwmon,
+                               &sensor_attrs[tz->id * 2 + 1].dev_attr);
+       }
+
+       device_remove_file(&tz->device, &dev_attr_type);
        device_remove_file(&tz->device, &dev_attr_temp);
        if (tz->ops->get_mode)
                device_remove_file(&tz->device, &dev_attr_mode);
@@ -705,6 +805,19 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
 
 EXPORT_SYMBOL(thermal_zone_device_unregister);
 
+static void thermal_exit(void)
+{
+       if (thermal_hwmon) {
+               device_remove_file(thermal_hwmon, &dev_attr_name);
+               hwmon_device_unregister(thermal_hwmon);
+       }
+       class_unregister(&thermal_class);
+       idr_destroy(&thermal_tz_idr);
+       idr_destroy(&thermal_cdev_idr);
+       mutex_destroy(&thermal_idr_lock);
+       mutex_destroy(&thermal_list_lock);
+}
+
 static int __init thermal_init(void)
 {
        int result = 0;
@@ -716,16 +829,20 @@ static int __init thermal_init(void)
                mutex_destroy(&thermal_idr_lock);
                mutex_destroy(&thermal_list_lock);
        }
-       return result;
-}
 
-static void __exit thermal_exit(void)
-{
-       class_unregister(&thermal_class);
-       idr_destroy(&thermal_tz_idr);
-       idr_destroy(&thermal_cdev_idr);
-       mutex_destroy(&thermal_idr_lock);
-       mutex_destroy(&thermal_list_lock);
+       thermal_hwmon = hwmon_device_register(NULL);
+       if (IS_ERR(thermal_hwmon)) {
+               result = PTR_ERR(thermal_hwmon);
+               thermal_hwmon = NULL;
+               printk(KERN_ERR PREFIX
+                       "unable to register hwmon device\n");
+               thermal_exit();
+               return result;
+       }
+
+       result = device_create_file(thermal_hwmon, &dev_attr_name);
+
+       return result;
 }
 
 subsys_initcall(thermal_init);