--- zzzz-none-000/linux-4.4.60/drivers/thermal/of-thermal.c 2017-04-08 07:53:53.000000000 +0000 +++ scorpion-7490-727/linux-4.4.60/drivers/thermal/of-thermal.c 2021-02-04 17:41:59.000000000 +0000 @@ -34,6 +34,27 @@ #include "thermal_core.h" +/* + * For some reason QCOM introduced checks throughout this code + * to abort calls when the thermal zone is disabled. + * + * However these checks seem to be completely counter-productive and + * unnessecary. Especially the thermal-core checks upon zone instantiation + * if the trip points are properly configured and usable. As the device + * is initializied disabled these checks will fail and the core will + * permanently disable the trip handling of these zones. + * + * This may be working for the tsense driver which seems to use hw based + * trip points. But this definitly does not work for polled sensor + * configurations like the lm75 might be. Therefore this disabled check + * is only active when the tsens driver is enabled. + */ +#if CONFIG_QCOM_TSENS +#define CHECK_MODE_DISABLED (data->mode == THERMAL_DEVICE_DISABLED) +#else +#define CHECK_MODE_DISABLED 0 +#endif + /*** Private data structures to represent thermal device tree data ***/ /** @@ -95,12 +116,34 @@ { struct __thermal_zone *data = tz->devdata; - if (!data->ops->get_temp) + if (!data->ops->get_temp || CHECK_MODE_DISABLED) return -EINVAL; return data->ops->get_temp(data->sensor_data, temp); } +static int of_thermal_set_trips(struct thermal_zone_device *tz, + int low, int high) +{ + struct __thermal_zone *data = tz->devdata; + + if (!data->ops || !data->ops->set_trips || CHECK_MODE_DISABLED) + return -EINVAL; + + return data->ops->set_trips(data->sensor_data, low, high); +} + +static int of_thermal_panic_notify(struct thermal_zone_device *tz) +{ + struct __thermal_zone *data = tz->devdata; + + if ((data->ops->panic_notify) && + (data->mode != THERMAL_DEVICE_DISABLED)) + data->ops->panic_notify(data->sensor_data); + + return 0; +} + /** * of_thermal_get_ntrips - function to export number of available trip * points. @@ -181,7 +224,7 @@ { struct __thermal_zone *data = tz->devdata; - if (!data->ops || !data->ops->set_emul_temp) + if (CHECK_MODE_DISABLED) return -EINVAL; return data->ops->set_emul_temp(data->sensor_data, temp); @@ -191,25 +234,11 @@ enum thermal_trend *trend) { struct __thermal_zone *data = tz->devdata; - long dev_trend; - int r; - if (!data->ops->get_trend) + if (!data->ops->get_trend || CHECK_MODE_DISABLED) return -EINVAL; - r = data->ops->get_trend(data->sensor_data, &dev_trend); - if (r) - return r; - - /* TODO: These intervals might have some thresholds, but in core code */ - if (dev_trend > 0) - *trend = THERMAL_TREND_RAISING; - else if (dev_trend < 0) - *trend = THERMAL_TREND_DROPPING; - else - *trend = THERMAL_TREND_STABLE; - - return 0; + return data->ops->get_trend(data->sensor_data, trip, trend); } static int of_thermal_bind(struct thermal_zone_device *thermal, @@ -292,7 +321,9 @@ mutex_unlock(&tz->lock); data->mode = mode; - thermal_zone_device_update(tz); + + if (mode == THERMAL_DEVICE_ENABLED) + thermal_zone_device_update(tz); return 0; } @@ -310,12 +341,37 @@ return 0; } +static int of_thermal_activate_trip_type(struct thermal_zone_device *tz, + int trip, enum thermal_trip_activation_mode mode) +{ + struct __thermal_zone *data = tz->devdata; + + if (trip >= data->ntrips || trip < 0 || CHECK_MODE_DISABLED) + return -EDOM; + + /* + * The configurable_hi and configurable_lo trip points can be + * activated and deactivated. + */ + + if (data->ops->set_trip_activate) { + int ret; + + ret = data->ops->set_trip_activate(data->sensor_data, + trip, mode); + if (ret) + return ret; + } + + return 0; +} + static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip, int *temp) { struct __thermal_zone *data = tz->devdata; - if (trip >= data->ntrips || trip < 0) + if (trip >= data->ntrips || trip < 0 || CHECK_MODE_DISABLED) return -EDOM; *temp = data->trips[trip].temperature; @@ -328,9 +384,17 @@ { struct __thermal_zone *data = tz->devdata; - if (trip >= data->ntrips || trip < 0) + if (trip >= data->ntrips || trip < 0 || CHECK_MODE_DISABLED) return -EDOM; + if (data->ops->set_trip_temp) { + int ret; + + ret = data->ops->set_trip_temp(data->sensor_data, trip, temp); + if (ret) + return ret; + } + /* thermal framework should take care of data->mask & (1 << trip) */ data->trips[trip].temperature = temp; @@ -342,7 +406,7 @@ { struct __thermal_zone *data = tz->devdata; - if (trip >= data->ntrips || trip < 0) + if (trip >= data->ntrips || trip < 0 || CHECK_MODE_DISABLED) return -EDOM; *hyst = data->trips[trip].hysteresis; @@ -355,7 +419,7 @@ { struct __thermal_zone *data = tz->devdata; - if (trip >= data->ntrips || trip < 0) + if (trip >= data->ntrips || trip < 0 || CHECK_MODE_DISABLED) return -EDOM; /* thermal framework should take care of data->mask & (1 << trip) */ @@ -418,8 +482,22 @@ tz->sensor_data = data; tzd->ops->get_temp = of_thermal_get_temp; + tzd->ops->panic_notify = of_thermal_panic_notify; tzd->ops->get_trend = of_thermal_get_trend; - tzd->ops->set_emul_temp = of_thermal_set_emul_temp; + + /* + * The thermal zone core will calculate the window if they have set the + * optional set_trips pointer. + */ + if (ops->set_trips) + tzd->ops->set_trips = of_thermal_set_trips; + + if (ops->set_emul_temp) + tzd->ops->set_emul_temp = of_thermal_set_emul_temp; + + if (ops->set_trip_activate) + tzd->ops->set_trip_activate = of_thermal_activate_trip_type; + mutex_unlock(&tzd->lock); return tzd; @@ -475,14 +553,10 @@ sensor_np = of_node_get(dev->of_node); - for_each_child_of_node(np, child) { + for_each_available_child_of_node(np, child) { struct of_phandle_args sensor_specs; int ret, id; - /* Check whether child is enabled or not */ - if (!of_device_is_available(child)) - continue; - /* For now, thermal framework supports only 1 sensor per zone */ ret = of_parse_phandle_with_args(child, "thermal-sensors", "#thermal-sensor-cells", @@ -559,6 +633,87 @@ } EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister); +static void devm_thermal_zone_of_sensor_release(struct device *dev, void *res) +{ + thermal_zone_of_sensor_unregister(dev, + *(struct thermal_zone_device **)res); +} + +static int devm_thermal_zone_of_sensor_match(struct device *dev, void *res, + void *data) +{ + struct thermal_zone_device **r = res; + + if (WARN_ON(!r || !*r)) + return 0; + + return *r == data; +} + +/** + * devm_thermal_zone_of_sensor_register - Resource managed version of + * thermal_zone_of_sensor_register() + * @dev: a valid struct device pointer of a sensor device. Must contain + * a valid .of_node, for the sensor node. + * @sensor_id: a sensor identifier, in case the sensor IP has more + * than one sensors + * @data: a private pointer (owned by the caller) that will be passed + * back, when a temperature reading is needed. + * @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp. + * + * Refer thermal_zone_of_sensor_register() for more details. + * + * Return: On success returns a valid struct thermal_zone_device, + * otherwise, it returns a corresponding ERR_PTR(). Caller must + * check the return value with help of IS_ERR() helper. + * Registered thermal_zone_device device will automatically be + * released when device is unbounded. + */ +struct thermal_zone_device *devm_thermal_zone_of_sensor_register( + struct device *dev, int sensor_id, + void *data, const struct thermal_zone_of_device_ops *ops) +{ + struct thermal_zone_device **ptr, *tzd; + + ptr = devres_alloc(devm_thermal_zone_of_sensor_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + tzd = thermal_zone_of_sensor_register(dev, sensor_id, data, ops); + if (IS_ERR(tzd)) { + devres_free(ptr); + return tzd; + } + + *ptr = tzd; + devres_add(dev, ptr); + + return tzd; +} +EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_register); + +/** + * devm_thermal_zone_of_sensor_unregister - Resource managed version of + * thermal_zone_of_sensor_unregister(). + * @dev: Device for which which resource was allocated. + * @tzd: a pointer to struct thermal_zone_device where the sensor is registered. + * + * This function removes the sensor callbacks and private data from the + * thermal zone device registered with devm_thermal_zone_of_sensor_register() + * API. It will also silent the zone by remove the .get_temp() and .get_trend() + * thermal zone device callbacks. + * Normally this function will not need to be called and the resource + * management code will ensure that the resource is freed. + */ +void devm_thermal_zone_of_sensor_unregister(struct device *dev, + struct thermal_zone_device *tzd) +{ + WARN_ON(devres_release(dev, devm_thermal_zone_of_sensor_release, + devm_thermal_zone_of_sensor_match, tzd)); +} +EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_unregister); + /*** functions parsing device tree nodes ***/ /** @@ -637,7 +792,10 @@ [THERMAL_TRIP_ACTIVE] = "active", [THERMAL_TRIP_PASSIVE] = "passive", [THERMAL_TRIP_HOT] = "hot", - [THERMAL_TRIP_CRITICAL] = "critical", + [THERMAL_TRIP_CRITICAL] = "critical_high", + [THERMAL_TRIP_CONFIGURABLE_HI] = "configurable_hi", + [THERMAL_TRIP_CONFIGURABLE_LOW] = "configurable_lo", + [THERMAL_TRIP_CRITICAL_LOW] = "critical_low", }; /** @@ -726,8 +884,8 @@ * otherwise, it returns a corresponding ERR_PTR(). Caller must * check the return value with help of IS_ERR() helper. */ -static struct __thermal_zone * -thermal_of_build_thermal_zone(struct device_node *np) +static struct __thermal_zone +__init *thermal_of_build_thermal_zone(struct device_node *np) { struct device_node *child = NULL, *gchild; struct __thermal_zone *tz; @@ -829,7 +987,7 @@ return tz; free_tbps: - for (i = 0; i < tz->num_tbps; i++) + for (i = i - 1; i >= 0; i--) of_node_put(tz->tbps[i].cooling_device); kfree(tz->tbps); free_trips: @@ -881,16 +1039,12 @@ return 0; /* Run successfully on systems without thermal DT */ } - for_each_child_of_node(np, child) { + for_each_available_child_of_node(np, child) { struct thermal_zone_device *zone; struct thermal_zone_params *tzp; int i, mask = 0; u32 prop; - /* Check whether child is enabled or not */ - if (!of_device_is_available(child)) - continue; - tz = thermal_of_build_thermal_zone(child); if (IS_ERR(tz)) { pr_err("failed to build thermal zone %s: %ld\n", @@ -968,13 +1122,9 @@ return; } - for_each_child_of_node(np, child) { + for_each_available_child_of_node(np, child) { struct thermal_zone_device *zone; - /* Check whether child is enabled or not */ - if (!of_device_is_available(child)) - continue; - zone = thermal_zone_get_zone_by_name(child->name); if (IS_ERR(zone)) continue;