diff options
author | Durgadoss R <dugardoss.r@intel.com> | 2012-07-25 10:10:59 +0800 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2012-07-24 23:19:26 -0400 |
commit | 27365a6c7d64a3bba22ee62109e4a071bbd7f933 (patch) | |
tree | d8a5c1bf246171e2983b7f801b64a758fa6f62e3 /drivers/thermal | |
parent | c56f5c0342dfee11a1a13d2f5bb7618de5b17590 (diff) | |
download | lwn-27365a6c7d64a3bba22ee62109e4a071bbd7f933.tar.gz lwn-27365a6c7d64a3bba22ee62109e4a071bbd7f933.zip |
Thermal: Add Hysteresis attributes
The Linux Thermal Framework does not support hysteresis
attributes. Most thermal sensors, today, have a
hysteresis value associated with trip points.
This patch adds hysteresis attributes on a per-trip-point
basis, to the Thermal Framework. These attributes are
optionally writable.
Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/thermal')
-rw-r--r-- | drivers/thermal/thermal_sys.c | 88 |
1 files changed, 83 insertions, 5 deletions
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 5feb3353213f..2d7a9fe8f365 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -240,6 +240,52 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr, } static ssize_t +trip_point_hyst_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct thermal_zone_device *tz = to_thermal_zone(dev); + int trip, ret; + unsigned long temperature; + + if (!tz->ops->set_trip_hyst) + return -EPERM; + + if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip)) + return -EINVAL; + + if (kstrtoul(buf, 10, &temperature)) + return -EINVAL; + + /* + * We are not doing any check on the 'temperature' value + * here. The driver implementing 'set_trip_hyst' has to + * take care of this. + */ + ret = tz->ops->set_trip_hyst(tz, trip, temperature); + + return ret ? ret : count; +} + +static ssize_t +trip_point_hyst_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct thermal_zone_device *tz = to_thermal_zone(dev); + int trip, ret; + unsigned long temperature; + + if (!tz->ops->get_trip_hyst) + return -EPERM; + + if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip)) + return -EINVAL; + + ret = tz->ops->get_trip_hyst(tz, trip, &temperature); + + return ret ? ret : sprintf(buf, "%ld\n", temperature); +} + +static ssize_t passive_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -1091,21 +1137,29 @@ EXPORT_SYMBOL(thermal_zone_device_update); static int create_trip_attrs(struct thermal_zone_device *tz, int mask) { int indx; + int size = sizeof(struct thermal_attr) * tz->trips; - tz->trip_type_attrs = - kzalloc(sizeof(struct thermal_attr) * tz->trips, GFP_KERNEL); + tz->trip_type_attrs = kzalloc(size, GFP_KERNEL); if (!tz->trip_type_attrs) return -ENOMEM; - tz->trip_temp_attrs = - kzalloc(sizeof(struct thermal_attr) * tz->trips, GFP_KERNEL); + tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL); if (!tz->trip_temp_attrs) { kfree(tz->trip_type_attrs); return -ENOMEM; } - for (indx = 0; indx < tz->trips; indx++) { + if (tz->ops->get_trip_hyst) { + tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL); + if (!tz->trip_hyst_attrs) { + kfree(tz->trip_type_attrs); + kfree(tz->trip_temp_attrs); + return -ENOMEM; + } + } + + for (indx = 0; indx < tz->trips; indx++) { /* create trip type attribute */ snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH, "trip_point_%d_type", indx); @@ -1136,6 +1190,26 @@ static int create_trip_attrs(struct thermal_zone_device *tz, int mask) device_create_file(&tz->device, &tz->trip_temp_attrs[indx].attr); + + /* create Optional trip hyst attribute */ + if (!tz->ops->get_trip_hyst) + continue; + snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH, + "trip_point_%d_hyst", indx); + + sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr); + tz->trip_hyst_attrs[indx].attr.attr.name = + tz->trip_hyst_attrs[indx].name; + tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO; + tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show; + if (tz->ops->set_trip_hyst) { + tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR; + tz->trip_hyst_attrs[indx].attr.store = + trip_point_hyst_store; + } + + device_create_file(&tz->device, + &tz->trip_hyst_attrs[indx].attr); } return 0; } @@ -1149,9 +1223,13 @@ static void remove_trip_attrs(struct thermal_zone_device *tz) &tz->trip_type_attrs[indx].attr); device_remove_file(&tz->device, &tz->trip_temp_attrs[indx].attr); + if (tz->ops->get_trip_hyst) + device_remove_file(&tz->device, + &tz->trip_hyst_attrs[indx].attr); } kfree(tz->trip_type_attrs); kfree(tz->trip_temp_attrs); + kfree(tz->trip_hyst_attrs); } /** |