@@ -121,6 +121,7 @@ Thermal zone device sys I/F, created once it's registered:
|---mode: Working mode of the thermal zone
|---trip_point_[0-*]_temp: Trip point temperature
|---trip_point_[0-*]_type: Trip point type
+ |---trip_point_[0-*]_hyst: Hysteresis value for this trip point
Thermal cooling device sys I/F, created once it's registered:
/sys/class/thermal/cooling_device[0-*]:
@@ -190,6 +191,11 @@ trip_point_[0-*]_type
thermal zone.
RO, Optional
+trip_point_[0-*]_hyst
+ The hysteresis value for a trip point, represented as an integer
+ Unit: Celsius
+ RW, Optional
+
cdev[0-*]
Sysfs link to the thermal cooling device node where the sys I/F
for cooling device throttling control represents.
@@ -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)
{
@@ -1132,6 +1178,31 @@ static int create_trip_temp_attr(struct thermal_zone_device *tz,
}
/**
+ * create_trip_hyst_attr - creates hysteresis attribute for a trip point
+ * @tz: the thermal zone device
+ * @indx: index into the trip_hyst_attrs array
+ */
+static int create_trip_hyst_attr(struct thermal_zone_device *tz, int indx)
+{
+ char *attr_name = kzalloc(THERMAL_NAME_LENGTH, GFP_KERNEL);
+ if (!attr_name)
+ return -ENOMEM;
+
+ snprintf(attr_name, THERMAL_NAME_LENGTH, "trip_point_%d_hyst", indx);
+
+ sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr);
+ tz->trip_hyst_attrs[indx].attr.name = attr_name;
+ tz->trip_hyst_attrs[indx].attr.mode = S_IRUGO;
+ tz->trip_hyst_attrs[indx].show = trip_point_hyst_show;
+ if (tz->ops->set_trip_hyst) {
+ tz->trip_hyst_attrs[indx].attr.mode |= S_IWUSR;
+ tz->trip_hyst_attrs[indx].store = trip_point_hyst_store;
+ }
+
+ return device_create_file(&tz->device, &tz->trip_hyst_attrs[indx]);
+}
+
+/**
* thermal_zone_device_register - register a new thermal zone device
* @type: the thermal zone device type
* @trips: the number of trip points the thermal zone support
@@ -1231,6 +1302,12 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
if (result)
goto unregister;
+ if (tz->ops->get_trip_hyst) {
+ result = create_trip_hyst_attr(tz, count);
+ if (result)
+ goto unregister;
+ }
+
tz->ops->get_trip_type(tz, count, &trip_type);
if (trip_type == THERMAL_TRIP_PASSIVE)
passive = 1;
@@ -1310,6 +1387,9 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
for (count = 0; count < tz->trips; count++) {
device_remove_file(&tz->device, &tz->trip_type_attrs[count]);
device_remove_file(&tz->device, &tz->trip_temp_attrs[count]);
+ if (tz->ops->get_trip_hyst)
+ device_remove_file(&tz->device,
+ &tz->trip_hyst_attrs[count]);
}
thermal_remove_hwmon_sysfs(tz);
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
@@ -60,6 +60,10 @@ struct thermal_zone_device_ops {
unsigned long *);
int (*set_trip_temp) (struct thermal_zone_device *, int,
unsigned long);
+ int (*get_trip_hyst) (struct thermal_zone_device *, int,
+ unsigned long *);
+ int (*set_trip_hyst) (struct thermal_zone_device *, int,
+ unsigned long);
int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
int (*notify) (struct thermal_zone_device *, int,
enum thermal_trip_type);
@@ -93,6 +97,7 @@ struct thermal_zone_device {
struct device device;
struct device_attribute trip_temp_attrs[THERMAL_MAX_TRIPS];
struct device_attribute trip_type_attrs[THERMAL_MAX_TRIPS];
+ struct device_attribute trip_hyst_attrs[THERMAL_MAX_TRIPS];
void *devdata;
int trips;
int tc1;
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> --- * This patch depends on v6 of 'writable trip points' patch. * Fixed an invalid memory reference in create_trip_hyst_attr function. --- Documentation/thermal/sysfs-api.txt | 6 +++ drivers/thermal/thermal_sys.c | 80 +++++++++++++++++++++++++++++++++++ include/linux/thermal.h | 5 ++ 3 files changed, 91 insertions(+), 0 deletions(-)