Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  gov_bang_bang.c - A simple thermal throttling governor using hysteresis
0004  *
0005  *  Copyright (C) 2014 Peter Kaestle <peter@piie.net>
0006  *
0007  *  Based on step_wise.c with following Copyrights:
0008  *  Copyright (C) 2012 Intel Corp
0009  *  Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
0010  */
0011 
0012 #include <linux/thermal.h>
0013 
0014 #include "thermal_core.h"
0015 
0016 static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
0017 {
0018     int trip_temp, trip_hyst;
0019     struct thermal_instance *instance;
0020 
0021     tz->ops->get_trip_temp(tz, trip, &trip_temp);
0022 
0023     if (!tz->ops->get_trip_hyst) {
0024         pr_warn_once("Undefined get_trip_hyst for thermal zone %s - "
0025                 "running with default hysteresis zero\n", tz->type);
0026         trip_hyst = 0;
0027     } else
0028         tz->ops->get_trip_hyst(tz, trip, &trip_hyst);
0029 
0030     dev_dbg(&tz->device, "Trip%d[temp=%d]:temp=%d:hyst=%d\n",
0031                 trip, trip_temp, tz->temperature,
0032                 trip_hyst);
0033 
0034     mutex_lock(&tz->lock);
0035 
0036     list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
0037         if (instance->trip != trip)
0038             continue;
0039 
0040         /* in case fan is in initial state, switch the fan off */
0041         if (instance->target == THERMAL_NO_TARGET)
0042             instance->target = 0;
0043 
0044         /* in case fan is neither on nor off set the fan to active */
0045         if (instance->target != 0 && instance->target != 1) {
0046             pr_warn("Thermal instance %s controlled by bang-bang has unexpected state: %ld\n",
0047                     instance->name, instance->target);
0048             instance->target = 1;
0049         }
0050 
0051         /*
0052          * enable fan when temperature exceeds trip_temp and disable
0053          * the fan in case it falls below trip_temp minus hysteresis
0054          */
0055         if (instance->target == 0 && tz->temperature >= trip_temp)
0056             instance->target = 1;
0057         else if (instance->target == 1 &&
0058                 tz->temperature <= trip_temp - trip_hyst)
0059             instance->target = 0;
0060 
0061         dev_dbg(&instance->cdev->device, "target=%d\n",
0062                     (int)instance->target);
0063 
0064         mutex_lock(&instance->cdev->lock);
0065         instance->cdev->updated = false; /* cdev needs update */
0066         mutex_unlock(&instance->cdev->lock);
0067     }
0068 
0069     mutex_unlock(&tz->lock);
0070 }
0071 
0072 /**
0073  * bang_bang_control - controls devices associated with the given zone
0074  * @tz: thermal_zone_device
0075  * @trip: the trip point
0076  *
0077  * Regulation Logic: a two point regulation, deliver cooling state depending
0078  * on the previous state shown in this diagram:
0079  *
0080  *                Fan:   OFF    ON
0081  *
0082  *                              |
0083  *                              |
0084  *          trip_temp:    +---->+
0085  *                        |     |        ^
0086  *                        |     |        |
0087  *                        |     |   Temperature
0088  * (trip_temp - hyst):    +<----+
0089  *                        |
0090  *                        |
0091  *                        |
0092  *
0093  *   * If the fan is not running and temperature exceeds trip_temp, the fan
0094  *     gets turned on.
0095  *   * In case the fan is running, temperature must fall below
0096  *     (trip_temp - hyst) so that the fan gets turned off again.
0097  *
0098  */
0099 static int bang_bang_control(struct thermal_zone_device *tz, int trip)
0100 {
0101     struct thermal_instance *instance;
0102 
0103     thermal_zone_trip_update(tz, trip);
0104 
0105     mutex_lock(&tz->lock);
0106 
0107     list_for_each_entry(instance, &tz->thermal_instances, tz_node)
0108         thermal_cdev_update(instance->cdev);
0109 
0110     mutex_unlock(&tz->lock);
0111 
0112     return 0;
0113 }
0114 
0115 static struct thermal_governor thermal_gov_bang_bang = {
0116     .name       = "bang_bang",
0117     .throttle   = bang_bang_control,
0118 };
0119 THERMAL_GOVERNOR_DECLARE(thermal_gov_bang_bang);