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 <[email protected]>
Signed-off-by: Zhang Rui <[email protected]>
Signed-off-by: Len Brown <[email protected]>
This commit is contained in:
Durgadoss R 2012-07-25 10:10:59 +08:00 • committed by Len Brown
commit 27365a6c7d
3 changed files with 94 additions and 5 deletions

View file

@ -239,6 +239,52 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%ld\n", temperature);
}
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);
}
/**