summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorAnshul Jain <anshulj@nvidia.com>2012-12-21 17:09:24 -0800
committerSimone Willett <swillett@nvidia.com>2013-01-09 18:27:03 -0800
commita3f396a68ecf540fa0c6b4c86babdc24c89bfd5b (patch)
treec0c8921127658c210ed71578b9cb7f658e92ca0d /drivers/misc
parenta50c4412e2a4ef4e4e1b0f470a56bf46df570847 (diff)
drivers: misc: Hysteresis support in fan est
This driver now can support hysteresis in trip temps. It now allows different cdev states for rising and falling trend in thermal framework. Bug 1200196 Bug 1201225 Change-Id: I9559eefdb1f2313e1d06f8945fdc1b68f62c6934 Signed-off-by: Anshul Jain <anshulj@nvidia.com> Reviewed-on: http://git-master/r/#change,173927 (cherry picked from commit 44330da37f6c45a1215df26c10ef55fd0828b8fd) Reviewed-on: http://git-master/r/173066 Reviewed-by: Simone Willett <swillett@nvidia.com> Tested-by: Simone Willett <swillett@nvidia.com>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/therm_fan_est.c91
1 files changed, 73 insertions, 18 deletions
diff --git a/drivers/misc/therm_fan_est.c b/drivers/misc/therm_fan_est.c
index 3d261376d47f..9a32eaffe821 100644
--- a/drivers/misc/therm_fan_est.c
+++ b/drivers/misc/therm_fan_est.c
@@ -42,12 +42,28 @@ struct therm_fan_estimator {
int ndevs;
struct therm_fan_est_subdevice *devs;
struct thermal_zone_device *thz;
+ int current_trip_index;
+ char *cdev_type;
int active_trip_temps[MAX_ACTIVE_STATES];
+ int active_hysteresis[MAX_ACTIVE_STATES];
+ int active_trip_temps_hyst[(MAX_ACTIVE_STATES << 1) + 1];
};
+
+static void fan_set_trip_temp_hyst(struct therm_fan_estimator *est, int trip,
+ unsigned long hyst_temp,
+ unsigned long trip_temp)
+{
+ est->active_hysteresis[trip] = hyst_temp;
+ est->active_trip_temps[trip] = trip_temp;
+ est->active_trip_temps_hyst[(trip << 1)] = trip_temp;
+ est->active_trip_temps_hyst[((trip - 1) << 1) + 1] =
+ trip_temp - hyst_temp;
+}
+
static void therm_fan_est_work_func(struct work_struct *work)
{
- int i, j, index, sum = 0;
+ int i, j, index, trip_index, sum = 0;
long temp;
struct delayed_work *dwork = container_of(work,
struct delayed_work, work);
@@ -72,10 +88,19 @@ static void therm_fan_est_work_func(struct work_struct *work)
est->cur_temp = sum / 100 + est->toffset;
- est->ntemp++;
+ for (trip_index = 0;
+ trip_index < ((MAX_ACTIVE_STATES << 1) + 1); trip_index++) {
+ if (est->cur_temp < est->active_trip_temps_hyst[trip_index])
+ break;
+ }
+
+ if (est->current_trip_index != (trip_index - 1)) {
+ est->current_trip_index = trip_index - 1;
+ if (!((trip_index - 1) % 2))
+ thermal_zone_device_update(est->thz);
+ }
- if (est->thz)
- thermal_zone_device_update(est->thz);
+ est->ntemp++;
queue_delayed_work(est->workqueue, &est->therm_fan_est_work,
msecs_to_jiffies(est->polling_period));
@@ -85,11 +110,10 @@ static int therm_fan_est_bind(struct thermal_zone_device *thz,
struct thermal_cooling_device *cdev)
{
int i;
-
- if (!strcmp(cdev->type, "pwm-fan")) {
+ struct therm_fan_estimator *est = thz->devdata;
+ if (!strcmp(cdev->type, est->cdev_type)) {
for (i = 0; i < MAX_ACTIVE_STATES; i++)
- thermal_zone_bind_cooling_device(thz, i, cdev,
- i + 1, i + 1);
+ thermal_zone_bind_cooling_device(thz, i, cdev, i, i);
}
return 0;
@@ -99,8 +123,8 @@ static int therm_fan_est_unbind(struct thermal_zone_device *thz,
struct thermal_cooling_device *cdev)
{
int i;
-
- if (!strcmp(cdev->type, "pwm-fan")) {
+ struct therm_fan_estimator *est = thz->devdata;
+ if (!strcmp(cdev->type, est->cdev_type)) {
for (i = 0; i < MAX_ACTIVE_STATES; i++)
thermal_zone_unbind_cooling_device(thz, i, cdev);
}
@@ -132,7 +156,11 @@ static int therm_fan_est_set_trip_temp(struct thermal_zone_device *thz,
{
struct therm_fan_estimator *est = thz->devdata;
- est->active_trip_temps[trip] = temp;
+ /*Need trip 0 to remain as it is*/
+ if (((temp - est->active_hysteresis[trip]) < 0) || (trip <= 0))
+ return -EINVAL;
+
+ fan_set_trip_temp_hyst(est, trip, est->active_hysteresis[trip], temp);
return 0;
}
@@ -145,10 +173,26 @@ static int therm_fan_est_get_temp(struct thermal_zone_device *thz,
return 0;
}
-static int therm_fan_est_get_trend(struct thermal_zone_device *thz,
- int trip, enum thermal_trend *trend)
+static int therm_fan_est_set_trip_hyst(struct thermal_zone_device *thz,
+ int trip, unsigned long hyst_temp)
+{
+ struct therm_fan_estimator *est = thz->devdata;
+
+ /*Need trip 0 to remain as it is*/
+ if ((est->active_trip_temps[trip] - hyst_temp) < 0 || trip <= 0)
+ return -EINVAL;
+
+ fan_set_trip_temp_hyst(est, trip,
+ hyst_temp, est->active_trip_temps[trip]);
+ return 0;
+}
+
+static int therm_fan_est_get_trip_hyst(struct thermal_zone_device *thz,
+ int trip, unsigned long *temp)
{
- *trend = THERMAL_TREND_RAISING;
+ struct therm_fan_estimator *est = thz->devdata;
+
+ *temp = est->active_hysteresis[trip];
return 0;
}
@@ -158,8 +202,9 @@ static struct thermal_zone_device_ops therm_fan_est_ops = {
.get_trip_type = therm_fan_est_get_trip_type,
.get_trip_temp = therm_fan_est_get_trip_temp,
.get_temp = therm_fan_est_get_temp,
- .get_trend = therm_fan_est_get_trend,
.set_trip_temp = therm_fan_est_set_trip_temp,
+ .get_trip_hyst = therm_fan_est_get_trip_hyst,
+ .set_trip_hyst = therm_fan_est_set_trip_hyst,
};
static ssize_t show_coeff(struct device *dev,
@@ -292,8 +337,17 @@ static int __devinit therm_fan_est_probe(struct platform_device *pdev)
est->toffset = data->toffset;
est->polling_period = data->polling_period;
- for (i = 0; i < MAX_ACTIVE_STATES; i++)
+ for (i = 0; i < MAX_ACTIVE_STATES; i++) {
est->active_trip_temps[i] = data->active_trip_temps[i];
+ est->active_hysteresis[i] = data->active_hysteresis[i];
+ }
+
+ est->active_trip_temps_hyst[0] = data->active_trip_temps[0];
+
+ for (i = 1; i < MAX_ACTIVE_STATES; i++)
+ fan_set_trip_temp_hyst(est, i,
+ data->active_hysteresis[i], est->active_trip_temps[i]);
+
/* initialize history */
for (i = 0; i < data->ndevs; i++) {
dev = &est->devs[i];
@@ -310,18 +364,19 @@ static int __devinit therm_fan_est_probe(struct platform_device *pdev)
if (!est->workqueue)
return -ENOMEM;
+ est->current_trip_index = 0;
+
INIT_DELAYED_WORK(&est->therm_fan_est_work, therm_fan_est_work_func);
queue_delayed_work(est->workqueue,
&est->therm_fan_est_work,
msecs_to_jiffies(est->polling_period));
-
+ est->cdev_type = data->cdev_type;
est->thz = thermal_zone_device_register((char *) dev_name(&pdev->dev),
10, 0x3FF, est,
&therm_fan_est_ops, NULL, 0, 0);
if (IS_ERR_OR_NULL(est->thz))
return -EINVAL;
-
for (i = 0; i < ARRAY_SIZE(therm_fan_est_nodes); i++)
device_create_file(&pdev->dev,
&therm_fan_est_nodes[i].dev_attr);