···11+* Temperature Sensor on hisilicon SoCs22+33+** Required properties :44+55+- compatible: "hisilicon,tsensor".66+- reg: physical base address of thermal sensor and length of memory mapped77+ region.88+- interrupt: The interrupt number to the cpu. Defines the interrupt used99+ by /SOCTHERM/tsensor.1010+- clock-names: Input clock name, should be 'thermal_clk'.1111+- clocks: phandles for clock specified in "clock-names" property.1212+- #thermal-sensor-cells: Should be 1. See ./thermal.txt for a description.1313+1414+Example :1515+1616+ tsensor: tsensor@0,f7030700 {1717+ compatible = "hisilicon,tsensor";1818+ reg = <0x0 0xf7030700 0x0 0x1000>;1919+ interrupts = <0 7 0x4>;2020+ clocks = <&sys_ctrl HI6220_TSENSOR_CLK>;2121+ clock-names = "thermal_clk";2222+ #thermal-sensor-cells = <1>;2323+ }
···11+Qualcomm QPNP PMIC Temperature Alarm22+33+QPNP temperature alarm peripherals are found inside of Qualcomm PMIC chips44+that utilize the Qualcomm SPMI implementation. These peripherals provide an55+interrupt signal and status register to identify high PMIC die temperature.66+77+Required properties:88+- compatible: Should contain "qcom,spmi-temp-alarm".99+- reg: Specifies the SPMI address and length of the controller's1010+ registers.1111+- interrupts: PMIC temperature alarm interrupt.1212+- #thermal-sensor-cells: Should be 0. See thermal.txt for a description.1313+1414+Optional properties:1515+- io-channels: Should contain IIO channel specifier for the ADC channel,1616+ which report chip die temperature.1717+- io-channel-names: Should contain "thermal".1818+1919+Example:2020+2121+ pm8941_temp: thermal-alarm@2400 {2222+ compatible = "qcom,spmi-temp-alarm";2323+ reg = <0x2400 0x100>;2424+ interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>;2525+ #thermal-sensor-cells = <0>;2626+2727+ io-channels = <&pm8941_vadc VADC_DIE_TEMP>;2828+ io-channel-names = "thermal";2929+ };3030+3131+ thermal-zones {3232+ pm8941 {3333+ polling-delay-passive = <250>;3434+ polling-delay = <1000>;3535+3636+ thermal-sensors = <&pm8941_temp>;3737+3838+ trips {3939+ passive {4040+ temperature = <1050000>;4141+ hysteresis = <2000>;4242+ type = "passive";4343+ };4444+ alert {4545+ temperature = <125000>;4646+ hysteresis = <2000>;4747+ type = "hot";4848+ };4949+ crit {5050+ temperature = <145000>;5151+ hysteresis = <2000>;5252+ type = "critical";5353+ };5454+ };5555+ };5656+ };5757+
···167167 by means of sensor ID. Additional coefficients are168168 interpreted as constant offset.169169170170+- sustainable-power: An estimate of the sustainable power (in mW) that the171171+ Type: unsigned thermal zone can dissipate at the desired172172+ Size: one cell control temperature. For reference, the173173+ sustainable power of a 4'' phone is typically174174+ 2000mW, while on a 10'' tablet is around175175+ 4500mW.176176+170177Note: The delay properties are bound to the maximum dT/dt (temperature171178derivative over time) in two situations for a thermal zone:172179(i) - when passive cooling is activated (polling-delay-passive); and···552545 * z = c1*x1 + c2*x2 + c3*x3553546 */554547 coefficients = <1200 -345 890>;548548+549549+ sustainable-power = <2500>;555550556551 trips {557552 /* Trips are based on resulting linear equation */
+155-1
Documentation/thermal/cpu-cooling-api.txt
···3636 np: pointer to the cooling device device tree node3737 clip_cpus: cpumask of cpus where the frequency constraints will happen.38383939-1.1.3 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)3939+1.1.3 struct thermal_cooling_device *cpufreq_power_cooling_register(4040+ const struct cpumask *clip_cpus, u32 capacitance,4141+ get_static_t plat_static_func)4242+4343+Similar to cpufreq_cooling_register, this function registers a cpufreq4444+cooling device. Using this function, the cooling device will4545+implement the power extensions by using a simple cpu power model. The4646+cpus must have registered their OPPs using the OPP library.4747+4848+The additional parameters are needed for the power model (See 2. Power4949+models). "capacitance" is the dynamic power coefficient (See 2.15050+Dynamic power). "plat_static_func" is a function to calculate the5151+static power consumed by these cpus (See 2.2 Static power).5252+5353+1.1.4 struct thermal_cooling_device *of_cpufreq_power_cooling_register(5454+ struct device_node *np, const struct cpumask *clip_cpus, u32 capacitance,5555+ get_static_t plat_static_func)5656+5757+Similar to cpufreq_power_cooling_register, this function register a5858+cpufreq cooling device with power extensions using the device tree5959+information supplied by the np parameter.6060+6161+1.1.5 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)40624163 This interface function unregisters the "thermal-cpufreq-%x" cooling device.42644365 cdev: Cooling device pointer which has to be unregistered.6666+6767+2. Power models6868+6969+The power API registration functions provide a simple power model for7070+CPUs. The current power is calculated as dynamic + (optionally)7171+static power. This power model requires that the operating-points of7272+the CPUs are registered using the kernel's opp library and the7373+`cpufreq_frequency_table` is assigned to the `struct device` of the7474+cpu. If you are using CONFIG_CPUFREQ_DT then the7575+`cpufreq_frequency_table` should already be assigned to the cpu7676+device.7777+7878+The `plat_static_func` parameter of `cpufreq_power_cooling_register()`7979+and `of_cpufreq_power_cooling_register()` is optional. If you don't8080+provide it, only dynamic power will be considered.8181+8282+2.1 Dynamic power8383+8484+The dynamic power consumption of a processor depends on many factors.8585+For a given processor implementation the primary factors are:8686+8787+- The time the processor spends running, consuming dynamic power, as8888+ compared to the time in idle states where dynamic consumption is8989+ negligible. Herein we refer to this as 'utilisation'.9090+- The voltage and frequency levels as a result of DVFS. The DVFS9191+ level is a dominant factor governing power consumption.9292+- In running time the 'execution' behaviour (instruction types, memory9393+ access patterns and so forth) causes, in most cases, a second order9494+ variation. In pathological cases this variation can be significant,9595+ but typically it is of a much lesser impact than the factors above.9696+9797+A high level dynamic power consumption model may then be represented as:9898+9999+Pdyn = f(run) * Voltage^2 * Frequency * Utilisation100100+101101+f(run) here represents the described execution behaviour and its102102+result has a units of Watts/Hz/Volt^2 (this often expressed in103103+mW/MHz/uVolt^2)104104+105105+The detailed behaviour for f(run) could be modelled on-line. However,106106+in practice, such an on-line model has dependencies on a number of107107+implementation specific processor support and characterisation108108+factors. Therefore, in initial implementation that contribution is109109+represented as a constant coefficient. This is a simplification110110+consistent with the relative contribution to overall power variation.111111+112112+In this simplified representation our model becomes:113113+114114+Pdyn = Capacitance * Voltage^2 * Frequency * Utilisation115115+116116+Where `capacitance` is a constant that represents an indicative117117+running time dynamic power coefficient in fundamental units of118118+mW/MHz/uVolt^2. Typical values for mobile CPUs might lie in range119119+from 100 to 500. For reference, the approximate values for the SoC in120120+ARM's Juno Development Platform are 530 for the Cortex-A57 cluster and121121+140 for the Cortex-A53 cluster.122122+123123+124124+2.2 Static power125125+126126+Static leakage power consumption depends on a number of factors. For a127127+given circuit implementation the primary factors are:128128+129129+- Time the circuit spends in each 'power state'130130+- Temperature131131+- Operating voltage132132+- Process grade133133+134134+The time the circuit spends in each 'power state' for a given135135+evaluation period at first order means OFF or ON. However,136136+'retention' states can also be supported that reduce power during137137+inactive periods without loss of context.138138+139139+Note: The visibility of state entries to the OS can vary, according to140140+platform specifics, and this can then impact the accuracy of a model141141+based on OS state information alone. It might be possible in some142142+cases to extract more accurate information from system resources.143143+144144+The temperature, operating voltage and process 'grade' (slow to fast)145145+of the circuit are all significant factors in static leakage power146146+consumption. All of these have complex relationships to static power.147147+148148+Circuit implementation specific factors include the chosen silicon149149+process as well as the type, number and size of transistors in both150150+the logic gates and any RAM elements included.151151+152152+The static power consumption modelling must take into account the153153+power managed regions that are implemented. Taking the example of an154154+ARM processor cluster, the modelling would take into account whether155155+each CPU can be powered OFF separately or if only a single power156156+region is implemented for the complete cluster.157157+158158+In one view, there are others, a static power consumption model can159159+then start from a set of reference values for each power managed160160+region (e.g. CPU, Cluster/L2) in each state (e.g. ON, OFF) at an161161+arbitrary process grade, voltage and temperature point. These values162162+are then scaled for all of the following: the time in each state, the163163+process grade, the current temperature and the operating voltage.164164+However, since both implementation specific and complex relationships165165+dominate the estimate, the appropriate interface to the model from the166166+cpu cooling device is to provide a function callback that calculates167167+the static power in this platform. When registering the cpu cooling168168+device pass a function pointer that follows the `get_static_t`169169+prototype:170170+171171+ int plat_get_static(cpumask_t *cpumask, int interval,172172+ unsigned long voltage, u32 &power);173173+174174+`cpumask` is the cpumask of the cpus involved in the calculation.175175+`voltage` is the voltage at which they are operating. The function176176+should calculate the average static power for the last `interval`177177+milliseconds. It returns 0 on success, -E* on error. If it178178+succeeds, it should store the static power in `power`. Reading the179179+temperature of the cpus described by `cpumask` is left for180180+plat_get_static() to do as the platform knows best which thermal181181+sensor is closest to the cpu.182182+183183+If `plat_static_func` is NULL, static power is considered to be184184+negligible for this platform and only dynamic power is considered.185185+186186+The platform specific callback can then use any combination of tables187187+and/or equations to permute the estimated value. Process grade188188+information is not passed to the model since access to such data, from189189+on-chip measurement capability or manufacture time data, is platform190190+specific.191191+192192+Note: the significance of static power for CPUs in comparison to193193+dynamic power is highly dependent on implementation. Given the194194+potential complexity in implementation, the importance and accuracy of195195+its inclusion when using cpu cooling devices should be assessed on a196196+case by case basis.197197+
+247
Documentation/thermal/power_allocator.txt
···11+Power allocator governor tunables22+=================================33+44+Trip points55+-----------66+77+The governor requires the following two passive trip points:88+99+1. "switch on" trip point: temperature above which the governor1010+ control loop starts operating. This is the first passive trip1111+ point of the thermal zone.1212+1313+2. "desired temperature" trip point: it should be higher than the1414+ "switch on" trip point. This the target temperature the governor1515+ is controlling for. This is the last passive trip point of the1616+ thermal zone.1717+1818+PID Controller1919+--------------2020+2121+The power allocator governor implements a2222+Proportional-Integral-Derivative controller (PID controller) with2323+temperature as the control input and power as the controlled output:2424+2525+ P_max = k_p * e + k_i * err_integral + k_d * diff_err + sustainable_power2626+2727+where2828+ e = desired_temperature - current_temperature2929+ err_integral is the sum of previous errors3030+ diff_err = e - previous_error3131+3232+It is similar to the one depicted below:3333+3434+ k_d3535+ |3636+current_temp |3737+ | v3838+ | +----------+ +---+3939+ | +----->| diff_err |-->| X |------+4040+ | | +----------+ +---+ |4141+ | | | tdp actor4242+ | | k_i | | get_requested_power()4343+ | | | | | | |4444+ | | | | | | | ...4545+ v | v v v v v4646+ +---+ | +-------+ +---+ +---+ +---+ +----------+4747+ | S |-------+----->| sum e |----->| X |--->| S |-->| S |-->|power |4848+ +---+ | +-------+ +---+ +---+ +---+ |allocation|4949+ ^ | ^ +----------+5050+ | | | | |5151+ | | +---+ | | |5252+ | +------->| X |-------------------+ v v5353+ | +---+ granted performance5454+desired_temperature ^5555+ |5656+ |5757+ k_po/k_pu5858+5959+Sustainable power6060+-----------------6161+6262+An estimate of the sustainable dissipatable power (in mW) should be6363+provided while registering the thermal zone. This estimates the6464+sustained power that can be dissipated at the desired control6565+temperature. This is the maximum sustained power for allocation at6666+the desired maximum temperature. The actual sustained power can vary6767+for a number of reasons. The closed loop controller will take care of6868+variations such as environmental conditions, and some factors related6969+to the speed-grade of the silicon. `sustainable_power` is therefore7070+simply an estimate, and may be tuned to affect the aggressiveness of7171+the thermal ramp. For reference, the sustainable power of a 4" phone7272+is typically 2000mW, while on a 10" tablet is around 4500mW (may vary7373+depending on screen size).7474+7575+If you are using device tree, do add it as a property of the7676+thermal-zone. For example:7777+7878+ thermal-zones {7979+ soc_thermal {8080+ polling-delay = <1000>;8181+ polling-delay-passive = <100>;8282+ sustainable-power = <2500>;8383+ ...8484+8585+Instead, if the thermal zone is registered from the platform code, pass a8686+`thermal_zone_params` that has a `sustainable_power`. If no8787+`thermal_zone_params` were being passed, then something like below8888+will suffice:8989+9090+ static const struct thermal_zone_params tz_params = {9191+ .sustainable_power = 3500,9292+ };9393+9494+and then pass `tz_params` as the 5th parameter to9595+`thermal_zone_device_register()`9696+9797+k_po and k_pu9898+-------------9999+100100+The implementation of the PID controller in the power allocator101101+thermal governor allows the configuration of two proportional term102102+constants: `k_po` and `k_pu`. `k_po` is the proportional term103103+constant during temperature overshoot periods (current temperature is104104+above "desired temperature" trip point). Conversely, `k_pu` is the105105+proportional term constant during temperature undershoot periods106106+(current temperature below "desired temperature" trip point).107107+108108+These controls are intended as the primary mechanism for configuring109109+the permitted thermal "ramp" of the system. For instance, a lower110110+`k_pu` value will provide a slower ramp, at the cost of capping111111+available capacity at a low temperature. On the other hand, a high112112+value of `k_pu` will result in the governor granting very high power113113+whilst temperature is low, and may lead to temperature overshooting.114114+115115+The default value for `k_pu` is:116116+117117+ 2 * sustainable_power / (desired_temperature - switch_on_temp)118118+119119+This means that at `switch_on_temp` the output of the controller's120120+proportional term will be 2 * `sustainable_power`. The default value121121+for `k_po` is:122122+123123+ sustainable_power / (desired_temperature - switch_on_temp)124124+125125+Focusing on the proportional and feed forward values of the PID126126+controller equation we have:127127+128128+ P_max = k_p * e + sustainable_power129129+130130+The proportional term is proportional to the difference between the131131+desired temperature and the current one. When the current temperature132132+is the desired one, then the proportional component is zero and133133+`P_max` = `sustainable_power`. That is, the system should operate in134134+thermal equilibrium under constant load. `sustainable_power` is only135135+an estimate, which is the reason for closed-loop control such as this.136136+137137+Expanding `k_pu` we get:138138+ P_max = 2 * sustainable_power * (T_set - T) / (T_set - T_on) +139139+ sustainable_power140140+141141+where142142+ T_set is the desired temperature143143+ T is the current temperature144144+ T_on is the switch on temperature145145+146146+When the current temperature is the switch_on temperature, the above147147+formula becomes:148148+149149+ P_max = 2 * sustainable_power * (T_set - T_on) / (T_set - T_on) +150150+ sustainable_power = 2 * sustainable_power + sustainable_power =151151+ 3 * sustainable_power152152+153153+Therefore, the proportional term alone linearly decreases power from154154+3 * `sustainable_power` to `sustainable_power` as the temperature155155+rises from the switch on temperature to the desired temperature.156156+157157+k_i and integral_cutoff158158+-----------------------159159+160160+`k_i` configures the PID loop's integral term constant. This term161161+allows the PID controller to compensate for long term drift and for162162+the quantized nature of the output control: cooling devices can't set163163+the exact power that the governor requests. When the temperature164164+error is below `integral_cutoff`, errors are accumulated in the165165+integral term. This term is then multiplied by `k_i` and the result166166+added to the output of the controller. Typically `k_i` is set low (1167167+or 2) and `integral_cutoff` is 0.168168+169169+k_d170170+---171171+172172+`k_d` configures the PID loop's derivative term constant. It's173173+recommended to leave it as the default: 0.174174+175175+Cooling device power API176176+========================177177+178178+Cooling devices controlled by this governor must supply the additional179179+"power" API in their `cooling_device_ops`. It consists on three ops:180180+181181+1. int get_requested_power(struct thermal_cooling_device *cdev,182182+ struct thermal_zone_device *tz, u32 *power);183183+@cdev: The `struct thermal_cooling_device` pointer184184+@tz: thermal zone in which we are currently operating185185+@power: pointer in which to store the calculated power186186+187187+`get_requested_power()` calculates the power requested by the device188188+in milliwatts and stores it in @power . It should return 0 on189189+success, -E* on failure. This is currently used by the power190190+allocator governor to calculate how much power to give to each cooling191191+device.192192+193193+2. int state2power(struct thermal_cooling_device *cdev, struct194194+ thermal_zone_device *tz, unsigned long state, u32 *power);195195+@cdev: The `struct thermal_cooling_device` pointer196196+@tz: thermal zone in which we are currently operating197197+@state: A cooling device state198198+@power: pointer in which to store the equivalent power199199+200200+Convert cooling device state @state into power consumption in201201+milliwatts and store it in @power. It should return 0 on success, -E*202202+on failure. This is currently used by thermal core to calculate the203203+maximum power that an actor can consume.204204+205205+3. int power2state(struct thermal_cooling_device *cdev, u32 power,206206+ unsigned long *state);207207+@cdev: The `struct thermal_cooling_device` pointer208208+@power: power in milliwatts209209+@state: pointer in which to store the resulting state210210+211211+Calculate a cooling device state that would make the device consume at212212+most @power mW and store it in @state. It should return 0 on success,213213+-E* on failure. This is currently used by the thermal core to convert214214+a given power set by the power allocator governor to a state that the215215+cooling device can set. It is a function because this conversion may216216+depend on external factors that may change so this function should the217217+best conversion given "current circumstances".218218+219219+Cooling device weights220220+----------------------221221+222222+Weights are a mechanism to bias the allocation among cooling223223+devices. They express the relative power efficiency of different224224+cooling devices. Higher weight can be used to express higher power225225+efficiency. Weighting is relative such that if each cooling device226226+has a weight of one they are considered equal. This is particularly227227+useful in heterogeneous systems where two cooling devices may perform228228+the same kind of compute, but with different efficiency. For example,229229+a system with two different types of processors.230230+231231+If the thermal zone is registered using232232+`thermal_zone_device_register()` (i.e., platform code), then weights233233+are passed as part of the thermal zone's `thermal_bind_parameters`.234234+If the platform is registered using device tree, then they are passed235235+as the `contribution` property of each map in the `cooling-maps` node.236236+237237+Limitations of the power allocator governor238238+===========================================239239+240240+The power allocator governor's PID controller works best if there is a241241+periodic tick. If you have a driver that calls242242+`thermal_zone_device_update()` (or anything that ends up calling the243243+governor's `throttle()` function) repetitively, the governor response244244+won't be very good. Note that this is not particular to this245245+governor, step-wise will also misbehave if you call its throttle()246246+faster than the normal thermal framework tick (due to interrupts for247247+example) as it will overreact.
+94-5
Documentation/thermal/sysfs-api.txt
···95951.3 interface for binding a thermal zone device with a thermal cooling device96961.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,9797 int trip, struct thermal_cooling_device *cdev,9898- unsigned long upper, unsigned long lower);9898+ unsigned long upper, unsigned long lower, unsigned int weight);9999100100 This interface function bind a thermal cooling device to the certain trip101101 point of a thermal zone device.···110110 lower:the Minimum cooling state can be used for this trip point.111111 THERMAL_NO_LIMIT means no lower limit,112112 and the cooling device can be in cooling state 0.113113+ weight: the influence of this cooling device in this thermal114114+ zone. See 1.4.1 below for more information.1131151141161.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,115117 int trip, struct thermal_cooling_device *cdev);···129127 This structure defines the following parameters that are used to bind130128 a zone with a cooling device for a particular trip point.131129 .cdev: The cooling device pointer132132- .weight: The 'influence' of a particular cooling device on this zone.133133- This is on a percentage scale. The sum of all these weights134134- (for a particular zone) cannot exceed 100.130130+ .weight: The 'influence' of a particular cooling device on this131131+ zone. This is relative to the rest of the cooling132132+ devices. For example, if all cooling devices have a133133+ weight of 1, then they all contribute the same. You can134134+ use percentages if you want, but it's not mandatory. A135135+ weight of 0 means that this cooling device doesn't136136+ contribute to the cooling of this zone unless all cooling137137+ devices have a weight of 0. If all weights are 0, then138138+ they all contribute the same.135139 .trip_mask:This is a bit mask that gives the binding relation between136140 this thermal zone and cdev, for a particular trip point.137141 If nth bit is set, then the cdev and thermal zone are bound···184176 |---trip_point_[0-*]_type: Trip point type185177 |---trip_point_[0-*]_hyst: Hysteresis value for this trip point186178 |---emul_temp: Emulated temperature set node179179+ |---sustainable_power: Sustainable dissipatable power180180+ |---k_po: Proportional term during temperature overshoot181181+ |---k_pu: Proportional term during temperature undershoot182182+ |---k_i: PID's integral term in the power allocator gov183183+ |---k_d: PID's derivative term in the power allocator184184+ |---integral_cutoff: Offset above which errors are accumulated185185+ |---slope: Slope constant applied as linear extrapolation186186+ |---offset: Offset constant applied as linear extrapolation187187188188Thermal cooling device sys I/F, created once it's registered:189189/sys/class/thermal/cooling_device[0-*]:···208192/sys/class/thermal/thermal_zone[0-*]:209193 |---cdev[0-*]: [0-*]th cooling device in current thermal zone210194 |---cdev[0-*]_trip_point: Trip point that cdev[0-*] is associated with195195+ |---cdev[0-*]_weight: Influence of the cooling device in196196+ this thermal zone211197212198Besides the thermal zone device sysfs I/F and cooling device sysfs I/F,213199the generic thermal driver also creates a hwmon sysfs I/F for each _type_···283265 point.284266 RO, Optional285267268268+cdev[0-*]_weight269269+ The influence of cdev[0-*] in this thermal zone. This value270270+ is relative to the rest of cooling devices in the thermal271271+ zone. For example, if a cooling device has a weight double272272+ than that of other, it's twice as effective in cooling the273273+ thermal zone.274274+ RW, Optional275275+286276passive287277 Attribute is only present for zones in which the passive cooling288278 policy is not supported by native thermal driver. Default is zero···314288 WARNING: Be careful while enabling this option on production systems,315289 because userland can easily disable the thermal policy by simply316290 flooding this sysfs node with low temperature values.291291+292292+sustainable_power293293+ An estimate of the sustained power that can be dissipated by294294+ the thermal zone. Used by the power allocator governor. For295295+ more information see Documentation/thermal/power_allocator.txt296296+ Unit: milliwatts297297+ RW, Optional298298+299299+k_po300300+ The proportional term of the power allocator governor's PID301301+ controller during temperature overshoot. Temperature overshoot302302+ is when the current temperature is above the "desired303303+ temperature" trip point. For more information see304304+ Documentation/thermal/power_allocator.txt305305+ RW, Optional306306+307307+k_pu308308+ The proportional term of the power allocator governor's PID309309+ controller during temperature undershoot. Temperature undershoot310310+ is when the current temperature is below the "desired311311+ temperature" trip point. For more information see312312+ Documentation/thermal/power_allocator.txt313313+ RW, Optional314314+315315+k_i316316+ The integral term of the power allocator governor's PID317317+ controller. This term allows the PID controller to compensate318318+ for long term drift. For more information see319319+ Documentation/thermal/power_allocator.txt320320+ RW, Optional321321+322322+k_d323323+ The derivative term of the power allocator governor's PID324324+ controller. For more information see325325+ Documentation/thermal/power_allocator.txt326326+ RW, Optional327327+328328+integral_cutoff329329+ Temperature offset from the desired temperature trip point330330+ above which the integral term of the power allocator331331+ governor's PID controller starts accumulating errors. For332332+ example, if integral_cutoff is 0, then the integral term only333333+ accumulates error when temperature is above the desired334334+ temperature trip point. For more information see335335+ Documentation/thermal/power_allocator.txt336336+ RW, Optional337337+338338+slope339339+ The slope constant used in a linear extrapolation model340340+ to determine a hotspot temperature based off the sensor's341341+ raw readings. It is up to the device driver to determine342342+ the usage of these values.343343+ RW, Optional344344+345345+offset346346+ The offset constant used in a linear extrapolation model347347+ to determine a hotspot temperature based off the sensor's348348+ raw readings. It is up to the device driver to determine349349+ the usage of these values.350350+ RW, Optional317351318352*****************************319353* Cooling device attributes *···404318active[0] and active[1] at the same time, it may register itself as a405319thermal_zone_device (thermal_zone1) with 4 trip points in all.406320It has one processor and one fan, which are both registered as407407-thermal_cooling_device.321321+thermal_cooling_device. Both are considered to have the same322322+effectiveness in cooling the thermal zone.408323409324If the processor is listed in _PSL method, and the fan is listed in _AL0410325method, the sys I/F structure will be built like this:···427340 |---trip_point_3_type: active1428341 |---cdev0: --->/sys/class/thermal/cooling_device0429342 |---cdev0_trip_point: 1 /* cdev0 can be used for passive */343343+ |---cdev0_weight: 1024430344 |---cdev1: --->/sys/class/thermal/cooling_device3431345 |---cdev1_trip_point: 2 /* cdev1 can be used for active[0]*/346346+ |---cdev1_weight: 1024432347433348|cooling_device0:434349 |---type: Processor
+6-3
drivers/acpi/thermal.c
···800800 result =801801 thermal_zone_bind_cooling_device802802 (thermal, trip, cdev,803803- THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);803803+ THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,804804+ THERMAL_WEIGHT_DEFAULT);804805 else805806 result =806807 thermal_zone_unbind_cooling_device···825824 if (bind)826825 result = thermal_zone_bind_cooling_device827826 (thermal, trip, cdev,828828- THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);827827+ THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,828828+ THERMAL_WEIGHT_DEFAULT);829829 else830830 result = thermal_zone_unbind_cooling_device831831 (thermal, trip, cdev);···843841 result = thermal_zone_bind_cooling_device844842 (thermal, THERMAL_TRIPS_NONE,845843 cdev, THERMAL_NO_LIMIT,846846- THERMAL_NO_LIMIT);844844+ THERMAL_NO_LIMIT,845845+ THERMAL_WEIGHT_DEFAULT);847846 else848847 result = thermal_zone_unbind_cooling_device849848 (thermal, THERMAL_TRIPS_NONE,
···4242 Say 'Y' here if you need to build thermal infrastructure4343 based on device tree.44444545+config THERMAL_WRITABLE_TRIPS4646+ bool "Enable writable trip points"4747+ help4848+ This option allows the system integrator to choose whether4949+ trip temperatures can be changed from userspace. The5050+ writable trips need to be specified when setting up the5151+ thermal zone but the choice here takes precedence.5252+5353+ Say 'Y' here if you would like to allow userspace tools to5454+ change trip temperatures.5555+4556choice4657 prompt "Default Thermal governor"4758 default THERMAL_DEFAULT_GOV_STEP_WISE···8271 Select this if you want to let the user space manage the8372 platform thermals.84737474+config THERMAL_DEFAULT_GOV_POWER_ALLOCATOR7575+ bool "power_allocator"7676+ select THERMAL_GOV_POWER_ALLOCATOR7777+ help7878+ Select this if you want to control temperature based on7979+ system and device power allocation. This governor can only8080+ operate on cooling devices that implement the power API.8181+8582endchoice86838784config THERMAL_GOV_FAIR_SHARE···11798 bool "User_space thermal governor"11899 help119100 Enable this to let the user space manage the platform thermals.101101+102102+config THERMAL_GOV_POWER_ALLOCATOR103103+ bool "Power allocator thermal governor"104104+ help105105+ Enable this to manage platform thermals by dynamically106106+ allocating and limiting power to devices.120107121108config CPU_THERMAL122109 bool "generic cpu cooling support"···160135 WARNING: Be careful while enabling this option on production systems,161136 because userland can easily disable the thermal policy by simply162137 flooding this sysfs node with low temperature values.138138+139139+config HISI_THERMAL140140+ tristate "Hisilicon thermal driver"141141+ depends on ARCH_HISI && CPU_THERMAL && OF142142+ help143143+ Enable this to plug hisilicon's thermal sensor driver into the Linux144144+ thermal framework. cpufreq is used as the cooling device to throttle145145+ CPUs when the passive trip is crossed.163146164147config IMX_THERMAL165148 tristate "Temperature sensor driver for Freescale i.MX SoCs"···331298depends on ARCH_STI && OF332299source "drivers/thermal/st/Kconfig"333300endmenu301301+302302+config QCOM_SPMI_TEMP_ALARM303303+ tristate "Qualcomm SPMI PMIC Temperature Alarm"304304+ depends on OF && SPMI && IIO305305+ select REGMAP_SPMI306306+ help307307+ This enables a thermal sysfs driver for Qualcomm plug-and-play (QPNP)308308+ PMIC devices. It shows up in sysfs as a thermal sensor with multiple309309+ trip points. The temperature reported by the thermal sensor reflects the310310+ real time die temperature if an ADC is present or an estimate of the311311+ temperature based upon the over temperature stage value.334312335313endif
···2626#include <linux/thermal.h>2727#include <linux/cpufreq.h>2828#include <linux/err.h>2929+#include <linux/pm_opp.h>2930#include <linux/slab.h>3031#include <linux/cpu.h>3132#include <linux/cpu_cooling.h>3333+3434+#include <trace/events/thermal.h>32353336/*3437 * Cooling state <-> CPUFreq frequency···4845 */49465047/**4848+ * struct power_table - frequency to power conversion4949+ * @frequency: frequency in KHz5050+ * @power: power in mW5151+ *5252+ * This structure is built when the cooling device registers and helps5353+ * in translating frequency to power and viceversa.5454+ */5555+struct power_table {5656+ u32 frequency;5757+ u32 power;5858+};5959+6060+/**5161 * struct cpufreq_cooling_device - data for cooling device with cpufreq5262 * @id: unique integer value corresponding to each cpufreq_cooling_device5363 * registered.···7458 * cpufreq frequencies.7559 * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device.7660 * @node: list_head to link all cpufreq_cooling_device together.6161+ * @last_load: load measured by the latest call to cpufreq_get_actual_power()6262+ * @time_in_idle: previous reading of the absolute time that this cpu was idle6363+ * @time_in_idle_timestamp: wall time of the last invocation of6464+ * get_cpu_idle_time_us()6565+ * @dyn_power_table: array of struct power_table for frequency to power6666+ * conversion, sorted in ascending order.6767+ * @dyn_power_table_entries: number of entries in the @dyn_power_table array6868+ * @cpu_dev: the first cpu_device from @allowed_cpus that has OPPs registered6969+ * @plat_get_static_power: callback to calculate the static power7770 *7871 * This structure is required for keeping information of each registered7972 * cpufreq_cooling_device.···9671 unsigned int *freq_table; /* In descending order */9772 struct cpumask allowed_cpus;9873 struct list_head node;7474+ u32 last_load;7575+ u64 *time_in_idle;7676+ u64 *time_in_idle_timestamp;7777+ struct power_table *dyn_power_table;7878+ int dyn_power_table_entries;7979+ struct device *cpu_dev;8080+ get_static_t plat_get_static_power;9981};10082static DEFINE_IDR(cpufreq_idr);10183static DEFINE_MUTEX(cooling_cpufreq_lock);···218186 unsigned long max_freq = 0;219187 struct cpufreq_cooling_device *cpufreq_dev;220188221221- if (event != CPUFREQ_ADJUST)222222- return 0;189189+ switch (event) {223190224224- mutex_lock(&cooling_cpufreq_lock);225225- list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {226226- if (!cpumask_test_cpu(policy->cpu,227227- &cpufreq_dev->allowed_cpus))228228- continue;191191+ case CPUFREQ_ADJUST:192192+ mutex_lock(&cooling_cpufreq_lock);193193+ list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {194194+ if (!cpumask_test_cpu(policy->cpu,195195+ &cpufreq_dev->allowed_cpus))196196+ continue;229197230230- max_freq = cpufreq_dev->cpufreq_val;198198+ max_freq = cpufreq_dev->cpufreq_val;231199232232- if (policy->max != max_freq)233233- cpufreq_verify_within_limits(policy, 0, max_freq);200200+ if (policy->max != max_freq)201201+ cpufreq_verify_within_limits(policy, 0,202202+ max_freq);203203+ }204204+ mutex_unlock(&cooling_cpufreq_lock);205205+ break;206206+ default:207207+ return NOTIFY_DONE;234208 }235235- mutex_unlock(&cooling_cpufreq_lock);236209237237- return 0;210210+ return NOTIFY_OK;211211+}212212+213213+/**214214+ * build_dyn_power_table() - create a dynamic power to frequency table215215+ * @cpufreq_device: the cpufreq cooling device in which to store the table216216+ * @capacitance: dynamic power coefficient for these cpus217217+ *218218+ * Build a dynamic power to frequency table for this cpu and store it219219+ * in @cpufreq_device. This table will be used in cpu_power_to_freq() and220220+ * cpu_freq_to_power() to convert between power and frequency221221+ * efficiently. Power is stored in mW, frequency in KHz. The222222+ * resulting table is in ascending order.223223+ *224224+ * Return: 0 on success, -E* on error.225225+ */226226+static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,227227+ u32 capacitance)228228+{229229+ struct power_table *power_table;230230+ struct dev_pm_opp *opp;231231+ struct device *dev = NULL;232232+ int num_opps = 0, cpu, i, ret = 0;233233+ unsigned long freq;234234+235235+ rcu_read_lock();236236+237237+ for_each_cpu(cpu, &cpufreq_device->allowed_cpus) {238238+ dev = get_cpu_device(cpu);239239+ if (!dev) {240240+ dev_warn(&cpufreq_device->cool_dev->device,241241+ "No cpu device for cpu %d\n", cpu);242242+ continue;243243+ }244244+245245+ num_opps = dev_pm_opp_get_opp_count(dev);246246+ if (num_opps > 0) {247247+ break;248248+ } else if (num_opps < 0) {249249+ ret = num_opps;250250+ goto unlock;251251+ }252252+ }253253+254254+ if (num_opps == 0) {255255+ ret = -EINVAL;256256+ goto unlock;257257+ }258258+259259+ power_table = kcalloc(num_opps, sizeof(*power_table), GFP_KERNEL);260260+ if (!power_table) {261261+ ret = -ENOMEM;262262+ goto unlock;263263+ }264264+265265+ for (freq = 0, i = 0;266266+ opp = dev_pm_opp_find_freq_ceil(dev, &freq), !IS_ERR(opp);267267+ freq++, i++) {268268+ u32 freq_mhz, voltage_mv;269269+ u64 power;270270+271271+ freq_mhz = freq / 1000000;272272+ voltage_mv = dev_pm_opp_get_voltage(opp) / 1000;273273+274274+ /*275275+ * Do the multiplication with MHz and millivolt so as276276+ * to not overflow.277277+ */278278+ power = (u64)capacitance * freq_mhz * voltage_mv * voltage_mv;279279+ do_div(power, 1000000000);280280+281281+ /* frequency is stored in power_table in KHz */282282+ power_table[i].frequency = freq / 1000;283283+284284+ /* power is stored in mW */285285+ power_table[i].power = power;286286+ }287287+288288+ if (i == 0) {289289+ ret = PTR_ERR(opp);290290+ goto unlock;291291+ }292292+293293+ cpufreq_device->cpu_dev = dev;294294+ cpufreq_device->dyn_power_table = power_table;295295+ cpufreq_device->dyn_power_table_entries = i;296296+297297+unlock:298298+ rcu_read_unlock();299299+ return ret;300300+}301301+302302+static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_device,303303+ u32 freq)304304+{305305+ int i;306306+ struct power_table *pt = cpufreq_device->dyn_power_table;307307+308308+ for (i = 1; i < cpufreq_device->dyn_power_table_entries; i++)309309+ if (freq < pt[i].frequency)310310+ break;311311+312312+ return pt[i - 1].power;313313+}314314+315315+static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_device,316316+ u32 power)317317+{318318+ int i;319319+ struct power_table *pt = cpufreq_device->dyn_power_table;320320+321321+ for (i = 1; i < cpufreq_device->dyn_power_table_entries; i++)322322+ if (power < pt[i].power)323323+ break;324324+325325+ return pt[i - 1].frequency;326326+}327327+328328+/**329329+ * get_load() - get load for a cpu since last updated330330+ * @cpufreq_device: &struct cpufreq_cooling_device for this cpu331331+ * @cpu: cpu number332332+ *333333+ * Return: The average load of cpu @cpu in percentage since this334334+ * function was last called.335335+ */336336+static u32 get_load(struct cpufreq_cooling_device *cpufreq_device, int cpu)337337+{338338+ u32 load;339339+ u64 now, now_idle, delta_time, delta_idle;340340+341341+ now_idle = get_cpu_idle_time(cpu, &now, 0);342342+ delta_idle = now_idle - cpufreq_device->time_in_idle[cpu];343343+ delta_time = now - cpufreq_device->time_in_idle_timestamp[cpu];344344+345345+ if (delta_time <= delta_idle)346346+ load = 0;347347+ else348348+ load = div64_u64(100 * (delta_time - delta_idle), delta_time);349349+350350+ cpufreq_device->time_in_idle[cpu] = now_idle;351351+ cpufreq_device->time_in_idle_timestamp[cpu] = now;352352+353353+ return load;354354+}355355+356356+/**357357+ * get_static_power() - calculate the static power consumed by the cpus358358+ * @cpufreq_device: struct &cpufreq_cooling_device for this cpu cdev359359+ * @tz: thermal zone device in which we're operating360360+ * @freq: frequency in KHz361361+ * @power: pointer in which to store the calculated static power362362+ *363363+ * Calculate the static power consumed by the cpus described by364364+ * @cpu_actor running at frequency @freq. This function relies on a365365+ * platform specific function that should have been provided when the366366+ * actor was registered. If it wasn't, the static power is assumed to367367+ * be negligible. The calculated static power is stored in @power.368368+ *369369+ * Return: 0 on success, -E* on failure.370370+ */371371+static int get_static_power(struct cpufreq_cooling_device *cpufreq_device,372372+ struct thermal_zone_device *tz, unsigned long freq,373373+ u32 *power)374374+{375375+ struct dev_pm_opp *opp;376376+ unsigned long voltage;377377+ struct cpumask *cpumask = &cpufreq_device->allowed_cpus;378378+ unsigned long freq_hz = freq * 1000;379379+380380+ if (!cpufreq_device->plat_get_static_power ||381381+ !cpufreq_device->cpu_dev) {382382+ *power = 0;383383+ return 0;384384+ }385385+386386+ rcu_read_lock();387387+388388+ opp = dev_pm_opp_find_freq_exact(cpufreq_device->cpu_dev, freq_hz,389389+ true);390390+ voltage = dev_pm_opp_get_voltage(opp);391391+392392+ rcu_read_unlock();393393+394394+ if (voltage == 0) {395395+ dev_warn_ratelimited(cpufreq_device->cpu_dev,396396+ "Failed to get voltage for frequency %lu: %ld\n",397397+ freq_hz, IS_ERR(opp) ? PTR_ERR(opp) : 0);398398+ return -EINVAL;399399+ }400400+401401+ return cpufreq_device->plat_get_static_power(cpumask, tz->passive_delay,402402+ voltage, power);403403+}404404+405405+/**406406+ * get_dynamic_power() - calculate the dynamic power407407+ * @cpufreq_device: &cpufreq_cooling_device for this cdev408408+ * @freq: current frequency409409+ *410410+ * Return: the dynamic power consumed by the cpus described by411411+ * @cpufreq_device.412412+ */413413+static u32 get_dynamic_power(struct cpufreq_cooling_device *cpufreq_device,414414+ unsigned long freq)415415+{416416+ u32 raw_cpu_power;417417+418418+ raw_cpu_power = cpu_freq_to_power(cpufreq_device, freq);419419+ return (raw_cpu_power * cpufreq_device->last_load) / 100;238420}239421240422/* cpufreq cooling device callback functions are defined below */···526280 return 0;527281}528282283283+/**284284+ * cpufreq_get_requested_power() - get the current power285285+ * @cdev: &thermal_cooling_device pointer286286+ * @tz: a valid thermal zone device pointer287287+ * @power: pointer in which to store the resulting power288288+ *289289+ * Calculate the current power consumption of the cpus in milliwatts290290+ * and store it in @power. This function should actually calculate291291+ * the requested power, but it's hard to get the frequency that292292+ * cpufreq would have assigned if there were no thermal limits.293293+ * Instead, we calculate the current power on the assumption that the294294+ * immediate future will look like the immediate past.295295+ *296296+ * We use the current frequency and the average load since this297297+ * function was last called. In reality, there could have been298298+ * multiple opps since this function was last called and that affects299299+ * the load calculation. While it's not perfectly accurate, this300300+ * simplification is good enough and works. REVISIT this, as more301301+ * complex code may be needed if experiments show that it's not302302+ * accurate enough.303303+ *304304+ * Return: 0 on success, -E* if getting the static power failed.305305+ */306306+static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,307307+ struct thermal_zone_device *tz,308308+ u32 *power)309309+{310310+ unsigned long freq;311311+ int i = 0, cpu, ret;312312+ u32 static_power, dynamic_power, total_load = 0;313313+ struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;314314+ u32 *load_cpu = NULL;315315+316316+ cpu = cpumask_any_and(&cpufreq_device->allowed_cpus, cpu_online_mask);317317+318318+ /*319319+ * All the CPUs are offline, thus the requested power by320320+ * the cdev is 0321321+ */322322+ if (cpu >= nr_cpu_ids) {323323+ *power = 0;324324+ return 0;325325+ }326326+327327+ freq = cpufreq_quick_get(cpu);328328+329329+ if (trace_thermal_power_cpu_get_power_enabled()) {330330+ u32 ncpus = cpumask_weight(&cpufreq_device->allowed_cpus);331331+332332+ load_cpu = devm_kcalloc(&cdev->device, ncpus, sizeof(*load_cpu),333333+ GFP_KERNEL);334334+ }335335+336336+ for_each_cpu(cpu, &cpufreq_device->allowed_cpus) {337337+ u32 load;338338+339339+ if (cpu_online(cpu))340340+ load = get_load(cpufreq_device, cpu);341341+ else342342+ load = 0;343343+344344+ total_load += load;345345+ if (trace_thermal_power_cpu_limit_enabled() && load_cpu)346346+ load_cpu[i] = load;347347+348348+ i++;349349+ }350350+351351+ cpufreq_device->last_load = total_load;352352+353353+ dynamic_power = get_dynamic_power(cpufreq_device, freq);354354+ ret = get_static_power(cpufreq_device, tz, freq, &static_power);355355+ if (ret) {356356+ if (load_cpu)357357+ devm_kfree(&cdev->device, load_cpu);358358+ return ret;359359+ }360360+361361+ if (load_cpu) {362362+ trace_thermal_power_cpu_get_power(363363+ &cpufreq_device->allowed_cpus,364364+ freq, load_cpu, i, dynamic_power, static_power);365365+366366+ devm_kfree(&cdev->device, load_cpu);367367+ }368368+369369+ *power = static_power + dynamic_power;370370+ return 0;371371+}372372+373373+/**374374+ * cpufreq_state2power() - convert a cpu cdev state to power consumed375375+ * @cdev: &thermal_cooling_device pointer376376+ * @tz: a valid thermal zone device pointer377377+ * @state: cooling device state to be converted378378+ * @power: pointer in which to store the resulting power379379+ *380380+ * Convert cooling device state @state into power consumption in381381+ * milliwatts assuming 100% load. Store the calculated power in382382+ * @power.383383+ *384384+ * Return: 0 on success, -EINVAL if the cooling device state could not385385+ * be converted into a frequency or other -E* if there was an error386386+ * when calculating the static power.387387+ */388388+static int cpufreq_state2power(struct thermal_cooling_device *cdev,389389+ struct thermal_zone_device *tz,390390+ unsigned long state, u32 *power)391391+{392392+ unsigned int freq, num_cpus;393393+ cpumask_t cpumask;394394+ u32 static_power, dynamic_power;395395+ int ret;396396+ struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;397397+398398+ cpumask_and(&cpumask, &cpufreq_device->allowed_cpus, cpu_online_mask);399399+ num_cpus = cpumask_weight(&cpumask);400400+401401+ /* None of our cpus are online, so no power */402402+ if (num_cpus == 0) {403403+ *power = 0;404404+ return 0;405405+ }406406+407407+ freq = cpufreq_device->freq_table[state];408408+ if (!freq)409409+ return -EINVAL;410410+411411+ dynamic_power = cpu_freq_to_power(cpufreq_device, freq) * num_cpus;412412+ ret = get_static_power(cpufreq_device, tz, freq, &static_power);413413+ if (ret)414414+ return ret;415415+416416+ *power = static_power + dynamic_power;417417+ return 0;418418+}419419+420420+/**421421+ * cpufreq_power2state() - convert power to a cooling device state422422+ * @cdev: &thermal_cooling_device pointer423423+ * @tz: a valid thermal zone device pointer424424+ * @power: power in milliwatts to be converted425425+ * @state: pointer in which to store the resulting state426426+ *427427+ * Calculate a cooling device state for the cpus described by @cdev428428+ * that would allow them to consume at most @power mW and store it in429429+ * @state. Note that this calculation depends on external factors430430+ * such as the cpu load or the current static power. Calling this431431+ * function with the same power as input can yield different cooling432432+ * device states depending on those external factors.433433+ *434434+ * Return: 0 on success, -ENODEV if no cpus are online or -EINVAL if435435+ * the calculated frequency could not be converted to a valid state.436436+ * The latter should not happen unless the frequencies available to437437+ * cpufreq have changed since the initialization of the cpu cooling438438+ * device.439439+ */440440+static int cpufreq_power2state(struct thermal_cooling_device *cdev,441441+ struct thermal_zone_device *tz, u32 power,442442+ unsigned long *state)443443+{444444+ unsigned int cpu, cur_freq, target_freq;445445+ int ret;446446+ s32 dyn_power;447447+ u32 last_load, normalised_power, static_power;448448+ struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;449449+450450+ cpu = cpumask_any_and(&cpufreq_device->allowed_cpus, cpu_online_mask);451451+452452+ /* None of our cpus are online */453453+ if (cpu >= nr_cpu_ids)454454+ return -ENODEV;455455+456456+ cur_freq = cpufreq_quick_get(cpu);457457+ ret = get_static_power(cpufreq_device, tz, cur_freq, &static_power);458458+ if (ret)459459+ return ret;460460+461461+ dyn_power = power - static_power;462462+ dyn_power = dyn_power > 0 ? dyn_power : 0;463463+ last_load = cpufreq_device->last_load ?: 1;464464+ normalised_power = (dyn_power * 100) / last_load;465465+ target_freq = cpu_power_to_freq(cpufreq_device, normalised_power);466466+467467+ *state = cpufreq_cooling_get_level(cpu, target_freq);468468+ if (*state == THERMAL_CSTATE_INVALID) {469469+ dev_warn_ratelimited(&cdev->device,470470+ "Failed to convert %dKHz for cpu %d into a cdev state\n",471471+ target_freq, cpu);472472+ return -EINVAL;473473+ }474474+475475+ trace_thermal_power_cpu_limit(&cpufreq_device->allowed_cpus,476476+ target_freq, *state, power);477477+ return 0;478478+}479479+529480/* Bind cpufreq callbacks to thermal cooling device ops */530530-static struct thermal_cooling_device_ops const cpufreq_cooling_ops = {481481+static struct thermal_cooling_device_ops cpufreq_cooling_ops = {531482 .get_max_state = cpufreq_get_max_state,532483 .get_cur_state = cpufreq_get_cur_state,533484 .set_cur_state = cpufreq_set_cur_state,···754311 * @np: a valid struct device_node to the cooling device device tree node755312 * @clip_cpus: cpumask of cpus where the frequency constraints will happen.756313 * Normally this should be same as cpufreq policy->related_cpus.314314+ * @capacitance: dynamic power coefficient for these cpus315315+ * @plat_static_func: function to calculate the static power consumed by these316316+ * cpus (optional)757317 *758318 * This interface function registers the cpufreq cooling device with the name759319 * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq···768322 */769323static struct thermal_cooling_device *770324__cpufreq_cooling_register(struct device_node *np,771771- const struct cpumask *clip_cpus)325325+ const struct cpumask *clip_cpus, u32 capacitance,326326+ get_static_t plat_static_func)772327{773328 struct thermal_cooling_device *cool_dev;774329 struct cpufreq_cooling_device *cpufreq_dev;775330 char dev_name[THERMAL_NAME_LENGTH];776331 struct cpufreq_frequency_table *pos, *table;777777- unsigned int freq, i;332332+ unsigned int freq, i, num_cpus;778333 int ret;779334780335 table = cpufreq_frequency_get_table(cpumask_first(clip_cpus));···788341 if (!cpufreq_dev)789342 return ERR_PTR(-ENOMEM);790343344344+ num_cpus = cpumask_weight(clip_cpus);345345+ cpufreq_dev->time_in_idle = kcalloc(num_cpus,346346+ sizeof(*cpufreq_dev->time_in_idle),347347+ GFP_KERNEL);348348+ if (!cpufreq_dev->time_in_idle) {349349+ cool_dev = ERR_PTR(-ENOMEM);350350+ goto free_cdev;351351+ }352352+353353+ cpufreq_dev->time_in_idle_timestamp =354354+ kcalloc(num_cpus, sizeof(*cpufreq_dev->time_in_idle_timestamp),355355+ GFP_KERNEL);356356+ if (!cpufreq_dev->time_in_idle_timestamp) {357357+ cool_dev = ERR_PTR(-ENOMEM);358358+ goto free_time_in_idle;359359+ }360360+791361 /* Find max levels */792362 cpufreq_for_each_valid_entry(pos, table)793363 cpufreq_dev->max_level++;···813349 cpufreq_dev->max_level, GFP_KERNEL);814350 if (!cpufreq_dev->freq_table) {815351 cool_dev = ERR_PTR(-ENOMEM);816816- goto free_cdev;352352+ goto free_time_in_idle_timestamp;817353 }818354819355 /* max_level is an index, not a counter */820356 cpufreq_dev->max_level--;821357822358 cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus);359359+360360+ if (capacitance) {361361+ cpufreq_cooling_ops.get_requested_power =362362+ cpufreq_get_requested_power;363363+ cpufreq_cooling_ops.state2power = cpufreq_state2power;364364+ cpufreq_cooling_ops.power2state = cpufreq_power2state;365365+ cpufreq_dev->plat_get_static_power = plat_static_func;366366+367367+ ret = build_dyn_power_table(cpufreq_dev, capacitance);368368+ if (ret) {369369+ cool_dev = ERR_PTR(ret);370370+ goto free_table;371371+ }372372+ }823373824374 ret = get_idr(&cpufreq_idr, &cpufreq_dev->id);825375 if (ret) {···880402 release_idr(&cpufreq_idr, cpufreq_dev->id);881403free_table:882404 kfree(cpufreq_dev->freq_table);405405+free_time_in_idle_timestamp:406406+ kfree(cpufreq_dev->time_in_idle_timestamp);407407+free_time_in_idle:408408+ kfree(cpufreq_dev->time_in_idle);883409free_cdev:884410 kfree(cpufreq_dev);885411···904422struct thermal_cooling_device *905423cpufreq_cooling_register(const struct cpumask *clip_cpus)906424{907907- return __cpufreq_cooling_register(NULL, clip_cpus);425425+ return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL);908426}909427EXPORT_SYMBOL_GPL(cpufreq_cooling_register);910428···928446 if (!np)929447 return ERR_PTR(-EINVAL);930448931931- return __cpufreq_cooling_register(np, clip_cpus);449449+ return __cpufreq_cooling_register(np, clip_cpus, 0, NULL);932450}933451EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);452452+453453+/**454454+ * cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions455455+ * @clip_cpus: cpumask of cpus where the frequency constraints will happen456456+ * @capacitance: dynamic power coefficient for these cpus457457+ * @plat_static_func: function to calculate the static power consumed by these458458+ * cpus (optional)459459+ *460460+ * This interface function registers the cpufreq cooling device with461461+ * the name "thermal-cpufreq-%x". This api can support multiple462462+ * instances of cpufreq cooling devices. Using this function, the463463+ * cooling device will implement the power extensions by using a464464+ * simple cpu power model. The cpus must have registered their OPPs465465+ * using the OPP library.466466+ *467467+ * An optional @plat_static_func may be provided to calculate the468468+ * static power consumed by these cpus. If the platform's static469469+ * power consumption is unknown or negligible, make it NULL.470470+ *471471+ * Return: a valid struct thermal_cooling_device pointer on success,472472+ * on failure, it returns a corresponding ERR_PTR().473473+ */474474+struct thermal_cooling_device *475475+cpufreq_power_cooling_register(const struct cpumask *clip_cpus, u32 capacitance,476476+ get_static_t plat_static_func)477477+{478478+ return __cpufreq_cooling_register(NULL, clip_cpus, capacitance,479479+ plat_static_func);480480+}481481+EXPORT_SYMBOL(cpufreq_power_cooling_register);482482+483483+/**484484+ * of_cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions485485+ * @np: a valid struct device_node to the cooling device device tree node486486+ * @clip_cpus: cpumask of cpus where the frequency constraints will happen487487+ * @capacitance: dynamic power coefficient for these cpus488488+ * @plat_static_func: function to calculate the static power consumed by these489489+ * cpus (optional)490490+ *491491+ * This interface function registers the cpufreq cooling device with492492+ * the name "thermal-cpufreq-%x". This api can support multiple493493+ * instances of cpufreq cooling devices. Using this API, the cpufreq494494+ * cooling device will be linked to the device tree node provided.495495+ * Using this function, the cooling device will implement the power496496+ * extensions by using a simple cpu power model. The cpus must have497497+ * registered their OPPs using the OPP library.498498+ *499499+ * An optional @plat_static_func may be provided to calculate the500500+ * static power consumed by these cpus. If the platform's static501501+ * power consumption is unknown or negligible, make it NULL.502502+ *503503+ * Return: a valid struct thermal_cooling_device pointer on success,504504+ * on failure, it returns a corresponding ERR_PTR().505505+ */506506+struct thermal_cooling_device *507507+of_cpufreq_power_cooling_register(struct device_node *np,508508+ const struct cpumask *clip_cpus,509509+ u32 capacitance,510510+ get_static_t plat_static_func)511511+{512512+ if (!np)513513+ return ERR_PTR(-EINVAL);514514+515515+ return __cpufreq_cooling_register(np, clip_cpus, capacitance,516516+ plat_static_func);517517+}518518+EXPORT_SYMBOL(of_cpufreq_power_cooling_register);934519935520/**936521 * cpufreq_cooling_unregister - function to remove cpufreq cooling device.···10244751025476 thermal_cooling_device_unregister(cpufreq_dev->cool_dev);1026477 release_idr(&cpufreq_idr, cpufreq_dev->id);478478+ kfree(cpufreq_dev->time_in_idle_timestamp);479479+ kfree(cpufreq_dev->time_in_idle);1027480 kfree(cpufreq_dev->freq_table);1028481 kfree(cpufreq_dev);1029482}
+1-1
drivers/thermal/db8500_thermal.c
···7676 upper = lower = i > max_state ? max_state : i;77777878 ret = thermal_zone_bind_cooling_device(thermal, i, cdev,7979- upper, lower);7979+ upper, lower, THERMAL_WEIGHT_DEFAULT);80808181 dev_info(&cdev->device, "%s bind to %d: %d-%s\n", cdev->type,8282 i, ret, ret ? "fail" : "succeed");
+24-19
drivers/thermal/fair_share.c
···5959}60606161static long get_target_state(struct thermal_zone_device *tz,6262- struct thermal_cooling_device *cdev, int weight, int level)6262+ struct thermal_cooling_device *cdev, int percentage, int level)6363{6464 unsigned long max_state;65656666 cdev->ops->get_max_state(cdev, &max_state);67676868- return (long)(weight * level * max_state) / (100 * tz->trips);6868+ return (long)(percentage * level * max_state) / (100 * tz->trips);6969}70707171/**7272- * fair_share_throttle - throttles devices asscciated with the given zone7272+ * fair_share_throttle - throttles devices associated with the given zone7373 * @tz - thermal_zone_device7474 *7575 * Throttling Logic: This uses three parameters to calculate the new···7777 *7878 * Parameters used for Throttling:7979 * P1. max_state: Maximum throttle state exposed by the cooling device.8080- * P2. weight[i]/100:8080+ * P2. percentage[i]/100:8181 * How 'effective' the 'i'th device is, in cooling the given zone.8282 * P3. cur_trip_level/max_no_of_trips:8383 * This describes the extent to which the devices should be throttled.···8888 */8989static int fair_share_throttle(struct thermal_zone_device *tz, int trip)9090{9191- const struct thermal_zone_params *tzp;9292- struct thermal_cooling_device *cdev;9391 struct thermal_instance *instance;9494- int i;9292+ int total_weight = 0;9393+ int total_instance = 0;9594 int cur_trip_level = get_trip_level(tz);96959797- if (!tz->tzp || !tz->tzp->tbp)9898- return -EINVAL;9999-100100- tzp = tz->tzp;101101-102102- for (i = 0; i < tzp->num_tbps; i++) {103103- if (!tzp->tbp[i].cdev)9696+ list_for_each_entry(instance, &tz->thermal_instances, tz_node) {9797+ if (instance->trip != trip)10498 continue;10599106106- cdev = tzp->tbp[i].cdev;107107- instance = get_thermal_instance(tz, cdev, trip);108108- if (!instance)100100+ total_weight += instance->weight;101101+ total_instance++;102102+ }103103+104104+ list_for_each_entry(instance, &tz->thermal_instances, tz_node) {105105+ int percentage;106106+ struct thermal_cooling_device *cdev = instance->cdev;107107+108108+ if (instance->trip != trip)109109 continue;110110111111- instance->target = get_target_state(tz, cdev,112112- tzp->tbp[i].weight, cur_trip_level);111111+ if (!total_weight)112112+ percentage = 100 / total_instance;113113+ else114114+ percentage = (instance->weight * 100) / total_weight;115115+116116+ instance->target = get_target_state(tz, cdev, percentage,117117+ cur_trip_level);113118114119 instance->cdev->updated = false;115120 thermal_cdev_update(cdev);
+421
drivers/thermal/hisi_thermal.c
···11+/*22+ * Hisilicon thermal sensor driver33+ *44+ * Copyright (c) 2014-2015 Hisilicon Limited.55+ * Copyright (c) 2014-2015 Linaro Limited.66+ *77+ * Xinwei Kong <kong.kongxinwei@hisilicon.com>88+ * Leo Yan <leo.yan@linaro.org>99+ *1010+ * This program is free software; you can redistribute it and/or modify1111+ * it under the terms of the GNU General Public License version 2 as1212+ * published by the Free Software Foundation.1313+ *1414+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any1515+ * kind, whether express or implied; without even the implied warranty1616+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1717+ * GNU General Public License for more details.1818+ */1919+2020+#include <linux/cpufreq.h>2121+#include <linux/delay.h>2222+#include <linux/interrupt.h>2323+#include <linux/module.h>2424+#include <linux/platform_device.h>2525+#include <linux/io.h>2626+2727+#include "thermal_core.h"2828+2929+#define TEMP0_TH (0x4)3030+#define TEMP0_RST_TH (0x8)3131+#define TEMP0_CFG (0xC)3232+#define TEMP0_EN (0x10)3333+#define TEMP0_INT_EN (0x14)3434+#define TEMP0_INT_CLR (0x18)3535+#define TEMP0_RST_MSK (0x1C)3636+#define TEMP0_VALUE (0x28)3737+3838+#define HISI_TEMP_BASE (-60)3939+#define HISI_TEMP_RESET (100000)4040+4141+#define HISI_MAX_SENSORS 44242+4343+struct hisi_thermal_sensor {4444+ struct hisi_thermal_data *thermal;4545+ struct thermal_zone_device *tzd;4646+4747+ long sensor_temp;4848+ uint32_t id;4949+ uint32_t thres_temp;5050+};5151+5252+struct hisi_thermal_data {5353+ struct mutex thermal_lock; /* protects register data */5454+ struct platform_device *pdev;5555+ struct clk *clk;5656+ struct hisi_thermal_sensor sensors[HISI_MAX_SENSORS];5757+5858+ int irq, irq_bind_sensor;5959+ bool irq_enabled;6060+6161+ void __iomem *regs;6262+};6363+6464+/* in millicelsius */6565+static inline int _step_to_temp(int step)6666+{6767+ /*6868+ * Every step equals (1 * 200) / 255 celsius, and finally6969+ * need convert to millicelsius.7070+ */7171+ return (HISI_TEMP_BASE + (step * 200 / 255)) * 1000;7272+}7373+7474+static inline long _temp_to_step(long temp)7575+{7676+ return ((temp / 1000 - HISI_TEMP_BASE) * 255 / 200);7777+}7878+7979+static long hisi_thermal_get_sensor_temp(struct hisi_thermal_data *data,8080+ struct hisi_thermal_sensor *sensor)8181+{8282+ long val;8383+8484+ mutex_lock(&data->thermal_lock);8585+8686+ /* disable interrupt */8787+ writel(0x0, data->regs + TEMP0_INT_EN);8888+ writel(0x1, data->regs + TEMP0_INT_CLR);8989+9090+ /* disable module firstly */9191+ writel(0x0, data->regs + TEMP0_EN);9292+9393+ /* select sensor id */9494+ writel((sensor->id << 12), data->regs + TEMP0_CFG);9595+9696+ /* enable module */9797+ writel(0x1, data->regs + TEMP0_EN);9898+9999+ usleep_range(3000, 5000);100100+101101+ val = readl(data->regs + TEMP0_VALUE);102102+ val = _step_to_temp(val);103103+104104+ mutex_unlock(&data->thermal_lock);105105+106106+ return val;107107+}108108+109109+static void hisi_thermal_enable_bind_irq_sensor110110+ (struct hisi_thermal_data *data)111111+{112112+ struct hisi_thermal_sensor *sensor;113113+114114+ mutex_lock(&data->thermal_lock);115115+116116+ sensor = &data->sensors[data->irq_bind_sensor];117117+118118+ /* setting the hdak time */119119+ writel(0x0, data->regs + TEMP0_CFG);120120+121121+ /* disable module firstly */122122+ writel(0x0, data->regs + TEMP0_RST_MSK);123123+ writel(0x0, data->regs + TEMP0_EN);124124+125125+ /* select sensor id */126126+ writel((sensor->id << 12), data->regs + TEMP0_CFG);127127+128128+ /* enable for interrupt */129129+ writel(_temp_to_step(sensor->thres_temp) | 0x0FFFFFF00,130130+ data->regs + TEMP0_TH);131131+132132+ writel(_temp_to_step(HISI_TEMP_RESET), data->regs + TEMP0_RST_TH);133133+134134+ /* enable module */135135+ writel(0x1, data->regs + TEMP0_RST_MSK);136136+ writel(0x1, data->regs + TEMP0_EN);137137+138138+ writel(0x0, data->regs + TEMP0_INT_CLR);139139+ writel(0x1, data->regs + TEMP0_INT_EN);140140+141141+ usleep_range(3000, 5000);142142+143143+ mutex_unlock(&data->thermal_lock);144144+}145145+146146+static void hisi_thermal_disable_sensor(struct hisi_thermal_data *data)147147+{148148+ mutex_lock(&data->thermal_lock);149149+150150+ /* disable sensor module */151151+ writel(0x0, data->regs + TEMP0_INT_EN);152152+ writel(0x0, data->regs + TEMP0_RST_MSK);153153+ writel(0x0, data->regs + TEMP0_EN);154154+155155+ mutex_unlock(&data->thermal_lock);156156+}157157+158158+static int hisi_thermal_get_temp(void *_sensor, long *temp)159159+{160160+ struct hisi_thermal_sensor *sensor = _sensor;161161+ struct hisi_thermal_data *data = sensor->thermal;162162+163163+ int sensor_id = 0, i;164164+ long max_temp = 0;165165+166166+ *temp = hisi_thermal_get_sensor_temp(data, sensor);167167+168168+ sensor->sensor_temp = *temp;169169+170170+ for (i = 0; i < HISI_MAX_SENSORS; i++) {171171+ if (data->sensors[i].sensor_temp >= max_temp) {172172+ max_temp = data->sensors[i].sensor_temp;173173+ sensor_id = i;174174+ }175175+ }176176+177177+ mutex_lock(&data->thermal_lock);178178+ data->irq_bind_sensor = sensor_id;179179+ mutex_unlock(&data->thermal_lock);180180+181181+ dev_dbg(&data->pdev->dev, "id=%d, irq=%d, temp=%ld, thres=%d\n",182182+ sensor->id, data->irq_enabled, *temp, sensor->thres_temp);183183+ /*184184+ * Bind irq to sensor for two cases:185185+ * Reenable alarm IRQ if temperature below threshold;186186+ * if irq has been enabled, always set it;187187+ */188188+ if (data->irq_enabled) {189189+ hisi_thermal_enable_bind_irq_sensor(data);190190+ return 0;191191+ }192192+193193+ if (max_temp < sensor->thres_temp) {194194+ data->irq_enabled = true;195195+ hisi_thermal_enable_bind_irq_sensor(data);196196+ enable_irq(data->irq);197197+ }198198+199199+ return 0;200200+}201201+202202+static struct thermal_zone_of_device_ops hisi_of_thermal_ops = {203203+ .get_temp = hisi_thermal_get_temp,204204+};205205+206206+static irqreturn_t hisi_thermal_alarm_irq(int irq, void *dev)207207+{208208+ struct hisi_thermal_data *data = dev;209209+210210+ disable_irq_nosync(irq);211211+ data->irq_enabled = false;212212+213213+ return IRQ_WAKE_THREAD;214214+}215215+216216+static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)217217+{218218+ struct hisi_thermal_data *data = dev;219219+ struct hisi_thermal_sensor *sensor;220220+ int i;221221+222222+ mutex_lock(&data->thermal_lock);223223+ sensor = &data->sensors[data->irq_bind_sensor];224224+225225+ dev_crit(&data->pdev->dev, "THERMAL ALARM: T > %d\n",226226+ sensor->thres_temp / 1000);227227+ mutex_unlock(&data->thermal_lock);228228+229229+ for (i = 0; i < HISI_MAX_SENSORS; i++)230230+ thermal_zone_device_update(data->sensors[i].tzd);231231+232232+ return IRQ_HANDLED;233233+}234234+235235+static int hisi_thermal_register_sensor(struct platform_device *pdev,236236+ struct hisi_thermal_data *data,237237+ struct hisi_thermal_sensor *sensor,238238+ int index)239239+{240240+ int ret, i;241241+ const struct thermal_trip *trip;242242+243243+ sensor->id = index;244244+ sensor->thermal = data;245245+246246+ sensor->tzd = thermal_zone_of_sensor_register(&pdev->dev, sensor->id,247247+ sensor, &hisi_of_thermal_ops);248248+ if (IS_ERR(sensor->tzd)) {249249+ ret = PTR_ERR(sensor->tzd);250250+ dev_err(&pdev->dev, "failed to register sensor id %d: %d\n",251251+ sensor->id, ret);252252+ return ret;253253+ }254254+255255+ trip = of_thermal_get_trip_points(sensor->tzd);256256+257257+ for (i = 0; i < of_thermal_get_ntrips(sensor->tzd); i++) {258258+ if (trip[i].type == THERMAL_TRIP_PASSIVE) {259259+ sensor->thres_temp = trip[i].temperature;260260+ break;261261+ }262262+ }263263+264264+ return 0;265265+}266266+267267+static const struct of_device_id of_hisi_thermal_match[] = {268268+ { .compatible = "hisilicon,tsensor" },269269+ { /* end */ }270270+};271271+MODULE_DEVICE_TABLE(of, of_hisi_thermal_match);272272+273273+static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,274274+ bool on)275275+{276276+ struct thermal_zone_device *tzd = sensor->tzd;277277+278278+ tzd->ops->set_mode(tzd,279279+ on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);280280+}281281+282282+static int hisi_thermal_probe(struct platform_device *pdev)283283+{284284+ struct hisi_thermal_data *data;285285+ struct resource *res;286286+ int i;287287+ int ret;288288+289289+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);290290+ if (!data)291291+ return -ENOMEM;292292+293293+ mutex_init(&data->thermal_lock);294294+ data->pdev = pdev;295295+296296+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);297297+ data->regs = devm_ioremap_resource(&pdev->dev, res);298298+ if (IS_ERR(data->regs)) {299299+ dev_err(&pdev->dev, "failed to get io address\n");300300+ return PTR_ERR(data->regs);301301+ }302302+303303+ data->irq = platform_get_irq(pdev, 0);304304+ if (data->irq < 0)305305+ return data->irq;306306+307307+ ret = devm_request_threaded_irq(&pdev->dev, data->irq,308308+ hisi_thermal_alarm_irq,309309+ hisi_thermal_alarm_irq_thread,310310+ 0, "hisi_thermal", data);311311+ if (ret < 0) {312312+ dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);313313+ return ret;314314+ }315315+316316+ platform_set_drvdata(pdev, data);317317+318318+ data->clk = devm_clk_get(&pdev->dev, "thermal_clk");319319+ if (IS_ERR(data->clk)) {320320+ ret = PTR_ERR(data->clk);321321+ if (ret != -EPROBE_DEFER)322322+ dev_err(&pdev->dev,323323+ "failed to get thermal clk: %d\n", ret);324324+ return ret;325325+ }326326+327327+ /* enable clock for thermal */328328+ ret = clk_prepare_enable(data->clk);329329+ if (ret) {330330+ dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret);331331+ return ret;332332+ }333333+334334+ for (i = 0; i < HISI_MAX_SENSORS; ++i) {335335+ ret = hisi_thermal_register_sensor(pdev, data,336336+ &data->sensors[i], i);337337+ if (ret) {338338+ dev_err(&pdev->dev,339339+ "failed to register thermal sensor: %d\n", ret);340340+ goto err_get_sensor_data;341341+ }342342+ }343343+344344+ hisi_thermal_enable_bind_irq_sensor(data);345345+ data->irq_enabled = true;346346+347347+ for (i = 0; i < HISI_MAX_SENSORS; i++)348348+ hisi_thermal_toggle_sensor(&data->sensors[i], true);349349+350350+ return 0;351351+352352+err_get_sensor_data:353353+ clk_disable_unprepare(data->clk);354354+355355+ return ret;356356+}357357+358358+static int hisi_thermal_remove(struct platform_device *pdev)359359+{360360+ struct hisi_thermal_data *data = platform_get_drvdata(pdev);361361+ int i;362362+363363+ for (i = 0; i < HISI_MAX_SENSORS; i++) {364364+ struct hisi_thermal_sensor *sensor = &data->sensors[i];365365+366366+ hisi_thermal_toggle_sensor(sensor, false);367367+ thermal_zone_of_sensor_unregister(&pdev->dev, sensor->tzd);368368+ }369369+370370+ hisi_thermal_disable_sensor(data);371371+ clk_disable_unprepare(data->clk);372372+373373+ return 0;374374+}375375+376376+#ifdef CONFIG_PM_SLEEP377377+static int hisi_thermal_suspend(struct device *dev)378378+{379379+ struct hisi_thermal_data *data = dev_get_drvdata(dev);380380+381381+ hisi_thermal_disable_sensor(data);382382+ data->irq_enabled = false;383383+384384+ clk_disable_unprepare(data->clk);385385+386386+ return 0;387387+}388388+389389+static int hisi_thermal_resume(struct device *dev)390390+{391391+ struct hisi_thermal_data *data = dev_get_drvdata(dev);392392+393393+ clk_prepare_enable(data->clk);394394+395395+ data->irq_enabled = true;396396+ hisi_thermal_enable_bind_irq_sensor(data);397397+398398+ return 0;399399+}400400+#endif401401+402402+static SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops,403403+ hisi_thermal_suspend, hisi_thermal_resume);404404+405405+static struct platform_driver hisi_thermal_driver = {406406+ .driver = {407407+ .name = "hisi_thermal",408408+ .owner = THIS_MODULE,409409+ .pm = &hisi_thermal_pm_ops,410410+ .of_match_table = of_hisi_thermal_match,411411+ },412412+ .probe = hisi_thermal_probe,413413+ .remove = hisi_thermal_remove,414414+};415415+416416+module_platform_driver(hisi_thermal_driver);417417+418418+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");419419+MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");420420+MODULE_DESCRIPTION("Hisilicon thermal driver");421421+MODULE_LICENSE("GPL v2");
+2-1
drivers/thermal/imx_thermal.c
···306306307307 ret = thermal_zone_bind_cooling_device(tz, IMX_TRIP_PASSIVE, cdev,308308 THERMAL_NO_LIMIT,309309- THERMAL_NO_LIMIT);309309+ THERMAL_NO_LIMIT,310310+ THERMAL_WEIGHT_DEFAULT);310311 if (ret) {311312 dev_err(&tz->device,312313 "binding zone %s with cdev %s failed:%d\n",
+36-5
drivers/thermal/of-thermal.c
···5858 * @mode: current thermal zone device mode (enabled/disabled)5959 * @passive_delay: polling interval while passive cooling is activated6060 * @polling_delay: zone polling interval6161+ * @slope: slope of the temperature adjustment curve6262+ * @offset: offset of the temperature adjustment curve6163 * @ntrips: number of trip points6264 * @trips: an array of trip points (0..ntrips - 1)6365 * @num_tbps: number of thermal bind params···7270 enum thermal_device_mode mode;7371 int passive_delay;7472 int polling_delay;7373+ int slope;7474+ int offset;75757676 /* trip data */7777 int ntrips;···231227 ret = thermal_zone_bind_cooling_device(thermal,232228 tbp->trip_id, cdev,233229 tbp->max,234234- tbp->min);230230+ tbp->min,231231+ tbp->usage);235232 if (ret)236233 return ret;237234 }···586581 u32 prop;587582588583 /* Default weight. Usage is optional */589589- __tbp->usage = 0;584584+ __tbp->usage = THERMAL_WEIGHT_DEFAULT;590585 ret = of_property_read_u32(np, "contribution", &prop);591586 if (ret == 0)592587 __tbp->usage = prop;···720715 * @np parameter and fills the read data into a __thermal_zone data structure721716 * and return this pointer.722717 *723723- * TODO: Missing properties to parse: thermal-sensor-names and coefficients718718+ * TODO: Missing properties to parse: thermal-sensor-names724719 *725720 * Return: On success returns a valid struct __thermal_zone,726721 * otherwise, it returns a corresponding ERR_PTR(). Caller must···732727 struct device_node *child = NULL, *gchild;733728 struct __thermal_zone *tz;734729 int ret, i;735735- u32 prop;730730+ u32 prop, coef[2];736731737732 if (!np) {738733 pr_err("no thermal zone np\n");···756751 goto free_tz;757752 }758753 tz->polling_delay = prop;754754+755755+ /*756756+ * REVIST: for now, the thermal framework supports only757757+ * one sensor per thermal zone. Thus, we are considering758758+ * only the first two values as slope and offset.759759+ */760760+ ret = of_property_read_u32_array(np, "coefficients", coef, 2);761761+ if (ret == 0) {762762+ tz->slope = coef[0];763763+ tz->offset = coef[1];764764+ } else {765765+ tz->slope = 1;766766+ tz->offset = 0;767767+ }759768760769 /* trips */761770 child = of_get_child_by_name(np, "trips");···884865 for_each_child_of_node(np, child) {885866 struct thermal_zone_device *zone;886867 struct thermal_zone_params *tzp;868868+ int i, mask = 0;869869+ u32 prop;887870888871 /* Check whether child is enabled or not */889872 if (!of_device_is_available(child))···912891 /* No hwmon because there might be hwmon drivers registering */913892 tzp->no_hwmon = true;914893894894+ if (!of_property_read_u32(child, "sustainable-power", &prop))895895+ tzp->sustainable_power = prop;896896+897897+ for (i = 0; i < tz->ntrips; i++)898898+ mask |= 1 << i;899899+900900+ /* these two are left for temperature drivers to use */901901+ tzp->slope = tz->slope;902902+ tzp->offset = tz->offset;903903+915904 zone = thermal_zone_device_register(child->name, tz->ntrips,916916- 0, tz,905905+ mask, tz,917906 ops, tzp,918907 tz->passive_delay,919908 tz->polling_delay);
+539
drivers/thermal/power_allocator.c
···11+/*22+ * A power allocator to manage temperature33+ *44+ * Copyright (C) 2014 ARM Ltd.55+ *66+ * This program is free software; you can redistribute it and/or modify77+ * it under the terms of the GNU General Public License version 2 as88+ * published by the Free Software Foundation.99+ *1010+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any1111+ * kind, whether express or implied; without even the implied warranty1212+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1313+ * GNU General Public License for more details.1414+ */1515+1616+#define pr_fmt(fmt) "Power allocator: " fmt1717+1818+#include <linux/rculist.h>1919+#include <linux/slab.h>2020+#include <linux/thermal.h>2121+2222+#define CREATE_TRACE_POINTS2323+#include <trace/events/thermal_power_allocator.h>2424+2525+#include "thermal_core.h"2626+2727+#define FRAC_BITS 102828+#define int_to_frac(x) ((x) << FRAC_BITS)2929+#define frac_to_int(x) ((x) >> FRAC_BITS)3030+3131+/**3232+ * mul_frac() - multiply two fixed-point numbers3333+ * @x: first multiplicand3434+ * @y: second multiplicand3535+ *3636+ * Return: the result of multiplying two fixed-point numbers. The3737+ * result is also a fixed-point number.3838+ */3939+static inline s64 mul_frac(s64 x, s64 y)4040+{4141+ return (x * y) >> FRAC_BITS;4242+}4343+4444+/**4545+ * div_frac() - divide two fixed-point numbers4646+ * @x: the dividend4747+ * @y: the divisor4848+ *4949+ * Return: the result of dividing two fixed-point numbers. The5050+ * result is also a fixed-point number.5151+ */5252+static inline s64 div_frac(s64 x, s64 y)5353+{5454+ return div_s64(x << FRAC_BITS, y);5555+}5656+5757+/**5858+ * struct power_allocator_params - parameters for the power allocator governor5959+ * @err_integral: accumulated error in the PID controller.6060+ * @prev_err: error in the previous iteration of the PID controller.6161+ * Used to calculate the derivative term.6262+ * @trip_switch_on: first passive trip point of the thermal zone. The6363+ * governor switches on when this trip point is crossed.6464+ * @trip_max_desired_temperature: last passive trip point of the thermal6565+ * zone. The temperature we are6666+ * controlling for.6767+ */6868+struct power_allocator_params {6969+ s64 err_integral;7070+ s32 prev_err;7171+ int trip_switch_on;7272+ int trip_max_desired_temperature;7373+};7474+7575+/**7676+ * pid_controller() - PID controller7777+ * @tz: thermal zone we are operating in7878+ * @current_temp: the current temperature in millicelsius7979+ * @control_temp: the target temperature in millicelsius8080+ * @max_allocatable_power: maximum allocatable power for this thermal zone8181+ *8282+ * This PID controller increases the available power budget so that the8383+ * temperature of the thermal zone gets as close as possible to8484+ * @control_temp and limits the power if it exceeds it. k_po is the8585+ * proportional term when we are overshooting, k_pu is the8686+ * proportional term when we are undershooting. integral_cutoff is a8787+ * threshold below which we stop accumulating the error. The8888+ * accumulated error is only valid if the requested power will make8989+ * the system warmer. If the system is mostly idle, there's no point9090+ * in accumulating positive error.9191+ *9292+ * Return: The power budget for the next period.9393+ */9494+static u32 pid_controller(struct thermal_zone_device *tz,9595+ unsigned long current_temp,9696+ unsigned long control_temp,9797+ u32 max_allocatable_power)9898+{9999+ s64 p, i, d, power_range;100100+ s32 err, max_power_frac;101101+ struct power_allocator_params *params = tz->governor_data;102102+103103+ max_power_frac = int_to_frac(max_allocatable_power);104104+105105+ err = ((s32)control_temp - (s32)current_temp);106106+ err = int_to_frac(err);107107+108108+ /* Calculate the proportional term */109109+ p = mul_frac(err < 0 ? tz->tzp->k_po : tz->tzp->k_pu, err);110110+111111+ /*112112+ * Calculate the integral term113113+ *114114+ * if the error is less than cut off allow integration (but115115+ * the integral is limited to max power)116116+ */117117+ i = mul_frac(tz->tzp->k_i, params->err_integral);118118+119119+ if (err < int_to_frac(tz->tzp->integral_cutoff)) {120120+ s64 i_next = i + mul_frac(tz->tzp->k_i, err);121121+122122+ if (abs64(i_next) < max_power_frac) {123123+ i = i_next;124124+ params->err_integral += err;125125+ }126126+ }127127+128128+ /*129129+ * Calculate the derivative term130130+ *131131+ * We do err - prev_err, so with a positive k_d, a decreasing132132+ * error (i.e. driving closer to the line) results in less133133+ * power being applied, slowing down the controller)134134+ */135135+ d = mul_frac(tz->tzp->k_d, err - params->prev_err);136136+ d = div_frac(d, tz->passive_delay);137137+ params->prev_err = err;138138+139139+ power_range = p + i + d;140140+141141+ /* feed-forward the known sustainable dissipatable power */142142+ power_range = tz->tzp->sustainable_power + frac_to_int(power_range);143143+144144+ power_range = clamp(power_range, (s64)0, (s64)max_allocatable_power);145145+146146+ trace_thermal_power_allocator_pid(tz, frac_to_int(err),147147+ frac_to_int(params->err_integral),148148+ frac_to_int(p), frac_to_int(i),149149+ frac_to_int(d), power_range);150150+151151+ return power_range;152152+}153153+154154+/**155155+ * divvy_up_power() - divvy the allocated power between the actors156156+ * @req_power: each actor's requested power157157+ * @max_power: each actor's maximum available power158158+ * @num_actors: size of the @req_power, @max_power and @granted_power's array159159+ * @total_req_power: sum of @req_power160160+ * @power_range: total allocated power161161+ * @granted_power: output array: each actor's granted power162162+ * @extra_actor_power: an appropriately sized array to be used in the163163+ * function as temporary storage of the extra power given164164+ * to the actors165165+ *166166+ * This function divides the total allocated power (@power_range)167167+ * fairly between the actors. It first tries to give each actor a168168+ * share of the @power_range according to how much power it requested169169+ * compared to the rest of the actors. For example, if only one actor170170+ * requests power, then it receives all the @power_range. If171171+ * three actors each requests 1mW, each receives a third of the172172+ * @power_range.173173+ *174174+ * If any actor received more than their maximum power, then that175175+ * surplus is re-divvied among the actors based on how far they are176176+ * from their respective maximums.177177+ *178178+ * Granted power for each actor is written to @granted_power, which179179+ * should've been allocated by the calling function.180180+ */181181+static void divvy_up_power(u32 *req_power, u32 *max_power, int num_actors,182182+ u32 total_req_power, u32 power_range,183183+ u32 *granted_power, u32 *extra_actor_power)184184+{185185+ u32 extra_power, capped_extra_power;186186+ int i;187187+188188+ /*189189+ * Prevent division by 0 if none of the actors request power.190190+ */191191+ if (!total_req_power)192192+ total_req_power = 1;193193+194194+ capped_extra_power = 0;195195+ extra_power = 0;196196+ for (i = 0; i < num_actors; i++) {197197+ u64 req_range = req_power[i] * power_range;198198+199199+ granted_power[i] = DIV_ROUND_CLOSEST_ULL(req_range,200200+ total_req_power);201201+202202+ if (granted_power[i] > max_power[i]) {203203+ extra_power += granted_power[i] - max_power[i];204204+ granted_power[i] = max_power[i];205205+ }206206+207207+ extra_actor_power[i] = max_power[i] - granted_power[i];208208+ capped_extra_power += extra_actor_power[i];209209+ }210210+211211+ if (!extra_power)212212+ return;213213+214214+ /*215215+ * Re-divvy the reclaimed extra among actors based on216216+ * how far they are from the max217217+ */218218+ extra_power = min(extra_power, capped_extra_power);219219+ if (capped_extra_power > 0)220220+ for (i = 0; i < num_actors; i++)221221+ granted_power[i] += (extra_actor_power[i] *222222+ extra_power) / capped_extra_power;223223+}224224+225225+static int allocate_power(struct thermal_zone_device *tz,226226+ unsigned long current_temp,227227+ unsigned long control_temp)228228+{229229+ struct thermal_instance *instance;230230+ struct power_allocator_params *params = tz->governor_data;231231+ u32 *req_power, *max_power, *granted_power, *extra_actor_power;232232+ u32 total_req_power, max_allocatable_power;233233+ u32 total_granted_power, power_range;234234+ int i, num_actors, total_weight, ret = 0;235235+ int trip_max_desired_temperature = params->trip_max_desired_temperature;236236+237237+ mutex_lock(&tz->lock);238238+239239+ num_actors = 0;240240+ total_weight = 0;241241+ list_for_each_entry(instance, &tz->thermal_instances, tz_node) {242242+ if ((instance->trip == trip_max_desired_temperature) &&243243+ cdev_is_power_actor(instance->cdev)) {244244+ num_actors++;245245+ total_weight += instance->weight;246246+ }247247+ }248248+249249+ /*250250+ * We need to allocate three arrays of the same size:251251+ * req_power, max_power and granted_power. They are going to252252+ * be needed until this function returns. Allocate them all253253+ * in one go to simplify the allocation and deallocation254254+ * logic.255255+ */256256+ BUILD_BUG_ON(sizeof(*req_power) != sizeof(*max_power));257257+ BUILD_BUG_ON(sizeof(*req_power) != sizeof(*granted_power));258258+ BUILD_BUG_ON(sizeof(*req_power) != sizeof(*extra_actor_power));259259+ req_power = devm_kcalloc(&tz->device, num_actors * 4,260260+ sizeof(*req_power), GFP_KERNEL);261261+ if (!req_power) {262262+ ret = -ENOMEM;263263+ goto unlock;264264+ }265265+266266+ max_power = &req_power[num_actors];267267+ granted_power = &req_power[2 * num_actors];268268+ extra_actor_power = &req_power[3 * num_actors];269269+270270+ i = 0;271271+ total_req_power = 0;272272+ max_allocatable_power = 0;273273+274274+ list_for_each_entry(instance, &tz->thermal_instances, tz_node) {275275+ int weight;276276+ struct thermal_cooling_device *cdev = instance->cdev;277277+278278+ if (instance->trip != trip_max_desired_temperature)279279+ continue;280280+281281+ if (!cdev_is_power_actor(cdev))282282+ continue;283283+284284+ if (cdev->ops->get_requested_power(cdev, tz, &req_power[i]))285285+ continue;286286+287287+ if (!total_weight)288288+ weight = 1 << FRAC_BITS;289289+ else290290+ weight = instance->weight;291291+292292+ req_power[i] = frac_to_int(weight * req_power[i]);293293+294294+ if (power_actor_get_max_power(cdev, tz, &max_power[i]))295295+ continue;296296+297297+ total_req_power += req_power[i];298298+ max_allocatable_power += max_power[i];299299+300300+ i++;301301+ }302302+303303+ power_range = pid_controller(tz, current_temp, control_temp,304304+ max_allocatable_power);305305+306306+ divvy_up_power(req_power, max_power, num_actors, total_req_power,307307+ power_range, granted_power, extra_actor_power);308308+309309+ total_granted_power = 0;310310+ i = 0;311311+ list_for_each_entry(instance, &tz->thermal_instances, tz_node) {312312+ if (instance->trip != trip_max_desired_temperature)313313+ continue;314314+315315+ if (!cdev_is_power_actor(instance->cdev))316316+ continue;317317+318318+ power_actor_set_power(instance->cdev, instance,319319+ granted_power[i]);320320+ total_granted_power += granted_power[i];321321+322322+ i++;323323+ }324324+325325+ trace_thermal_power_allocator(tz, req_power, total_req_power,326326+ granted_power, total_granted_power,327327+ num_actors, power_range,328328+ max_allocatable_power, current_temp,329329+ (s32)control_temp - (s32)current_temp);330330+331331+ devm_kfree(&tz->device, req_power);332332+unlock:333333+ mutex_unlock(&tz->lock);334334+335335+ return ret;336336+}337337+338338+static int get_governor_trips(struct thermal_zone_device *tz,339339+ struct power_allocator_params *params)340340+{341341+ int i, ret, last_passive;342342+ bool found_first_passive;343343+344344+ found_first_passive = false;345345+ last_passive = -1;346346+ ret = -EINVAL;347347+348348+ for (i = 0; i < tz->trips; i++) {349349+ enum thermal_trip_type type;350350+351351+ ret = tz->ops->get_trip_type(tz, i, &type);352352+ if (ret)353353+ return ret;354354+355355+ if (!found_first_passive) {356356+ if (type == THERMAL_TRIP_PASSIVE) {357357+ params->trip_switch_on = i;358358+ found_first_passive = true;359359+ }360360+ } else if (type == THERMAL_TRIP_PASSIVE) {361361+ last_passive = i;362362+ } else {363363+ break;364364+ }365365+ }366366+367367+ if (last_passive != -1) {368368+ params->trip_max_desired_temperature = last_passive;369369+ ret = 0;370370+ } else {371371+ ret = -EINVAL;372372+ }373373+374374+ return ret;375375+}376376+377377+static void reset_pid_controller(struct power_allocator_params *params)378378+{379379+ params->err_integral = 0;380380+ params->prev_err = 0;381381+}382382+383383+static void allow_maximum_power(struct thermal_zone_device *tz)384384+{385385+ struct thermal_instance *instance;386386+ struct power_allocator_params *params = tz->governor_data;387387+388388+ list_for_each_entry(instance, &tz->thermal_instances, tz_node) {389389+ if ((instance->trip != params->trip_max_desired_temperature) ||390390+ (!cdev_is_power_actor(instance->cdev)))391391+ continue;392392+393393+ instance->target = 0;394394+ instance->cdev->updated = false;395395+ thermal_cdev_update(instance->cdev);396396+ }397397+}398398+399399+/**400400+ * power_allocator_bind() - bind the power_allocator governor to a thermal zone401401+ * @tz: thermal zone to bind it to402402+ *403403+ * Check that the thermal zone is valid for this governor, that is, it404404+ * has two thermal trips. If so, initialize the PID controller405405+ * parameters and bind it to the thermal zone.406406+ *407407+ * Return: 0 on success, -EINVAL if the trips were invalid or -ENOMEM408408+ * if we ran out of memory.409409+ */410410+static int power_allocator_bind(struct thermal_zone_device *tz)411411+{412412+ int ret;413413+ struct power_allocator_params *params;414414+ unsigned long switch_on_temp, control_temp;415415+ u32 temperature_threshold;416416+417417+ if (!tz->tzp || !tz->tzp->sustainable_power) {418418+ dev_err(&tz->device,419419+ "power_allocator: missing sustainable_power\n");420420+ return -EINVAL;421421+ }422422+423423+ params = devm_kzalloc(&tz->device, sizeof(*params), GFP_KERNEL);424424+ if (!params)425425+ return -ENOMEM;426426+427427+ ret = get_governor_trips(tz, params);428428+ if (ret) {429429+ dev_err(&tz->device,430430+ "thermal zone %s has wrong trip setup for power allocator\n",431431+ tz->type);432432+ goto free;433433+ }434434+435435+ ret = tz->ops->get_trip_temp(tz, params->trip_switch_on,436436+ &switch_on_temp);437437+ if (ret)438438+ goto free;439439+440440+ ret = tz->ops->get_trip_temp(tz, params->trip_max_desired_temperature,441441+ &control_temp);442442+ if (ret)443443+ goto free;444444+445445+ temperature_threshold = control_temp - switch_on_temp;446446+447447+ tz->tzp->k_po = tz->tzp->k_po ?:448448+ int_to_frac(tz->tzp->sustainable_power) / temperature_threshold;449449+ tz->tzp->k_pu = tz->tzp->k_pu ?:450450+ int_to_frac(2 * tz->tzp->sustainable_power) /451451+ temperature_threshold;452452+ tz->tzp->k_i = tz->tzp->k_i ?: int_to_frac(10) / 1000;453453+ /*454454+ * The default for k_d and integral_cutoff is 0, so we can455455+ * leave them as they are.456456+ */457457+458458+ reset_pid_controller(params);459459+460460+ tz->governor_data = params;461461+462462+ return 0;463463+464464+free:465465+ devm_kfree(&tz->device, params);466466+ return ret;467467+}468468+469469+static void power_allocator_unbind(struct thermal_zone_device *tz)470470+{471471+ dev_dbg(&tz->device, "Unbinding from thermal zone %d\n", tz->id);472472+ devm_kfree(&tz->device, tz->governor_data);473473+ tz->governor_data = NULL;474474+}475475+476476+static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)477477+{478478+ int ret;479479+ unsigned long switch_on_temp, control_temp, current_temp;480480+ struct power_allocator_params *params = tz->governor_data;481481+482482+ /*483483+ * We get called for every trip point but we only need to do484484+ * our calculations once485485+ */486486+ if (trip != params->trip_max_desired_temperature)487487+ return 0;488488+489489+ ret = thermal_zone_get_temp(tz, ¤t_temp);490490+ if (ret) {491491+ dev_warn(&tz->device, "Failed to get temperature: %d\n", ret);492492+ return ret;493493+ }494494+495495+ ret = tz->ops->get_trip_temp(tz, params->trip_switch_on,496496+ &switch_on_temp);497497+ if (ret) {498498+ dev_warn(&tz->device,499499+ "Failed to get switch on temperature: %d\n", ret);500500+ return ret;501501+ }502502+503503+ if (current_temp < switch_on_temp) {504504+ tz->passive = 0;505505+ reset_pid_controller(params);506506+ allow_maximum_power(tz);507507+ return 0;508508+ }509509+510510+ tz->passive = 1;511511+512512+ ret = tz->ops->get_trip_temp(tz, params->trip_max_desired_temperature,513513+ &control_temp);514514+ if (ret) {515515+ dev_warn(&tz->device,516516+ "Failed to get the maximum desired temperature: %d\n",517517+ ret);518518+ return ret;519519+ }520520+521521+ return allocate_power(tz, current_temp, control_temp);522522+}523523+524524+static struct thermal_governor thermal_gov_power_allocator = {525525+ .name = "power_allocator",526526+ .bind_to_tz = power_allocator_bind,527527+ .unbind_from_tz = power_allocator_unbind,528528+ .throttle = power_allocator_throttle,529529+};530530+531531+int thermal_gov_power_allocator_register(void)532532+{533533+ return thermal_register_governor(&thermal_gov_power_allocator);534534+}535535+536536+void thermal_gov_power_allocator_unregister(void)537537+{538538+ thermal_unregister_governor(&thermal_gov_power_allocator);539539+}
+309
drivers/thermal/qcom-spmi-temp-alarm.c
···11+/*22+ * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.33+ *44+ * This program is free software; you can redistribute it and/or modify55+ * it under the terms of the GNU General Public License version 2 and66+ * only version 2 as published by the Free Software Foundation.77+ *88+ * This program is distributed in the hope that it will be useful,99+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1010+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1111+ * GNU General Public License for more details.1212+ */1313+1414+#include <linux/delay.h>1515+#include <linux/err.h>1616+#include <linux/iio/consumer.h>1717+#include <linux/interrupt.h>1818+#include <linux/module.h>1919+#include <linux/of.h>2020+#include <linux/of_device.h>2121+#include <linux/platform_device.h>2222+#include <linux/regmap.h>2323+#include <linux/thermal.h>2424+2525+#define QPNP_TM_REG_TYPE 0x042626+#define QPNP_TM_REG_SUBTYPE 0x052727+#define QPNP_TM_REG_STATUS 0x082828+#define QPNP_TM_REG_SHUTDOWN_CTRL1 0x402929+#define QPNP_TM_REG_ALARM_CTRL 0x463030+3131+#define QPNP_TM_TYPE 0x093232+#define QPNP_TM_SUBTYPE 0x083333+3434+#define STATUS_STAGE_MASK 0x033535+3636+#define SHUTDOWN_CTRL1_THRESHOLD_MASK 0x033737+3838+#define ALARM_CTRL_FORCE_ENABLE 0x803939+4040+/*4141+ * Trip point values based on threshold control4242+ * 0 = {105 C, 125 C, 145 C}4343+ * 1 = {110 C, 130 C, 150 C}4444+ * 2 = {115 C, 135 C, 155 C}4545+ * 3 = {120 C, 140 C, 160 C}4646+*/4747+#define TEMP_STAGE_STEP 20000 /* Stage step: 20.000 C */4848+#define TEMP_STAGE_HYSTERESIS 20004949+5050+#define TEMP_THRESH_MIN 105000 /* Threshold Min: 105 C */5151+#define TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */5252+5353+#define THRESH_MIN 05454+5555+/* Temperature in Milli Celsius reported during stage 0 if no ADC is present */5656+#define DEFAULT_TEMP 370005757+5858+struct qpnp_tm_chip {5959+ struct regmap *map;6060+ struct thermal_zone_device *tz_dev;6161+ long temp;6262+ unsigned int thresh;6363+ unsigned int stage;6464+ unsigned int prev_stage;6565+ unsigned int base;6666+ struct iio_channel *adc;6767+};6868+6969+static int qpnp_tm_read(struct qpnp_tm_chip *chip, u16 addr, u8 *data)7070+{7171+ unsigned int val;7272+ int ret;7373+7474+ ret = regmap_read(chip->map, chip->base + addr, &val);7575+ if (ret < 0)7676+ return ret;7777+7878+ *data = val;7979+ return 0;8080+}8181+8282+static int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 data)8383+{8484+ return regmap_write(chip->map, chip->base + addr, data);8585+}8686+8787+/*8888+ * This function updates the internal temp value based on the8989+ * current thermal stage and threshold as well as the previous stage9090+ */9191+static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)9292+{9393+ unsigned int stage;9494+ int ret;9595+ u8 reg = 0;9696+9797+ ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, ®);9898+ if (ret < 0)9999+ return ret;100100+101101+ stage = reg & STATUS_STAGE_MASK;102102+103103+ if (stage > chip->stage) {104104+ /* increasing stage, use lower bound */105105+ chip->temp = (stage - 1) * TEMP_STAGE_STEP +106106+ chip->thresh * TEMP_THRESH_STEP +107107+ TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;108108+ } else if (stage < chip->stage) {109109+ /* decreasing stage, use upper bound */110110+ chip->temp = stage * TEMP_STAGE_STEP +111111+ chip->thresh * TEMP_THRESH_STEP -112112+ TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;113113+ }114114+115115+ chip->stage = stage;116116+117117+ return 0;118118+}119119+120120+static int qpnp_tm_get_temp(void *data, long *temp)121121+{122122+ struct qpnp_tm_chip *chip = data;123123+ int ret, mili_celsius;124124+125125+ if (!temp)126126+ return -EINVAL;127127+128128+ if (IS_ERR(chip->adc)) {129129+ ret = qpnp_tm_update_temp_no_adc(chip);130130+ if (ret < 0)131131+ return ret;132132+ } else {133133+ ret = iio_read_channel_processed(chip->adc, &mili_celsius);134134+ if (ret < 0)135135+ return ret;136136+137137+ chip->temp = mili_celsius;138138+ }139139+140140+ *temp = chip->temp < 0 ? 0 : chip->temp;141141+142142+ return 0;143143+}144144+145145+static const struct thermal_zone_of_device_ops qpnp_tm_sensor_ops = {146146+ .get_temp = qpnp_tm_get_temp,147147+};148148+149149+static irqreturn_t qpnp_tm_isr(int irq, void *data)150150+{151151+ struct qpnp_tm_chip *chip = data;152152+153153+ thermal_zone_device_update(chip->tz_dev);154154+155155+ return IRQ_HANDLED;156156+}157157+158158+/*159159+ * This function initializes the internal temp value based on only the160160+ * current thermal stage and threshold. Setup threshold control and161161+ * disable shutdown override.162162+ */163163+static int qpnp_tm_init(struct qpnp_tm_chip *chip)164164+{165165+ int ret;166166+ u8 reg;167167+168168+ chip->thresh = THRESH_MIN;169169+ chip->temp = DEFAULT_TEMP;170170+171171+ ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, ®);172172+ if (ret < 0)173173+ return ret;174174+175175+ chip->stage = reg & STATUS_STAGE_MASK;176176+177177+ if (chip->stage)178178+ chip->temp = chip->thresh * TEMP_THRESH_STEP +179179+ (chip->stage - 1) * TEMP_STAGE_STEP +180180+ TEMP_THRESH_MIN;181181+182182+ /*183183+ * Set threshold and disable software override of stage 2 and 3184184+ * shutdowns.185185+ */186186+ reg = chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK;187187+ ret = qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, reg);188188+ if (ret < 0)189189+ return ret;190190+191191+ /* Enable the thermal alarm PMIC module in always-on mode. */192192+ reg = ALARM_CTRL_FORCE_ENABLE;193193+ ret = qpnp_tm_write(chip, QPNP_TM_REG_ALARM_CTRL, reg);194194+195195+ return ret;196196+}197197+198198+static int qpnp_tm_probe(struct platform_device *pdev)199199+{200200+ struct qpnp_tm_chip *chip;201201+ struct device_node *node;202202+ u8 type, subtype;203203+ u32 res[2];204204+ int ret, irq;205205+206206+ node = pdev->dev.of_node;207207+208208+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);209209+ if (!chip)210210+ return -ENOMEM;211211+212212+ dev_set_drvdata(&pdev->dev, chip);213213+214214+ chip->map = dev_get_regmap(pdev->dev.parent, NULL);215215+ if (!chip->map)216216+ return -ENXIO;217217+218218+ ret = of_property_read_u32_array(node, "reg", res, 2);219219+ if (ret < 0)220220+ return ret;221221+222222+ irq = platform_get_irq(pdev, 0);223223+ if (irq < 0)224224+ return irq;225225+226226+ /* ADC based measurements are optional */227227+ chip->adc = iio_channel_get(&pdev->dev, "thermal");228228+ if (PTR_ERR(chip->adc) == -EPROBE_DEFER)229229+ return PTR_ERR(chip->adc);230230+231231+ chip->base = res[0];232232+233233+ ret = qpnp_tm_read(chip, QPNP_TM_REG_TYPE, &type);234234+ if (ret < 0) {235235+ dev_err(&pdev->dev, "could not read type\n");236236+ goto fail;237237+ }238238+239239+ ret = qpnp_tm_read(chip, QPNP_TM_REG_SUBTYPE, &subtype);240240+ if (ret < 0) {241241+ dev_err(&pdev->dev, "could not read subtype\n");242242+ goto fail;243243+ }244244+245245+ if (type != QPNP_TM_TYPE || subtype != QPNP_TM_SUBTYPE) {246246+ dev_err(&pdev->dev, "invalid type 0x%02x or subtype 0x%02x\n",247247+ type, subtype);248248+ ret = -ENODEV;249249+ goto fail;250250+ }251251+252252+ ret = qpnp_tm_init(chip);253253+ if (ret < 0) {254254+ dev_err(&pdev->dev, "init failed\n");255255+ goto fail;256256+ }257257+258258+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, qpnp_tm_isr,259259+ IRQF_ONESHOT, node->name, chip);260260+ if (ret < 0)261261+ goto fail;262262+263263+ chip->tz_dev = thermal_zone_of_sensor_register(&pdev->dev, 0, chip,264264+ &qpnp_tm_sensor_ops);265265+ if (IS_ERR(chip->tz_dev)) {266266+ dev_err(&pdev->dev, "failed to register sensor\n");267267+ ret = PTR_ERR(chip->tz_dev);268268+ goto fail;269269+ }270270+271271+ return 0;272272+273273+fail:274274+ if (!IS_ERR(chip->adc))275275+ iio_channel_release(chip->adc);276276+277277+ return ret;278278+}279279+280280+static int qpnp_tm_remove(struct platform_device *pdev)281281+{282282+ struct qpnp_tm_chip *chip = dev_get_drvdata(&pdev->dev);283283+284284+ thermal_zone_of_sensor_unregister(&pdev->dev, chip->tz_dev);285285+ if (!IS_ERR(chip->adc))286286+ iio_channel_release(chip->adc);287287+288288+ return 0;289289+}290290+291291+static const struct of_device_id qpnp_tm_match_table[] = {292292+ { .compatible = "qcom,spmi-temp-alarm" },293293+ { }294294+};295295+MODULE_DEVICE_TABLE(of, qpnp_tm_match_table);296296+297297+static struct platform_driver qpnp_tm_driver = {298298+ .driver = {299299+ .name = "spmi-temp-alarm",300300+ .of_match_table = qpnp_tm_match_table,301301+ },302302+ .probe = qpnp_tm_probe,303303+ .remove = qpnp_tm_remove,304304+};305305+module_platform_driver(qpnp_tm_driver);306306+307307+MODULE_ALIAS("platform:spmi-temp-alarm");308308+MODULE_DESCRIPTION("QPNP PMIC Temperature Alarm driver");309309+MODULE_LICENSE("GPL v2");
+185-2
drivers/thermal/samsung/exynos_tmu.c
···9797#define EXYNOS4412_MUX_ADDR_VALUE 69898#define EXYNOS4412_MUX_ADDR_SHIFT 209999100100+/* Exynos5433 specific registers */101101+#define EXYNOS5433_TMU_REG_CONTROL1 0x024102102+#define EXYNOS5433_TMU_SAMPLING_INTERVAL 0x02c103103+#define EXYNOS5433_TMU_COUNTER_VALUE0 0x030104104+#define EXYNOS5433_TMU_COUNTER_VALUE1 0x034105105+#define EXYNOS5433_TMU_REG_CURRENT_TEMP1 0x044106106+#define EXYNOS5433_THD_TEMP_RISE3_0 0x050107107+#define EXYNOS5433_THD_TEMP_RISE7_4 0x054108108+#define EXYNOS5433_THD_TEMP_FALL3_0 0x060109109+#define EXYNOS5433_THD_TEMP_FALL7_4 0x064110110+#define EXYNOS5433_TMU_REG_INTEN 0x0c0111111+#define EXYNOS5433_TMU_REG_INTPEND 0x0c8112112+#define EXYNOS5433_TMU_EMUL_CON 0x110113113+#define EXYNOS5433_TMU_PD_DET_EN 0x130114114+115115+#define EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT 16116116+#define EXYNOS5433_TRIMINFO_CALIB_SEL_SHIFT 23117117+#define EXYNOS5433_TRIMINFO_SENSOR_ID_MASK \118118+ (0xf << EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT)119119+#define EXYNOS5433_TRIMINFO_CALIB_SEL_MASK BIT(23)120120+121121+#define EXYNOS5433_TRIMINFO_ONE_POINT_TRIMMING 0122122+#define EXYNOS5433_TRIMINFO_TWO_POINT_TRIMMING 1123123+124124+#define EXYNOS5433_PD_DET_EN 1125125+100126/*exynos5440 specific registers*/101127#define EXYNOS5440_TMU_S0_7_TRIM 0x000102128#define EXYNOS5440_TMU_S0_7_CTRL 0x020···510484 return ret;511485}512486487487+static int exynos5433_tmu_initialize(struct platform_device *pdev)488488+{489489+ struct exynos_tmu_data *data = platform_get_drvdata(pdev);490490+ struct exynos_tmu_platform_data *pdata = data->pdata;491491+ struct thermal_zone_device *tz = data->tzd;492492+ unsigned int status, trim_info;493493+ unsigned int rising_threshold = 0, falling_threshold = 0;494494+ unsigned long temp, temp_hist;495495+ int ret = 0, threshold_code, i, sensor_id, cal_type;496496+497497+ status = readb(data->base + EXYNOS_TMU_REG_STATUS);498498+ if (!status) {499499+ ret = -EBUSY;500500+ goto out;501501+ }502502+503503+ trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);504504+ sanitize_temp_error(data, trim_info);505505+506506+ /* Read the temperature sensor id */507507+ sensor_id = (trim_info & EXYNOS5433_TRIMINFO_SENSOR_ID_MASK)508508+ >> EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT;509509+ dev_info(&pdev->dev, "Temperature sensor ID: 0x%x\n", sensor_id);510510+511511+ /* Read the calibration mode */512512+ writel(trim_info, data->base + EXYNOS_TMU_REG_TRIMINFO);513513+ cal_type = (trim_info & EXYNOS5433_TRIMINFO_CALIB_SEL_MASK)514514+ >> EXYNOS5433_TRIMINFO_CALIB_SEL_SHIFT;515515+516516+ switch (cal_type) {517517+ case EXYNOS5433_TRIMINFO_ONE_POINT_TRIMMING:518518+ pdata->cal_type = TYPE_ONE_POINT_TRIMMING;519519+ break;520520+ case EXYNOS5433_TRIMINFO_TWO_POINT_TRIMMING:521521+ pdata->cal_type = TYPE_TWO_POINT_TRIMMING;522522+ break;523523+ default:524524+ pdata->cal_type = TYPE_ONE_POINT_TRIMMING;525525+ break;526526+ };527527+528528+ dev_info(&pdev->dev, "Calibration type is %d-point calibration\n",529529+ cal_type ? 2 : 1);530530+531531+ /* Write temperature code for rising and falling threshold */532532+ for (i = 0; i < of_thermal_get_ntrips(tz); i++) {533533+ int rising_reg_offset, falling_reg_offset;534534+ int j = 0;535535+536536+ switch (i) {537537+ case 0:538538+ case 1:539539+ case 2:540540+ case 3:541541+ rising_reg_offset = EXYNOS5433_THD_TEMP_RISE3_0;542542+ falling_reg_offset = EXYNOS5433_THD_TEMP_FALL3_0;543543+ j = i;544544+ break;545545+ case 4:546546+ case 5:547547+ case 6:548548+ case 7:549549+ rising_reg_offset = EXYNOS5433_THD_TEMP_RISE7_4;550550+ falling_reg_offset = EXYNOS5433_THD_TEMP_FALL7_4;551551+ j = i - 4;552552+ break;553553+ default:554554+ continue;555555+ }556556+557557+ /* Write temperature code for rising threshold */558558+ tz->ops->get_trip_temp(tz, i, &temp);559559+ temp /= MCELSIUS;560560+ threshold_code = temp_to_code(data, temp);561561+562562+ rising_threshold = readl(data->base + rising_reg_offset);563563+ rising_threshold |= (threshold_code << j * 8);564564+ writel(rising_threshold, data->base + rising_reg_offset);565565+566566+ /* Write temperature code for falling threshold */567567+ tz->ops->get_trip_hyst(tz, i, &temp_hist);568568+ temp_hist = temp - (temp_hist / MCELSIUS);569569+ threshold_code = temp_to_code(data, temp_hist);570570+571571+ falling_threshold = readl(data->base + falling_reg_offset);572572+ falling_threshold &= ~(0xff << j * 8);573573+ falling_threshold |= (threshold_code << j * 8);574574+ writel(falling_threshold, data->base + falling_reg_offset);575575+ }576576+577577+ data->tmu_clear_irqs(data);578578+out:579579+ return ret;580580+}581581+513582static int exynos5440_tmu_initialize(struct platform_device *pdev)514583{515584 struct exynos_tmu_data *data = platform_get_drvdata(pdev);···764643 writel(con, data->base + EXYNOS_TMU_REG_CONTROL);765644}766645646646+static void exynos5433_tmu_control(struct platform_device *pdev, bool on)647647+{648648+ struct exynos_tmu_data *data = platform_get_drvdata(pdev);649649+ struct thermal_zone_device *tz = data->tzd;650650+ unsigned int con, interrupt_en, pd_det_en;651651+652652+ con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL));653653+654654+ if (on) {655655+ con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);656656+ interrupt_en =657657+ (of_thermal_is_trip_valid(tz, 7)658658+ << EXYNOS7_TMU_INTEN_RISE7_SHIFT) |659659+ (of_thermal_is_trip_valid(tz, 6)660660+ << EXYNOS7_TMU_INTEN_RISE6_SHIFT) |661661+ (of_thermal_is_trip_valid(tz, 5)662662+ << EXYNOS7_TMU_INTEN_RISE5_SHIFT) |663663+ (of_thermal_is_trip_valid(tz, 4)664664+ << EXYNOS7_TMU_INTEN_RISE4_SHIFT) |665665+ (of_thermal_is_trip_valid(tz, 3)666666+ << EXYNOS7_TMU_INTEN_RISE3_SHIFT) |667667+ (of_thermal_is_trip_valid(tz, 2)668668+ << EXYNOS7_TMU_INTEN_RISE2_SHIFT) |669669+ (of_thermal_is_trip_valid(tz, 1)670670+ << EXYNOS7_TMU_INTEN_RISE1_SHIFT) |671671+ (of_thermal_is_trip_valid(tz, 0)672672+ << EXYNOS7_TMU_INTEN_RISE0_SHIFT);673673+674674+ interrupt_en |=675675+ interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;676676+ } else {677677+ con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);678678+ interrupt_en = 0; /* Disable all interrupts */679679+ }680680+681681+ pd_det_en = on ? EXYNOS5433_PD_DET_EN : 0;682682+683683+ writel(pd_det_en, data->base + EXYNOS5433_TMU_PD_DET_EN);684684+ writel(interrupt_en, data->base + EXYNOS5433_TMU_REG_INTEN);685685+ writel(con, data->base + EXYNOS_TMU_REG_CONTROL);686686+}687687+767688static void exynos5440_tmu_control(struct platform_device *pdev, bool on)768689{769690 struct exynos_tmu_data *data = platform_get_drvdata(pdev);···933770934771 if (data->soc == SOC_ARCH_EXYNOS5260)935772 emul_con = EXYNOS5260_EMUL_CON;773773+ if (data->soc == SOC_ARCH_EXYNOS5433)774774+ emul_con = EXYNOS5433_TMU_EMUL_CON;936775 else if (data->soc == SOC_ARCH_EXYNOS7)937776 emul_con = EXYNOS7_TMU_REG_EMUL_CON;938777 else···1047882 } else if (data->soc == SOC_ARCH_EXYNOS7) {1048883 tmu_intstat = EXYNOS7_TMU_REG_INTPEND;1049884 tmu_intclear = EXYNOS7_TMU_REG_INTPEND;885885+ } else if (data->soc == SOC_ARCH_EXYNOS5433) {886886+ tmu_intstat = EXYNOS5433_TMU_REG_INTPEND;887887+ tmu_intclear = EXYNOS5433_TMU_REG_INTPEND;1050888 } else {1051889 tmu_intstat = EXYNOS_TMU_REG_INTSTAT;1052890 tmu_intclear = EXYNOS_TMU_REG_INTCLEAR;···1094926 { .compatible = "samsung,exynos5260-tmu", },1095927 { .compatible = "samsung,exynos5420-tmu", },1096928 { .compatible = "samsung,exynos5420-tmu-ext-triminfo", },929929+ { .compatible = "samsung,exynos5433-tmu", },1097930 { .compatible = "samsung,exynos5440-tmu", },1098931 { .compatible = "samsung,exynos7-tmu", },1099932 { /* sentinel */ },···1118949 else if (of_device_is_compatible(np,1119950 "samsung,exynos5420-tmu-ext-triminfo"))1120951 return SOC_ARCH_EXYNOS5420_TRIMINFO;952952+ else if (of_device_is_compatible(np, "samsung,exynos5433-tmu"))953953+ return SOC_ARCH_EXYNOS5433;1121954 else if (of_device_is_compatible(np, "samsung,exynos5440-tmu"))1122955 return SOC_ARCH_EXYNOS5440;1123956 else if (of_device_is_compatible(np, "samsung,exynos7-tmu"))···12401069 data->tmu_set_emulation = exynos4412_tmu_set_emulation;12411070 data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;12421071 break;10721072+ case SOC_ARCH_EXYNOS5433:10731073+ data->tmu_initialize = exynos5433_tmu_initialize;10741074+ data->tmu_control = exynos5433_tmu_control;10751075+ data->tmu_read = exynos4412_tmu_read;10761076+ data->tmu_set_emulation = exynos4412_tmu_set_emulation;10771077+ data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;10781078+ break;12431079 case SOC_ARCH_EXYNOS5440:12441080 data->tmu_initialize = exynos5440_tmu_initialize;12451081 data->tmu_control = exynos5440_tmu_control;···13501172 goto err_clk_sec;13511173 }1352117413531353- if (data->soc == SOC_ARCH_EXYNOS7) {11751175+ switch (data->soc) {11761176+ case SOC_ARCH_EXYNOS5433:11771177+ case SOC_ARCH_EXYNOS7:13541178 data->sclk = devm_clk_get(&pdev->dev, "tmu_sclk");13551179 if (IS_ERR(data->sclk)) {13561180 dev_err(&pdev->dev, "Failed to get sclk\n");···13641184 goto err_clk;13651185 }13661186 }13671367- }11871187+ break;11881188+ default:11891189+ break;11901190+ };1368119113691192 ret = exynos_tmu_initialize(pdev);13701193 if (ret) {
···7575 return NULL;7676}77777878+/**7979+ * bind_previous_governor() - bind the previous governor of the thermal zone8080+ * @tz: a valid pointer to a struct thermal_zone_device8181+ * @failed_gov_name: the name of the governor that failed to register8282+ *8383+ * Register the previous governor of the thermal zone after a new8484+ * governor has failed to be bound.8585+ */8686+static void bind_previous_governor(struct thermal_zone_device *tz,8787+ const char *failed_gov_name)8888+{8989+ if (tz->governor && tz->governor->bind_to_tz) {9090+ if (tz->governor->bind_to_tz(tz)) {9191+ dev_err(&tz->device,9292+ "governor %s failed to bind and the previous one (%s) failed to bind again, thermal zone %s has no governor\n",9393+ failed_gov_name, tz->governor->name, tz->type);9494+ tz->governor = NULL;9595+ }9696+ }9797+}9898+9999+/**100100+ * thermal_set_governor() - Switch to another governor101101+ * @tz: a valid pointer to a struct thermal_zone_device102102+ * @new_gov: pointer to the new governor103103+ *104104+ * Change the governor of thermal zone @tz.105105+ *106106+ * Return: 0 on success, an error if the new governor's bind_to_tz() failed.107107+ */108108+static int thermal_set_governor(struct thermal_zone_device *tz,109109+ struct thermal_governor *new_gov)110110+{111111+ int ret = 0;112112+113113+ if (tz->governor && tz->governor->unbind_from_tz)114114+ tz->governor->unbind_from_tz(tz);115115+116116+ if (new_gov && new_gov->bind_to_tz) {117117+ ret = new_gov->bind_to_tz(tz);118118+ if (ret) {119119+ bind_previous_governor(tz, new_gov->name);120120+121121+ return ret;122122+ }123123+ }124124+125125+ tz->governor = new_gov;126126+127127+ return ret;128128+}129129+78130int thermal_register_governor(struct thermal_governor *governor)79131{80132 int err;···159107160108 name = pos->tzp->governor_name;161109162162- if (!strncasecmp(name, governor->name, THERMAL_NAME_LENGTH))163163- pos->governor = governor;110110+ if (!strncasecmp(name, governor->name, THERMAL_NAME_LENGTH)) {111111+ int ret;112112+113113+ ret = thermal_set_governor(pos, governor);114114+ if (ret)115115+ dev_err(&pos->device,116116+ "Failed to set governor %s for thermal zone %s: %d\n",117117+ governor->name, pos->type, ret);118118+ }164119 }165120166121 mutex_unlock(&thermal_list_lock);···193134 list_for_each_entry(pos, &thermal_tz_list, node) {194135 if (!strncasecmp(pos->governor->name, governor->name,195136 THERMAL_NAME_LENGTH))196196- pos->governor = NULL;137137+ thermal_set_governor(pos, NULL);197138 }198139199140 mutex_unlock(&thermal_list_lock);···277218278219static void __bind(struct thermal_zone_device *tz, int mask,279220 struct thermal_cooling_device *cdev,280280- unsigned long *limits)221221+ unsigned long *limits,222222+ unsigned int weight)281223{282224 int i, ret;283225···293233 upper = limits[i * 2 + 1];294234 }295235 ret = thermal_zone_bind_cooling_device(tz, i, cdev,296296- upper, lower);236236+ upper, lower,237237+ weight);297238 if (ret)298239 print_bind_err_msg(tz, cdev, ret);299240 }···341280 continue;342281 tzp->tbp[i].cdev = cdev;343282 __bind(pos, tzp->tbp[i].trip_mask, cdev,344344- tzp->tbp[i].binding_limits);283283+ tzp->tbp[i].binding_limits,284284+ tzp->tbp[i].weight);345285 }346286 }347287···381319 continue;382320 tzp->tbp[i].cdev = pos;383321 __bind(tz, tzp->tbp[i].trip_mask, pos,384384- tzp->tbp[i].binding_limits);322322+ tzp->tbp[i].binding_limits,323323+ tzp->tbp[i].weight);385324 }386325 }387326exit:···776713 thermal_zone_bind_cooling_device(tz,777714 THERMAL_TRIPS_NONE, cdev,778715 THERMAL_NO_LIMIT,779779- THERMAL_NO_LIMIT);716716+ THERMAL_NO_LIMIT,717717+ THERMAL_WEIGHT_DEFAULT);780718 }781719 mutex_unlock(&thermal_list_lock);782720 if (!tz->passive_delay)···829765 if (!gov)830766 goto exit;831767832832- tz->governor = gov;833833- ret = count;768768+ ret = thermal_set_governor(tz, gov);769769+ if (!ret)770770+ ret = count;834771835772exit:836773 mutex_unlock(&tz->lock);···874809}875810static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);876811#endif/*CONFIG_THERMAL_EMULATION*/812812+813813+static ssize_t814814+sustainable_power_show(struct device *dev, struct device_attribute *devattr,815815+ char *buf)816816+{817817+ struct thermal_zone_device *tz = to_thermal_zone(dev);818818+819819+ if (tz->tzp)820820+ return sprintf(buf, "%u\n", tz->tzp->sustainable_power);821821+ else822822+ return -EIO;823823+}824824+825825+static ssize_t826826+sustainable_power_store(struct device *dev, struct device_attribute *devattr,827827+ const char *buf, size_t count)828828+{829829+ struct thermal_zone_device *tz = to_thermal_zone(dev);830830+ u32 sustainable_power;831831+832832+ if (!tz->tzp)833833+ return -EIO;834834+835835+ if (kstrtou32(buf, 10, &sustainable_power))836836+ return -EINVAL;837837+838838+ tz->tzp->sustainable_power = sustainable_power;839839+840840+ return count;841841+}842842+static DEVICE_ATTR(sustainable_power, S_IWUSR | S_IRUGO, sustainable_power_show,843843+ sustainable_power_store);844844+845845+#define create_s32_tzp_attr(name) \846846+ static ssize_t \847847+ name##_show(struct device *dev, struct device_attribute *devattr, \848848+ char *buf) \849849+ { \850850+ struct thermal_zone_device *tz = to_thermal_zone(dev); \851851+ \852852+ if (tz->tzp) \853853+ return sprintf(buf, "%u\n", tz->tzp->name); \854854+ else \855855+ return -EIO; \856856+ } \857857+ \858858+ static ssize_t \859859+ name##_store(struct device *dev, struct device_attribute *devattr, \860860+ const char *buf, size_t count) \861861+ { \862862+ struct thermal_zone_device *tz = to_thermal_zone(dev); \863863+ s32 value; \864864+ \865865+ if (!tz->tzp) \866866+ return -EIO; \867867+ \868868+ if (kstrtos32(buf, 10, &value)) \869869+ return -EINVAL; \870870+ \871871+ tz->tzp->name = value; \872872+ \873873+ return count; \874874+ } \875875+ static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, name##_show, name##_store)876876+877877+create_s32_tzp_attr(k_po);878878+create_s32_tzp_attr(k_pu);879879+create_s32_tzp_attr(k_i);880880+create_s32_tzp_attr(k_d);881881+create_s32_tzp_attr(integral_cutoff);882882+create_s32_tzp_attr(slope);883883+create_s32_tzp_attr(offset);884884+#undef create_s32_tzp_attr885885+886886+static struct device_attribute *dev_tzp_attrs[] = {887887+ &dev_attr_sustainable_power,888888+ &dev_attr_k_po,889889+ &dev_attr_k_pu,890890+ &dev_attr_k_i,891891+ &dev_attr_k_d,892892+ &dev_attr_integral_cutoff,893893+ &dev_attr_slope,894894+ &dev_attr_offset,895895+};896896+897897+static int create_tzp_attrs(struct device *dev)898898+{899899+ int i;900900+901901+ for (i = 0; i < ARRAY_SIZE(dev_tzp_attrs); i++) {902902+ int ret;903903+ struct device_attribute *dev_attr = dev_tzp_attrs[i];904904+905905+ ret = device_create_file(dev, dev_attr);906906+ if (ret)907907+ return ret;908908+ }909909+910910+ return 0;911911+}912912+913913+/**914914+ * power_actor_get_max_power() - get the maximum power that a cdev can consume915915+ * @cdev: pointer to &thermal_cooling_device916916+ * @tz: a valid thermal zone device pointer917917+ * @max_power: pointer in which to store the maximum power918918+ *919919+ * Calculate the maximum power consumption in milliwats that the920920+ * cooling device can currently consume and store it in @max_power.921921+ *922922+ * Return: 0 on success, -EINVAL if @cdev doesn't support the923923+ * power_actor API or -E* on other error.924924+ */925925+int power_actor_get_max_power(struct thermal_cooling_device *cdev,926926+ struct thermal_zone_device *tz, u32 *max_power)927927+{928928+ if (!cdev_is_power_actor(cdev))929929+ return -EINVAL;930930+931931+ return cdev->ops->state2power(cdev, tz, 0, max_power);932932+}933933+934934+/**935935+ * power_actor_set_power() - limit the maximum power that a cooling device can consume936936+ * @cdev: pointer to &thermal_cooling_device937937+ * @instance: thermal instance to update938938+ * @power: the power in milliwatts939939+ *940940+ * Set the cooling device to consume at most @power milliwatts.941941+ *942942+ * Return: 0 on success, -EINVAL if the cooling device does not943943+ * implement the power actor API or -E* for other failures.944944+ */945945+int power_actor_set_power(struct thermal_cooling_device *cdev,946946+ struct thermal_instance *instance, u32 power)947947+{948948+ unsigned long state;949949+ int ret;950950+951951+ if (!cdev_is_power_actor(cdev))952952+ return -EINVAL;953953+954954+ ret = cdev->ops->power2state(cdev, instance->tz, power, &state);955955+ if (ret)956956+ return ret;957957+958958+ instance->target = state;959959+ cdev->updated = false;960960+ thermal_cdev_update(cdev);961961+962962+ return 0;963963+}877964878965static DEVICE_ATTR(type, 0444, type_show, NULL);879966static DEVICE_ATTR(temp, 0444, temp_show, NULL);···1134917 NULL,1135918};1136919920920+static ssize_t921921+thermal_cooling_device_weight_show(struct device *dev,922922+ struct device_attribute *attr, char *buf)923923+{924924+ struct thermal_instance *instance;925925+926926+ instance = container_of(attr, struct thermal_instance, weight_attr);927927+928928+ return sprintf(buf, "%d\n", instance->weight);929929+}930930+931931+static ssize_t932932+thermal_cooling_device_weight_store(struct device *dev,933933+ struct device_attribute *attr,934934+ const char *buf, size_t count)935935+{936936+ struct thermal_instance *instance;937937+ int ret, weight;938938+939939+ ret = kstrtoint(buf, 0, &weight);940940+ if (ret)941941+ return ret;942942+943943+ instance = container_of(attr, struct thermal_instance, weight_attr);944944+ instance->weight = weight;945945+946946+ return count;947947+}1137948/* Device management */11389491139950/**···1176931 * @lower: the Minimum cooling state can be used for this trip point.1177932 * THERMAL_NO_LIMIT means no lower limit,1178933 * and the cooling device can be in cooling state 0.934934+ * @weight: The weight of the cooling device to be bound to the935935+ * thermal zone. Use THERMAL_WEIGHT_DEFAULT for the936936+ * default value1179937 *1180938 * This interface function bind a thermal cooling device to the certain trip1181939 * point of a thermal zone device.···1189941int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,1190942 int trip,1191943 struct thermal_cooling_device *cdev,11921192- unsigned long upper, unsigned long lower)944944+ unsigned long upper, unsigned long lower,945945+ unsigned int weight)1193946{1194947 struct thermal_instance *dev;1195948 struct thermal_instance *pos;···1235986 dev->upper = upper;1236987 dev->lower = lower;1237988 dev->target = THERMAL_NO_TARGET;989989+ dev->weight = weight;12389901239991 result = get_idr(&tz->idr, &tz->lock, &dev->id);1240992 if (result)···12561006 if (result)12571007 goto remove_symbol_link;1258100810091009+ sprintf(dev->weight_attr_name, "cdev%d_weight", dev->id);10101010+ sysfs_attr_init(&dev->weight_attr.attr);10111011+ dev->weight_attr.attr.name = dev->weight_attr_name;10121012+ dev->weight_attr.attr.mode = S_IWUSR | S_IRUGO;10131013+ dev->weight_attr.show = thermal_cooling_device_weight_show;10141014+ dev->weight_attr.store = thermal_cooling_device_weight_store;10151015+ result = device_create_file(&tz->device, &dev->weight_attr);10161016+ if (result)10171017+ goto remove_trip_file;10181018+12591019 mutex_lock(&tz->lock);12601020 mutex_lock(&cdev->lock);12611021 list_for_each_entry(pos, &tz->thermal_instances, tz_node)···12831023 if (!result)12841024 return 0;1285102510261026+ device_remove_file(&tz->device, &dev->weight_attr);10271027+remove_trip_file:12861028 device_remove_file(&tz->device, &dev->attr);12871029remove_symbol_link:12881030 sysfs_remove_link(&tz->device.kobj, dev->name);···16391377 tz->trip_temp_attrs[indx].name;16401378 tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;16411379 tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;16421642- if (mask & (1 << indx)) {13801380+ if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS) &&13811381+ mask & (1 << indx)) {16431382 tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;16441383 tz->trip_temp_attrs[indx].attr.store =16451384 trip_point_temp_store;···17171454struct thermal_zone_device *thermal_zone_device_register(const char *type,17181455 int trips, int mask, void *devdata,17191456 struct thermal_zone_device_ops *ops,17201720- const struct thermal_zone_params *tzp,14571457+ struct thermal_zone_params *tzp,17211458 int passive_delay, int polling_delay)17221459{17231460 struct thermal_zone_device *tz;···17251462 int result;17261463 int count;17271464 int passive = 0;14651465+ struct thermal_governor *governor;1728146617291467 if (type && strlen(type) >= THERMAL_NAME_LENGTH)17301468 return ERR_PTR(-EINVAL);···18121548 if (result)18131549 goto unregister;1814155015511551+ /* Add thermal zone params */15521552+ result = create_tzp_attrs(&tz->device);15531553+ if (result)15541554+ goto unregister;15551555+18151556 /* Update 'this' zone's governor information */18161557 mutex_lock(&thermal_governor_lock);1817155818181559 if (tz->tzp)18191819- tz->governor = __find_governor(tz->tzp->governor_name);15601560+ governor = __find_governor(tz->tzp->governor_name);18201561 else18211821- tz->governor = def_governor;15621562+ governor = def_governor;15631563+15641564+ result = thermal_set_governor(tz, governor);15651565+ if (result) {15661566+ mutex_unlock(&thermal_governor_lock);15671567+ goto unregister;15681568+ }1822156918231570 mutex_unlock(&thermal_governor_lock);18241571···19181643 device_remove_file(&tz->device, &dev_attr_mode);19191644 device_remove_file(&tz->device, &dev_attr_policy);19201645 remove_trip_attrs(tz);19211921- tz->governor = NULL;16461646+ thermal_set_governor(tz, NULL);1922164719231648 thermal_remove_hwmon_sysfs(tz);19241649 release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);···20741799 if (result)20751800 return result;2076180120772077- return thermal_gov_user_space_register();18021802+ result = thermal_gov_user_space_register();18031803+ if (result)18041804+ return result;18051805+18061806+ return thermal_gov_power_allocator_register();20781807}2079180820801809static void thermal_unregister_governors(void)···20871808 thermal_gov_fair_share_unregister();20881809 thermal_gov_bang_bang_unregister();20891810 thermal_gov_user_space_unregister();18111811+ thermal_gov_power_allocator_unregister();20901812}2091181320921814static int __init thermal_init(void)
+11
drivers/thermal/thermal_core.h
···4646 unsigned long target; /* expected cooling state */4747 char attr_name[THERMAL_NAME_LENGTH];4848 struct device_attribute attr;4949+ char weight_attr_name[THERMAL_NAME_LENGTH];5050+ struct device_attribute weight_attr;4951 struct list_head tz_node; /* node in tz->thermal_instances */5052 struct list_head cdev_node; /* node in cdev->thermal_instances */5353+ unsigned int weight; /* The weight of the cooling device */5154};52555356int thermal_register_governor(struct thermal_governor *);···8784static inline int thermal_gov_user_space_register(void) { return 0; }8885static inline void thermal_gov_user_space_unregister(void) {}8986#endif /* CONFIG_THERMAL_GOV_USER_SPACE */8787+8888+#ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR8989+int thermal_gov_power_allocator_register(void);9090+void thermal_gov_power_allocator_unregister(void);9191+#else9292+static inline int thermal_gov_power_allocator_register(void) { return 0; }9393+static inline void thermal_gov_power_allocator_unregister(void) {}9494+#endif /* CONFIG_THERMAL_GOV_POWER_ALLOCATOR */90959196/* device tree support */9297#ifdef CONFIG_THERMAL_OF
+50-54
drivers/thermal/ti-soc-thermal/ti-bandgap.c
···43434444#include "ti-bandgap.h"45454646+static int ti_bandgap_force_single_read(struct ti_bandgap *bgp, int id);4747+4648/*** Helper functions to access registers and their bitfields ***/47494850/**···105103 */106104static int ti_bandgap_power(struct ti_bandgap *bgp, bool on)107105{108108- int i, ret = 0;106106+ int i;109107110110- if (!TI_BANDGAP_HAS(bgp, POWER_SWITCH)) {111111- ret = -ENOTSUPP;112112- goto exit;113113- }108108+ if (!TI_BANDGAP_HAS(bgp, POWER_SWITCH))109109+ return -ENOTSUPP;114110115111 for (i = 0; i < bgp->conf->sensor_count; i++)116112 /* active on 0 */117113 RMW_BITS(bgp, i, temp_sensor_ctrl, bgap_tempsoff_mask, !on);118118-119119-exit:120120- return ret;114114+ return 0;121115}122116123117/**···261263int ti_bandgap_adc_to_mcelsius(struct ti_bandgap *bgp, int adc_val, int *t)262264{263265 const struct ti_bandgap_data *conf = bgp->conf;264264- int ret = 0;265266266267 /* look up for temperature in the table and return the temperature */267267- if (adc_val < conf->adc_start_val || adc_val > conf->adc_end_val) {268268- ret = -ERANGE;269269- goto exit;270270- }268268+ if (adc_val < conf->adc_start_val || adc_val > conf->adc_end_val)269269+ return -ERANGE;271270272271 *t = bgp->conf->conv_table[adc_val - conf->adc_start_val];273273-274274-exit:275275- return ret;272272+ return 0;276273}277274278275/**···288295{289296 const struct ti_bandgap_data *conf = bgp->conf;290297 const int *conv_table = bgp->conf->conv_table;291291- int high, low, mid, ret = 0;298298+ int high, low, mid;292299293300 low = 0;294301 high = conf->adc_end_val - conf->adc_start_val;295302 mid = (high + low) / 2;296303297297- if (temp < conv_table[low] || temp > conv_table[high]) {298298- ret = -ERANGE;299299- goto exit;300300- }304304+ if (temp < conv_table[low] || temp > conv_table[high])305305+ return -ERANGE;301306302307 while (low < high) {303308 if (temp < conv_table[mid])···306315 }307316308317 *adc = conf->adc_start_val + low;309309-310310-exit:311311- return ret;318318+ return 0;312319}313320314321/**···332343 */333344 ret = ti_bandgap_adc_to_mcelsius(bgp, adc_val, &temp);334345 if (ret < 0)335335- goto exit;346346+ return ret;336347337348 temp += hyst_val;338349339350 ret = ti_bandgap_mcelsius_to_adc(bgp, temp, sum);340340-341341-exit:342351 return ret;343352}344353···455468 */456469static inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id)457470{458458- int ret = 0;459459-460471 if (!bgp || IS_ERR(bgp)) {461472 pr_err("%s: invalid bandgap pointer\n", __func__);462462- ret = -EINVAL;463463- goto exit;473473+ return -EINVAL;464474 }465475466476 if ((id < 0) || (id >= bgp->conf->sensor_count)) {467477 dev_err(bgp->dev, "%s: sensor id out of range (%d)\n",468478 __func__, id);469469- ret = -ERANGE;479479+ return -ERANGE;470480 }471481472472-exit:473473- return ret;482482+ return 0;474483}475484476485/**···494511495512 ret = ti_bandgap_validate(bgp, id);496513 if (ret)497497- goto exit;514514+ return ret;498515499499- if (!TI_BANDGAP_HAS(bgp, TALERT)) {500500- ret = -ENOTSUPP;501501- goto exit;502502- }516516+ if (!TI_BANDGAP_HAS(bgp, TALERT))517517+ return -ENOTSUPP;503518504519 ts_data = bgp->conf->sensors[id].ts_data;505520 tsr = bgp->conf->sensors[id].registers;···510529 }511530512531 if (ret)513513- goto exit;532532+ return ret;514533515534 ret = ti_bandgap_mcelsius_to_adc(bgp, val, &adc_val);516535 if (ret < 0)517517- goto exit;536536+ return ret;518537519538 spin_lock(&bgp->lock);520539 ret = ti_bandgap_update_alert_threshold(bgp, id, adc_val, hot);521540 spin_unlock(&bgp->lock);522522-523523-exit:524541 return ret;525542}526543···561582562583 temp = ti_bandgap_readl(bgp, tsr->bgap_threshold);563584 temp = (temp & mask) >> __ffs(mask);564564- ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);585585+ ret = ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);565586 if (ret) {566587 dev_err(bgp->dev, "failed to read thot\n");567588 ret = -EIO;···831852 if (ret)832853 return ret;833854855855+ if (!TI_BANDGAP_HAS(bgp, MODE_CONFIG)) {856856+ ret = ti_bandgap_force_single_read(bgp, id);857857+ if (ret)858858+ return ret;859859+ }860860+834861 spin_lock(&bgp->lock);835862 temp = ti_bandgap_read_temp(bgp, id);836863 spin_unlock(&bgp->lock);837864838838- ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);865865+ ret = ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);839866 if (ret)840867 return -EIO;841868···902917static int903918ti_bandgap_force_single_read(struct ti_bandgap *bgp, int id)904919{905905- u32 temp = 0, counter = 1000;920920+ u32 counter = 1000;921921+ struct temp_sensor_registers *tsr;906922907923 /* Select single conversion mode */908924 if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))···911925912926 /* Start of Conversion = 1 */913927 RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 1);914914- /* Wait until DTEMP is updated */915915- temp = ti_bandgap_read_temp(bgp, id);916928917917- while ((temp == 0) && --counter)918918- temp = ti_bandgap_read_temp(bgp, id);919919- /* REVISIT: Check correct condition for end of conversion */929929+ /* Wait for EOCZ going up */930930+ tsr = bgp->conf->sensors[id].registers;931931+932932+ while (--counter) {933933+ if (ti_bandgap_readl(bgp, tsr->temp_sensor_ctrl) &934934+ tsr->bgap_eocz_mask)935935+ break;936936+ }920937921938 /* Start of Conversion = 0 */922939 RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 0);940940+941941+ /* Wait for EOCZ going down */942942+ counter = 1000;943943+ while (--counter) {944944+ if (!(ti_bandgap_readl(bgp, tsr->temp_sensor_ctrl) &945945+ tsr->bgap_eocz_mask))946946+ break;947947+ }923948924949 return 0;925950}···12171220 goto free_irqs;12181221 }1219122212201220- bgp->div_clk = clk_get(NULL, bgp->conf->div_ck_name);12231223+ bgp->div_clk = clk_get(NULL, bgp->conf->div_ck_name);12211224 ret = IS_ERR(bgp->div_clk);12221225 if (ret) {12231223- dev_err(&pdev->dev,12241224- "failed to request div_ts_ck clock ref\n");12261226+ dev_err(&pdev->dev, "failed to request div_ts_ck clock ref\n");12251227 ret = PTR_ERR(bgp->div_clk);12261228 goto free_irqs;12271229 }
···7575}76767777/* thermal zone ops */7878-/* Get temperature callback function for thermal zone*/7878+/* Get temperature callback function for thermal zone */7979static inline int __ti_thermal_get_temp(void *devdata, long *temp)8080{8181 struct thermal_zone_device *pcb_tz = NULL;···146146 return thermal_zone_bind_cooling_device(thermal, 0, cdev,147147 /* bind with min and max states defined by cpu_cooling */148148 THERMAL_NO_LIMIT,149149- THERMAL_NO_LIMIT);149149+ THERMAL_NO_LIMIT,150150+ THERMAL_WEIGHT_DEFAULT);150151}151152152153/* Unbind callback functions for thermal zone */
···4040/* No upper/lower limit requirement */4141#define THERMAL_NO_LIMIT ((u32)~0)42424343+/* Default weight of a bound cooling device */4444+#define THERMAL_WEIGHT_DEFAULT 04545+4346/* Unit conversion macros */4447#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \4548 ((long)t-2732+5)/10 : ((long)t-2732-5)/10)···5956#define DEFAULT_THERMAL_GOVERNOR "fair_share"6057#elif defined(CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE)6158#define DEFAULT_THERMAL_GOVERNOR "user_space"5959+#elif defined(CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR)6060+#define DEFAULT_THERMAL_GOVERNOR "power_allocator"6261#endif63626463struct thermal_zone_device;6564struct thermal_cooling_device;6565+struct thermal_instance;66666767enum thermal_device_mode {6868 THERMAL_DEVICE_DISABLED = 0,···119113 int (*get_max_state) (struct thermal_cooling_device *, unsigned long *);120114 int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *);121115 int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);116116+ int (*get_requested_power)(struct thermal_cooling_device *,117117+ struct thermal_zone_device *, u32 *);118118+ int (*state2power)(struct thermal_cooling_device *,119119+ struct thermal_zone_device *, unsigned long, u32 *);120120+ int (*power2state)(struct thermal_cooling_device *,121121+ struct thermal_zone_device *, u32, unsigned long *);122122};123123124124struct thermal_cooling_device {···156144 * @devdata: private pointer for device private data157145 * @trips: number of trip points the thermal zone supports158146 * @passive_delay: number of milliseconds to wait between polls when159159- * performing passive cooling. Currenty only used by the160160- * step-wise governor147147+ * performing passive cooling.161148 * @polling_delay: number of milliseconds to wait between polls when162149 * checking whether trip points have been crossed (0 for163150 * interrupt driven systems)···166155 * @last_temperature: previous temperature read167156 * @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION168157 * @passive: 1 if you've crossed a passive trip point, 0 otherwise.169169- * Currenty only used by the step-wise governor.170158 * @forced_passive: If > 0, temperature at which to switch on all ACPI171159 * processor cooling devices. Currently only used by the172160 * step-wise governor.173161 * @ops: operations this &thermal_zone_device supports174162 * @tzp: thermal zone parameters175163 * @governor: pointer to the governor for this thermal zone164164+ * @governor_data: private pointer for governor data176165 * @thermal_instances: list of &struct thermal_instance of this thermal zone177166 * @idr: &struct idr to generate unique id for this zone's cooling178167 * devices···197186 int passive;198187 unsigned int forced_passive;199188 struct thermal_zone_device_ops *ops;200200- const struct thermal_zone_params *tzp;189189+ struct thermal_zone_params *tzp;201190 struct thermal_governor *governor;191191+ void *governor_data;202192 struct list_head thermal_instances;203193 struct idr idr;204194 struct mutex lock;···210198/**211199 * struct thermal_governor - structure that holds thermal governor information212200 * @name: name of the governor201201+ * @bind_to_tz: callback called when binding to a thermal zone. If it202202+ * returns 0, the governor is bound to the thermal zone,203203+ * otherwise it fails.204204+ * @unbind_from_tz: callback called when a governor is unbound from a205205+ * thermal zone.213206 * @throttle: callback called for every trip point even if temperature is214207 * below the trip point temperature215208 * @governor_list: node in thermal_governor_list (in thermal_core.c)216209 */217210struct thermal_governor {218211 char name[THERMAL_NAME_LENGTH];212212+ int (*bind_to_tz)(struct thermal_zone_device *tz);213213+ void (*unbind_from_tz)(struct thermal_zone_device *tz);219214 int (*throttle)(struct thermal_zone_device *tz, int trip);220215 struct list_head governor_list;221216};···233214234215 /*235216 * This is a measure of 'how effectively these devices can236236- * cool 'this' thermal zone. The shall be determined by platform237237- * characterization. This is on a 'percentage' scale.238238- * See Documentation/thermal/sysfs-api.txt for more information.217217+ * cool 'this' thermal zone. It shall be determined by218218+ * platform characterization. This value is relative to the219219+ * rest of the weights so a cooling device whose weight is220220+ * double that of another cooling device is twice as221221+ * effective. See Documentation/thermal/sysfs-api.txt for more222222+ * information.239223 */240224 int weight;241225···275253276254 int num_tbps; /* Number of tbp entries */277255 struct thermal_bind_params *tbp;256256+257257+ /*258258+ * Sustainable power (heat) that this thermal zone can dissipate in259259+ * mW260260+ */261261+ u32 sustainable_power;262262+263263+ /*264264+ * Proportional parameter of the PID controller when265265+ * overshooting (i.e., when temperature is below the target)266266+ */267267+ s32 k_po;268268+269269+ /*270270+ * Proportional parameter of the PID controller when271271+ * undershooting272272+ */273273+ s32 k_pu;274274+275275+ /* Integral parameter of the PID controller */276276+ s32 k_i;277277+278278+ /* Derivative parameter of the PID controller */279279+ s32 k_d;280280+281281+ /* threshold below which the error is no longer accumulated */282282+ s32 integral_cutoff;283283+284284+ /*285285+ * @slope: slope of a linear temperature adjustment curve.286286+ * Used by thermal zone drivers.287287+ */288288+ int slope;289289+ /*290290+ * @offset: offset of a linear temperature adjustment curve.291291+ * Used by thermal zone drivers (default 0).292292+ */293293+ int offset;278294};279295280296struct thermal_genl_event {···376316#endif377317378318#if IS_ENABLED(CONFIG_THERMAL)319319+static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)320320+{321321+ return cdev->ops->get_requested_power && cdev->ops->state2power &&322322+ cdev->ops->power2state;323323+}324324+325325+int power_actor_get_max_power(struct thermal_cooling_device *,326326+ struct thermal_zone_device *tz, u32 *max_power);327327+int power_actor_set_power(struct thermal_cooling_device *,328328+ struct thermal_instance *, u32);379329struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,380330 void *, struct thermal_zone_device_ops *,381381- const struct thermal_zone_params *, int, int);331331+ struct thermal_zone_params *, int, int);382332void thermal_zone_device_unregister(struct thermal_zone_device *);383333384334int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,385335 struct thermal_cooling_device *,386386- unsigned long, unsigned long);336336+ unsigned long, unsigned long,337337+ unsigned int);387338int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,388339 struct thermal_cooling_device *);389340void thermal_zone_device_update(struct thermal_zone_device *);···414343void thermal_cdev_update(struct thermal_cooling_device *);415344void thermal_notify_framework(struct thermal_zone_device *, int);416345#else346346+static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)347347+{ return false; }348348+static inline int power_actor_get_max_power(struct thermal_cooling_device *cdev,349349+ struct thermal_zone_device *tz, u32 *max_power)350350+{ return 0; }351351+static inline int power_actor_set_power(struct thermal_cooling_device *cdev,352352+ struct thermal_instance *tz, u32 power)353353+{ return 0; }417354static inline struct thermal_zone_device *thermal_zone_device_register(418355 const char *type, int trips, int mask, void *devdata,419356 struct thermal_zone_device_ops *ops,