mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-24 21:54:34 -04:00
drivers: thermal: of-thermal: Add a snapshot of of-thermal
This is a snapshot of the thermal framework from msm-4.19 to msm-5.4 as of 'commit <f6559eba09482b9dc66279c72c8867a52f23498c> (drivers: thermal: Use correct last temperature during trip violation check)'. Change-Id: I1618ee42e5948da7e3e02b0fe4b8b5650f1c7447 Signed-off-by: Ram Chandrasekar <rkumbako@codeaurora.org>
This commit is contained in:
parent
e836a8acf3
commit
b492c6077b
1 changed files with 632 additions and 6 deletions
|
|
@ -4,6 +4,7 @@
|
|||
*
|
||||
* Copyright (C) 2013 Texas Instruments
|
||||
* Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com>
|
||||
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
|
@ -16,6 +17,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "thermal_core.h"
|
||||
|
||||
|
|
@ -49,6 +51,104 @@ struct __thermal_bind_params {
|
|||
unsigned int usage;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_QTI_THERMAL
|
||||
/**
|
||||
* struct __sensor_param - Holds individual sensor data
|
||||
* @sensor_data: sensor driver private data passed as input argument
|
||||
* @ops: sensor driver ops
|
||||
* @trip_high: last trip high value programmed in the sensor driver
|
||||
* @trip_low: last trip low value programmed in the sensor driver
|
||||
* @lock: mutex lock acquired before updating the trip temperatures
|
||||
* @first_tz: list head pointing the first thermal zone
|
||||
*/
|
||||
struct __sensor_param {
|
||||
void *sensor_data;
|
||||
const struct thermal_zone_of_device_ops *ops;
|
||||
int trip_high, trip_low;
|
||||
struct mutex lock;
|
||||
struct list_head first_tz;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct __thermal_zone - internal representation of a thermal zone
|
||||
* @mode: current thermal zone device mode (enabled/disabled)
|
||||
* @passive_delay: polling interval while passive cooling is activated
|
||||
* @polling_delay: zone polling interval
|
||||
* @slope: slope of the temperature adjustment curve
|
||||
* @offset: offset of the temperature adjustment curve
|
||||
* @ntrips: number of trip points
|
||||
* @trips: an array of trip points (0..ntrips - 1)
|
||||
* @num_tbps: number of thermal bind params
|
||||
* @tbps: an array of thermal bind params (0..num_tbps - 1)
|
||||
* @default_disable: Keep the thermal zone disabled by default
|
||||
* @tzd: thermal zone device pointer for this sensor
|
||||
* @list: sibling thermal zone pointer
|
||||
* @senps: sensor related parameters
|
||||
*/
|
||||
|
||||
struct __thermal_zone {
|
||||
enum thermal_device_mode mode;
|
||||
int passive_delay;
|
||||
int polling_delay;
|
||||
int slope;
|
||||
int offset;
|
||||
|
||||
/* trip data */
|
||||
int ntrips;
|
||||
struct thermal_trip *trips;
|
||||
|
||||
/* cooling binding data */
|
||||
int num_tbps;
|
||||
struct __thermal_bind_params *tbps;
|
||||
|
||||
struct thermal_zone_device *tzd;
|
||||
bool default_disable;
|
||||
struct list_head list;
|
||||
/* sensor interface */
|
||||
struct __sensor_param *senps;
|
||||
};
|
||||
|
||||
static int of_thermal_aggregate_trip_types(struct thermal_zone_device *tz,
|
||||
unsigned int trip_type_mask, int *low, int *high);
|
||||
|
||||
/*** DT thermal zone device callbacks ***/
|
||||
|
||||
static int of_thermal_get_temp(struct thermal_zone_device *tz,
|
||||
int *temp)
|
||||
{
|
||||
struct __thermal_zone *data = tz->devdata;
|
||||
|
||||
if (!data->senps || !data->senps->ops->get_temp)
|
||||
return -EINVAL;
|
||||
if (data->mode == THERMAL_DEVICE_DISABLED) {
|
||||
*temp = THERMAL_TEMP_INVALID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return data->senps->ops->get_temp(data->senps->sensor_data, temp);
|
||||
}
|
||||
|
||||
static int of_thermal_set_trips(struct thermal_zone_device *tz,
|
||||
int inp_low, int inp_high)
|
||||
{
|
||||
struct __thermal_zone *data = tz->devdata;
|
||||
int high = INT_MAX, low = INT_MIN, ret = 0;
|
||||
|
||||
if (!data->senps || !data->senps->ops->set_trips)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->senps->lock);
|
||||
of_thermal_aggregate_trip_types(tz, GENMASK(THERMAL_TRIP_CRITICAL, 0),
|
||||
&low, &high);
|
||||
data->senps->trip_low = low;
|
||||
data->senps->trip_high = high;
|
||||
ret = data->senps->ops->set_trips(data->senps->sensor_data,
|
||||
low, high);
|
||||
|
||||
mutex_unlock(&data->senps->lock);
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
/**
|
||||
* struct __thermal_zone - internal representation of a thermal zone
|
||||
* @mode: current thermal zone device mode (enabled/disabled)
|
||||
|
|
@ -107,7 +207,7 @@ static int of_thermal_set_trips(struct thermal_zone_device *tz,
|
|||
|
||||
return data->ops->set_trips(data->sensor_data, low, high);
|
||||
}
|
||||
|
||||
#endif
|
||||
/**
|
||||
* of_thermal_get_ntrips - function to export number of available trip
|
||||
* points.
|
||||
|
|
@ -183,6 +283,30 @@ EXPORT_SYMBOL_GPL(of_thermal_get_trip_points);
|
|||
*
|
||||
* Return: zero on success, error code otherwise
|
||||
*/
|
||||
#ifdef CONFIG_QTI_THERMAL
|
||||
static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
|
||||
int temp)
|
||||
{
|
||||
struct __thermal_zone *data = tz->devdata;
|
||||
|
||||
if (!data->senps || !data->senps->ops->set_emul_temp)
|
||||
return -EINVAL;
|
||||
|
||||
return data->senps->ops->set_emul_temp(data->senps->sensor_data, temp);
|
||||
}
|
||||
|
||||
static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
|
||||
enum thermal_trend *trend)
|
||||
{
|
||||
struct __thermal_zone *data = tz->devdata;
|
||||
|
||||
if (!data->senps || !data->senps->ops->get_trend)
|
||||
return -EINVAL;
|
||||
|
||||
return data->senps->ops->get_trend(data->senps->sensor_data,
|
||||
trip, trend);
|
||||
}
|
||||
#else
|
||||
static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
|
||||
int temp)
|
||||
{
|
||||
|
|
@ -201,6 +325,7 @@ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
|
|||
|
||||
return data->ops->get_trend(data->sensor_data, trip, trend);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int of_thermal_bind(struct thermal_zone_device *thermal,
|
||||
struct thermal_cooling_device *cdev)
|
||||
|
|
@ -328,6 +453,30 @@ static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_QTI_THERMAL
|
||||
static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
|
||||
int temp)
|
||||
{
|
||||
struct __thermal_zone *data = tz->devdata;
|
||||
|
||||
if (trip >= data->ntrips || trip < 0)
|
||||
return -EDOM;
|
||||
|
||||
if (data->senps && data->senps->ops->set_trip_temp) {
|
||||
int ret;
|
||||
|
||||
ret = data->senps->ops->set_trip_temp(data->senps->sensor_data,
|
||||
trip, temp);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* thermal framework should take care of data->mask & (1 << trip) */
|
||||
data->trips[trip].temperature = temp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
|
||||
int temp)
|
||||
{
|
||||
|
|
@ -349,6 +498,7 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip,
|
||||
int *hyst)
|
||||
|
|
@ -392,6 +542,139 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_QTI_THERMAL
|
||||
static int of_thermal_aggregate_trip_types(struct thermal_zone_device *tz,
|
||||
unsigned int trip_type_mask, int *low, int *high)
|
||||
{
|
||||
int min = INT_MIN;
|
||||
int max = INT_MAX;
|
||||
int tt, th, trip;
|
||||
int temp = tz->temperature;
|
||||
struct thermal_zone_device *zone = NULL;
|
||||
struct __thermal_zone *data = tz->devdata;
|
||||
struct list_head *head;
|
||||
enum thermal_trip_type type = 0;
|
||||
|
||||
head = &data->senps->first_tz;
|
||||
list_for_each_entry(data, head, list) {
|
||||
zone = data->tzd;
|
||||
if (data->mode == THERMAL_DEVICE_DISABLED)
|
||||
continue;
|
||||
for (trip = 0; trip < data->ntrips; trip++) {
|
||||
of_thermal_get_trip_type(zone, trip, &type);
|
||||
if (!(BIT(type) & trip_type_mask))
|
||||
continue;
|
||||
|
||||
tt = data->trips[trip].temperature;
|
||||
if (tt > temp && tt < max)
|
||||
max = tt;
|
||||
th = tt - data->trips[trip].hysteresis;
|
||||
if (th < temp && th > min)
|
||||
min = th;
|
||||
}
|
||||
}
|
||||
|
||||
*high = max;
|
||||
*low = min;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool of_thermal_is_trips_triggered(struct thermal_zone_device *tz,
|
||||
int temp)
|
||||
{
|
||||
int tt, th, trip, last_temp;
|
||||
struct __thermal_zone *data = tz->devdata;
|
||||
bool triggered = false;
|
||||
|
||||
mutex_lock(&tz->lock);
|
||||
last_temp = tz->temperature;
|
||||
for (trip = 0; trip < data->ntrips; trip++) {
|
||||
tt = data->trips[trip].temperature;
|
||||
if (temp >= tt && last_temp < tt) {
|
||||
triggered = true;
|
||||
break;
|
||||
}
|
||||
th = tt - data->trips[trip].hysteresis;
|
||||
if (temp <= th && last_temp > th) {
|
||||
triggered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&tz->lock);
|
||||
|
||||
return triggered;
|
||||
}
|
||||
|
||||
static void handle_thermal_trip(struct thermal_zone_device *tz,
|
||||
bool temp_valid, int trip_temp)
|
||||
{
|
||||
struct thermal_zone_device *zone;
|
||||
struct __thermal_zone *data = tz->devdata;
|
||||
struct list_head *head;
|
||||
|
||||
head = &data->senps->first_tz;
|
||||
list_for_each_entry(data, head, list) {
|
||||
zone = data->tzd;
|
||||
if (data->mode == THERMAL_DEVICE_DISABLED)
|
||||
continue;
|
||||
if (!temp_valid) {
|
||||
thermal_zone_device_update(zone,
|
||||
THERMAL_EVENT_UNSPECIFIED);
|
||||
} else {
|
||||
if (!of_thermal_is_trips_triggered(zone, trip_temp))
|
||||
continue;
|
||||
thermal_zone_device_update_temp(zone,
|
||||
THERMAL_EVENT_UNSPECIFIED, trip_temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* of_thermal_aggregate_trip - aggregate trip temperatures across sibling
|
||||
* thermal zones.
|
||||
* @tz: pointer to the primary thermal zone.
|
||||
* @type: the thermal trip type to be aggregated upon
|
||||
* @low: the low trip threshold which the most lesser than the @temp
|
||||
* @high: the high trip threshold which is the least greater than the @temp
|
||||
*/
|
||||
int of_thermal_aggregate_trip(struct thermal_zone_device *tz,
|
||||
enum thermal_trip_type type,
|
||||
int *low, int *high)
|
||||
{
|
||||
if (type <= THERMAL_TRIP_CRITICAL)
|
||||
return of_thermal_aggregate_trip_types(tz, BIT(type), low,
|
||||
high);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(of_thermal_aggregate_trip);
|
||||
|
||||
/*
|
||||
* of_thermal_handle_trip_temp - Handle thermal trip from sensors
|
||||
*
|
||||
* @tz: pointer to the primary thermal zone.
|
||||
* @trip_temp: The temperature
|
||||
*/
|
||||
void of_thermal_handle_trip_temp(struct thermal_zone_device *tz,
|
||||
int trip_temp)
|
||||
{
|
||||
return handle_thermal_trip(tz, true, trip_temp);
|
||||
}
|
||||
EXPORT_SYMBOL(of_thermal_handle_trip_temp);
|
||||
|
||||
/*
|
||||
* of_thermal_handle_trip - Handle thermal trip from sensors
|
||||
*
|
||||
* @tz: pointer to the primary thermal zone.
|
||||
*/
|
||||
void of_thermal_handle_trip(struct thermal_zone_device *tz)
|
||||
{
|
||||
return handle_thermal_trip(tz, false, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(of_thermal_handle_trip);
|
||||
#endif
|
||||
|
||||
static struct thermal_zone_device_ops of_thermal_ops = {
|
||||
.get_mode = of_thermal_get_mode,
|
||||
.set_mode = of_thermal_set_mode,
|
||||
|
|
@ -408,7 +691,194 @@ static struct thermal_zone_device_ops of_thermal_ops = {
|
|||
};
|
||||
|
||||
/*** sensor API ***/
|
||||
#ifdef CONFIG_QTI_THERMAL
|
||||
static struct thermal_zone_device *
|
||||
thermal_zone_of_add_sensor(struct device_node *zone,
|
||||
struct device_node *sensor,
|
||||
struct __sensor_param *sens_param)
|
||||
{
|
||||
struct thermal_zone_device *tzd;
|
||||
struct __thermal_zone *tz;
|
||||
|
||||
tzd = thermal_zone_get_zone_by_name(zone->name);
|
||||
if (IS_ERR(tzd))
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
tz = tzd->devdata;
|
||||
|
||||
if (!sens_param->ops)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
mutex_lock(&tzd->lock);
|
||||
tz->senps = sens_param;
|
||||
|
||||
tzd->ops->get_temp = of_thermal_get_temp;
|
||||
tzd->ops->get_trend = of_thermal_get_trend;
|
||||
|
||||
/*
|
||||
* The thermal zone core will calculate the window if they have set the
|
||||
* optional set_trips pointer.
|
||||
*/
|
||||
if (sens_param->ops->set_trips)
|
||||
tzd->ops->set_trips = of_thermal_set_trips;
|
||||
|
||||
if (sens_param->ops->set_emul_temp)
|
||||
tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
|
||||
|
||||
list_add_tail(&tz->list, &sens_param->first_tz);
|
||||
mutex_unlock(&tzd->lock);
|
||||
|
||||
return tzd;
|
||||
}
|
||||
|
||||
/**
|
||||
* thermal_zone_of_sensor_register - registers a sensor to a DT thermal zone
|
||||
* @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.
|
||||
*
|
||||
* This function will search the list of thermal zones described in device
|
||||
* tree and look for the zone that refer to the sensor device pointed by
|
||||
* @dev->of_node as temperature providers. For the zone pointing to the
|
||||
* sensor node, the sensor will be added to the DT thermal zone device.
|
||||
*
|
||||
* The thermal zone temperature is provided by the @get_temp function
|
||||
* pointer. When called, it will have the private pointer @data back.
|
||||
*
|
||||
* The thermal zone temperature trend is provided by the @get_trend function
|
||||
* pointer. When called, it will have the private pointer @data back.
|
||||
*
|
||||
* Return: On success returns a valid struct thermal_zone_device,
|
||||
* otherwise, it returns a corresponding ERR_PTR(). Incase there are multiple
|
||||
* thermal zones referencing the same sensor, the return value will be
|
||||
* thermal_zone_device pointer of the first thermal zone. Caller must
|
||||
* check the return value with help of IS_ERR() helper.
|
||||
*/
|
||||
struct thermal_zone_device *
|
||||
thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
|
||||
const struct thermal_zone_of_device_ops *ops)
|
||||
{
|
||||
struct device_node *np, *child, *sensor_np;
|
||||
struct thermal_zone_device *tzd = ERR_PTR(-ENODEV);
|
||||
struct thermal_zone_device *first_tzd = NULL;
|
||||
struct __sensor_param *sens_param = NULL;
|
||||
|
||||
np = of_find_node_by_name(NULL, "thermal-zones");
|
||||
if (!np)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
if (!dev || !dev->of_node) {
|
||||
of_node_put(np);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
sens_param = devm_kzalloc(dev, sizeof(*sens_param), GFP_KERNEL);
|
||||
if (!sens_param) {
|
||||
of_node_put(np);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
sens_param->sensor_data = data;
|
||||
sens_param->ops = ops;
|
||||
INIT_LIST_HEAD(&sens_param->first_tz);
|
||||
sens_param->trip_high = INT_MAX;
|
||||
sens_param->trip_low = INT_MIN;
|
||||
mutex_init(&sens_param->lock);
|
||||
sensor_np = of_node_get(dev->of_node);
|
||||
|
||||
for_each_available_child_of_node(np, child) {
|
||||
struct of_phandle_args sensor_specs;
|
||||
int ret, id;
|
||||
struct __thermal_zone *tz;
|
||||
|
||||
/* For now, thermal framework supports only 1 sensor per zone */
|
||||
ret = of_parse_phandle_with_args(child, "thermal-sensors",
|
||||
"#thermal-sensor-cells",
|
||||
0, &sensor_specs);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
if (sensor_specs.args_count >= 1) {
|
||||
id = sensor_specs.args[0];
|
||||
WARN(sensor_specs.args_count > 1,
|
||||
"%pKOFn: too many cells in sensor specifier %d\n",
|
||||
sensor_specs.np, sensor_specs.args_count);
|
||||
} else {
|
||||
id = 0;
|
||||
}
|
||||
|
||||
if (sensor_specs.np == sensor_np && id == sensor_id) {
|
||||
tzd = thermal_zone_of_add_sensor(child, sensor_np,
|
||||
sens_param);
|
||||
if (!IS_ERR(tzd)) {
|
||||
if (!first_tzd)
|
||||
first_tzd = tzd;
|
||||
tz = tzd->devdata;
|
||||
if (!tz->default_disable)
|
||||
tzd->ops->set_mode(tzd,
|
||||
THERMAL_DEVICE_ENABLED);
|
||||
}
|
||||
}
|
||||
of_node_put(sensor_specs.np);
|
||||
}
|
||||
of_node_put(sensor_np);
|
||||
of_node_put(np);
|
||||
|
||||
if (!first_tzd) {
|
||||
first_tzd = ERR_PTR(-ENODEV);
|
||||
devm_kfree(dev, sens_param);
|
||||
}
|
||||
return first_tzd;
|
||||
}
|
||||
EXPORT_SYMBOL(thermal_zone_of_sensor_register);
|
||||
|
||||
/**
|
||||
* thermal_zone_of_sensor_unregister - unregisters a sensor from a DT
|
||||
* thermal zone
|
||||
* @dev: a valid struct device pointer of a sensor device. Must contain
|
||||
* a valid .of_node, for the sensor node.
|
||||
* @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 thermal_zone_of_sensor_register()
|
||||
* API. It will also silent the zone by remove the .get_temp() and .get_trend()
|
||||
* thermal zone device callbacks.
|
||||
*/
|
||||
void thermal_zone_of_sensor_unregister(struct device *dev,
|
||||
struct thermal_zone_device *tzd)
|
||||
{
|
||||
struct __thermal_zone *tz, *next;
|
||||
struct thermal_zone_device *pos;
|
||||
struct list_head *head;
|
||||
|
||||
if (!dev || !tzd || !tzd->devdata)
|
||||
return;
|
||||
|
||||
tz = tzd->devdata;
|
||||
|
||||
/* no __thermal_zone, nothing to be done */
|
||||
if (!tz)
|
||||
return;
|
||||
|
||||
head = &tz->senps->first_tz;
|
||||
list_for_each_entry_safe(tz, next, head, list) {
|
||||
pos = tz->tzd;
|
||||
mutex_lock(&pos->lock);
|
||||
pos->ops->get_temp = NULL;
|
||||
pos->ops->get_trend = NULL;
|
||||
pos->ops->set_emul_temp = NULL;
|
||||
pos->ops = NULL;
|
||||
|
||||
list_del(&tz->list);
|
||||
tz->senps = NULL;
|
||||
mutex_unlock(&pos->lock);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(thermal_zone_of_sensor_unregister);
|
||||
#else
|
||||
static struct thermal_zone_device *
|
||||
thermal_zone_of_add_sensor(struct device_node *zone,
|
||||
struct device_node *sensor, void *data,
|
||||
|
|
@ -512,7 +982,7 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
|
|||
if (sensor_specs.args_count >= 1) {
|
||||
id = sensor_specs.args[0];
|
||||
WARN(sensor_specs.args_count > 1,
|
||||
"%pOFn: too many cells in sensor specifier %d\n",
|
||||
"%pKOFn: too many cells in sensor specifier %d\n",
|
||||
sensor_specs.np, sensor_specs.args_count);
|
||||
} else {
|
||||
id = 0;
|
||||
|
|
@ -577,6 +1047,7 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
|
|||
mutex_unlock(&tzd->lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister);
|
||||
#endif
|
||||
|
||||
static void devm_thermal_zone_of_sensor_release(struct device *dev, void *res)
|
||||
{
|
||||
|
|
@ -851,6 +1322,7 @@ static int thermal_of_populate_trip(struct device_node *np,
|
|||
* otherwise, it returns a corresponding ERR_PTR(). Caller must
|
||||
* check the return value with help of IS_ERR() helper.
|
||||
*/
|
||||
#ifdef CONFIG_QTI_THERMAL
|
||||
static struct __thermal_zone
|
||||
__init *thermal_of_build_thermal_zone(struct device_node *np)
|
||||
{
|
||||
|
|
@ -870,14 +1342,144 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
|
|||
|
||||
ret = of_property_read_u32(np, "polling-delay-passive", &prop);
|
||||
if (ret < 0) {
|
||||
pr_err("%pOFn: missing polling-delay-passive property\n", np);
|
||||
pr_err("%pKOFn: missing polling-delay-passive property\n", np);
|
||||
goto free_tz;
|
||||
}
|
||||
tz->passive_delay = prop;
|
||||
|
||||
ret = of_property_read_u32(np, "polling-delay", &prop);
|
||||
if (ret < 0) {
|
||||
pr_err("%pOFn: missing polling-delay property\n", np);
|
||||
pr_err("%pKOFn: missing polling-delay property\n", np);
|
||||
goto free_tz;
|
||||
}
|
||||
tz->polling_delay = prop;
|
||||
|
||||
INIT_LIST_HEAD(&tz->list);
|
||||
tz->default_disable = of_property_read_bool(np,
|
||||
"disable-thermal-zone");
|
||||
|
||||
/*
|
||||
* REVIST: for now, the thermal framework supports only
|
||||
* one sensor per thermal zone. Thus, we are considering
|
||||
* only the first two values as slope and offset.
|
||||
*/
|
||||
ret = of_property_read_u32_array(np, "coefficients", coef, 2);
|
||||
if (ret == 0) {
|
||||
tz->slope = coef[0];
|
||||
tz->offset = coef[1];
|
||||
} else {
|
||||
tz->slope = 1;
|
||||
tz->offset = 0;
|
||||
}
|
||||
|
||||
/* trips */
|
||||
child = of_get_child_by_name(np, "trips");
|
||||
|
||||
/* No trips provided */
|
||||
if (!child)
|
||||
goto finish;
|
||||
|
||||
tz->ntrips = of_get_child_count(child);
|
||||
if (tz->ntrips == 0) /* must have at least one child */
|
||||
goto finish;
|
||||
|
||||
tz->trips = kcalloc(tz->ntrips, sizeof(*tz->trips), GFP_KERNEL);
|
||||
if (!tz->trips) {
|
||||
ret = -ENOMEM;
|
||||
goto free_tz;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for_each_child_of_node(child, gchild) {
|
||||
ret = thermal_of_populate_trip(gchild, &tz->trips[i++]);
|
||||
if (ret)
|
||||
goto free_trips;
|
||||
}
|
||||
|
||||
of_node_put(child);
|
||||
|
||||
/* cooling-maps */
|
||||
child = of_get_child_by_name(np, "cooling-maps");
|
||||
|
||||
/* cooling-maps not provided */
|
||||
if (!child)
|
||||
goto finish;
|
||||
|
||||
tz->num_tbps = of_get_child_count(child);
|
||||
if (tz->num_tbps == 0)
|
||||
goto finish;
|
||||
|
||||
tz->tbps = kcalloc(tz->num_tbps, sizeof(*tz->tbps), GFP_KERNEL);
|
||||
if (!tz->tbps) {
|
||||
ret = -ENOMEM;
|
||||
goto free_trips;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for_each_child_of_node(child, gchild) {
|
||||
ret = thermal_of_populate_bind_params(gchild, &tz->tbps[i++],
|
||||
tz->trips, tz->ntrips);
|
||||
if (ret)
|
||||
goto free_tbps;
|
||||
}
|
||||
|
||||
finish:
|
||||
of_node_put(child);
|
||||
tz->mode = THERMAL_DEVICE_DISABLED;
|
||||
|
||||
return tz;
|
||||
|
||||
free_tbps:
|
||||
for (i = i - 1; i >= 0; i--) {
|
||||
struct __thermal_bind_params *tbp = tz->tbps + i;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < tbp->count; j++)
|
||||
of_node_put(tbp->tcbp[j].cooling_device);
|
||||
|
||||
kfree(tbp->tcbp);
|
||||
}
|
||||
|
||||
kfree(tz->tbps);
|
||||
free_trips:
|
||||
for (i = 0; i < tz->ntrips; i++)
|
||||
of_node_put(tz->trips[i].np);
|
||||
kfree(tz->trips);
|
||||
of_node_put(gchild);
|
||||
free_tz:
|
||||
kfree(tz);
|
||||
of_node_put(child);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
#else
|
||||
static struct __thermal_zone
|
||||
__init *thermal_of_build_thermal_zone(struct device_node *np)
|
||||
{
|
||||
struct device_node *child = NULL, *gchild;
|
||||
struct __thermal_zone *tz;
|
||||
int ret, i;
|
||||
u32 prop, coef[2];
|
||||
|
||||
if (!np) {
|
||||
pr_err("no thermal zone np\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
tz = kzalloc(sizeof(*tz), GFP_KERNEL);
|
||||
if (!tz)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = of_property_read_u32(np, "polling-delay-passive", &prop);
|
||||
if (ret < 0) {
|
||||
pr_err("%pKOFn: missing polling-delay-passive property\n", np);
|
||||
goto free_tz;
|
||||
}
|
||||
tz->passive_delay = prop;
|
||||
|
||||
ret = of_property_read_u32(np, "polling-delay", &prop);
|
||||
if (ret < 0) {
|
||||
pr_err("%pKOFn: missing polling-delay property\n", np);
|
||||
goto free_tz;
|
||||
}
|
||||
tz->polling_delay = prop;
|
||||
|
|
@ -976,6 +1578,7 @@ free_tz:
|
|||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void of_thermal_free_zone(struct __thermal_zone *tz)
|
||||
{
|
||||
|
|
@ -1027,10 +1630,13 @@ int __init of_parse_thermal_zones(void)
|
|||
struct thermal_zone_params *tzp;
|
||||
int i, mask = 0;
|
||||
u32 prop;
|
||||
#ifdef CONFIG_QTI_THERMAL
|
||||
const char *governor_name;
|
||||
#endif
|
||||
|
||||
tz = thermal_of_build_thermal_zone(child);
|
||||
if (IS_ERR(tz)) {
|
||||
pr_err("failed to build thermal zone %pOFn: %ld\n",
|
||||
pr_err("failed to build thermal zone %pKOFn: %ld\n",
|
||||
child,
|
||||
PTR_ERR(tz));
|
||||
continue;
|
||||
|
|
@ -1049,6 +1655,13 @@ int __init of_parse_thermal_zones(void)
|
|||
/* No hwmon because there might be hwmon drivers registering */
|
||||
tzp->no_hwmon = true;
|
||||
|
||||
#ifdef CONFIG_QTI_THERMAL
|
||||
if (!of_property_read_string(child, "thermal-governor",
|
||||
&governor_name))
|
||||
strlcpy(tzp->governor_name, governor_name,
|
||||
THERMAL_NAME_LENGTH);
|
||||
#endif
|
||||
|
||||
if (!of_property_read_u32(child, "sustainable-power", &prop))
|
||||
tzp->sustainable_power = prop;
|
||||
|
||||
|
|
@ -1064,14 +1677,27 @@ int __init of_parse_thermal_zones(void)
|
|||
ops, tzp,
|
||||
tz->passive_delay,
|
||||
tz->polling_delay);
|
||||
#ifdef CONFIG_QTI_THERMAL
|
||||
if (IS_ERR(zone)) {
|
||||
pr_err("Failed to build %pOFn zone %ld\n", child,
|
||||
pr_err("Failed to build %pKOFn zone %ld\n", child,
|
||||
PTR_ERR(zone));
|
||||
kfree(tzp);
|
||||
kfree(ops);
|
||||
of_thermal_free_zone(tz);
|
||||
/* attempting to build remaining zones still */
|
||||
continue;
|
||||
}
|
||||
tz->tzd = zone;
|
||||
#else
|
||||
if (IS_ERR(zone)) {
|
||||
pr_err("Failed to build %pKOFn zone %ld\n", child,
|
||||
PTR_ERR(zone));
|
||||
kfree(tzp);
|
||||
kfree(ops);
|
||||
of_thermal_free_zone(tz);
|
||||
/* attempting to build remaining zones still */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
of_node_put(np);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue