Pull thermal updates from Daniel Lezcano: - Add support to enable/disable the thermal zones resulting on core code and drivers cleanup (Andrzej Pietrasiewicz) - Add generic netlink support for userspace notifications: events, temperature and discovery commands (Daniel Lezcano) - Fix redundant initialization for a ret variable (Colin Ian King) - Remove the clock cooling code as it is used nowhere (Amit Kucheria) - Add the rcar_gen3_thermal's r8a774e1 support (Marian-Cristian Rotariu) - Replace all references to thermal.txt in the documentation to the corresponding yaml files (Amit Kucheria) - Add maintainer entry for the IPA (Lukasz Luba) - Add support for MSM8939 for the tsens (Shawn Guo) - Update power allocator and devfreq cooling to SPDX licensing (Lukasz Luba) - Add Cannon Lake Low Power PCH support (Sumeet Pawnikar) - Add tsensor support for V2 mediatek thermal system (Henry Yen) - Fix thermal zone lookup by ID for the core code (Thierry Reding) * tag 'thermal-v5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux: (40 commits) thermal: intel: intel_pch_thermal: Add Cannon Lake Low Power PCH support thermal: mediatek: Add tsensor support for V2 thermal system thermal: mediatek: Prepare to add support for other platforms thermal: Update power allocator and devfreq cooling to SPDX licensing MAINTAINERS: update entry to thermal governors file name prefixing thermal: core: Add thermal zone enable/disable notification thermal: qcom: tsens-v0_1: Add support for MSM8939 dt-bindings: tsens: qcom: Document MSM8939 compatible thermal: core: Fix thermal zone lookup by ID thermal: int340x: processor_thermal: fix: update Jasper Lake PCI id thermal: imx8mm: Support module autoloading thermal: ti-soc-thermal: Fix reversed condition in ti_thermal_expose_sensor() MAINTAINERS: Add maintenance information for IPA thermal: rcar_gen3_thermal: Do not shadow thcode variable dt-bindings: thermal: Get rid of thermal.txt and replace references thermal: core: Move initialization after core initcall thermal: netlink: Improve the initcall ordering net: genetlink: Move initialization to core_initcall thermal: rcar_gen3_thermal: Add r8a774e1 support thermal/drivers/clock_cooling: Remove clock_cooling code ...
Unified · Split
| @@ -102,7 +102,7 @@ Required sub-node properties: · 101 unmodified lines | ||
| 102 | 102 | [0] http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/index.html |
| 103 | 103 | [1] Documentation/devicetree/bindings/clock/clock-bindings.txt |
| 104 | 104 | [2] Documentation/devicetree/bindings/power/power-domain.yaml |
| 105 | −[3] Documentation/devicetree/bindings/thermal/thermal.txt | |
| 105 | +[3] Documentation/devicetree/bindings/thermal/thermal*.yaml | |
| 106 | 106 | [4] Documentation/devicetree/bindings/sram/sram.yaml |
| 107 | 107 | [5] Documentation/devicetree/bindings/reset/reset.txt |
| 108 | 108 | |
| @@ -108,7 +108,7 @@ Required properties: · 107 unmodified lines | ||
| 108 | 108 | |
| 109 | 109 | [0] http://infocenter.arm.com/help/topic/com.arm.doc.dui0922b/index.html |
| 110 | 110 | [1] Documentation/devicetree/bindings/clock/clock-bindings.txt |
| 111 | −[2] Documentation/devicetree/bindings/thermal/thermal.txt | |
| 111 | +[2] Documentation/devicetree/bindings/thermal/thermal*.yaml | |
| 112 | 112 | [3] Documentation/devicetree/bindings/sram/sram.yaml |
| 113 | 113 | [4] Documentation/devicetree/bindings/power/power-domain.yaml |
| 114 | 114 | |
| @@ -176,7 +176,7 @@ Required properties: · 175 unmodified lines | ||
| 176 | 176 | "fsl,imx8qxp-sc-thermal" |
| 177 | 177 | followed by "fsl,imx-sc-thermal"; |
| 178 | 178 | |
| 179 | −- #thermal-sensor-cells: See Documentation/devicetree/bindings/thermal/thermal.txt | |
| 179 | +- #thermal-sensor-cells: See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml | |
| 180 | 180 | for a description. |
| 181 | 181 | |
| 182 | 182 | Example (imx8qxp): |
| @@ -111,7 +111,7 @@ Thermal: · 110 unmodified lines | ||
| 111 | 111 | -------- |
| 112 | 112 | |
| 113 | 113 | For common binding part and usage, refer to |
| 114 | −Documentation/devicetree/bindings/thermal/thermal.txt | |
| 114 | +Documentation/devicetree/bindings/thermal/thermal*.yaml | |
| 115 | 115 | |
| 116 | 116 | The thermal IP can probe the temperature all around the processor. It |
| 117 | 117 | may feature several channels, each of them wired to one sensor. |
| @@ -203,7 +203,7 @@ It is possible to setup an overheat interrupt by giving at least one · 202 unmodified lines | ||
| 203 | 203 | critical point to any subnode of the thermal-zone node. |
| 204 | 204 | |
| 205 | 205 | For common binding part and usage, refer to |
| 206 | −Documentation/devicetree/bindings/thermal/thermal.txt | |
| 206 | +Documentation/devicetree/bindings/thermal/thermal*.yaml | |
| 207 | 207 | |
| 208 | 208 | Required properties: |
| 209 | 209 | - compatible: must be one of: |
| @@ -18,7 +18,8 @@ Optional properties: · 17 unmodified lines | ||
| 18 | 18 | in unit of nanoseconds. |
| 19 | 19 | - voltage-tolerance: Specify the CPU voltage tolerance in percentage. |
| 20 | 20 | - #cooling-cells: |
| 21 | − Please refer to Documentation/devicetree/bindings/thermal/thermal.txt. | |
| 21 | + Please refer to | |
| 22 | + Documentation/devicetree/bindings/thermal/thermal-cooling-devices.yaml. | |
| 22 | 23 | |
| 23 | 24 | Examples: |
| 24 | 25 | |
| @@ -21,8 +21,8 @@ Optional properties: · 20 unmodified lines | ||
| 21 | 21 | flow is handled by hardware, hence no software "voltage tracking" is |
| 22 | 22 | needed. |
| 23 | 23 | - #cooling-cells: |
| 24 | − Please refer to Documentation/devicetree/bindings/thermal/thermal.txt | |
| 25 | − for detail. | |
| 24 | + For details, please refer to | |
| 25 | + Documentation/devicetree/bindings/thermal/thermal-cooling-devices.yaml | |
| 26 | 26 | |
| 27 | 27 | Example 1 (MT7623 SoC): |
| 28 | 28 | |
| @@ -5,7 +5,7 @@ Required properties: · 4 unmodified lines | ||
| 5 | 5 | - clocks: Must contain an entry for the CPU clock. |
| 6 | 6 | See ../clocks/clock-bindings.txt for details. |
| 7 | 7 | - operating-points-v2: See ../bindings/opp/opp.txt for details. |
| 8 | −- #cooling-cells: Should be 2. See ../thermal/thermal.txt for details. | |
| 8 | +- #cooling-cells: Should be 2. See ../thermal/thermal-cooling-devices.yaml for details. | |
| 9 | 9 | |
| 10 | 10 | For each opp entry in 'operating-points-v2' table: |
| 11 | 11 | - opp-supported-hw: Two bitfields indicating: |
| @@ -12,7 +12,8 @@ Optional properties: · 11 unmodified lines | ||
| 12 | 12 | - alarm-gpios: This pin going active indicates something is wrong with |
| 13 | 13 | the fan, and a udev event will be fired. |
| 14 | 14 | - #cooling-cells: If used as a cooling device, must be <2> |
| 15 | − Also see: Documentation/devicetree/bindings/thermal/thermal.txt | |
| 15 | + Also see: | |
| 16 | + Documentation/devicetree/bindings/thermal/thermal-cooling-devices.yaml | |
| 16 | 17 | min and max states are derived from the speed-map of the fan. |
| 17 | 18 | |
| 18 | 19 | Note: At least one the "gpios" or "alarm-gpios" properties must be set. |
| @@ -34,8 +34,8 @@ Optional properties: · 33 unmodified lines | ||
| 34 | 34 | LM90 "-ALERT" pin output. |
| 35 | 35 | See interrupt-controller/interrupts.txt for the format. |
| 36 | 36 | |
| 37 | −- #thermal-sensor-cells: should be set to 1. See thermal/thermal.txt for | |
| 38 | − details. See <include/dt-bindings/thermal/lm90.h> for the | |
| 37 | +- #thermal-sensor-cells: should be set to 1. See thermal/thermal-sensor.yaml | |
| 38 | + for details. See <include/dt-bindings/thermal/lm90.h> for the | |
| 39 | 39 | definition of the local, remote and 2nd remote sensor index |
| 40 | 40 | constants. |
| 41 | 41 | |
| @@ -50,7 +50,7 @@ properties: · 49 unmodified lines | ||
| 50 | 50 | nvmem-cell-names: |
| 51 | 51 | const: calibration |
| 52 | 52 | |
| 53 | − # See ./thermal.txt for details | |
| 53 | + # See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for details | |
| 54 | 54 | "#thermal-sensor-cells": |
| 55 | 55 | enum: |
| 56 | 56 | - 0 |
| @@ -6,7 +6,7 @@ transaction. · 5 unmodified lines | ||
| 6 | 6 | Required properties: |
| 7 | 7 | - compatible: "amazon,al-thermal". |
| 8 | 8 | - reg: The physical base address and length of the sensor's registers. |
| 9 | −- #thermal-sensor-cells: Must be 1. See ./thermal.txt for a description. | |
| 9 | +- #thermal-sensor-cells: Must be 1. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description. | |
| 10 | 10 | |
| 11 | 11 | Example: |
| 12 | 12 | thermal: thermal { |
| @@ -23,7 +23,7 @@ properties: · 22 unmodified lines | ||
| 23 | 23 | compatible: |
| 24 | 24 | const: brcm,bcm2711-thermal |
| 25 | 25 | |
| 26 | − # See ./thermal.txt for details | |
| 26 | + # See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for details | |
| 27 | 27 | "#thermal-sensor-cells": |
| 28 | 28 | const: 0 |
| 29 | 29 | |
| @@ -7,7 +7,7 @@ compatible: should be one of: "brcm,bcm2835-thermal", · 6 unmodified lines | ||
| 7 | 7 | "brcm,bcm2836-thermal" or "brcm,bcm2837-thermal" |
| 8 | 8 | reg: Address range of the thermal registers. |
| 9 | 9 | clocks: Phandle of the clock used by the thermal sensor. |
| 10 | −#thermal-sensor-cells: should be 0 (see thermal.txt) | |
| 10 | +#thermal-sensor-cells: should be 0 (see Documentation/devicetree/bindings/thermal/thermal-sensor.yaml) | |
| 11 | 11 | |
| 12 | 12 | Example: |
| 13 | 13 | |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | by /SOCTHERM/tsensor. |
| 10 | 10 | - clock-names: Input clock name, should be 'thermal_clk'. |
| 11 | 11 | - clocks: phandles for clock specified in "clock-names" property. |
| 12 | −- #thermal-sensor-cells: Should be 1. See ./thermal.txt for a description. | |
| 12 | +- #thermal-sensor-cells: Should be 1. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description. | |
| 13 | 13 | |
| 14 | 14 | Example : |
| 15 | 15 | |
| @@ -8,12 +8,12 @@ below threshold level. · 7 unmodified lines | ||
| 8 | 8 | |
| 9 | 9 | Required properties: |
| 10 | 10 | ------------------- |
| 11 | −#thermal-sensor-cells: Please refer <devicetree/bindings/thermal/thermal.txt> | |
| 12 | − for more details. | |
| 11 | +#thermal-sensor-cells: For more details, please refer to | |
| 12 | + <devicetree/bindings/thermal/thermal-sensor.yaml> | |
| 13 | 13 | The value must be 0. |
| 14 | 14 | |
| 15 | 15 | For more details, please refer generic thermal DT binding document |
| 16 | −<devicetree/bindings/thermal/thermal.txt>. | |
| 16 | +<devicetree/bindings/thermal/thermal*.yaml>. | |
| 17 | 17 | |
| 18 | 18 | Please refer <devicetree/bindings/mfd/max77620.txt> for mfd DT binding |
| 19 | 19 | document for the MAX77620. |
| @@ -23,7 +23,7 @@ Required properties: · 22 unmodified lines | ||
| 23 | 23 | - resets: Reference to the reset controller controlling the thermal controller. |
| 24 | 24 | - mediatek,auxadc: A phandle to the AUXADC which the thermal controller uses |
| 25 | 25 | - mediatek,apmixedsys: A phandle to the APMIXEDSYS controller. |
| 26 | −- #thermal-sensor-cells : Should be 0. See ./thermal.txt for a description. | |
| 26 | +- #thermal-sensor-cells : Should be 0. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description. | |
| 27 | 27 | |
| 28 | 28 | Optional properties: |
| 29 | 29 | - nvmem-cells: A phandle to the calibration data provided by a nvmem device. If |
| @@ -28,9 +28,10 @@ Required properties : · 27 unmodified lines | ||
| 28 | 28 | See ../reset/reset.txt for details. |
| 29 | 29 | - reset-names : Must include the following entries: |
| 30 | 30 | - soctherm |
| 31 | −- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description | |
| 32 | − of this property. See <dt-bindings/thermal/tegra124-soctherm.h> for a | |
| 33 | − list of valid values when referring to thermal sensors. | |
| 31 | +- #thermal-sensor-cells : Should be 1. For a description of this property, see | |
| 32 | + Documentation/devicetree/bindings/thermal/thermal-sensor.yaml. | |
| 33 | + See <dt-bindings/thermal/tegra124-soctherm.h> for a list of valid values | |
| 34 | + when referring to thermal sensors. | |
| 34 | 35 | - throttle-cfgs: A sub-node which is a container of configuration for each |
| 35 | 36 | hardware throttle events. These events can be set as cooling devices. |
| 36 | 37 | * throttle events: Sub-nodes must be named as "light" or "heavy". |
| @@ -62,7 +63,8 @@ Required properties : · 25 unmodified lines | ||
| 62 | 63 | TEGRA_SOCTHERM_THROT_LEVEL_MED (75%), |
| 63 | 64 | TEGRA_SOCTHERM_THROT_LEVEL_HIGH (85%). |
| 64 | 65 | - #cooling-cells: Should be 1. This cooling device only support on/off state. |
| 65 | − See ./thermal.txt for a description of this property. | |
| 66 | + For a description of this property see: | |
| 67 | + Documentation/devicetree/bindings/thermal/thermal-cooling-devices.yaml | |
| 66 | 68 | |
| 67 | 69 | Optional properties: The following properties are T210 specific and |
| 68 | 70 | valid only for OCx throttle events. |
| @@ -8,7 +8,7 @@ exposed by BPMP. · 7 unmodified lines | ||
| 8 | 8 | The BPMP thermal node must be located directly inside the main BPMP node. See |
| 9 | 9 | ../firmware/nvidia,tegra186-bpmp.txt for details of the BPMP binding. |
| 10 | 10 | |
| 11 | −This node represents a thermal sensor. See thermal.txt for details of the | |
| 11 | +This node represents a thermal sensor. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for details of the | |
| 12 | 12 | core thermal binding. |
| 13 | 13 | |
| 14 | 14 | Required properties: |
| @@ -8,7 +8,7 @@ Required properties: · 7 unmodified lines | ||
| 8 | 8 | - compatible: Should contain "qcom,spmi-temp-alarm". |
| 9 | 9 | - reg: Specifies the SPMI address. |
| 10 | 10 | - interrupts: PMIC temperature alarm interrupt. |
| 11 | −- #thermal-sensor-cells: Should be 0. See thermal.txt for a description. | |
| 11 | +- #thermal-sensor-cells: Should be 0. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description. | |
| 12 | 12 | |
| 13 | 13 | Optional properties: |
| 14 | 14 | - io-channels: Should contain IIO channel specifier for the ADC channel, |
| @@ -23,6 +23,7 @@ properties: · 22 unmodified lines | ||
| 23 | 23 | items: |
| 24 | 24 | - enum: |
| 25 | 25 | - qcom,msm8916-tsens |
| 26 | + - qcom,msm8939-tsens | |
| 26 | 27 | - qcom,msm8974-tsens |
| 27 | 28 | - const: qcom,tsens-v0_1 |
| 28 | 29 | |
| @@ -24,7 +24,7 @@ Required properties: · 23 unmodified lines | ||
| 24 | 24 | - pinctrl-1 : The "default" pinctrl state, it will be set after reset the |
| 25 | 25 | TSADC controller. |
| 26 | 26 | - pinctrl-2 : The "sleep" pinctrl state, it will be in for suspend. |
| 27 | −- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description. | |
| 27 | +- #thermal-sensor-cells : Should be 1. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description. | |
| 28 | 28 | |
| 29 | 29 | Optional properties: |
| 30 | 30 | - rockchip,hw-tshut-temp : The hardware-controlled shutdown temperature value. |
| @@ -4,7 +4,7 @@ The SMP8758 SoC includes 3 instances of this temperature sensor · 3 unmodified lines | ||
| 4 | 4 | (in the CPU, video decoder, and PCIe controller). |
| 5 | 5 | |
| 6 | 6 | Required properties: |
| 7 | −- #thermal-sensor-cells: Should be 0 (see thermal.txt) | |
| 7 | +- #thermal-sensor-cells: Should be 0 (see Documentation/devicetree/bindings/thermal/thermal-sensor.yaml) | |
| 8 | 8 | - compatible: "sigma,smp8758-thermal" |
| 9 | 9 | - reg: Address range of the thermal registers |
| 10 | 10 | |
| @@ -8,7 +8,7 @@ temperature using voltage-temperature lookup table. · 7 unmodified lines | ||
| 8 | 8 | Required properties: |
| 9 | 9 | =================== |
| 10 | 10 | - compatible: Must be "generic-adc-thermal". |
| 11 | −- #thermal-sensor-cells: Should be 1. See ./thermal.txt for a description | |
| 11 | +- #thermal-sensor-cells: Should be 1. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description | |
| 12 | 12 | of this property. |
| 13 | 13 | Optional properties: |
| 14 | 14 | =================== |
| @@ -1,586 +0,0 @@ | ||
| 1 | −* Thermal Framework Device Tree descriptor | |
| 2 | − | |
| 3 | −This file describes a generic binding to provide a way of | |
| 4 | −defining hardware thermal structure using device tree. | |
| 5 | −A thermal structure includes thermal zones and their components, | |
| 6 | −such as trip points, polling intervals, sensors and cooling devices | |
| 7 | −binding descriptors. | |
| 8 | − | |
| 9 | −The target of device tree thermal descriptors is to describe only | |
| 10 | −the hardware thermal aspects. The thermal device tree bindings are | |
| 11 | −not about how the system must control or which algorithm or policy | |
| 12 | −must be taken in place. | |
| 13 | − | |
| 14 | −There are five types of nodes involved to describe thermal bindings: | |
| 15 | −- thermal sensors: devices which may be used to take temperature | |
| 16 | − measurements. | |
| 17 | −- cooling devices: devices which may be used to dissipate heat. | |
| 18 | −- trip points: describe key temperatures at which cooling is recommended. The | |
| 19 | − set of points should be chosen based on hardware limits. | |
| 20 | −- cooling maps: used to describe links between trip points and cooling devices; | |
| 21 | −- thermal zones: used to describe thermal data within the hardware; | |
| 22 | − | |
| 23 | −The following is a description of each of these node types. | |
| 24 | − | |
| 25 | −* Thermal sensor devices | |
| 26 | − | |
| 27 | −Thermal sensor devices are nodes providing temperature sensing capabilities on | |
| 28 | −thermal zones. Typical devices are I2C ADC converters and bandgaps. These are | |
| 29 | −nodes providing temperature data to thermal zones. Thermal sensor devices may | |
| 30 | −control one or more internal sensors. | |
| 31 | − | |
| 32 | −Required property: | |
| 33 | −- #thermal-sensor-cells: Used to provide sensor device specific information | |
| 34 | − Type: unsigned while referring to it. Typically 0 on thermal sensor | |
| 35 | − Size: one cell nodes with only one sensor, and at least 1 on nodes | |
| 36 | − with several internal sensors, in order | |
| 37 | − to identify uniquely the sensor instances within | |
| 38 | − the IC. See thermal zone binding for more details | |
| 39 | − on how consumers refer to sensor devices. | |
| 40 | − | |
| 41 | −* Cooling device nodes | |
| 42 | − | |
| 43 | −Cooling devices are nodes providing control on power dissipation. There | |
| 44 | −are essentially two ways to provide control on power dissipation. First | |
| 45 | −is by means of regulating device performance, which is known as passive | |
| 46 | −cooling. A typical passive cooling is a CPU that has dynamic voltage and | |
| 47 | −frequency scaling (DVFS), and uses lower frequencies as cooling states. | |
| 48 | −Second is by means of activating devices in order to remove | |
| 49 | −the dissipated heat, which is known as active cooling, e.g. regulating | |
| 50 | −fan speeds. In both cases, cooling devices shall have a way to determine | |
| 51 | −the state of cooling in which the device is. | |
| 52 | − | |
| 53 | −Any cooling device has a range of cooling states (i.e. different levels | |
| 54 | −of heat dissipation). For example a fan's cooling states correspond to | |
| 55 | −the different fan speeds possible. Cooling states are referred to by | |
| 56 | −single unsigned integers, where larger numbers mean greater heat | |
| 57 | −dissipation. The precise set of cooling states associated with a device | |
| 58 | −should be defined in a particular device's binding. | |
| 59 | −For more examples of cooling devices, refer to the example sections below. | |
| 60 | − | |
| 61 | −Required properties: | |
| 62 | −- #cooling-cells: Used to provide cooling device specific information | |
| 63 | − Type: unsigned while referring to it. Must be at least 2, in order | |
| 64 | − Size: one cell to specify minimum and maximum cooling state used | |
| 65 | − in the reference. The first cell is the minimum | |
| 66 | − cooling state requested and the second cell is | |
| 67 | − the maximum cooling state requested in the reference. | |
| 68 | − See Cooling device maps section below for more details | |
| 69 | − on how consumers refer to cooling devices. | |
| 70 | − | |
| 71 | −* Trip points | |
| 72 | − | |
| 73 | −The trip node is a node to describe a point in the temperature domain | |
| 74 | −in which the system takes an action. This node describes just the point, | |
| 75 | −not the action. | |
| 76 | − | |
| 77 | −Required properties: | |
| 78 | −- temperature: An integer indicating the trip temperature level, | |
| 79 | − Type: signed in millicelsius. | |
| 80 | − Size: one cell | |
| 81 | − | |
| 82 | −- hysteresis: A low hysteresis value on temperature property (above). | |
| 83 | − Type: unsigned This is a relative value, in millicelsius. | |
| 84 | − Size: one cell | |
| 85 | − | |
| 86 | −- type: a string containing the trip type. Expected values are: | |
| 87 | − "active": A trip point to enable active cooling | |
| 88 | − "passive": A trip point to enable passive cooling | |
| 89 | − "hot": A trip point to notify emergency | |
| 90 | − "critical": Hardware not reliable. | |
| 91 | − Type: string | |
| 92 | − | |
| 93 | −* Cooling device maps | |
| 94 | − | |
| 95 | −The cooling device maps node is a node to describe how cooling devices | |
| 96 | −get assigned to trip points of the zone. The cooling devices are expected | |
| 97 | −to be loaded in the target system. | |
| 98 | − | |
| 99 | −Required properties: | |
| 100 | −- cooling-device: A list of phandles of cooling devices with their specifiers, | |
| 101 | − Type: phandle + referring to which cooling devices are used in this | |
| 102 | − cooling specifier binding. In the cooling specifier, the first cell | |
| 103 | − is the minimum cooling state and the second cell | |
| 104 | − is the maximum cooling state used in this map. | |
| 105 | −- trip: A phandle of a trip point node within the same thermal | |
| 106 | − Type: phandle of zone. | |
| 107 | − trip point node | |
| 108 | − | |
| 109 | −Optional property: | |
| 110 | −- contribution: The cooling contribution to the thermal zone of the | |
| 111 | − Type: unsigned referred cooling device at the referred trip point. | |
| 112 | − Size: one cell The contribution is a ratio of the sum | |
| 113 | − of all cooling contributions within a thermal zone. | |
| 114 | − | |
| 115 | −Note: Using the THERMAL_NO_LIMIT (-1UL) constant in the cooling-device phandle | |
| 116 | −limit specifier means: | |
| 117 | −(i) - minimum state allowed for minimum cooling state used in the reference. | |
| 118 | −(ii) - maximum state allowed for maximum cooling state used in the reference. | |
| 119 | −Refer to include/dt-bindings/thermal/thermal.h for definition of this constant. | |
| 120 | − | |
| 121 | −* Thermal zone nodes | |
| 122 | − | |
| 123 | −The thermal zone node is the node containing all the required info | |
| 124 | −for describing a thermal zone, including its cooling device bindings. The | |
| 125 | −thermal zone node must contain, apart from its own properties, one sub-node | |
| 126 | −containing trip nodes and one sub-node containing all the zone cooling maps. | |
| 127 | − | |
| 128 | −Required properties: | |
| 129 | −- polling-delay: The maximum number of milliseconds to wait between polls | |
| 130 | − Type: unsigned when checking this thermal zone. | |
| 131 | − Size: one cell | |
| 132 | − | |
| 133 | −- polling-delay-passive: The maximum number of milliseconds to wait | |
| 134 | − Type: unsigned between polls when performing passive cooling. | |
| 135 | − Size: one cell | |
| 136 | − | |
| 137 | −- thermal-sensors: A list of thermal sensor phandles and sensor specifier | |
| 138 | − Type: list of used while monitoring the thermal zone. | |
| 139 | − phandles + sensor | |
| 140 | − specifier | |
| 141 | − | |
| 142 | −- trips: A sub-node which is a container of only trip point nodes | |
| 143 | − Type: sub-node required to describe the thermal zone. | |
| 144 | − | |
| 145 | −Optional property: | |
| 146 | −- cooling-maps: A sub-node which is a container of only cooling device | |
| 147 | − Type: sub-node map nodes, used to describe the relation between trips | |
| 148 | − and cooling devices. | |
| 149 | − | |
| 150 | −- coefficients: An array of integers (one signed cell) containing | |
| 151 | − Type: array coefficients to compose a linear relation between | |
| 152 | − Elem size: one cell the sensors listed in the thermal-sensors property. | |
| 153 | − Elem type: signed Coefficients defaults to 1, in case this property | |
| 154 | − is not specified. A simple linear polynomial is used: | |
| 155 | − Z = c0 * x0 + c1 * x1 + ... + c(n-1) * x(n-1) + cn. | |
| 156 | − | |
| 157 | − The coefficients are ordered and they match with sensors | |
| 158 | − by means of sensor ID. Additional coefficients are | |
| 159 | − interpreted as constant offset. | |
| 160 | − | |
| 161 | −- sustainable-power: An estimate of the sustainable power (in mW) that the | |
| 162 | − Type: unsigned thermal zone can dissipate at the desired | |
| 163 | − Size: one cell control temperature. For reference, the | |
| 164 | − sustainable power of a 4'' phone is typically | |
| 165 | − 2000mW, while on a 10'' tablet is around | |
| 166 | − 4500mW. | |
| 167 | − | |
| 168 | −Note: The delay properties are bound to the maximum dT/dt (temperature | |
| 169 | −derivative over time) in two situations for a thermal zone: | |
| 170 | −(i) - when passive cooling is activated (polling-delay-passive); and | |
| 171 | −(ii) - when the zone just needs to be monitored (polling-delay) or | |
| 172 | −when active cooling is activated. | |
| 173 | − | |
| 174 | −The maximum dT/dt is highly bound to hardware power consumption and dissipation | |
| 175 | −capability. The delays should be chosen to account for said max dT/dt, | |
| 176 | −such that a device does not cross several trip boundaries unexpectedly | |
| 177 | −between polls. Choosing the right polling delays shall avoid having the | |
| 178 | −device in temperature ranges that may damage the silicon structures and | |
| 179 | −reduce silicon lifetime. | |
| 180 | − | |
| 181 | −* The thermal-zones node | |
| 182 | − | |
| 183 | −The "thermal-zones" node is a container for all thermal zone nodes. It shall | |
| 184 | −contain only sub-nodes describing thermal zones as in the section | |
| 185 | −"Thermal zone nodes". The "thermal-zones" node appears under "/". | |
| 186 | − | |
| 187 | −* Examples | |
| 188 | − | |
| 189 | −Below are several examples on how to use thermal data descriptors | |
| 190 | −using device tree bindings: | |
| 191 | − | |
| 192 | −(a) - CPU thermal zone | |
| 193 | − | |
| 194 | −The CPU thermal zone example below describes how to setup one thermal zone | |
| 195 | −using one single sensor as temperature source and many cooling devices and | |
| 196 | −power dissipation control sources. | |
| 197 | − | |
| 198 | −#include <dt-bindings/thermal/thermal.h> | |
| 199 | − | |
| 200 | −cpus { | |
| 201 | − /* | |
| 202 | − * Here is an example of describing a cooling device for a DVFS | |
| 203 | − * capable CPU. The CPU node describes its four OPPs. | |
| 204 | − * The cooling states possible are 0..3, and they are | |
| 205 | − * used as OPP indexes. The minimum cooling state is 0, which means | |
| 206 | − * all four OPPs can be available to the system. The maximum | |
| 207 | − * cooling state is 3, which means only the lowest OPPs (198MHz@0.85V) | |
| 208 | − * can be available in the system. | |
| 209 | − */ | |
| 210 | − cpu0: cpu@0 { | |
| 211 | − ... | |
| 212 | − operating-points = < | |
| 213 | − /* kHz uV */ | |
| 214 | − 970000 1200000 | |
| 215 | − 792000 1100000 | |
| 216 | − 396000 950000 | |
| 217 | − 198000 850000 | |
| 218 | − >; | |
| 219 | − #cooling-cells = <2>; /* min followed by max */ | |
| 220 | − }; | |
| 221 | − ... | |
| 222 | −}; | |
| 223 | − | |
| 224 | −&i2c1 { | |
| 225 | − ... | |
| 226 | − /* | |
| 227 | − * A simple fan controller which supports 10 speeds of operation | |
| 228 | − * (represented as 0-9). | |
| 229 | − */ | |
| 230 | − fan0: fan@48 { | |
| 231 | − ... | |
| 232 | − #cooling-cells = <2>; /* min followed by max */ | |
| 233 | − }; | |
| 234 | −}; | |
| 235 | − | |
| 236 | −ocp { | |
| 237 | − ... | |
| 238 | − /* | |
| 239 | − * A simple IC with a single bandgap temperature sensor. | |
| 240 | − */ | |
| 241 | − bandgap0: bandgap@0000ed00 { | |
| 242 | − ... | |
| 243 | − #thermal-sensor-cells = <0>; | |
| 244 | − }; | |
| 245 | −}; | |
| 246 | − | |
| 247 | −thermal-zones { | |
| 248 | − cpu_thermal: cpu-thermal { | |
| 249 | − polling-delay-passive = <250>; /* milliseconds */ | |
| 250 | − polling-delay = <1000>; /* milliseconds */ | |
| 251 | − | |
| 252 | − thermal-sensors = <&bandgap0>; | |
| 253 | − | |
| 254 | − trips { | |
| 255 | − cpu_alert0: cpu-alert0 { | |
| 256 | − temperature = <90000>; /* millicelsius */ | |
| 257 | − hysteresis = <2000>; /* millicelsius */ | |
| 258 | − type = "active"; | |
| 259 | − }; | |
| 260 | − cpu_alert1: cpu-alert1 { | |
| 261 | − temperature = <100000>; /* millicelsius */ | |
| 262 | − hysteresis = <2000>; /* millicelsius */ | |
| 263 | − type = "passive"; | |
| 264 | − }; | |
| 265 | − cpu_crit: cpu-crit { | |
| 266 | − temperature = <125000>; /* millicelsius */ | |
| 267 | − hysteresis = <2000>; /* millicelsius */ | |
| 268 | − type = "critical"; | |
| 269 | − }; | |
| 270 | − }; | |
| 271 | − | |
| 272 | − cooling-maps { | |
| 273 | − map0 { | |
| 274 | − trip = <&cpu_alert0>; | |
| 275 | − cooling-device = <&fan0 THERMAL_NO_LIMIT 4>; | |
| 276 | − }; | |
| 277 | − map1 { | |
| 278 | − trip = <&cpu_alert1>; | |
| 279 | − cooling-device = <&fan0 5 THERMAL_NO_LIMIT>, <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; | |
| 280 | − }; | |
| 281 | − }; | |
| 282 | − }; | |
| 283 | −}; | |
| 284 | − | |
| 285 | −In the example above, the ADC sensor (bandgap0) at address 0x0000ED00 is | |
| 286 | −used to monitor the zone 'cpu-thermal' using its sole sensor. A fan | |
| 287 | −device (fan0) is controlled via I2C bus 1, at address 0x48, and has ten | |
| 288 | −different cooling states 0-9. It is used to remove the heat out of | |
| 289 | −the thermal zone 'cpu-thermal' using its cooling states | |
| 290 | −from its minimum to 4, when it reaches trip point 'cpu_alert0' | |
| 291 | −at 90C, as an example of active cooling. The same cooling device is used at | |
| 292 | −'cpu_alert1', but from 5 to its maximum state. The cpu@0 device is also | |
| 293 | −linked to the same thermal zone, 'cpu-thermal', as a passive cooling device, | |
| 294 | −using all its cooling states at trip point 'cpu_alert1', | |
| 295 | −which is a trip point at 100C. On the thermal zone 'cpu-thermal', at the | |
| 296 | −temperature of 125C, represented by the trip point 'cpu_crit', the silicon | |
| 297 | −is not reliable anymore. | |
| 298 | − | |
| 299 | −(b) - IC with several internal sensors | |
| 300 | − | |
| 301 | −The example below describes how to deploy several thermal zones based off a | |
| 302 | −single sensor IC, assuming it has several internal sensors. This is a common | |
| 303 | −case on SoC designs with several internal IPs that may need different thermal | |
| 304 | −requirements, and thus may have their own sensor to monitor or detect internal | |
| 305 | −hotspots in their silicon. | |
| 306 | − | |
| 307 | −#include <dt-bindings/thermal/thermal.h> | |
| 308 | − | |
| 309 | −ocp { | |
| 310 | − ... | |
| 311 | − /* | |
| 312 | − * A simple IC with several bandgap temperature sensors. | |
| 313 | − */ | |
| 314 | − bandgap0: bandgap@0000ed00 { | |
| 315 | − ... | |
| 316 | − #thermal-sensor-cells = <1>; | |
| 317 | − }; | |
| 318 | −}; | |
| 319 | − | |
| 320 | −thermal-zones { | |
| 321 | − cpu_thermal: cpu-thermal { | |
| 322 | − polling-delay-passive = <250>; /* milliseconds */ | |
| 323 | − polling-delay = <1000>; /* milliseconds */ | |
| 324 | − | |
| 325 | − /* sensor ID */ | |
| 326 | − thermal-sensors = <&bandgap0 0>; | |
| 327 | − | |
| 328 | − trips { | |
| 329 | − /* each zone within the SoC may have its own trips */ | |
| 330 | − cpu_alert: cpu-alert { | |
| 331 | − temperature = <100000>; /* millicelsius */ | |
| 332 | − hysteresis = <2000>; /* millicelsius */ | |
| 333 | − type = "passive"; | |
| 334 | − }; | |
| 335 | − cpu_crit: cpu-crit { | |
| 336 | − temperature = <125000>; /* millicelsius */ | |
| 337 | − hysteresis = <2000>; /* millicelsius */ | |
| 338 | − type = "critical"; | |
| 339 | − }; | |
| 340 | − }; | |
| 341 | − | |
| 342 | − cooling-maps { | |
| 343 | − /* each zone within the SoC may have its own cooling */ | |
| 344 | − ... | |
| 345 | − }; | |
| 346 | − }; | |
| 347 | − | |
| 348 | − gpu_thermal: gpu-thermal { | |
| 349 | − polling-delay-passive = <120>; /* milliseconds */ | |
| 350 | − polling-delay = <1000>; /* milliseconds */ | |
| 351 | − | |
| 352 | − /* sensor ID */ | |
| 353 | − thermal-sensors = <&bandgap0 1>; | |
| 354 | − | |
| 355 | − trips { | |
| 356 | − /* each zone within the SoC may have its own trips */ | |
| 357 | − gpu_alert: gpu-alert { | |
| 358 | − temperature = <90000>; /* millicelsius */ | |
| 359 | − hysteresis = <2000>; /* millicelsius */ | |
| 360 | − type = "passive"; | |
| 361 | − }; | |
| 362 | − gpu_crit: gpu-crit { | |
| 363 | − temperature = <105000>; /* millicelsius */ | |
| 364 | − hysteresis = <2000>; /* millicelsius */ | |
| 365 | − type = "critical"; | |
| 366 | − }; | |
| 367 | − }; | |
| 368 | − | |
| 369 | − cooling-maps { | |
| 370 | − /* each zone within the SoC may have its own cooling */ | |
| 371 | − ... | |
| 372 | − }; | |
| 373 | − }; | |
| 374 | − | |
| 375 | − dsp_thermal: dsp-thermal { | |
| 376 | − polling-delay-passive = <50>; /* milliseconds */ | |
| 377 | − polling-delay = <1000>; /* milliseconds */ | |
| 378 | − | |
| 379 | − /* sensor ID */ | |
| 380 | − thermal-sensors = <&bandgap0 2>; | |
| 381 | − | |
| 382 | − trips { | |
| 383 | − /* each zone within the SoC may have its own trips */ | |
| 384 | − dsp_alert: dsp-alert { | |
| 385 | − temperature = <90000>; /* millicelsius */ | |
| 386 | − hysteresis = <2000>; /* millicelsius */ | |
| 387 | − type = "passive"; | |
| 388 | − }; | |
| 389 | − dsp_crit: gpu-crit { | |
| 390 | − temperature = <135000>; /* millicelsius */ | |
| 391 | − hysteresis = <2000>; /* millicelsius */ | |
| 392 | − type = "critical"; | |
| 393 | − }; | |
| 394 | − }; | |
| 395 | − | |
| 396 | − cooling-maps { | |
| 397 | − /* each zone within the SoC may have its own cooling */ | |
| 398 | − ... | |
| 399 | − }; | |
| 400 | − }; | |
| 401 | −}; | |
| 402 | − | |
| 403 | −In the example above, there is one bandgap IC which has the capability to | |
| 404 | −monitor three sensors. The hardware has been designed so that sensors are | |
| 405 | −placed on different places in the DIE to monitor different temperature | |
| 406 | −hotspots: one for CPU thermal zone, one for GPU thermal zone and the | |
| 407 | −other to monitor a DSP thermal zone. | |
| 408 | − | |
| 409 | −Thus, there is a need to assign each sensor provided by the bandgap IC | |
| 410 | −to different thermal zones. This is achieved by means of using the | |
| 411 | −#thermal-sensor-cells property and using the first cell of the sensor | |
| 412 | −specifier as sensor ID. In the example, then, <bandgap 0> is used to | |
| 413 | −monitor CPU thermal zone, <bandgap 1> is used to monitor GPU thermal | |
| 414 | −zone and <bandgap 2> is used to monitor DSP thermal zone. Each zone | |
| 415 | −may be uncorrelated, having its own dT/dt requirements, trips | |
| 416 | −and cooling maps. | |
| 417 | − | |
| 418 | − | |
| 419 | −(c) - Several sensors within one single thermal zone | |
| 420 | − | |
| 421 | −The example below illustrates how to use more than one sensor within | |
| 422 | −one thermal zone. | |
| 423 | − | |
| 424 | −#include <dt-bindings/thermal/thermal.h> | |
| 425 | − | |
| 426 | −&i2c1 { | |
| 427 | − ... | |
| 428 | − /* | |
| 429 | − * A simple IC with a single temperature sensor. | |
| 430 | − */ | |
| 431 | − adc: sensor@49 { | |
| 432 | − ... | |
| 433 | − #thermal-sensor-cells = <0>; | |
| 434 | − }; | |
| 435 | −}; | |
| 436 | − | |
| 437 | −ocp { | |
| 438 | − ... | |
| 439 | − /* | |
| 440 | − * A simple IC with a single bandgap temperature sensor. | |
| 441 | − */ | |
| 442 | − bandgap0: bandgap@0000ed00 { | |
| 443 | − ... | |
| 444 | − #thermal-sensor-cells = <0>; | |
| 445 | − }; | |
| 446 | −}; | |
| 447 | − | |
| 448 | −thermal-zones { | |
| 449 | − cpu_thermal: cpu-thermal { | |
| 450 | − polling-delay-passive = <250>; /* milliseconds */ | |
| 451 | − polling-delay = <1000>; /* milliseconds */ | |
| 452 | − | |
| 453 | − thermal-sensors = <&bandgap0>, /* cpu */ | |
| 454 | − <&adc>; /* pcb north */ | |
| 455 | − | |
| 456 | − /* hotspot = 100 * bandgap - 120 * adc + 484 */ | |
| 457 | − coefficients = <100 -120 484>; | |
| 458 | − | |
| 459 | − trips { | |
| 460 | − ... | |
| 461 | − }; | |
| 462 | − | |
| 463 | − cooling-maps { | |
| 464 | − ... | |
| 465 | − }; | |
| 466 | − }; | |
| 467 | −}; | |
| 468 | − | |
| 469 | −In some cases, there is a need to use more than one sensor to extrapolate | |
| 470 | −a thermal hotspot in the silicon. The above example illustrates this situation. | |
| 471 | −For instance, it may be the case that a sensor external to CPU IP may be placed | |
| 472 | −close to CPU hotspot and together with internal CPU sensor, it is used | |
| 473 | −to determine the hotspot. Assuming this is the case for the above example, | |
| 474 | −the hypothetical extrapolation rule would be: | |
| 475 | − hotspot = 100 * bandgap - 120 * adc + 484 | |
| 476 | − | |
| 477 | −In other context, the same idea can be used to add fixed offset. For instance, | |
| 478 | −consider the hotspot extrapolation rule below: | |
| 479 | − hotspot = 1 * adc + 6000 | |
| 480 | − | |
| 481 | −In the above equation, the hotspot is always 6C higher than what is read | |
| 482 | −from the ADC sensor. The binding would be then: | |
| 483 | − thermal-sensors = <&adc>; | |
| 484 | − | |
| 485 | − /* hotspot = 1 * adc + 6000 */ | |
| 486 | − coefficients = <1 6000>; | |
| 487 | − | |
| 488 | −(d) - Board thermal | |
| 489 | − | |
| 490 | −The board thermal example below illustrates how to setup one thermal zone | |
| 491 | −with many sensors and many cooling devices. | |
| 492 | − | |
| 493 | −#include <dt-bindings/thermal/thermal.h> | |
| 494 | − | |
| 495 | −&i2c1 { | |
| 496 | − ... | |
| 497 | − /* | |
| 498 | − * An IC with several temperature sensor. | |
| 499 | − */ | |
| 500 | − adc_dummy: sensor@50 { | |
| 501 | − ... | |
| 502 | − #thermal-sensor-cells = <1>; /* sensor internal ID */ | |
| 503 | − }; | |
| 504 | −}; | |
| 505 | − | |
| 506 | −thermal-zones { | |
| 507 | − batt-thermal { | |
| 508 | − polling-delay-passive = <500>; /* milliseconds */ | |
| 509 | − polling-delay = <2500>; /* milliseconds */ | |
| 510 | − | |
| 511 | − /* sensor ID */ | |
| 512 | − thermal-sensors = <&adc_dummy 4>; | |
| 513 | − | |
| 514 | − trips { | |
| 515 | − ... | |
| 516 | − }; | |
| 517 | − | |
| 518 | − cooling-maps { | |
| 519 | − ... | |
| 520 | − }; | |
| 521 | − }; | |
| 522 | − | |
| 523 | − board_thermal: board-thermal { | |
| 524 | − polling-delay-passive = <1000>; /* milliseconds */ | |
| 525 | − polling-delay = <2500>; /* milliseconds */ | |
| 526 | − | |
| 527 | − /* sensor ID */ | |
| 528 | − thermal-sensors = <&adc_dummy 0>, /* pcb top edge */ | |
| 529 | − <&adc_dummy 1>, /* lcd */ | |
| 530 | − <&adc_dummy 2>; /* back cover */ | |
| 531 | − /* | |
| 532 | − * An array of coefficients describing the sensor | |
| 533 | − * linear relation. E.g.: | |
| 534 | − * z = c1*x1 + c2*x2 + c3*x3 | |
| 535 | − */ | |
| 536 | − coefficients = <1200 -345 890>; | |
| 537 | − | |
| 538 | − sustainable-power = <2500>; | |
| 539 | − | |
| 540 | − trips { | |
| 541 | − /* Trips are based on resulting linear equation */ | |
| 542 | − cpu_trip: cpu-trip { | |
| 543 | − temperature = <60000>; /* millicelsius */ | |
| 544 | − hysteresis = <2000>; /* millicelsius */ | |
| 545 | − type = "passive"; | |
| 546 | − }; | |
| 547 | − gpu_trip: gpu-trip { | |
| 548 | − temperature = <55000>; /* millicelsius */ | |
| 549 | − hysteresis = <2000>; /* millicelsius */ | |
| 550 | − type = "passive"; | |
| 551 | − } | |
| 552 | − lcd_trip: lcp-trip { | |
| 553 | − temperature = <53000>; /* millicelsius */ | |
| 554 | − hysteresis = <2000>; /* millicelsius */ | |
| 555 | − type = "passive"; | |
| 556 | − }; | |
| 557 | − crit_trip: crit-trip { | |
| 558 | − temperature = <68000>; /* millicelsius */ | |
| 559 | − hysteresis = <2000>; /* millicelsius */ | |
| 560 | − type = "critical"; | |
| 561 | − }; | |
| 562 | − }; | |
| 563 | − | |
| 564 | − cooling-maps { | |
| 565 | − map0 { | |
| 566 | − trip = <&cpu_trip>; | |
| 567 | − cooling-device = <&cpu0 0 2>; | |
| 568 | − contribution = <55>; | |
| 569 | − }; | |
| 570 | − map1 { | |
| 571 | − trip = <&gpu_trip>; | |
| 572 | − cooling-device = <&gpu0 0 2>; | |
| 573 | − contribution = <20>; | |
| 574 | − }; | |
| 575 | − map2 { | |
| 576 | − trip = <&lcd_trip>; | |
| 577 | − cooling-device = <&lcd0 5 10>; | |
| 578 | − contribution = <15>; | |
| 579 | − }; | |
| 580 | − }; | |
| 581 | − }; | |
| 582 | −}; | |
| 583 | − | |
| 584 | −The above example is a mix of previous examples, a sensor IP with several internal | |
| 585 | −sensors used to monitor different zones, one of them is composed by several sensors and | |
| 586 | −with different cooling devices. | |
| @@ -17086,6 +17086,14 @@ F: drivers/thermal/cpufreq_cooling.c · 17085 unmodified lines | ||
| 17086 | 17086 | F: drivers/thermal/cpuidle_cooling.c |
| 17087 | 17087 | F: include/linux/cpu_cooling.h |
| 17088 | 17088 | |
| 17089 | +THERMAL/POWER_ALLOCATOR | |
| 17090 | +M: Lukasz Luba <lukasz.luba@arm.com> | |
| 17091 | +L: linux-pm@vger.kernel.org | |
| 17092 | +S: Maintained | |
| 17093 | +F: Documentation/driver-api/thermal/power_allocator.rst | |
| 17094 | +F: drivers/thermal/gov_power_allocator.c | |
| 17095 | +F: include/trace/events/thermal_power_allocator.h | |
| 17096 | + | |
| 17089 | 17097 | THINKPAD ACPI EXTRAS DRIVER |
| 17090 | 17098 | M: Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br> |
| 17091 | 17099 | L: ibm-acpi-devel@lists.sourceforge.net |
| @@ -172,7 +172,6 @@ struct acpi_thermal { · 171 unmodified lines | ||
| 172 | 172 | struct acpi_thermal_trips trips; |
| 173 | 173 | struct acpi_handle_list devices; |
| 174 | 174 | struct thermal_zone_device *thermal_zone; |
| 175 | − int tz_enabled; | |
| 176 | 175 | int kelvin_offset; /* in millidegrees */ |
| 177 | 176 | struct work_struct thermal_check_work; |
| 178 | 177 | }; |
| @@ -500,9 +499,6 @@ static void acpi_thermal_check(void *data) · 321 unmodified lines | ||
| 500 | 499 | { |
| 501 | 500 | struct acpi_thermal *tz = data; |
| 502 | 501 | |
| 503 | − if (!tz->tz_enabled) | |
| 504 | − return; | |
| 505 | − | |
| 506 | 502 | thermal_zone_device_update(tz->thermal_zone, |
| 507 | 503 | THERMAL_EVENT_UNSPECIFIED); |
| 508 | 504 | } |
| @@ -526,50 +522,6 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp) · 17 unmodified lines | ||
| 526 | 522 | return 0; |
| 527 | 523 | } |
| 528 | 524 | |
| 529 | −static int thermal_get_mode(struct thermal_zone_device *thermal, | |
| 530 | − enum thermal_device_mode *mode) | |
| 531 | −{ | |
| 532 | − struct acpi_thermal *tz = thermal->devdata; | |
| 533 | − | |
| 534 | − if (!tz) | |
| 535 | − return -EINVAL; | |
| 536 | − | |
| 537 | − *mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED : | |
| 538 | − THERMAL_DEVICE_DISABLED; | |
| 539 | − | |
| 540 | − return 0; | |
| 541 | −} | |
| 542 | − | |
| 543 | −static int thermal_set_mode(struct thermal_zone_device *thermal, | |
| 544 | − enum thermal_device_mode mode) | |
| 545 | −{ | |
| 546 | − struct acpi_thermal *tz = thermal->devdata; | |
| 547 | − int enable; | |
| 548 | − | |
| 549 | − if (!tz) | |
| 550 | − return -EINVAL; | |
| 551 | − | |
| 552 | − /* | |
| 553 | − * enable/disable thermal management from ACPI thermal driver | |
| 554 | − */ | |
| 555 | − if (mode == THERMAL_DEVICE_ENABLED) | |
| 556 | − enable = 1; | |
| 557 | − else if (mode == THERMAL_DEVICE_DISABLED) { | |
| 558 | − enable = 0; | |
| 559 | − pr_warn("thermal zone will be disabled\n"); | |
| 560 | − } else | |
| 561 | − return -EINVAL; | |
| 562 | − | |
| 563 | − if (enable != tz->tz_enabled) { | |
| 564 | − tz->tz_enabled = enable; | |
| 565 | − ACPI_DEBUG_PRINT((ACPI_DB_INFO, | |
| 566 | − "%s kernel ACPI thermal control\n", | |
| 567 | − tz->tz_enabled ? "Enable" : "Disable")); | |
| 568 | − acpi_thermal_check(tz); | |
| 569 | − } | |
| 570 | − return 0; | |
| 571 | −} | |
| 572 | − | |
| 573 | 525 | static int thermal_get_trip_type(struct thermal_zone_device *thermal, |
| 574 | 526 | int trip, enum thermal_trip_type *type) |
| 575 | 527 | { |
| @@ -856,8 +808,6 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = { · 280 unmodified lines | ||
| 856 | 808 | .bind = acpi_thermal_bind_cooling_device, |
| 857 | 809 | .unbind = acpi_thermal_unbind_cooling_device, |
| 858 | 810 | .get_temp = thermal_get_temp, |
| 859 | − .get_mode = thermal_get_mode, | |
| 860 | − .set_mode = thermal_set_mode, | |
| 861 | 811 | .get_trip_type = thermal_get_trip_type, |
| 862 | 812 | .get_trip_temp = thermal_get_trip_temp, |
| 863 | 813 | .get_crit_temp = thermal_get_crit_temp, |
| @@ -901,23 +851,39 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) · 37 unmodified lines | ||
| 901 | 851 | result = sysfs_create_link(&tz->device->dev.kobj, |
| 902 | 852 | &tz->thermal_zone->device.kobj, "thermal_zone"); |
| 903 | 853 | if (result) |
| 904 | − return result; | |
| 854 | + goto unregister_tzd; | |
| 905 | 855 | |
| 906 | 856 | result = sysfs_create_link(&tz->thermal_zone->device.kobj, |
| 907 | 857 | &tz->device->dev.kobj, "device"); |
| 908 | 858 | if (result) |
| 909 | − return result; | |
| 859 | + goto remove_tz_link; | |
| 910 | 860 | |
| 911 | 861 | status = acpi_bus_attach_private_data(tz->device->handle, |
| 912 | 862 | tz->thermal_zone); |
| 913 | − if (ACPI_FAILURE(status)) | |
| 914 | − return -ENODEV; | |
| 863 | + if (ACPI_FAILURE(status)) { | |
| 864 | + result = -ENODEV; | |
| 865 | + goto remove_dev_link; | |
| 866 | + } | |
| 915 | 867 | |
| 916 | − tz->tz_enabled = 1; | |
| 868 | + result = thermal_zone_device_enable(tz->thermal_zone); | |
| 869 | + if (result) | |
| 870 | + goto acpi_bus_detach; | |
| 917 | 871 | |
| 918 | 872 | dev_info(&tz->device->dev, "registered as thermal_zone%d\n", |
| 919 | 873 | tz->thermal_zone->id); |
| 874 | + | |
| 920 | 875 | return 0; |
| 876 | + | |
| 877 | +acpi_bus_detach: | |
| 878 | + acpi_bus_detach_private_data(tz->device->handle); | |
| 879 | +remove_dev_link: | |
| 880 | + sysfs_remove_link(&tz->thermal_zone->device.kobj, "device"); | |
| 881 | +remove_tz_link: | |
| 882 | + sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone"); | |
| 883 | +unregister_tzd: | |
| 884 | + thermal_zone_device_unregister(tz->thermal_zone); | |
| 885 | + | |
| 886 | + return result; | |
| 921 | 887 | } |
| 922 | 888 | |
| 923 | 889 | static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) |
| @@ -92,6 +92,14 @@ int cxgb4_thermal_init(struct adapter *adap) · 91 unmodified lines | ||
| 92 | 92 | ch_thermal->tzdev = NULL; |
| 93 | 93 | return ret; |
| 94 | 94 | } |
| 95 | + | |
| 96 | + ret = thermal_zone_device_enable(ch_thermal->tzdev); | |
| 97 | + if (ret) { | |
| 98 | + dev_err(adap->pdev_dev, "Failed to enable thermal zone\n"); | |
| 99 | + thermal_zone_device_unregister(adap->ch_thermal.tzdev); | |
| 100 | + return ret; | |
| 101 | + } | |
| 102 | + | |
| 95 | 103 | return 0; |
| 96 | 104 | } |
| 97 | 105 | |
| @@ -98,7 +98,6 @@ struct mlxsw_thermal_module { · 97 unmodified lines | ||
| 98 | 98 | struct mlxsw_thermal *parent; |
| 99 | 99 | struct thermal_zone_device *tzdev; |
| 100 | 100 | struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; |
| 101 | − enum thermal_device_mode mode; | |
| 102 | 101 | int module; /* Module or gearbox number */ |
| 103 | 102 | }; |
| 104 | 103 | |
| @@ -110,7 +109,6 @@ struct mlxsw_thermal { · 5 unmodified lines | ||
| 110 | 109 | struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX]; |
| 111 | 110 | u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1]; |
| 112 | 111 | struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; |
| 113 | − enum thermal_device_mode mode; | |
| 114 | 112 | struct mlxsw_thermal_module *tz_module_arr; |
| 115 | 113 | u8 tz_module_num; |
| 116 | 114 | struct mlxsw_thermal_module *tz_gearbox_arr; |
| @@ -277,36 +275,6 @@ static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev, · 160 unmodified lines | ||
| 277 | 275 | return 0; |
| 278 | 276 | } |
| 279 | 277 | |
| 280 | −static int mlxsw_thermal_get_mode(struct thermal_zone_device *tzdev, | |
| 281 | − enum thermal_device_mode *mode) | |
| 282 | −{ | |
| 283 | − struct mlxsw_thermal *thermal = tzdev->devdata; | |
| 284 | − | |
| 285 | − *mode = thermal->mode; | |
| 286 | − | |
| 287 | − return 0; | |
| 288 | −} | |
| 289 | − | |
| 290 | −static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev, | |
| 291 | − enum thermal_device_mode mode) | |
| 292 | −{ | |
| 293 | − struct mlxsw_thermal *thermal = tzdev->devdata; | |
| 294 | − | |
| 295 | − mutex_lock(&tzdev->lock); | |
| 296 | − | |
| 297 | − if (mode == THERMAL_DEVICE_ENABLED) | |
| 298 | − tzdev->polling_delay = thermal->polling_delay; | |
| 299 | − else | |
| 300 | − tzdev->polling_delay = 0; | |
| 301 | − | |
| 302 | − mutex_unlock(&tzdev->lock); | |
| 303 | − | |
| 304 | − thermal->mode = mode; | |
| 305 | − thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED); | |
| 306 | − | |
| 307 | − return 0; | |
| 308 | −} | |
| 309 | − | |
| 310 | 278 | static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, |
| 311 | 279 | int *p_temp) |
| 312 | 280 | { |
| @@ -406,8 +374,6 @@ static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev, · 93 unmodified lines | ||
| 406 | 374 | static struct thermal_zone_device_ops mlxsw_thermal_ops = { |
| 407 | 375 | .bind = mlxsw_thermal_bind, |
| 408 | 376 | .unbind = mlxsw_thermal_unbind, |
| 409 | − .get_mode = mlxsw_thermal_get_mode, | |
| 410 | − .set_mode = mlxsw_thermal_set_mode, | |
| 411 | 377 | .get_temp = mlxsw_thermal_get_temp, |
| 412 | 378 | .get_trip_type = mlxsw_thermal_get_trip_type, |
| 413 | 379 | .get_trip_temp = mlxsw_thermal_get_trip_temp, |
| @@ -465,37 +431,6 @@ static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev, · 51 unmodified lines | ||
| 465 | 431 | return err; |
| 466 | 432 | } |
| 467 | 433 | |
| 468 | −static int mlxsw_thermal_module_mode_get(struct thermal_zone_device *tzdev, | |
| 469 | − enum thermal_device_mode *mode) | |
| 470 | −{ | |
| 471 | − struct mlxsw_thermal_module *tz = tzdev->devdata; | |
| 472 | − | |
| 473 | − *mode = tz->mode; | |
| 474 | − | |
| 475 | − return 0; | |
| 476 | −} | |
| 477 | − | |
| 478 | −static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev, | |
| 479 | − enum thermal_device_mode mode) | |
| 480 | −{ | |
| 481 | − struct mlxsw_thermal_module *tz = tzdev->devdata; | |
| 482 | − struct mlxsw_thermal *thermal = tz->parent; | |
| 483 | − | |
| 484 | − mutex_lock(&tzdev->lock); | |
| 485 | − | |
| 486 | − if (mode == THERMAL_DEVICE_ENABLED) | |
| 487 | − tzdev->polling_delay = thermal->polling_delay; | |
| 488 | − else | |
| 489 | − tzdev->polling_delay = 0; | |
| 490 | − | |
| 491 | − mutex_unlock(&tzdev->lock); | |
| 492 | − | |
| 493 | − tz->mode = mode; | |
| 494 | − thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED); | |
| 495 | − | |
| 496 | − return 0; | |
| 497 | −} | |
| 498 | − | |
| 499 | 434 | static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, |
| 500 | 435 | int *p_temp) |
| 501 | 436 | { |
| @@ -611,8 +546,6 @@ static int mlxsw_thermal_module_trend_get(struct thermal_zone_device *tzdev, · 109 unmodified lines | ||
| 611 | 546 | static struct thermal_zone_device_ops mlxsw_thermal_module_ops = { |
| 612 | 547 | .bind = mlxsw_thermal_module_bind, |
| 613 | 548 | .unbind = mlxsw_thermal_module_unbind, |
| 614 | − .get_mode = mlxsw_thermal_module_mode_get, | |
| 615 | − .set_mode = mlxsw_thermal_module_mode_set, | |
| 616 | 549 | .get_temp = mlxsw_thermal_module_temp_get, |
| 617 | 550 | .get_trip_type = mlxsw_thermal_module_trip_type_get, |
| 618 | 551 | .get_trip_temp = mlxsw_thermal_module_trip_temp_get, |
| @@ -650,8 +583,6 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, · 31 unmodified lines | ||
| 650 | 583 | static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = { |
| 651 | 584 | .bind = mlxsw_thermal_module_bind, |
| 652 | 585 | .unbind = mlxsw_thermal_module_unbind, |
| 653 | − .get_mode = mlxsw_thermal_module_mode_get, | |
| 654 | − .set_mode = mlxsw_thermal_module_mode_set, | |
| 655 | 586 | .get_temp = mlxsw_thermal_gearbox_temp_get, |
| 656 | 587 | .get_trip_type = mlxsw_thermal_module_trip_type_get, |
| 657 | 588 | .get_trip_temp = mlxsw_thermal_module_trip_temp_get, |
| @@ -780,8 +711,11 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz) · 122 unmodified lines | ||
| 780 | 711 | return err; |
| 781 | 712 | } |
| 782 | 713 | |
| 783 | − module_tz->mode = THERMAL_DEVICE_ENABLED; | |
| 784 | − return 0; | |
| 714 | + err = thermal_zone_device_enable(module_tz->tzdev); | |
| 715 | + if (err) | |
| 716 | + thermal_zone_device_unregister(module_tz->tzdev); | |
| 717 | + | |
| 718 | + return err; | |
| 785 | 719 | } |
| 786 | 720 | |
| 787 | 721 | static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev) |
| @@ -884,6 +818,7 @@ static int · 96 unmodified lines | ||
| 884 | 818 | mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) |
| 885 | 819 | { |
| 886 | 820 | char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME]; |
| 821 | + int ret; | |
| 887 | 822 | |
| 888 | 823 | snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d", |
| 889 | 824 | gearbox_tz->module + 1); |
| @@ -896,8 +831,11 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) · 6 unmodified lines | ||
| 896 | 831 | if (IS_ERR(gearbox_tz->tzdev)) |
| 897 | 832 | return PTR_ERR(gearbox_tz->tzdev); |
| 898 | 833 | |
| 899 | − gearbox_tz->mode = THERMAL_DEVICE_ENABLED; | |
| 900 | − return 0; | |
| 834 | + ret = thermal_zone_device_enable(gearbox_tz->tzdev); | |
| 835 | + if (ret) | |
| 836 | + thermal_zone_device_unregister(gearbox_tz->tzdev); | |
| 837 | + | |
| 838 | + return ret; | |
| 901 | 839 | } |
| 902 | 840 | |
| 903 | 841 | static void |
| @@ -1065,10 +1003,15 @@ int mlxsw_thermal_init(struct mlxsw_core *core, · 161 unmodified lines | ||
| 1065 | 1003 | if (err) |
| 1066 | 1004 | goto err_unreg_modules_tzdev; |
| 1067 | 1005 | |
| 1068 | − thermal->mode = THERMAL_DEVICE_ENABLED; | |
| 1006 | + err = thermal_zone_device_enable(thermal->tzdev); | |
| 1007 | + if (err) | |
| 1008 | + goto err_unreg_gearboxes; | |
| 1009 | + | |
| 1069 | 1010 | *p_thermal = thermal; |
| 1070 | 1011 | return 0; |
| 1071 | 1012 | |
| 1013 | +err_unreg_gearboxes: | |
| 1014 | + mlxsw_thermal_gearboxes_fini(thermal); | |
| 1072 | 1015 | err_unreg_modules_tzdev: |
| 1073 | 1016 | mlxsw_thermal_modules_fini(thermal); |
| 1074 | 1017 | err_unreg_tzdev: |
| @@ -733,7 +733,7 @@ static struct thermal_zone_device_ops tzone_ops = { · 732 unmodified lines | ||
| 733 | 733 | |
| 734 | 734 | static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm) |
| 735 | 735 | { |
| 736 | − int i; | |
| 736 | + int i, ret; | |
| 737 | 737 | char name[16]; |
| 738 | 738 | static atomic_t counter = ATOMIC_INIT(0); |
| 739 | 739 | |
| @@ -759,6 +759,13 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm) · 19 unmodified lines | ||
| 759 | 759 | return; |
| 760 | 760 | } |
| 761 | 761 | |
| 762 | + ret = thermal_zone_device_enable(mvm->tz_device.tzone); | |
| 763 | + if (ret) { | |
| 764 | + IWL_DEBUG_TEMP(mvm, "Failed to enable thermal zone\n"); | |
| 765 | + thermal_zone_device_unregister(mvm->tz_device.tzone); | |
| 766 | + return; | |
| 767 | + } | |
| 768 | + | |
| 762 | 769 | /* 0 is a valid temperature, |
| 763 | 770 | * so initialize the array with S16_MIN which invalid temperature |
| 764 | 771 | */ |
| @@ -397,39 +397,24 @@ static inline void acerhdf_revert_to_bios_mode(void) · 396 unmodified lines | ||
| 397 | 397 | { |
| 398 | 398 | acerhdf_change_fanstate(ACERHDF_FAN_AUTO); |
| 399 | 399 | kernelmode = 0; |
| 400 | − if (thz_dev) | |
| 401 | − thz_dev->polling_delay = 0; | |
| 400 | + | |
| 402 | 401 | pr_notice("kernel mode fan control OFF\n"); |
| 403 | 402 | } |
| 404 | 403 | static inline void acerhdf_enable_kernelmode(void) |
| 405 | 404 | { |
| 406 | 405 | kernelmode = 1; |
| 407 | 406 | |
| 408 | − thz_dev->polling_delay = interval*1000; | |
| 409 | − thermal_zone_device_update(thz_dev, THERMAL_EVENT_UNSPECIFIED); | |
| 410 | 407 | pr_notice("kernel mode fan control ON\n"); |
| 411 | 408 | } |
| 412 | 409 | |
| 413 | −static int acerhdf_get_mode(struct thermal_zone_device *thermal, | |
| 414 | − enum thermal_device_mode *mode) | |
| 415 | −{ | |
| 416 | − if (verbose) | |
| 417 | − pr_notice("kernel mode fan control %d\n", kernelmode); | |
| 418 | − | |
| 419 | − *mode = (kernelmode) ? THERMAL_DEVICE_ENABLED | |
| 420 | − : THERMAL_DEVICE_DISABLED; | |
| 421 | − | |
| 422 | − return 0; | |
| 423 | −} | |
| 424 | − | |
| 425 | 410 | /* |
| 426 | 411 | * set operation mode; |
| 427 | 412 | * enabled: the thermal layer of the kernel takes care about |
| 428 | 413 | * the temperature and the fan. |
| 429 | 414 | * disabled: the BIOS takes control of the fan. |
| 430 | 415 | */ |
| 431 | −static int acerhdf_set_mode(struct thermal_zone_device *thermal, | |
| 432 | − enum thermal_device_mode mode) | |
| 416 | +static int acerhdf_change_mode(struct thermal_zone_device *thermal, | |
| 417 | + enum thermal_device_mode mode) | |
| 433 | 418 | { |
| 434 | 419 | if (mode == THERMAL_DEVICE_DISABLED && kernelmode) |
| 435 | 420 | acerhdf_revert_to_bios_mode(); |
| @@ -488,8 +473,7 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = { · 52 unmodified lines | ||
| 488 | 473 | .bind = acerhdf_bind, |
| 489 | 474 | .unbind = acerhdf_unbind, |
| 490 | 475 | .get_temp = acerhdf_get_ec_temp, |
| 491 | − .get_mode = acerhdf_get_mode, | |
| 492 | − .set_mode = acerhdf_set_mode, | |
| 476 | + .change_mode = acerhdf_change_mode, | |
| 493 | 477 | .get_trip_type = acerhdf_get_trip_type, |
| 494 | 478 | .get_trip_hyst = acerhdf_get_trip_hyst, |
| 495 | 479 | .get_trip_temp = acerhdf_get_trip_temp, |
| @@ -733,6 +717,8 @@ static void acerhdf_unregister_platform(void) · 237 unmodified lines | ||
| 733 | 717 | |
| 734 | 718 | static int __init acerhdf_register_thermal(void) |
| 735 | 719 | { |
| 720 | + int ret; | |
| 721 | + | |
| 736 | 722 | cl_dev = thermal_cooling_device_register("acerhdf-fan", NULL, |
| 737 | 723 | &acerhdf_cooling_ops); |
| 738 | 724 | |
| @@ -746,6 +732,13 @@ static int __init acerhdf_register_thermal(void) · 7 unmodified lines | ||
| 746 | 732 | if (IS_ERR(thz_dev)) |
| 747 | 733 | return -EINVAL; |
| 748 | 734 | |
| 735 | + if (kernelmode) | |
| 736 | + ret = thermal_zone_device_enable(thz_dev); | |
| 737 | + else | |
| 738 | + ret = thermal_zone_device_disable(thz_dev); | |
| 739 | + if (ret) | |
| 740 | + return ret; | |
| 741 | + | |
| 749 | 742 | if (strcmp(thz_dev->governor->name, |
| 750 | 743 | acerhdf_zone_params.governor_name)) { |
| 751 | 744 | pr_err("Didn't get thermal governor %s, perhaps not compiled into thermal subsystem.\n", |
| @@ -493,6 +493,12 @@ static int mid_thermal_probe(struct platform_device *pdev) · 492 unmodified lines | ||
| 493 | 493 | ret = PTR_ERR(pinfo->tzd[i]); |
| 494 | 494 | goto err; |
| 495 | 495 | } |
| 496 | + ret = thermal_zone_device_enable(pinfo->tzd[i]); | |
| 497 | + if (ret) { | |
| 498 | + kfree(td_info); | |
| 499 | + thermal_zone_device_unregister(pinfo->tzd[i]); | |
| 500 | + goto err; | |
| 501 | + } | |
| 496 | 502 | } |
| 497 | 503 | |
| 498 | 504 | pinfo->pdev = pdev; |
| @@ -939,7 +939,7 @@ static struct thermal_zone_device_ops psy_tzd_ops = { · 938 unmodified lines | ||
| 939 | 939 | |
| 940 | 940 | static int psy_register_thermal(struct power_supply *psy) |
| 941 | 941 | { |
| 942 | − int i; | |
| 942 | + int i, ret; | |
| 943 | 943 | |
| 944 | 944 | if (psy->desc->no_thermal) |
| 945 | 945 | return 0; |
| @@ -949,7 +949,12 @@ static int psy_register_thermal(struct power_supply *psy) · 3 unmodified lines | ||
| 949 | 949 | if (psy->desc->properties[i] == POWER_SUPPLY_PROP_TEMP) { |
| 950 | 950 | psy->tzd = thermal_zone_device_register(psy->desc->name, |
| 951 | 951 | 0, 0, psy, &psy_tzd_ops, NULL, 0, 0); |
| 952 | − return PTR_ERR_OR_ZERO(psy->tzd); | |
| 952 | + if (IS_ERR(psy->tzd)) | |
| 953 | + return PTR_ERR(psy->tzd); | |
| 954 | + ret = thermal_zone_device_enable(psy->tzd); | |
| 955 | + if (ret) | |
| 956 | + thermal_zone_device_unregister(psy->tzd); | |
| 957 | + return ret; | |
| 953 | 958 | } |
| 954 | 959 | } |
| 955 | 960 | return 0; |
| @@ -17,6 +17,16 @@ menuconfig THERMAL · 16 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | if THERMAL |
| 19 | 19 | |
| 20 | +config THERMAL_NETLINK | |
| 21 | + bool "Thermal netlink management" | |
| 22 | + depends on NET | |
| 23 | + default y | |
| 24 | + help | |
| 25 | + The thermal framework has a netlink interface to do thermal | |
| 26 | + zones discovery, temperature readings and events such as | |
| 27 | + trip point crossed, cooling device update or governor | |
| 28 | + change. It is recommended to enable the feature. | |
| 29 | + | |
| 20 | 30 | config THERMAL_STATISTICS |
| 21 | 31 | bool "Thermal state transition statistics" |
| 22 | 32 | help |
| @@ -180,16 +190,6 @@ config CPU_IDLE_THERMAL · 157 unmodified lines | ||
| 180 | 190 | idle cycle. |
| 181 | 191 | endif |
| 182 | 192 | |
| 183 | −config CLOCK_THERMAL | |
| 184 | − bool "Generic clock cooling support" | |
| 185 | − depends on COMMON_CLK | |
| 186 | − depends on PM_OPP | |
| 187 | − help | |
| 188 | − This entry implements the generic clock cooling mechanism through | |
| 189 | − frequency clipping. Typically used to cool off co-processors. The | |
| 190 | − device that is configured to use this cooling mechanism will be | |
| 191 | − controlled to reduce clock frequency whenever temperature is high. | |
| 192 | − | |
| 193 | 193 | config DEVFREQ_THERMAL |
| 194 | 194 | bool "Generic device cooling support" |
| 195 | 195 | depends on PM_DEVFREQ |
| @@ -7,6 +7,9 @@ obj-$(CONFIG_THERMAL) += thermal_sys.o · 6 unmodified lines | ||
| 7 | 7 | thermal_sys-y += thermal_core.o thermal_sysfs.o \ |
| 8 | 8 | thermal_helpers.o |
| 9 | 9 | |
| 10 | +# netlink interface to manage the thermal framework | |
| 11 | +thermal_sys-$(CONFIG_THERMAL_NETLINK) += thermal_netlink.o | |
| 12 | + | |
| 10 | 13 | # interface to/from other layers providing sensors |
| 11 | 14 | thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o |
| 12 | 15 | thermal_sys-$(CONFIG_THERMAL_OF) += thermal_of.o |
| @@ -22,9 +25,6 @@ thermal_sys-$(CONFIG_THERMAL_GOV_POWER_ALLOCATOR) += gov_power_allocator.o · 9 unmodified lines | ||
| 22 | 25 | thermal_sys-$(CONFIG_CPU_FREQ_THERMAL) += cpufreq_cooling.o |
| 23 | 26 | thermal_sys-$(CONFIG_CPU_IDLE_THERMAL) += cpuidle_cooling.o |
| 24 | 27 | |
| 25 | −# clock cooling | |
| 26 | −thermal_sys-$(CONFIG_CLOCK_THERMAL) += clock_cooling.o | |
| 27 | − | |
| 28 | 28 | # devfreq cooling |
| 29 | 29 | thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o |
| 30 | 30 | |
| @@ -874,6 +874,12 @@ static int armada_thermal_probe(struct platform_device *pdev) · 873 unmodified lines | ||
| 874 | 874 | return PTR_ERR(tz); |
| 875 | 875 | } |
| 876 | 876 | |
| 877 | + ret = thermal_zone_device_enable(tz); | |
| 878 | + if (ret) { | |
| 879 | + thermal_zone_device_unregister(tz); | |
| 880 | + return ret; | |
| 881 | + } | |
| 882 | + | |
| 877 | 883 | drvdata->type = LEGACY; |
| 878 | 884 | drvdata->data.tz = tz; |
| 879 | 885 | platform_set_drvdata(pdev, drvdata); |
| @@ -1,445 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −/* | |
| 3 | − * drivers/thermal/clock_cooling.c | |
| 4 | − * | |
| 5 | − * Copyright (C) 2014 Eduardo Valentin <edubezval@gmail.com> | |
| 6 | − * | |
| 7 | − * Copyright (C) 2013 Texas Instruments Inc. | |
| 8 | − * Contact: Eduardo Valentin <eduardo.valentin@ti.com> | |
| 9 | − * | |
| 10 | − * Highly based on cpufreq_cooling.c. | |
| 11 | − * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com) | |
| 12 | − * Copyright (C) 2012 Amit Daniel <amit.kachhap@linaro.org> | |
| 13 | − */ | |
| 14 | −#include <linux/clk.h> | |
| 15 | −#include <linux/clock_cooling.h> | |
| 16 | −#include <linux/cpufreq.h> | |
| 17 | −#include <linux/device.h> | |
| 18 | −#include <linux/err.h> | |
| 19 | −#include <linux/export.h> | |
| 20 | −#include <linux/idr.h> | |
| 21 | −#include <linux/mutex.h> | |
| 22 | −#include <linux/pm_opp.h> | |
| 23 | −#include <linux/slab.h> | |
| 24 | −#include <linux/thermal.h> | |
| 25 | − | |
| 26 | −/** | |
| 27 | − * struct clock_cooling_device - data for cooling device with clock | |
| 28 | − * @id: unique integer value corresponding to each clock_cooling_device | |
| 29 | − * registered. | |
| 30 | − * @dev: struct device pointer to the device being used to cool off using | |
| 31 | − * clock frequencies. | |
| 32 | − * @cdev: thermal_cooling_device pointer to keep track of the | |
| 33 | − * registered cooling device. | |
| 34 | − * @clk_rate_change_nb: reference to notifier block used to receive clock | |
| 35 | − * rate changes. | |
| 36 | − * @freq_table: frequency table used to keep track of available frequencies. | |
| 37 | − * @clock_state: integer value representing the current state of clock | |
| 38 | − * cooling devices. | |
| 39 | − * @clock_val: integer value representing the absolute value of the clipped | |
| 40 | − * frequency. | |
| 41 | − * @clk: struct clk reference used to enforce clock limits. | |
| 42 | − * @lock: mutex lock to protect this struct. | |
| 43 | − * | |
| 44 | − * This structure is required for keeping information of each | |
| 45 | − * clock_cooling_device registered. In order to prevent corruption of this a | |
| 46 | − * mutex @lock is used. | |
| 47 | − */ | |
| 48 | −struct clock_cooling_device { | |
| 49 | − int id; | |
| 50 | − struct device *dev; | |
| 51 | − struct thermal_cooling_device *cdev; | |
| 52 | − struct notifier_block clk_rate_change_nb; | |
| 53 | − struct cpufreq_frequency_table *freq_table; | |
| 54 | − unsigned long clock_state; | |
| 55 | − unsigned long clock_val; | |
| 56 | − struct clk *clk; | |
| 57 | − struct mutex lock; /* lock to protect the content of this struct */ | |
| 58 | −}; | |
| 59 | −#define to_clock_cooling_device(x) \ | |
| 60 | − container_of(x, struct clock_cooling_device, clk_rate_change_nb) | |
| 61 | −static DEFINE_IDA(clock_ida); | |
| 62 | − | |
| 63 | −/* Below code defines functions to be used for clock as cooling device */ | |
| 64 | − | |
| 65 | −enum clock_cooling_property { | |
| 66 | − GET_LEVEL, | |
| 67 | − GET_FREQ, | |
| 68 | − GET_MAXL, | |
| 69 | −}; | |
| 70 | − | |
| 71 | −/** | |
| 72 | − * clock_cooling_get_property - fetch a property of interest for a give cpu. | |
| 73 | − * @ccdev: clock cooling device reference | |
| 74 | − * @input: query parameter | |
| 75 | − * @output: query return | |
| 76 | − * @property: type of query (frequency, level, max level) | |
| 77 | − * | |
| 78 | − * This is the common function to | |
| 79 | − * 1. get maximum clock cooling states | |
| 80 | − * 2. translate frequency to cooling state | |
| 81 | − * 3. translate cooling state to frequency | |
| 82 | − * Note that the code may be not in good shape | |
| 83 | − * but it is written in this way in order to: | |
| 84 | − * a) reduce duplicate code as most of the code can be shared. | |
| 85 | − * b) make sure the logic is consistent when translating between | |
| 86 | − * cooling states and frequencies. | |
| 87 | − * | |
| 88 | − * Return: 0 on success, -EINVAL when invalid parameters are passed. | |
| 89 | − */ | |
| 90 | −static int clock_cooling_get_property(struct clock_cooling_device *ccdev, | |
| 91 | − unsigned long input, | |
| 92 | − unsigned long *output, | |
| 93 | − enum clock_cooling_property property) | |
| 94 | −{ | |
| 95 | − int i; | |
| 96 | − unsigned long max_level = 0, level = 0; | |
| 97 | − unsigned int freq = CPUFREQ_ENTRY_INVALID; | |
| 98 | − int descend = -1; | |
| 99 | − struct cpufreq_frequency_table *pos, *table = ccdev->freq_table; | |
| 100 | − | |
| 101 | − if (!output) | |
| 102 | − return -EINVAL; | |
| 103 | − | |
| 104 | − if (!table) | |
| 105 | − return -EINVAL; | |
| 106 | − | |
| 107 | − cpufreq_for_each_valid_entry(pos, table) { | |
| 108 | − /* ignore duplicate entry */ | |
| 109 | − if (freq == pos->frequency) | |
| 110 | − continue; | |
| 111 | − | |
| 112 | − /* get the frequency order */ | |
| 113 | − if (freq != CPUFREQ_ENTRY_INVALID && descend == -1) | |
| 114 | − descend = freq > pos->frequency; | |
| 115 | − | |
| 116 | − freq = pos->frequency; | |
| 117 | − max_level++; | |
| 118 | − } | |
| 119 | − | |
| 120 | − /* No valid cpu frequency entry */ | |
| 121 | − if (max_level == 0) | |
| 122 | − return -EINVAL; | |
| 123 | − | |
| 124 | − /* max_level is an index, not a counter */ | |
| 125 | − max_level--; | |
| 126 | − | |
| 127 | − /* get max level */ | |
| 128 | − if (property == GET_MAXL) { | |
| 129 | − *output = max_level; | |
| 130 | − return 0; | |
| 131 | − } | |
| 132 | − | |
| 133 | − if (property == GET_FREQ) | |
| 134 | − level = descend ? input : (max_level - input); | |
| 135 | − | |
| 136 | − i = 0; | |
| 137 | − cpufreq_for_each_valid_entry(pos, table) { | |
| 138 | − /* ignore duplicate entry */ | |
| 139 | − if (freq == pos->frequency) | |
| 140 | − continue; | |
| 141 | − | |
| 142 | − /* now we have a valid frequency entry */ | |
| 143 | − freq = pos->frequency; | |
| 144 | − | |
| 145 | − if (property == GET_LEVEL && (unsigned int)input == freq) { | |
| 146 | − /* get level by frequency */ | |
| 147 | − *output = descend ? i : (max_level - i); | |
| 148 | − return 0; | |
| 149 | − } | |
| 150 | − if (property == GET_FREQ && level == i) { | |
| 151 | − /* get frequency by level */ | |
| 152 | − *output = freq; | |
| 153 | − return 0; | |
| 154 | − } | |
| 155 | − i++; | |
| 156 | − } | |
| 157 | − | |
| 158 | − return -EINVAL; | |
| 159 | −} | |
| 160 | − | |
| 161 | −/** | |
| 162 | − * clock_cooling_get_level - return the cooling level of given clock cooling. | |
| 163 | − * @cdev: reference of a thermal cooling device of used as clock cooling device | |
| 164 | − * @freq: the frequency of interest | |
| 165 | − * | |
| 166 | − * This function will match the cooling level corresponding to the | |
| 167 | − * requested @freq and return it. | |
| 168 | − * | |
| 169 | − * Return: The matched cooling level on success or THERMAL_CSTATE_INVALID | |
| 170 | − * otherwise. | |
| 171 | − */ | |
| 172 | −unsigned long clock_cooling_get_level(struct thermal_cooling_device *cdev, | |
| 173 | − unsigned long freq) | |
| 174 | −{ | |
| 175 | − struct clock_cooling_device *ccdev = cdev->devdata; | |
| 176 | − unsigned long val; | |
| 177 | − | |
| 178 | − if (clock_cooling_get_property(ccdev, (unsigned long)freq, &val, | |
| 179 | − GET_LEVEL)) | |
| 180 | − return THERMAL_CSTATE_INVALID; | |
| 181 | − | |
| 182 | − return val; | |
| 183 | −} | |
| 184 | −EXPORT_SYMBOL_GPL(clock_cooling_get_level); | |
| 185 | − | |
| 186 | −/** | |
| 187 | − * clock_cooling_get_frequency - get the absolute value of frequency from level. | |
| 188 | − * @ccdev: clock cooling device reference | |
| 189 | − * @level: cooling level | |
| 190 | − * | |
| 191 | − * This function matches cooling level with frequency. Based on a cooling level | |
| 192 | − * of frequency, equals cooling state of cpu cooling device, it will return | |
| 193 | − * the corresponding frequency. | |
| 194 | − * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc | |
| 195 | − * | |
| 196 | − * Return: 0 on error, the corresponding frequency otherwise. | |
| 197 | − */ | |
| 198 | −static unsigned long | |
| 199 | −clock_cooling_get_frequency(struct clock_cooling_device *ccdev, | |
| 200 | − unsigned long level) | |
| 201 | −{ | |
| 202 | − int ret = 0; | |
| 203 | − unsigned long freq; | |
| 204 | − | |
| 205 | − ret = clock_cooling_get_property(ccdev, level, &freq, GET_FREQ); | |
| 206 | − if (ret) | |
| 207 | − return 0; | |
| 208 | − | |
| 209 | − return freq; | |
| 210 | −} | |
| 211 | − | |
| 212 | −/** | |
| 213 | − * clock_cooling_apply - function to apply frequency clipping. | |
| 214 | − * @ccdev: clock_cooling_device pointer containing frequency clipping data. | |
| 215 | − * @cooling_state: value of the cooling state. | |
| 216 | − * | |
| 217 | − * Function used to make sure the clock layer is aware of current thermal | |
| 218 | − * limits. The limits are applied by updating the clock rate in case it is | |
| 219 | − * higher than the corresponding frequency based on the requested cooling_state. | |
| 220 | − * | |
| 221 | − * Return: 0 on success, an error code otherwise (-EINVAL in case wrong | |
| 222 | − * cooling state). | |
| 223 | − */ | |
| 224 | −static int clock_cooling_apply(struct clock_cooling_device *ccdev, | |
| 225 | − unsigned long cooling_state) | |
| 226 | −{ | |
| 227 | − unsigned long clip_freq, cur_freq; | |
| 228 | − int ret = 0; | |
| 229 | − | |
| 230 | − /* Here we write the clipping */ | |
| 231 | − /* Check if the old cooling action is same as new cooling action */ | |
| 232 | − if (ccdev->clock_state == cooling_state) | |
| 233 | − return 0; | |
| 234 | − | |
| 235 | − clip_freq = clock_cooling_get_frequency(ccdev, cooling_state); | |
| 236 | − if (!clip_freq) | |
| 237 | − return -EINVAL; | |
| 238 | − | |
| 239 | − cur_freq = clk_get_rate(ccdev->clk); | |
| 240 | − | |
| 241 | − mutex_lock(&ccdev->lock); | |
| 242 | − ccdev->clock_state = cooling_state; | |
| 243 | − ccdev->clock_val = clip_freq; | |
| 244 | − /* enforce clock level */ | |
| 245 | − if (cur_freq > clip_freq) | |
| 246 | − ret = clk_set_rate(ccdev->clk, clip_freq); | |
| 247 | − mutex_unlock(&ccdev->lock); | |
| 248 | − | |
| 249 | − return ret; | |
| 250 | −} | |
| 251 | − | |
| 252 | −/** | |
| 253 | − * clock_cooling_clock_notifier - notifier callback on clock rate changes. | |
| 254 | − * @nb: struct notifier_block * with callback info. | |
| 255 | − * @event: value showing clock event for which this function invoked. | |
| 256 | − * @data: callback-specific data | |
| 257 | − * | |
| 258 | − * Callback to hijack the notification on clock transition. | |
| 259 | − * Every time there is a clock change, we intercept all pre change events | |
| 260 | − * and block the transition in case the new rate infringes thermal limits. | |
| 261 | − * | |
| 262 | − * Return: NOTIFY_DONE (success) or NOTIFY_BAD (new_rate > thermal limit). | |
| 263 | − */ | |
| 264 | −static int clock_cooling_clock_notifier(struct notifier_block *nb, | |
| 265 | − unsigned long event, void *data) | |
| 266 | −{ | |
| 267 | − struct clk_notifier_data *ndata = data; | |
| 268 | − struct clock_cooling_device *ccdev = to_clock_cooling_device(nb); | |
| 269 | − | |
| 270 | − switch (event) { | |
| 271 | − case PRE_RATE_CHANGE: | |
| 272 | − /* | |
| 273 | − * checks on current state | |
| 274 | − * TODO: current method is not best we can find as it | |
| 275 | − * allows possibly voltage transitions, in case DVFS | |
| 276 | − * layer is also hijacking clock pre notifications. | |
| 277 | − */ | |
| 278 | − if (ndata->new_rate > ccdev->clock_val) | |
| 279 | − return NOTIFY_BAD; | |
| 280 | − /* fall through */ | |
| 281 | − case POST_RATE_CHANGE: | |
| 282 | − case ABORT_RATE_CHANGE: | |
| 283 | − default: | |
| 284 | − return NOTIFY_DONE; | |
| 285 | − } | |
| 286 | −} | |
| 287 | − | |
| 288 | −/* clock cooling device thermal callback functions are defined below */ | |
| 289 | − | |
| 290 | −/** | |
| 291 | − * clock_cooling_get_max_state - callback function to get the max cooling state. | |
| 292 | − * @cdev: thermal cooling device pointer. | |
| 293 | − * @state: fill this variable with the max cooling state. | |
| 294 | − * | |
| 295 | − * Callback for the thermal cooling device to return the clock | |
| 296 | − * max cooling state. | |
| 297 | − * | |
| 298 | − * Return: 0 on success, an error code otherwise. | |
| 299 | − */ | |
| 300 | −static int clock_cooling_get_max_state(struct thermal_cooling_device *cdev, | |
| 301 | − unsigned long *state) | |
| 302 | −{ | |
| 303 | − struct clock_cooling_device *ccdev = cdev->devdata; | |
| 304 | − unsigned long count = 0; | |
| 305 | − int ret; | |
| 306 | − | |
| 307 | − ret = clock_cooling_get_property(ccdev, 0, &count, GET_MAXL); | |
| 308 | − if (!ret) | |
| 309 | − *state = count; | |
| 310 | − | |
| 311 | − return ret; | |
| 312 | −} | |
| 313 | − | |
| 314 | −/** | |
| 315 | − * clock_cooling_get_cur_state - function to get the current cooling state. | |
| 316 | − * @cdev: thermal cooling device pointer. | |
| 317 | − * @state: fill this variable with the current cooling state. | |
| 318 | − * | |
| 319 | − * Callback for the thermal cooling device to return the clock | |
| 320 | − * current cooling state. | |
| 321 | − * | |
| 322 | − * Return: 0 (success) | |
| 323 | − */ | |
| 324 | −static int clock_cooling_get_cur_state(struct thermal_cooling_device *cdev, | |
| 325 | − unsigned long *state) | |
| 326 | −{ | |
| 327 | − struct clock_cooling_device *ccdev = cdev->devdata; | |
| 328 | − | |
| 329 | − *state = ccdev->clock_state; | |
| 330 | − | |
| 331 | − return 0; | |
| 332 | −} | |
| 333 | − | |
| 334 | −/** | |
| 335 | − * clock_cooling_set_cur_state - function to set the current cooling state. | |
| 336 | − * @cdev: thermal cooling device pointer. | |
| 337 | − * @state: set this variable to the current cooling state. | |
| 338 | − * | |
| 339 | − * Callback for the thermal cooling device to change the clock cooling | |
| 340 | − * current cooling state. | |
| 341 | − * | |
| 342 | − * Return: 0 on success, an error code otherwise. | |
| 343 | − */ | |
| 344 | −static int clock_cooling_set_cur_state(struct thermal_cooling_device *cdev, | |
| 345 | − unsigned long state) | |
| 346 | −{ | |
| 347 | − struct clock_cooling_device *clock_device = cdev->devdata; | |
| 348 | − | |
| 349 | − return clock_cooling_apply(clock_device, state); | |
| 350 | −} | |
| 351 | − | |
| 352 | −/* Bind clock callbacks to thermal cooling device ops */ | |
| 353 | −static struct thermal_cooling_device_ops const clock_cooling_ops = { | |
| 354 | − .get_max_state = clock_cooling_get_max_state, | |
| 355 | − .get_cur_state = clock_cooling_get_cur_state, | |
| 356 | − .set_cur_state = clock_cooling_set_cur_state, | |
| 357 | −}; | |
| 358 | − | |
| 359 | −/** | |
| 360 | − * clock_cooling_register - function to create clock cooling device. | |
| 361 | − * @dev: struct device pointer to the device used as clock cooling device. | |
| 362 | − * @clock_name: string containing the clock used as cooling mechanism. | |
| 363 | − * | |
| 364 | − * This interface function registers the clock cooling device with the name | |
| 365 | − * "thermal-clock-%x". The cooling device is based on clock frequencies. | |
| 366 | − * The struct device is assumed to be capable of DVFS transitions. | |
| 367 | − * The OPP layer is used to fetch and fill the available frequencies for | |
| 368 | − * the referred device. The ordered frequency table is used to control | |
| 369 | − * the clock cooling device cooling states and to limit clock transitions | |
| 370 | − * based on the cooling state requested by the thermal framework. | |
| 371 | − * | |
| 372 | − * Return: a valid struct thermal_cooling_device pointer on success, | |
| 373 | − * on failure, it returns a corresponding ERR_PTR(). | |
| 374 | − */ | |
| 375 | −struct thermal_cooling_device * | |
| 376 | −clock_cooling_register(struct device *dev, const char *clock_name) | |
| 377 | −{ | |
| 378 | − struct thermal_cooling_device *cdev; | |
| 379 | − struct clock_cooling_device *ccdev = NULL; | |
| 380 | − char dev_name[THERMAL_NAME_LENGTH]; | |
| 381 | − int ret = 0; | |
| 382 | − | |
| 383 | − ccdev = devm_kzalloc(dev, sizeof(*ccdev), GFP_KERNEL); | |
| 384 | − if (!ccdev) | |
| 385 | − return ERR_PTR(-ENOMEM); | |
| 386 | − | |
| 387 | − mutex_init(&ccdev->lock); | |
| 388 | − ccdev->dev = dev; | |
| 389 | − ccdev->clk = devm_clk_get(dev, clock_name); | |
| 390 | − if (IS_ERR(ccdev->clk)) | |
| 391 | − return ERR_CAST(ccdev->clk); | |
| 392 | − | |
| 393 | − ret = ida_simple_get(&clock_ida, 0, 0, GFP_KERNEL); | |
| 394 | − if (ret < 0) | |
| 395 | − return ERR_PTR(ret); | |
| 396 | − ccdev->id = ret; | |
| 397 | − | |
| 398 | − snprintf(dev_name, sizeof(dev_name), "thermal-clock-%d", ccdev->id); | |
| 399 | − | |
| 400 | − cdev = thermal_cooling_device_register(dev_name, ccdev, | |
| 401 | − &clock_cooling_ops); | |
| 402 | − if (IS_ERR(cdev)) { | |
| 403 | − ida_simple_remove(&clock_ida, ccdev->id); | |
| 404 | − return ERR_PTR(-EINVAL); | |
| 405 | − } | |
| 406 | − ccdev->cdev = cdev; | |
| 407 | − ccdev->clk_rate_change_nb.notifier_call = clock_cooling_clock_notifier; | |
| 408 | − | |
| 409 | − /* Assuming someone has already filled the opp table for this device */ | |
| 410 | − ret = dev_pm_opp_init_cpufreq_table(dev, &ccdev->freq_table); | |
| 411 | − if (ret) { | |
| 412 | − ida_simple_remove(&clock_ida, ccdev->id); | |
| 413 | − return ERR_PTR(ret); | |
| 414 | − } | |
| 415 | − ccdev->clock_state = 0; | |
| 416 | − ccdev->clock_val = clock_cooling_get_frequency(ccdev, 0); | |
| 417 | − | |
| 418 | − clk_notifier_register(ccdev->clk, &ccdev->clk_rate_change_nb); | |
| 419 | − | |
| 420 | − return cdev; | |
| 421 | −} | |
| 422 | −EXPORT_SYMBOL_GPL(clock_cooling_register); | |
| 423 | − | |
| 424 | −/** | |
| 425 | − * clock_cooling_unregister - function to remove clock cooling device. | |
| 426 | − * @cdev: thermal cooling device pointer. | |
| 427 | − * | |
| 428 | − * This interface function unregisters the "thermal-clock-%x" cooling device. | |
| 429 | − */ | |
| 430 | −void clock_cooling_unregister(struct thermal_cooling_device *cdev) | |
| 431 | −{ | |
| 432 | − struct clock_cooling_device *ccdev; | |
| 433 | − | |
| 434 | − if (!cdev) | |
| 435 | − return; | |
| 436 | − | |
| 437 | − ccdev = cdev->devdata; | |
| 438 | − | |
| 439 | − clk_notifier_unregister(ccdev->clk, &ccdev->clk_rate_change_nb); | |
| 440 | − dev_pm_opp_free_cpufreq_table(ccdev->dev, &ccdev->freq_table); | |
| 441 | − | |
| 442 | − thermal_cooling_device_unregister(ccdev->cdev); | |
| 443 | − ida_simple_remove(&clock_ida, ccdev->id); | |
| 444 | −} | |
| 445 | −EXPORT_SYMBOL_GPL(clock_cooling_unregister); | |
| @@ -49,7 +49,6 @@ struct da9062_thermal { · 48 unmodified lines | ||
| 49 | 49 | struct da9062 *hw; |
| 50 | 50 | struct delayed_work work; |
| 51 | 51 | struct thermal_zone_device *zone; |
| 52 | − enum thermal_device_mode mode; | |
| 53 | 52 | struct mutex lock; /* protection for da9062_thermal temperature */ |
| 54 | 53 | int temperature; |
| 55 | 54 | int irq; |
| @@ -121,14 +120,6 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data) · 65 unmodified lines | ||
| 121 | 120 | return IRQ_HANDLED; |
| 122 | 121 | } |
| 123 | 122 | |
| 124 | −static int da9062_thermal_get_mode(struct thermal_zone_device *z, | |
| 125 | − enum thermal_device_mode *mode) | |
| 126 | −{ | |
| 127 | − struct da9062_thermal *thermal = z->devdata; | |
| 128 | − *mode = thermal->mode; | |
| 129 | − return 0; | |
| 130 | −} | |
| 131 | − | |
| 132 | 123 | static int da9062_thermal_get_trip_type(struct thermal_zone_device *z, |
| 133 | 124 | int trip, |
| 134 | 125 | enum thermal_trip_type *type) |
| @@ -181,7 +172,6 @@ static int da9062_thermal_get_temp(struct thermal_zone_device *z, · 46 unmodified lines | ||
| 181 | 172 | |
| 182 | 173 | static struct thermal_zone_device_ops da9062_thermal_ops = { |
| 183 | 174 | .get_temp = da9062_thermal_get_temp, |
| 184 | − .get_mode = da9062_thermal_get_mode, | |
| 185 | 175 | .get_trip_type = da9062_thermal_get_trip_type, |
| 186 | 176 | .get_trip_temp = da9062_thermal_get_trip_temp, |
| 187 | 177 | }; |
| @@ -233,7 +223,6 @@ static int da9062_thermal_probe(struct platform_device *pdev) · 45 unmodified lines | ||
| 233 | 223 | |
| 234 | 224 | thermal->config = match->data; |
| 235 | 225 | thermal->hw = chip; |
| 236 | − thermal->mode = THERMAL_DEVICE_ENABLED; | |
| 237 | 226 | thermal->dev = &pdev->dev; |
| 238 | 227 | |
| 239 | 228 | INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on); |
| @@ -248,6 +237,11 @@ static int da9062_thermal_probe(struct platform_device *pdev) · 8 unmodified lines | ||
| 248 | 237 | ret = PTR_ERR(thermal->zone); |
| 249 | 238 | goto err; |
| 250 | 239 | } |
| 240 | + ret = thermal_zone_device_enable(thermal->zone); | |
| 241 | + if (ret) { | |
| 242 | + dev_err(&pdev->dev, "Cannot enable thermal zone device\n"); | |
| 243 | + goto err_zone; | |
| 244 | + } | |
| 251 | 245 | |
| 252 | 246 | dev_dbg(&pdev->dev, |
| 253 | 247 | "TJUNC temperature polling period set at %d ms\n", |
| @@ -1,18 +1,10 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 1 | 2 | /* |
| 2 | 3 | * devfreq_cooling: Thermal cooling device implementation for devices using |
| 3 | 4 | * devfreq |
| 4 | 5 | * |
| 5 | 6 | * Copyright (C) 2014-2015 ARM Limited |
| 6 | 7 | * |
| 7 | − * This program is free software; you can redistribute it and/or modify | |
| 8 | − * it under the terms of the GNU General Public License version 2 as | |
| 9 | − * published by the Free Software Foundation. | |
| 10 | − * | |
| 11 | − * This program is distributed "as is" WITHOUT ANY WARRANTY of any | |
| 12 | − * kind, whether express or implied; without even the implied warranty | |
| 13 | − * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | − * GNU General Public License for more details. | |
| 15 | − * | |
| 16 | 8 | * TODO: |
| 17 | 9 | * - If OPPs are added or removed after devfreq cooling has |
| 18 | 10 | * registered, the devfreq cooling won't react to it. |
| @@ -153,6 +153,12 @@ static int dove_thermal_probe(struct platform_device *pdev) · 152 unmodified lines | ||
| 153 | 153 | return PTR_ERR(thermal); |
| 154 | 154 | } |
| 155 | 155 | |
| 156 | + ret = thermal_zone_device_enable(thermal); | |
| 157 | + if (ret) { | |
| 158 | + thermal_zone_device_unregister(thermal); | |
| 159 | + return ret; | |
| 160 | + } | |
| 161 | + | |
| 156 | 162 | platform_set_drvdata(pdev, thermal); |
| 157 | 163 | |
| 158 | 164 | return 0; |
| @@ -1,16 +1,9 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 1 | 2 | /* |
| 2 | 3 | * A power allocator to manage temperature |
| 3 | 4 | * |
| 4 | 5 | * Copyright (C) 2014 ARM Ltd. |
| 5 | 6 | * |
| 6 | − * This program is free software; you can redistribute it and/or modify | |
| 7 | − * it under the terms of the GNU General Public License version 2 as | |
| 8 | − * published by the Free Software Foundation. | |
| 9 | − * | |
| 10 | − * This program is distributed "as is" WITHOUT ANY WARRANTY of any | |
| 11 | − * kind, whether express or implied; without even the implied warranty | |
| 12 | − * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 | − * GNU General Public License for more details. | |
| 14 | 7 | */ |
| 15 | 8 | |
| 16 | 9 | #define pr_fmt(fmt) "Power allocator: " fmt |
| @@ -549,8 +549,10 @@ static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor, · 548 unmodified lines | ||
| 549 | 549 | { |
| 550 | 550 | struct thermal_zone_device *tzd = sensor->tzd; |
| 551 | 551 | |
| 552 | − tzd->ops->set_mode(tzd, | |
| 553 | − on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED); | |
| 552 | + if (on) | |
| 553 | + thermal_zone_device_enable(tzd); | |
| 554 | + else | |
| 555 | + thermal_zone_device_disable(tzd); | |
| 554 | 556 | } |
| 555 | 557 | |
| 556 | 558 | static int hisi_thermal_probe(struct platform_device *pdev) |
| @@ -220,6 +220,7 @@ static const struct of_device_id imx8mm_tmu_table[] = { · 219 unmodified lines | ||
| 220 | 220 | { .compatible = "fsl,imx8mp-tmu", .data = &imx8mp_tmu_data, }, |
| 221 | 221 | { }, |
| 222 | 222 | }; |
| 223 | +MODULE_DEVICE_TABLE(of, imx8mm_tmu_table); | |
| 223 | 224 | |
| 224 | 225 | static struct platform_driver imx8mm_tmu = { |
| 225 | 226 | .driver = { |
| @@ -197,7 +197,6 @@ struct imx_thermal_data { · 196 unmodified lines | ||
| 197 | 197 | struct cpufreq_policy *policy; |
| 198 | 198 | struct thermal_zone_device *tz; |
| 199 | 199 | struct thermal_cooling_device *cdev; |
| 200 | − enum thermal_device_mode mode; | |
| 201 | 200 | struct regmap *tempmon; |
| 202 | 201 | u32 c1, c2; /* See formula in imx_init_calib() */ |
| 203 | 202 | int temp_passive; |
| @@ -253,10 +252,11 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp) · 49 unmodified lines | ||
| 253 | 252 | const struct thermal_soc_data *soc_data = data->socdata; |
| 254 | 253 | struct regmap *map = data->tempmon; |
| 255 | 254 | unsigned int n_meas; |
| 256 | − bool wait; | |
| 255 | + bool wait, run_measurement; | |
| 257 | 256 | u32 val; |
| 258 | 257 | |
| 259 | − if (data->mode == THERMAL_DEVICE_ENABLED) { | |
| 258 | + run_measurement = !data->irq_enabled; | |
| 259 | + if (!run_measurement) { | |
| 260 | 260 | /* Check if a measurement is currently in progress */ |
| 261 | 261 | regmap_read(map, soc_data->temp_data, &val); |
| 262 | 262 | wait = !(val & soc_data->temp_valid_mask); |
| @@ -283,7 +283,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp) · 20 unmodified lines | ||
| 283 | 283 | |
| 284 | 284 | regmap_read(map, soc_data->temp_data, &val); |
| 285 | 285 | |
| 286 | − if (data->mode != THERMAL_DEVICE_ENABLED) { | |
| 286 | + if (run_measurement) { | |
| 287 | 287 | regmap_write(map, soc_data->sensor_ctrl + REG_CLR, |
| 288 | 288 | soc_data->measure_temp_mask); |
| 289 | 289 | regmap_write(map, soc_data->sensor_ctrl + REG_SET, |
| @@ -331,27 +331,14 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp) · 41 unmodified lines | ||
| 331 | 331 | return 0; |
| 332 | 332 | } |
| 333 | 333 | |
| 334 | −static int imx_get_mode(struct thermal_zone_device *tz, | |
| 335 | − enum thermal_device_mode *mode) | |
| 336 | −{ | |
| 337 | − struct imx_thermal_data *data = tz->devdata; | |
| 338 | − | |
| 339 | − *mode = data->mode; | |
| 340 | − | |
| 341 | − return 0; | |
| 342 | −} | |
| 343 | − | |
| 344 | −static int imx_set_mode(struct thermal_zone_device *tz, | |
| 345 | − enum thermal_device_mode mode) | |
| 334 | +static int imx_change_mode(struct thermal_zone_device *tz, | |
| 335 | + enum thermal_device_mode mode) | |
| 346 | 336 | { |
| 347 | 337 | struct imx_thermal_data *data = tz->devdata; |
| 348 | 338 | struct regmap *map = data->tempmon; |
| 349 | 339 | const struct thermal_soc_data *soc_data = data->socdata; |
| 350 | 340 | |
| 351 | 341 | if (mode == THERMAL_DEVICE_ENABLED) { |
| 352 | − tz->polling_delay = IMX_POLLING_DELAY; | |
| 353 | − tz->passive_delay = IMX_PASSIVE_DELAY; | |
| 354 | − | |
| 355 | 342 | regmap_write(map, soc_data->sensor_ctrl + REG_CLR, |
| 356 | 343 | soc_data->power_down_mask); |
| 357 | 344 | regmap_write(map, soc_data->sensor_ctrl + REG_SET, |
| @@ -367,18 +354,12 @@ static int imx_set_mode(struct thermal_zone_device *tz, · 9 unmodified lines | ||
| 367 | 354 | regmap_write(map, soc_data->sensor_ctrl + REG_SET, |
| 368 | 355 | soc_data->power_down_mask); |
| 369 | 356 | |
| 370 | − tz->polling_delay = 0; | |
| 371 | − tz->passive_delay = 0; | |
| 372 | − | |
| 373 | 357 | if (data->irq_enabled) { |
| 374 | 358 | disable_irq(data->irq); |
| 375 | 359 | data->irq_enabled = false; |
| 376 | 360 | } |
| 377 | 361 | } |
| 378 | 362 | |
| 379 | − data->mode = mode; | |
| 380 | − thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); | |
| 381 | − | |
| 382 | 363 | return 0; |
| 383 | 364 | } |
| 384 | 365 | |
| @@ -467,8 +448,7 @@ static struct thermal_zone_device_ops imx_tz_ops = { · 82 unmodified lines | ||
| 467 | 448 | .bind = imx_bind, |
| 468 | 449 | .unbind = imx_unbind, |
| 469 | 450 | .get_temp = imx_get_temp, |
| 470 | − .get_mode = imx_get_mode, | |
| 471 | − .set_mode = imx_set_mode, | |
| 451 | + .change_mode = imx_change_mode, | |
| 472 | 452 | .get_trip_type = imx_get_trip_type, |
| 473 | 453 | .get_trip_temp = imx_get_trip_temp, |
| 474 | 454 | .get_crit_temp = imx_get_crit_temp, |
| @@ -832,7 +812,9 @@ static int imx_thermal_probe(struct platform_device *pdev) · 357 unmodified lines | ||
| 832 | 812 | data->socdata->measure_temp_mask); |
| 833 | 813 | |
| 834 | 814 | data->irq_enabled = true; |
| 835 | − data->mode = THERMAL_DEVICE_ENABLED; | |
| 815 | + ret = thermal_zone_device_enable(data->tz); | |
| 816 | + if (ret) | |
| 817 | + goto thermal_zone_unregister; | |
| 836 | 818 | |
| 837 | 819 | ret = devm_request_threaded_irq(&pdev->dev, data->irq, |
| 838 | 820 | imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread, |
| @@ -874,19 +856,18 @@ static int imx_thermal_remove(struct platform_device *pdev) · 35 unmodified lines | ||
| 874 | 856 | static int __maybe_unused imx_thermal_suspend(struct device *dev) |
| 875 | 857 | { |
| 876 | 858 | struct imx_thermal_data *data = dev_get_drvdata(dev); |
| 877 | − struct regmap *map = data->tempmon; | |
| 859 | + int ret; | |
| 878 | 860 | |
| 879 | 861 | /* |
| 880 | 862 | * Need to disable thermal sensor, otherwise, when thermal core |
| 881 | 863 | * try to get temperature before thermal sensor resume, a wrong |
| 882 | 864 | * temperature will be read as the thermal sensor is powered |
| 883 | − * down. | |
| 865 | + * down. This is done in change_mode() operation called from | |
| 866 | + * thermal_zone_device_disable() | |
| 884 | 867 | */ |
| 885 | − regmap_write(map, data->socdata->sensor_ctrl + REG_CLR, | |
| 886 | − data->socdata->measure_temp_mask); | |
| 887 | − regmap_write(map, data->socdata->sensor_ctrl + REG_SET, | |
| 888 | − data->socdata->power_down_mask); | |
| 889 | − data->mode = THERMAL_DEVICE_DISABLED; | |
| 868 | + ret = thermal_zone_device_disable(data->tz); | |
| 869 | + if (ret) | |
| 870 | + return ret; | |
| 890 | 871 | clk_disable_unprepare(data->thermal_clk); |
| 891 | 872 | |
| 892 | 873 | return 0; |
| @@ -895,18 +876,15 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev) · 2 unmodified lines | ||
| 895 | 876 | static int __maybe_unused imx_thermal_resume(struct device *dev) |
| 896 | 877 | { |
| 897 | 878 | struct imx_thermal_data *data = dev_get_drvdata(dev); |
| 898 | − struct regmap *map = data->tempmon; | |
| 899 | 879 | int ret; |
| 900 | 880 | |
| 901 | 881 | ret = clk_prepare_enable(data->thermal_clk); |
| 902 | 882 | if (ret) |
| 903 | 883 | return ret; |
| 904 | 884 | /* Enabled thermal sensor after resume */ |
| 905 | − regmap_write(map, data->socdata->sensor_ctrl + REG_CLR, | |
| 906 | − data->socdata->power_down_mask); | |
| 907 | − regmap_write(map, data->socdata->sensor_ctrl + REG_SET, | |
| 908 | − data->socdata->measure_temp_mask); | |
| 909 | − data->mode = THERMAL_DEVICE_ENABLED; | |
| 885 | + ret = thermal_zone_device_enable(data->tz); | |
| 886 | + if (ret) | |
| 887 | + return ret; | |
| 910 | 888 | |
| 911 | 889 | return 0; |
| 912 | 890 | } |
| @@ -48,7 +48,6 @@ struct int3400_thermal_priv { · 47 unmodified lines | ||
| 48 | 48 | struct acpi_device *adev; |
| 49 | 49 | struct platform_device *pdev; |
| 50 | 50 | struct thermal_zone_device *thermal; |
| 51 | − int mode; | |
| 52 | 51 | int art_count; |
| 53 | 52 | struct art *arts; |
| 54 | 53 | int trt_count; |
| @@ -383,42 +382,20 @@ static int int3400_thermal_get_temp(struct thermal_zone_device *thermal, · 328 unmodified lines | ||
| 383 | 382 | return 0; |
| 384 | 383 | } |
| 385 | 384 | |
| 386 | −static int int3400_thermal_get_mode(struct thermal_zone_device *thermal, | |
| 387 | − enum thermal_device_mode *mode) | |
| 385 | +static int int3400_thermal_change_mode(struct thermal_zone_device *thermal, | |
| 386 | + enum thermal_device_mode mode) | |
| 388 | 387 | { |
| 389 | 388 | struct int3400_thermal_priv *priv = thermal->devdata; |
| 390 | − | |
| 391 | − if (!priv) | |
| 392 | − return -EINVAL; | |
| 393 | − | |
| 394 | − *mode = priv->mode; | |
| 395 | − | |
| 396 | − return 0; | |
| 397 | −} | |
| 398 | − | |
| 399 | −static int int3400_thermal_set_mode(struct thermal_zone_device *thermal, | |
| 400 | − enum thermal_device_mode mode) | |
| 401 | −{ | |
| 402 | − struct int3400_thermal_priv *priv = thermal->devdata; | |
| 403 | − bool enable; | |
| 404 | 389 | int result = 0; |
| 405 | 390 | |
| 406 | 391 | if (!priv) |
| 407 | 392 | return -EINVAL; |
| 408 | 393 | |
| 409 | − if (mode == THERMAL_DEVICE_ENABLED) | |
| 410 | − enable = true; | |
| 411 | − else if (mode == THERMAL_DEVICE_DISABLED) | |
| 412 | − enable = false; | |
| 413 | − else | |
| 414 | − return -EINVAL; | |
| 415 | − | |
| 416 | − if (enable != priv->mode) { | |
| 417 | − priv->mode = enable; | |
| 394 | + if (mode != thermal->mode) | |
| 418 | 395 | result = int3400_thermal_run_osc(priv->adev->handle, |
| 419 | − priv->current_uuid_index, | |
| 420 | − enable); | |
| 421 | − } | |
| 396 | + priv->current_uuid_index, | |
| 397 | + mode == THERMAL_DEVICE_ENABLED); | |
| 398 | + | |
| 422 | 399 | |
| 423 | 400 | evaluate_odvp(priv); |
| 424 | 401 | |
| @@ -427,8 +404,7 @@ static int int3400_thermal_set_mode(struct thermal_zone_device *thermal, · 2 unmodified lines | ||
| 427 | 404 | |
| 428 | 405 | static struct thermal_zone_device_ops int3400_thermal_ops = { |
| 429 | 406 | .get_temp = int3400_thermal_get_temp, |
| 430 | − .get_mode = int3400_thermal_get_mode, | |
| 431 | − .set_mode = int3400_thermal_set_mode, | |
| 407 | + .change_mode = int3400_thermal_change_mode, | |
| 432 | 408 | }; |
| 433 | 409 | |
| 434 | 410 | static struct thermal_zone_params int3400_thermal_params = { |
| @@ -259,9 +259,14 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev, · 258 unmodified lines | ||
| 259 | 259 | ret = PTR_ERR(int34x_thermal_zone->zone); |
| 260 | 260 | goto err_thermal_zone; |
| 261 | 261 | } |
| 262 | + ret = thermal_zone_device_enable(int34x_thermal_zone->zone); | |
| 263 | + if (ret) | |
| 264 | + goto err_enable; | |
| 262 | 265 | |
| 263 | 266 | return int34x_thermal_zone; |
| 264 | 267 | |
| 268 | +err_enable: | |
| 269 | + thermal_zone_device_unregister(int34x_thermal_zone->zone); | |
| 265 | 270 | err_thermal_zone: |
| 266 | 271 | acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); |
| 267 | 272 | kfree(int34x_thermal_zone->aux_trips); |
| @@ -43,7 +43,7 @@ · 42 unmodified lines | ||
| 43 | 43 | #define PCI_DEVICE_ID_PROC_ICL_THERMAL 0x8a03 |
| 44 | 44 | |
| 45 | 45 | /* JasperLake thermal reporting device */ |
| 46 | −#define PCI_DEVICE_ID_PROC_JSL_THERMAL 0x4503 | |
| 46 | +#define PCI_DEVICE_ID_PROC_JSL_THERMAL 0x4E03 | |
| 47 | 47 | |
| 48 | 48 | /* TigerLake thermal reporting device */ |
| 49 | 49 | #define PCI_DEVICE_ID_PROC_TGL_THERMAL 0x9A03 |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | ||
| 24 | 24 | #define PCH_THERMAL_DID_SKL_H 0xA131 /* Skylake PCH 100 series */ |
| 25 | 25 | #define PCH_THERMAL_DID_CNL 0x9Df9 /* CNL PCH */ |
| 26 | 26 | #define PCH_THERMAL_DID_CNL_H 0xA379 /* CNL-H PCH */ |
| 27 | +#define PCH_THERMAL_DID_CNL_LP 0x02F9 /* CNL-LP PCH */ | |
| 27 | 28 | #define PCH_THERMAL_DID_CML_H 0X06F9 /* CML-H PCH */ |
| 28 | 29 | |
| 29 | 30 | /* Wildcat Point-LP PCH Thermal registers */ |
| @@ -352,9 +353,14 @@ static int intel_pch_thermal_probe(struct pci_dev *pdev, · 322 unmodified lines | ||
| 352 | 353 | err = PTR_ERR(ptd->tzd); |
| 353 | 354 | goto error_cleanup; |
| 354 | 355 | } |
| 356 | + err = thermal_zone_device_enable(ptd->tzd); | |
| 357 | + if (err) | |
| 358 | + goto err_unregister; | |
| 355 | 359 | |
| 356 | 360 | return 0; |
| 357 | 361 | |
| 362 | +err_unregister: | |
| 363 | + thermal_zone_device_unregister(ptd->tzd); | |
| 358 | 364 | error_cleanup: |
| 359 | 365 | iounmap(ptd->hw_base); |
| 360 | 366 | error_release: |
| @@ -405,6 +411,8 @@ static const struct pci_device_id intel_pch_thermal_id[] = { · 44 unmodified lines | ||
| 405 | 411 | .driver_data = board_cnl, }, |
| 406 | 412 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL_H), |
| 407 | 413 | .driver_data = board_cnl, }, |
| 414 | + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL_LP), | |
| 415 | + .driver_data = board_cnl, }, | |
| 408 | 416 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CML_H), |
| 409 | 417 | .driver_data = board_cml, }, |
| 410 | 418 | { 0, }, |
| @@ -103,7 +103,6 @@ struct soc_sensor_entry { · 102 unmodified lines | ||
| 103 | 103 | bool locked; |
| 104 | 104 | u32 store_ptps; |
| 105 | 105 | u32 store_dts_enable; |
| 106 | − enum thermal_device_mode mode; | |
| 107 | 106 | struct thermal_zone_device *tzone; |
| 108 | 107 | }; |
| 109 | 108 | |
| @@ -127,10 +126,8 @@ static int soc_dts_enable(struct thermal_zone_device *tzd) · 17 unmodified lines | ||
| 127 | 126 | if (ret) |
| 128 | 127 | return ret; |
| 129 | 128 | |
| 130 | − if (out & QRK_DTS_ENABLE_BIT) { | |
| 131 | − aux_entry->mode = THERMAL_DEVICE_ENABLED; | |
| 129 | + if (out & QRK_DTS_ENABLE_BIT) | |
| 132 | 130 | return 0; |
| 133 | − } | |
| 134 | 131 | |
| 135 | 132 | if (!aux_entry->locked) { |
| 136 | 133 | out |= QRK_DTS_ENABLE_BIT; |
| @@ -138,10 +135,7 @@ static int soc_dts_enable(struct thermal_zone_device *tzd) · 1 unmodified line | ||
| 138 | 135 | QRK_DTS_REG_OFFSET_ENABLE, out); |
| 139 | 136 | if (ret) |
| 140 | 137 | return ret; |
| 141 | − | |
| 142 | − aux_entry->mode = THERMAL_DEVICE_ENABLED; | |
| 143 | 138 | } else { |
| 144 | − aux_entry->mode = THERMAL_DEVICE_DISABLED; | |
| 145 | 139 | pr_info("DTS is locked. Cannot enable DTS\n"); |
| 146 | 140 | ret = -EPERM; |
| 147 | 141 | } |
| @@ -160,10 +154,8 @@ static int soc_dts_disable(struct thermal_zone_device *tzd) · 12 unmodified lines | ||
| 160 | 154 | if (ret) |
| 161 | 155 | return ret; |
| 162 | 156 | |
| 163 | − if (!(out & QRK_DTS_ENABLE_BIT)) { | |
| 164 | − aux_entry->mode = THERMAL_DEVICE_DISABLED; | |
| 157 | + if (!(out & QRK_DTS_ENABLE_BIT)) | |
| 165 | 158 | return 0; |
| 166 | − } | |
| 167 | 159 | |
| 168 | 160 | if (!aux_entry->locked) { |
| 169 | 161 | out &= ~QRK_DTS_ENABLE_BIT; |
| @@ -172,10 +164,7 @@ static int soc_dts_disable(struct thermal_zone_device *tzd) · 2 unmodified lines | ||
| 172 | 164 | |
| 173 | 165 | if (ret) |
| 174 | 166 | return ret; |
| 175 | − | |
| 176 | − aux_entry->mode = THERMAL_DEVICE_DISABLED; | |
| 177 | 167 | } else { |
| 178 | − aux_entry->mode = THERMAL_DEVICE_ENABLED; | |
| 179 | 168 | pr_info("DTS is locked. Cannot disable DTS\n"); |
| 180 | 169 | ret = -EPERM; |
| 181 | 170 | } |
| @@ -309,16 +298,8 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, · 127 unmodified lines | ||
| 309 | 298 | return 0; |
| 310 | 299 | } |
| 311 | 300 | |
| 312 | −static int sys_get_mode(struct thermal_zone_device *tzd, | |
| 313 | − enum thermal_device_mode *mode) | |
| 314 | −{ | |
| 315 | − struct soc_sensor_entry *aux_entry = tzd->devdata; | |
| 316 | − *mode = aux_entry->mode; | |
| 317 | − return 0; | |
| 318 | −} | |
| 319 | − | |
| 320 | −static int sys_set_mode(struct thermal_zone_device *tzd, | |
| 321 | − enum thermal_device_mode mode) | |
| 301 | +static int sys_change_mode(struct thermal_zone_device *tzd, | |
| 302 | + enum thermal_device_mode mode) | |
| 322 | 303 | { |
| 323 | 304 | int ret; |
| 324 | 305 | |
| @@ -338,8 +319,7 @@ static struct thermal_zone_device_ops tzone_ops = { · 13 unmodified lines | ||
| 338 | 319 | .get_trip_type = sys_get_trip_type, |
| 339 | 320 | .set_trip_temp = sys_set_trip_temp, |
| 340 | 321 | .get_crit_temp = sys_get_crit_temp, |
| 341 | − .get_mode = sys_get_mode, | |
| 342 | − .set_mode = sys_set_mode, | |
| 322 | + .change_mode = sys_change_mode, | |
| 343 | 323 | }; |
| 344 | 324 | |
| 345 | 325 | static void free_soc_dts(struct soc_sensor_entry *aux_entry) |
| @@ -414,9 +394,7 @@ static struct soc_sensor_entry *alloc_soc_dts(void) · 68 unmodified lines | ||
| 414 | 394 | goto err_ret; |
| 415 | 395 | } |
| 416 | 396 | |
| 417 | − mutex_lock(&dts_update_mutex); | |
| 418 | − err = soc_dts_enable(aux_entry->tzone); | |
| 419 | − mutex_unlock(&dts_update_mutex); | |
| 397 | + err = thermal_zone_device_enable(aux_entry->tzone); | |
| 420 | 398 | if (err) |
| 421 | 399 | goto err_aux_status; |
| 422 | 400 | |
| @@ -329,6 +329,9 @@ static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts, · 328 unmodified lines | ||
| 329 | 329 | ret = PTR_ERR(dts->tzone); |
| 330 | 330 | goto err_ret; |
| 331 | 331 | } |
| 332 | + ret = thermal_zone_device_enable(dts->tzone); | |
| 333 | + if (ret) | |
| 334 | + goto err_enable; | |
| 332 | 335 | |
| 333 | 336 | ret = soc_dts_enable(id); |
| 334 | 337 | if (ret) |
| @@ -363,6 +363,12 @@ static int pkg_temp_thermal_device_add(unsigned int cpu) · 362 unmodified lines | ||
| 363 | 363 | kfree(zonedev); |
| 364 | 364 | return err; |
| 365 | 365 | } |
| 366 | + err = thermal_zone_device_enable(zonedev->tzone); | |
| 367 | + if (err) { | |
| 368 | + thermal_zone_device_unregister(zonedev->tzone); | |
| 369 | + kfree(zonedev); | |
| 370 | + return err; | |
| 371 | + } | |
| 366 | 372 | /* Store MSR value for package thermal interrupt, to restore at exit */ |
| 367 | 373 | rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, zonedev->msr_pkg_therm_low, |
| 368 | 374 | zonedev->msr_pkg_therm_high); |
| @@ -65,6 +65,7 @@ static int kirkwood_thermal_probe(struct platform_device *pdev) · 64 unmodified lines | ||
| 65 | 65 | struct thermal_zone_device *thermal = NULL; |
| 66 | 66 | struct kirkwood_thermal_priv *priv; |
| 67 | 67 | struct resource *res; |
| 68 | + int ret; | |
| 68 | 69 | |
| 69 | 70 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); |
| 70 | 71 | if (!priv) |
| @@ -82,6 +83,12 @@ static int kirkwood_thermal_probe(struct platform_device *pdev) · 11 unmodified lines | ||
| 82 | 83 | "Failed to register thermal zone device\n"); |
| 83 | 84 | return PTR_ERR(thermal); |
| 84 | 85 | } |
| 86 | + ret = thermal_zone_device_enable(thermal); | |
| 87 | + if (ret) { | |
| 88 | + thermal_zone_device_unregister(thermal); | |
| 89 | + dev_err(&pdev->dev, "Failed to enable thermal zone device\n"); | |
| 90 | + return ret; | |
| 91 | + } | |
| 85 | 92 | |
| 86 | 93 | platform_set_drvdata(pdev, thermal); |
| 87 | 94 | |
| @@ -38,6 +38,7 @@ · 37 unmodified lines | ||
| 38 | 38 | #define TEMP_MONIDET0 0x014 |
| 39 | 39 | #define TEMP_MONIDET1 0x018 |
| 40 | 40 | #define TEMP_MSRCTL0 0x038 |
| 41 | +#define TEMP_MSRCTL1 0x03c | |
| 41 | 42 | #define TEMP_AHBPOLL 0x040 |
| 42 | 43 | #define TEMP_AHBTO 0x044 |
| 43 | 44 | #define TEMP_ADCPNP0 0x048 |
| @@ -120,18 +121,32 @@ · 76 unmodified lines | ||
| 120 | 121 | * MT2701 has 3 sensors and needs 3 VTS calibration data. |
| 121 | 122 | * MT2712 has 4 sensors and needs 4 VTS calibration data. |
| 122 | 123 | */ |
| 123 | −#define CALIB_BUF0_VALID BIT(0) | |
| 124 | −#define CALIB_BUF1_ADC_GE(x) (((x) >> 22) & 0x3ff) | |
| 125 | −#define CALIB_BUF0_VTS_TS1(x) (((x) >> 17) & 0x1ff) | |
| 126 | −#define CALIB_BUF0_VTS_TS2(x) (((x) >> 8) & 0x1ff) | |
| 127 | −#define CALIB_BUF1_VTS_TS3(x) (((x) >> 0) & 0x1ff) | |
| 128 | −#define CALIB_BUF2_VTS_TS4(x) (((x) >> 23) & 0x1ff) | |
| 129 | −#define CALIB_BUF2_VTS_TS5(x) (((x) >> 5) & 0x1ff) | |
| 130 | −#define CALIB_BUF2_VTS_TSABB(x) (((x) >> 14) & 0x1ff) | |
| 131 | −#define CALIB_BUF0_DEGC_CALI(x) (((x) >> 1) & 0x3f) | |
| 132 | −#define CALIB_BUF0_O_SLOPE(x) (((x) >> 26) & 0x3f) | |
| 133 | −#define CALIB_BUF0_O_SLOPE_SIGN(x) (((x) >> 7) & 0x1) | |
| 134 | −#define CALIB_BUF1_ID(x) (((x) >> 9) & 0x1) | |
| 124 | +#define CALIB_BUF0_VALID_V1 BIT(0) | |
| 125 | +#define CALIB_BUF1_ADC_GE_V1(x) (((x) >> 22) & 0x3ff) | |
| 126 | +#define CALIB_BUF0_VTS_TS1_V1(x) (((x) >> 17) & 0x1ff) | |
| 127 | +#define CALIB_BUF0_VTS_TS2_V1(x) (((x) >> 8) & 0x1ff) | |
| 128 | +#define CALIB_BUF1_VTS_TS3_V1(x) (((x) >> 0) & 0x1ff) | |
| 129 | +#define CALIB_BUF2_VTS_TS4_V1(x) (((x) >> 23) & 0x1ff) | |
| 130 | +#define CALIB_BUF2_VTS_TS5_V1(x) (((x) >> 5) & 0x1ff) | |
| 131 | +#define CALIB_BUF2_VTS_TSABB_V1(x) (((x) >> 14) & 0x1ff) | |
| 132 | +#define CALIB_BUF0_DEGC_CALI_V1(x) (((x) >> 1) & 0x3f) | |
| 133 | +#define CALIB_BUF0_O_SLOPE_V1(x) (((x) >> 26) & 0x3f) | |
| 134 | +#define CALIB_BUF0_O_SLOPE_SIGN_V1(x) (((x) >> 7) & 0x1) | |
| 135 | +#define CALIB_BUF1_ID_V1(x) (((x) >> 9) & 0x1) | |
| 136 | + | |
| 137 | +/* | |
| 138 | + * Layout of the fuses providing the calibration data | |
| 139 | + * These macros could be used for MT7622. | |
| 140 | + */ | |
| 141 | +#define CALIB_BUF0_ADC_OE_V2(x) (((x) >> 22) & 0x3ff) | |
| 142 | +#define CALIB_BUF0_ADC_GE_V2(x) (((x) >> 12) & 0x3ff) | |
| 143 | +#define CALIB_BUF0_DEGC_CALI_V2(x) (((x) >> 6) & 0x3f) | |
| 144 | +#define CALIB_BUF0_O_SLOPE_V2(x) (((x) >> 0) & 0x3f) | |
| 145 | +#define CALIB_BUF1_VTS_TS1_V2(x) (((x) >> 23) & 0x1ff) | |
| 146 | +#define CALIB_BUF1_VTS_TS2_V2(x) (((x) >> 14) & 0x1ff) | |
| 147 | +#define CALIB_BUF1_VTS_TSABB_V2(x) (((x) >> 5) & 0x1ff) | |
| 148 | +#define CALIB_BUF1_VALID_V2(x) (((x) >> 4) & 0x1) | |
| 149 | +#define CALIB_BUF1_O_SLOPE_SIGN_V2(x) (((x) >> 3) & 0x1) | |
| 135 | 150 | |
| 136 | 151 | enum { |
| 137 | 152 | VTS1, |
| @@ -143,6 +158,11 @@ enum { · 5 unmodified lines | ||
| 143 | 158 | MAX_NUM_VTS, |
| 144 | 159 | }; |
| 145 | 160 | |
| 161 | +enum mtk_thermal_version { | |
| 162 | + MTK_THERMAL_V1 = 1, | |
| 163 | + MTK_THERMAL_V2, | |
| 164 | +}; | |
| 165 | + | |
| 146 | 166 | /* MT2701 thermal sensors */ |
| 147 | 167 | #define MT2701_TS1 0 |
| 148 | 168 | #define MT2701_TS2 1 |
| @@ -248,6 +268,7 @@ struct mtk_thermal_data { · 99 unmodified lines | ||
| 248 | 268 | const int *controller_offset; |
| 249 | 269 | bool need_switch_bank; |
| 250 | 270 | struct thermal_bank_cfg bank_data[MAX_NUM_ZONES]; |
| 271 | + enum mtk_thermal_version version; | |
| 251 | 272 | }; |
| 252 | 273 | |
| 253 | 274 | struct mtk_thermal { |
| @@ -261,8 +282,10 @@ struct mtk_thermal { · 7 unmodified lines | ||
| 261 | 282 | |
| 262 | 283 | /* Calibration values */ |
| 263 | 284 | s32 adc_ge; |
| 285 | + s32 adc_oe; | |
| 264 | 286 | s32 degc_cali; |
| 265 | 287 | s32 o_slope; |
| 288 | + s32 o_slope_sign; | |
| 266 | 289 | s32 vts[MAX_NUM_VTS]; |
| 267 | 290 | |
| 268 | 291 | const struct mtk_thermal_data *conf; |
| @@ -401,6 +424,7 @@ static const struct mtk_thermal_data mt8173_thermal_data = { · 132 unmodified lines | ||
| 401 | 424 | .msr = mt8173_msr, |
| 402 | 425 | .adcpnp = mt8173_adcpnp, |
| 403 | 426 | .sensor_mux_values = mt8173_mux_values, |
| 427 | + .version = MTK_THERMAL_V1, | |
| 404 | 428 | }; |
| 405 | 429 | |
| 406 | 430 | /* |
| @@ -431,6 +455,7 @@ static const struct mtk_thermal_data mt2701_thermal_data = { · 24 unmodified lines | ||
| 431 | 455 | .msr = mt2701_msr, |
| 432 | 456 | .adcpnp = mt2701_adcpnp, |
| 433 | 457 | .sensor_mux_values = mt2701_mux_values, |
| 458 | + .version = MTK_THERMAL_V1, | |
| 434 | 459 | }; |
| 435 | 460 | |
| 436 | 461 | /* |
| @@ -461,6 +486,7 @@ static const struct mtk_thermal_data mt2712_thermal_data = { · 24 unmodified lines | ||
| 461 | 486 | .msr = mt2712_msr, |
| 462 | 487 | .adcpnp = mt2712_adcpnp, |
| 463 | 488 | .sensor_mux_values = mt2712_mux_values, |
| 489 | + .version = MTK_THERMAL_V1, | |
| 464 | 490 | }; |
| 465 | 491 | |
| 466 | 492 | /* |
| @@ -485,6 +511,7 @@ static const struct mtk_thermal_data mt7622_thermal_data = { · 18 unmodified lines | ||
| 485 | 511 | .msr = mt7622_msr, |
| 486 | 512 | .adcpnp = mt7622_adcpnp, |
| 487 | 513 | .sensor_mux_values = mt7622_mux_values, |
| 514 | + .version = MTK_THERMAL_V2, | |
| 488 | 515 | }; |
| 489 | 516 | |
| 490 | 517 | /* |
| @@ -517,6 +544,7 @@ static const struct mtk_thermal_data mt8183_thermal_data = { · 26 unmodified lines | ||
| 517 | 544 | .msr = mt8183_msr, |
| 518 | 545 | .adcpnp = mt8183_adcpnp, |
| 519 | 546 | .sensor_mux_values = mt8183_mux_values, |
| 547 | + .version = MTK_THERMAL_V1, | |
| 520 | 548 | }; |
| 521 | 549 | |
| 522 | 550 | /** |
| @@ -528,7 +556,7 @@ static const struct mtk_thermal_data mt8183_thermal_data = { · 5 unmodified lines | ||
| 528 | 556 | * This converts the raw ADC value to mcelsius using the SoC specific |
| 529 | 557 | * calibration constants |
| 530 | 558 | */ |
| 531 | −static int raw_to_mcelsius(struct mtk_thermal *mt, int sensno, s32 raw) | |
| 559 | +static int raw_to_mcelsius_v1(struct mtk_thermal *mt, int sensno, s32 raw) | |
| 532 | 560 | { |
| 533 | 561 | s32 tmp; |
| 534 | 562 | |
| @@ -543,6 +571,36 @@ static int raw_to_mcelsius(struct mtk_thermal *mt, int sensno, s32 raw) · 8 unmodified lines | ||
| 543 | 571 | return mt->degc_cali * 500 - tmp; |
| 544 | 572 | } |
| 545 | 573 | |
| 574 | +static int raw_to_mcelsius_v2(struct mtk_thermal *mt, int sensno, s32 raw) | |
| 575 | +{ | |
| 576 | + s32 format_1 = 0; | |
| 577 | + s32 format_2 = 0; | |
| 578 | + s32 g_oe = 1; | |
| 579 | + s32 g_gain = 1; | |
| 580 | + s32 g_x_roomt = 0; | |
| 581 | + s32 tmp = 0; | |
| 582 | + | |
| 583 | + if (raw == 0) | |
| 584 | + return 0; | |
| 585 | + | |
| 586 | + raw &= 0xfff; | |
| 587 | + g_gain = 10000 + (((mt->adc_ge - 512) * 10000) >> 12); | |
| 588 | + g_oe = mt->adc_oe - 512; | |
| 589 | + format_1 = mt->vts[VTS2] + 3105 - g_oe; | |
| 590 | + format_2 = (mt->degc_cali * 10) >> 1; | |
| 591 | + g_x_roomt = (((format_1 * 10000) >> 12) * 10000) / g_gain; | |
| 592 | + | |
| 593 | + tmp = (((((raw - g_oe) * 10000) >> 12) * 10000) / g_gain) - g_x_roomt; | |
| 594 | + tmp = tmp * 10 * 100 / 11; | |
| 595 | + | |
| 596 | + if (mt->o_slope_sign == 0) | |
| 597 | + tmp = tmp / (165 - mt->o_slope); | |
| 598 | + else | |
| 599 | + tmp = tmp / (165 + mt->o_slope); | |
| 600 | + | |
| 601 | + return (format_2 - tmp) * 100; | |
| 602 | +} | |
| 603 | + | |
| 546 | 604 | /** |
| 547 | 605 | * mtk_thermal_get_bank - get bank |
| 548 | 606 | * @bank: The bank |
| @@ -596,9 +654,13 @@ static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank) · 47 unmodified lines | ||
| 596 | 654 | for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) { |
| 597 | 655 | raw = readl(mt->thermal_base + conf->msr[i]); |
| 598 | 656 | |
| 599 | − temp = raw_to_mcelsius(mt, | |
| 600 | − conf->bank_data[bank->id].sensors[i], | |
| 601 | − raw); | |
| 657 | + if (mt->conf->version == MTK_THERMAL_V1) { | |
| 658 | + temp = raw_to_mcelsius_v1( | |
| 659 | + mt, conf->bank_data[bank->id].sensors[i], raw); | |
| 660 | + } else { | |
| 661 | + temp = raw_to_mcelsius_v2( | |
| 662 | + mt, conf->bank_data[bank->id].sensors[i], raw); | |
| 663 | + } | |
| 602 | 664 | |
| 603 | 665 | /* |
| 604 | 666 | * The first read of a sensor often contains very high bogus |
| @@ -700,9 +762,11 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num, · 95 unmodified lines | ||
| 700 | 762 | writel(auxadc_phys_base + AUXADC_CON1_CLR_V, |
| 701 | 763 | controller_base + TEMP_ADCMUXADDR); |
| 702 | 764 | |
| 703 | − /* AHB address for pnp sensor mux selection */ | |
| 704 | − writel(apmixed_phys_base + APMIXED_SYS_TS_CON1, | |
| 705 | − controller_base + TEMP_PNPMUXADDR); | |
| 765 | + if (mt->conf->version == MTK_THERMAL_V1) { | |
| 766 | + /* AHB address for pnp sensor mux selection */ | |
| 767 | + writel(apmixed_phys_base + APMIXED_SYS_TS_CON1, | |
| 768 | + controller_base + TEMP_PNPMUXADDR); | |
| 769 | + } | |
| 706 | 770 | |
| 707 | 771 | /* AHB value for auxadc enable */ |
| 708 | 772 | writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCEN); |
| @@ -759,6 +823,68 @@ static u64 of_get_phys_base(struct device_node *np) · 50 unmodified lines | ||
| 759 | 823 | return of_translate_address(np, regaddr_p); |
| 760 | 824 | } |
| 761 | 825 | |
| 826 | +static int mtk_thermal_extract_efuse_v1(struct mtk_thermal *mt, u32 *buf) | |
| 827 | +{ | |
| 828 | + int i; | |
| 829 | + | |
| 830 | + if (!(buf[0] & CALIB_BUF0_VALID_V1)) | |
| 831 | + return -EINVAL; | |
| 832 | + | |
| 833 | + mt->adc_ge = CALIB_BUF1_ADC_GE_V1(buf[1]); | |
| 834 | + | |
| 835 | + for (i = 0; i < mt->conf->num_sensors; i++) { | |
| 836 | + switch (mt->conf->vts_index[i]) { | |
| 837 | + case VTS1: | |
| 838 | + mt->vts[VTS1] = CALIB_BUF0_VTS_TS1_V1(buf[0]); | |
| 839 | + break; | |
| 840 | + case VTS2: | |
| 841 | + mt->vts[VTS2] = CALIB_BUF0_VTS_TS2_V1(buf[0]); | |
| 842 | + break; | |
| 843 | + case VTS3: | |
| 844 | + mt->vts[VTS3] = CALIB_BUF1_VTS_TS3_V1(buf[1]); | |
| 845 | + break; | |
| 846 | + case VTS4: | |
| 847 | + mt->vts[VTS4] = CALIB_BUF2_VTS_TS4_V1(buf[2]); | |
| 848 | + break; | |
| 849 | + case VTS5: | |
| 850 | + mt->vts[VTS5] = CALIB_BUF2_VTS_TS5_V1(buf[2]); | |
| 851 | + break; | |
| 852 | + case VTSABB: | |
| 853 | + mt->vts[VTSABB] = | |
| 854 | + CALIB_BUF2_VTS_TSABB_V1(buf[2]); | |
| 855 | + break; | |
| 856 | + default: | |
| 857 | + break; | |
| 858 | + } | |
| 859 | + } | |
| 860 | + | |
| 861 | + mt->degc_cali = CALIB_BUF0_DEGC_CALI_V1(buf[0]); | |
| 862 | + if (CALIB_BUF1_ID_V1(buf[1]) & | |
| 863 | + CALIB_BUF0_O_SLOPE_SIGN_V1(buf[0])) | |
| 864 | + mt->o_slope = -CALIB_BUF0_O_SLOPE_V1(buf[0]); | |
| 865 | + else | |
| 866 | + mt->o_slope = CALIB_BUF0_O_SLOPE_V1(buf[0]); | |
| 867 | + | |
| 868 | + return 0; | |
| 869 | +} | |
| 870 | + | |
| 871 | +static int mtk_thermal_extract_efuse_v2(struct mtk_thermal *mt, u32 *buf) | |
| 872 | +{ | |
| 873 | + if (!CALIB_BUF1_VALID_V2(buf[1])) | |
| 874 | + return -EINVAL; | |
| 875 | + | |
| 876 | + mt->adc_oe = CALIB_BUF0_ADC_OE_V2(buf[0]); | |
| 877 | + mt->adc_ge = CALIB_BUF0_ADC_GE_V2(buf[0]); | |
| 878 | + mt->degc_cali = CALIB_BUF0_DEGC_CALI_V2(buf[0]); | |
| 879 | + mt->o_slope = CALIB_BUF0_O_SLOPE_V2(buf[0]); | |
| 880 | + mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V2(buf[1]); | |
| 881 | + mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V2(buf[1]); | |
| 882 | + mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V2(buf[1]); | |
| 883 | + mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V2(buf[1]); | |
| 884 | + | |
| 885 | + return 0; | |
| 886 | +} | |
| 887 | + | |
| 762 | 888 | static int mtk_thermal_get_calibration_data(struct device *dev, |
| 763 | 889 | struct mtk_thermal *mt) |
| 764 | 890 | { |
| @@ -794,42 +920,14 @@ static int mtk_thermal_get_calibration_data(struct device *dev, · 29 unmodified lines | ||
| 794 | 920 | goto out; |
| 795 | 921 | } |
| 796 | 922 | |
| 797 | − if (buf[0] & CALIB_BUF0_VALID) { | |
| 798 | − mt->adc_ge = CALIB_BUF1_ADC_GE(buf[1]); | |
| 799 | − | |
| 800 | − for (i = 0; i < mt->conf->num_sensors; i++) { | |
| 801 | − switch (mt->conf->vts_index[i]) { | |
| 802 | − case VTS1: | |
| 803 | − mt->vts[VTS1] = CALIB_BUF0_VTS_TS1(buf[0]); | |
| 804 | − break; | |
| 805 | − case VTS2: | |
| 806 | − mt->vts[VTS2] = CALIB_BUF0_VTS_TS2(buf[0]); | |
| 807 | − break; | |
| 808 | − case VTS3: | |
| 809 | − mt->vts[VTS3] = CALIB_BUF1_VTS_TS3(buf[1]); | |
| 810 | − break; | |
| 811 | − case VTS4: | |
| 812 | − mt->vts[VTS4] = CALIB_BUF2_VTS_TS4(buf[2]); | |
| 813 | − break; | |
| 814 | − case VTS5: | |
| 815 | − mt->vts[VTS5] = CALIB_BUF2_VTS_TS5(buf[2]); | |
| 816 | − break; | |
| 817 | − case VTSABB: | |
| 818 | − mt->vts[VTSABB] = CALIB_BUF2_VTS_TSABB(buf[2]); | |
| 819 | − break; | |
| 820 | − default: | |
| 821 | − break; | |
| 822 | − } | |
| 823 | − } | |
| 923 | + if (mt->conf->version == MTK_THERMAL_V1) | |
| 924 | + ret = mtk_thermal_extract_efuse_v1(mt, buf); | |
| 925 | + else | |
| 926 | + ret = mtk_thermal_extract_efuse_v2(mt, buf); | |
| 824 | 927 | |
| 825 | − mt->degc_cali = CALIB_BUF0_DEGC_CALI(buf[0]); | |
| 826 | − if (CALIB_BUF1_ID(buf[1]) & | |
| 827 | − CALIB_BUF0_O_SLOPE_SIGN(buf[0])) | |
| 828 | − mt->o_slope = -CALIB_BUF0_O_SLOPE(buf[0]); | |
| 829 | − else | |
| 830 | − mt->o_slope = CALIB_BUF0_O_SLOPE(buf[0]); | |
| 831 | − } else { | |
| 928 | + if (ret) { | |
| 832 | 929 | dev_info(dev, "Device not calibrated, using default calibration values\n"); |
| 930 | + ret = 0; | |
| 833 | 931 | } |
| 834 | 932 | |
| 835 | 933 | out: |
| @@ -863,6 +961,28 @@ static const struct of_device_id mtk_thermal_of_match[] = { · 27 unmodified lines | ||
| 863 | 961 | }; |
| 864 | 962 | MODULE_DEVICE_TABLE(of, mtk_thermal_of_match); |
| 865 | 963 | |
| 964 | +static void mtk_thermal_turn_on_buffer(void __iomem *apmixed_base) | |
| 965 | +{ | |
| 966 | + int tmp; | |
| 967 | + | |
| 968 | + tmp = readl(apmixed_base + APMIXED_SYS_TS_CON1); | |
| 969 | + tmp &= ~(0x37); | |
| 970 | + tmp |= 0x1; | |
| 971 | + writel(tmp, apmixed_base + APMIXED_SYS_TS_CON1); | |
| 972 | + udelay(200); | |
| 973 | +} | |
| 974 | + | |
| 975 | +static void mtk_thermal_release_periodic_ts(struct mtk_thermal *mt, | |
| 976 | + void __iomem *auxadc_base) | |
| 977 | +{ | |
| 978 | + int tmp; | |
| 979 | + | |
| 980 | + writel(0x800, auxadc_base + AUXADC_CON1_SET_V); | |
| 981 | + writel(0x1, mt->thermal_base + TEMP_MONCTL0); | |
| 982 | + tmp = readl(mt->thermal_base + TEMP_MSRCTL1); | |
| 983 | + writel((tmp & (~0x10e)), mt->thermal_base + TEMP_MSRCTL1); | |
| 984 | +} | |
| 985 | + | |
| 866 | 986 | static int mtk_thermal_probe(struct platform_device *pdev) |
| 867 | 987 | { |
| 868 | 988 | int ret, i, ctrl_id; |
| @@ -871,6 +991,7 @@ static int mtk_thermal_probe(struct platform_device *pdev) · 2 unmodified lines | ||
| 871 | 991 | struct resource *res; |
| 872 | 992 | u64 auxadc_phys_base, apmixed_phys_base; |
| 873 | 993 | struct thermal_zone_device *tzdev; |
| 994 | + void __iomem *apmixed_base, *auxadc_base; | |
| 874 | 995 | |
| 875 | 996 | mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL); |
| 876 | 997 | if (!mt) |
| @@ -905,6 +1026,7 @@ static int mtk_thermal_probe(struct platform_device *pdev) · 28 unmodified lines | ||
| 905 | 1026 | return -ENODEV; |
| 906 | 1027 | } |
| 907 | 1028 | |
| 1029 | + auxadc_base = of_iomap(auxadc, 0); | |
| 908 | 1030 | auxadc_phys_base = of_get_phys_base(auxadc); |
| 909 | 1031 | |
| 910 | 1032 | of_node_put(auxadc); |
| @@ -920,6 +1042,7 @@ static int mtk_thermal_probe(struct platform_device *pdev) · 9 unmodified lines | ||
| 920 | 1042 | return -ENODEV; |
| 921 | 1043 | } |
| 922 | 1044 | |
| 1045 | + apmixed_base = of_iomap(apmixedsys, 0); | |
| 923 | 1046 | apmixed_phys_base = of_get_phys_base(apmixedsys); |
| 924 | 1047 | |
| 925 | 1048 | of_node_put(apmixedsys); |
| @@ -945,6 +1068,11 @@ static int mtk_thermal_probe(struct platform_device *pdev) · 19 unmodified lines | ||
| 945 | 1068 | goto err_disable_clk_auxadc; |
| 946 | 1069 | } |
| 947 | 1070 | |
| 1071 | + if (mt->conf->version == MTK_THERMAL_V2) { | |
| 1072 | + mtk_thermal_turn_on_buffer(apmixed_base); | |
| 1073 | + mtk_thermal_release_periodic_ts(mt, auxadc_base); | |
| 1074 | + } | |
| 1075 | + | |
| 948 | 1076 | for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++) |
| 949 | 1077 | for (i = 0; i < mt->conf->num_banks; i++) |
| 950 | 1078 | mtk_thermal_init_bank(mt, i, apmixed_phys_base, |
| @@ -48,6 +48,63 @@ · 47 unmodified lines | ||
| 48 | 48 | #define MSM8916_CAL_SEL_MASK 0xe0000000 |
| 49 | 49 | #define MSM8916_CAL_SEL_SHIFT 29 |
| 50 | 50 | |
| 51 | +/* eeprom layout data for 8939 */ | |
| 52 | +#define MSM8939_BASE0_MASK 0x000000ff | |
| 53 | +#define MSM8939_BASE1_MASK 0xff000000 | |
| 54 | +#define MSM8939_BASE0_SHIFT 0 | |
| 55 | +#define MSM8939_BASE1_SHIFT 24 | |
| 56 | + | |
| 57 | +#define MSM8939_S0_P1_MASK 0x000001f8 | |
| 58 | +#define MSM8939_S1_P1_MASK 0x001f8000 | |
| 59 | +#define MSM8939_S2_P1_MASK_0_4 0xf8000000 | |
| 60 | +#define MSM8939_S2_P1_MASK_5 0x00000001 | |
| 61 | +#define MSM8939_S3_P1_MASK 0x00001f80 | |
| 62 | +#define MSM8939_S4_P1_MASK 0x01f80000 | |
| 63 | +#define MSM8939_S5_P1_MASK 0x00003f00 | |
| 64 | +#define MSM8939_S6_P1_MASK 0x03f00000 | |
| 65 | +#define MSM8939_S7_P1_MASK 0x0000003f | |
| 66 | +#define MSM8939_S8_P1_MASK 0x0003f000 | |
| 67 | +#define MSM8939_S9_P1_MASK 0x07e00000 | |
| 68 | + | |
| 69 | +#define MSM8939_S0_P2_MASK 0x00007e00 | |
| 70 | +#define MSM8939_S1_P2_MASK 0x07e00000 | |
| 71 | +#define MSM8939_S2_P2_MASK 0x0000007e | |
| 72 | +#define MSM8939_S3_P2_MASK 0x0007e000 | |
| 73 | +#define MSM8939_S4_P2_MASK 0x7e000000 | |
| 74 | +#define MSM8939_S5_P2_MASK 0x000fc000 | |
| 75 | +#define MSM8939_S6_P2_MASK 0xfc000000 | |
| 76 | +#define MSM8939_S7_P2_MASK 0x00000fc0 | |
| 77 | +#define MSM8939_S8_P2_MASK 0x00fc0000 | |
| 78 | +#define MSM8939_S9_P2_MASK_0_4 0xf8000000 | |
| 79 | +#define MSM8939_S9_P2_MASK_5 0x00002000 | |
| 80 | + | |
| 81 | +#define MSM8939_S0_P1_SHIFT 3 | |
| 82 | +#define MSM8939_S1_P1_SHIFT 15 | |
| 83 | +#define MSM8939_S2_P1_SHIFT_0_4 27 | |
| 84 | +#define MSM8939_S2_P1_SHIFT_5 0 | |
| 85 | +#define MSM8939_S3_P1_SHIFT 7 | |
| 86 | +#define MSM8939_S4_P1_SHIFT 19 | |
| 87 | +#define MSM8939_S5_P1_SHIFT 8 | |
| 88 | +#define MSM8939_S6_P1_SHIFT 20 | |
| 89 | +#define MSM8939_S7_P1_SHIFT 0 | |
| 90 | +#define MSM8939_S8_P1_SHIFT 12 | |
| 91 | +#define MSM8939_S9_P1_SHIFT 21 | |
| 92 | + | |
| 93 | +#define MSM8939_S0_P2_SHIFT 9 | |
| 94 | +#define MSM8939_S1_P2_SHIFT 21 | |
| 95 | +#define MSM8939_S2_P2_SHIFT 1 | |
| 96 | +#define MSM8939_S3_P2_SHIFT 13 | |
| 97 | +#define MSM8939_S4_P2_SHIFT 25 | |
| 98 | +#define MSM8939_S5_P2_SHIFT 14 | |
| 99 | +#define MSM8939_S6_P2_SHIFT 26 | |
| 100 | +#define MSM8939_S7_P2_SHIFT 6 | |
| 101 | +#define MSM8939_S8_P2_SHIFT 18 | |
| 102 | +#define MSM8939_S9_P2_SHIFT_0_4 27 | |
| 103 | +#define MSM8939_S9_P2_SHIFT_5 13 | |
| 104 | + | |
| 105 | +#define MSM8939_CAL_SEL_MASK 0x7 | |
| 106 | +#define MSM8939_CAL_SEL_SHIFT 0 | |
| 107 | + | |
| 51 | 108 | /* eeprom layout data for 8974 */ |
| 52 | 109 | #define BASE1_MASK 0xff |
| 53 | 110 | #define S0_P1_MASK 0x3f00 |
| @@ -189,6 +246,76 @@ static int calibrate_8916(struct tsens_priv *priv) · 135 unmodified lines | ||
| 189 | 246 | return 0; |
| 190 | 247 | } |
| 191 | 248 | |
| 249 | +static int calibrate_8939(struct tsens_priv *priv) | |
| 250 | +{ | |
| 251 | + int base0 = 0, base1 = 0, i; | |
| 252 | + u32 p1[10], p2[10]; | |
| 253 | + int mode = 0; | |
| 254 | + u32 *qfprom_cdata; | |
| 255 | + u32 cdata[6]; | |
| 256 | + | |
| 257 | + qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib"); | |
| 258 | + if (IS_ERR(qfprom_cdata)) | |
| 259 | + return PTR_ERR(qfprom_cdata); | |
| 260 | + | |
| 261 | + /* Mapping between qfprom nvmem and calibration data */ | |
| 262 | + cdata[0] = qfprom_cdata[12]; | |
| 263 | + cdata[1] = qfprom_cdata[13]; | |
| 264 | + cdata[2] = qfprom_cdata[0]; | |
| 265 | + cdata[3] = qfprom_cdata[1]; | |
| 266 | + cdata[4] = qfprom_cdata[22]; | |
| 267 | + cdata[5] = qfprom_cdata[21]; | |
| 268 | + | |
| 269 | + mode = (cdata[0] & MSM8939_CAL_SEL_MASK) >> MSM8939_CAL_SEL_SHIFT; | |
| 270 | + dev_dbg(priv->dev, "calibration mode is %d\n", mode); | |
| 271 | + | |
| 272 | + switch (mode) { | |
| 273 | + case TWO_PT_CALIB: | |
| 274 | + base1 = (cdata[3] & MSM8939_BASE1_MASK) >> MSM8939_BASE1_SHIFT; | |
| 275 | + p2[0] = (cdata[0] & MSM8939_S0_P2_MASK) >> MSM8939_S0_P2_SHIFT; | |
| 276 | + p2[1] = (cdata[0] & MSM8939_S1_P2_MASK) >> MSM8939_S1_P2_SHIFT; | |
| 277 | + p2[2] = (cdata[1] & MSM8939_S2_P2_MASK) >> MSM8939_S2_P2_SHIFT; | |
| 278 | + p2[3] = (cdata[1] & MSM8939_S3_P2_MASK) >> MSM8939_S3_P2_SHIFT; | |
| 279 | + p2[4] = (cdata[1] & MSM8939_S4_P2_MASK) >> MSM8939_S4_P2_SHIFT; | |
| 280 | + p2[5] = (cdata[2] & MSM8939_S5_P2_MASK) >> MSM8939_S5_P2_SHIFT; | |
| 281 | + p2[6] = (cdata[2] & MSM8939_S6_P2_MASK) >> MSM8939_S6_P2_SHIFT; | |
| 282 | + p2[7] = (cdata[3] & MSM8939_S7_P2_MASK) >> MSM8939_S7_P2_SHIFT; | |
| 283 | + p2[8] = (cdata[3] & MSM8939_S8_P2_MASK) >> MSM8939_S8_P2_SHIFT; | |
| 284 | + p2[9] = (cdata[4] & MSM8939_S9_P2_MASK_0_4) >> MSM8939_S9_P2_SHIFT_0_4; | |
| 285 | + p2[9] |= ((cdata[5] & MSM8939_S9_P2_MASK_5) >> MSM8939_S9_P2_SHIFT_5) << 5; | |
| 286 | + for (i = 0; i < priv->num_sensors; i++) | |
| 287 | + p2[i] = (base1 + p2[i]) << 2; | |
| 288 | + fallthrough; | |
| 289 | + case ONE_PT_CALIB2: | |
| 290 | + base0 = (cdata[2] & MSM8939_BASE0_MASK) >> MSM8939_BASE0_SHIFT; | |
| 291 | + p1[0] = (cdata[0] & MSM8939_S0_P1_MASK) >> MSM8939_S0_P1_SHIFT; | |
| 292 | + p1[1] = (cdata[0] & MSM8939_S1_P1_MASK) >> MSM8939_S1_P1_SHIFT; | |
| 293 | + p1[2] = (cdata[0] & MSM8939_S2_P1_MASK_0_4) >> MSM8939_S2_P1_SHIFT_0_4; | |
| 294 | + p1[2] |= ((cdata[1] & MSM8939_S2_P1_MASK_5) >> MSM8939_S2_P1_SHIFT_5) << 5; | |
| 295 | + p1[3] = (cdata[1] & MSM8939_S3_P1_MASK) >> MSM8939_S3_P1_SHIFT; | |
| 296 | + p1[4] = (cdata[1] & MSM8939_S4_P1_MASK) >> MSM8939_S4_P1_SHIFT; | |
| 297 | + p1[5] = (cdata[2] & MSM8939_S5_P1_MASK) >> MSM8939_S5_P1_SHIFT; | |
| 298 | + p1[6] = (cdata[2] & MSM8939_S6_P1_MASK) >> MSM8939_S6_P1_SHIFT; | |
| 299 | + p1[7] = (cdata[3] & MSM8939_S7_P1_MASK) >> MSM8939_S7_P1_SHIFT; | |
| 300 | + p1[8] = (cdata[3] & MSM8939_S8_P1_MASK) >> MSM8939_S8_P1_SHIFT; | |
| 301 | + p1[9] = (cdata[4] & MSM8939_S9_P1_MASK) >> MSM8939_S9_P1_SHIFT; | |
| 302 | + for (i = 0; i < priv->num_sensors; i++) | |
| 303 | + p1[i] = ((base0) + p1[i]) << 2; | |
| 304 | + break; | |
| 305 | + default: | |
| 306 | + for (i = 0; i < priv->num_sensors; i++) { | |
| 307 | + p1[i] = 500; | |
| 308 | + p2[i] = 780; | |
| 309 | + } | |
| 310 | + break; | |
| 311 | + } | |
| 312 | + | |
| 313 | + compute_intercept_slope(priv, p1, p2, mode); | |
| 314 | + kfree(qfprom_cdata); | |
| 315 | + | |
| 316 | + return 0; | |
| 317 | +} | |
| 318 | + | |
| 192 | 319 | static int calibrate_8974(struct tsens_priv *priv) |
| 193 | 320 | { |
| 194 | 321 | int base1 = 0, base2 = 0, i; |
| @@ -325,7 +452,7 @@ static int calibrate_8974(struct tsens_priv *priv) · 130 unmodified lines | ||
| 325 | 452 | return 0; |
| 326 | 453 | } |
| 327 | 454 | |
| 328 | −/* v0.1: 8916, 8974 */ | |
| 455 | +/* v0.1: 8916, 8939, 8974 */ | |
| 329 | 456 | |
| 330 | 457 | static struct tsens_features tsens_v0_1_feat = { |
| 331 | 458 | .ver_major = VER_0_1, |
| @@ -386,6 +513,21 @@ struct tsens_plat_data data_8916 = { · 54 unmodified lines | ||
| 386 | 513 | .fields = tsens_v0_1_regfields, |
| 387 | 514 | }; |
| 388 | 515 | |
| 516 | +static const struct tsens_ops ops_8939 = { | |
| 517 | + .init = init_common, | |
| 518 | + .calibrate = calibrate_8939, | |
| 519 | + .get_temp = get_temp_common, | |
| 520 | +}; | |
| 521 | + | |
| 522 | +struct tsens_plat_data data_8939 = { | |
| 523 | + .num_sensors = 10, | |
| 524 | + .ops = &ops_8939, | |
| 525 | + .hw_ids = (unsigned int []){ 0, 1, 2, 4, 5, 6, 7, 8, 9, 10 }, | |
| 526 | + | |
| 527 | + .feat = &tsens_v0_1_feat, | |
| 528 | + .fields = tsens_v0_1_regfields, | |
| 529 | +}; | |
| 530 | + | |
| 389 | 531 | static const struct tsens_ops ops_8974 = { |
| 390 | 532 | .init = init_common, |
| 391 | 533 | .calibrate = calibrate_8974, |
| @@ -897,6 +897,9 @@ static const struct of_device_id tsens_table[] = { · 896 unmodified lines | ||
| 897 | 897 | { |
| 898 | 898 | .compatible = "qcom,msm8916-tsens", |
| 899 | 899 | .data = &data_8916, |
| 900 | + }, { | |
| 901 | + .compatible = "qcom,msm8939-tsens", | |
| 902 | + .data = &data_8939, | |
| 900 | 903 | }, { |
| 901 | 904 | .compatible = "qcom,msm8974-tsens", |
| 902 | 905 | .data = &data_8974, |
| @@ -585,7 +585,7 @@ int get_temp_common(const struct tsens_sensor *s, int *temp); · 584 unmodified lines | ||
| 585 | 585 | extern struct tsens_plat_data data_8960; |
| 586 | 586 | |
| 587 | 587 | /* TSENS v0.1 targets */ |
| 588 | −extern struct tsens_plat_data data_8916, data_8974; | |
| 588 | +extern struct tsens_plat_data data_8916, data_8939, data_8974; | |
| 589 | 589 | |
| 590 | 590 | /* TSENS v1 targets */ |
| 591 | 591 | extern struct tsens_plat_data data_tsens_v1, data_8976; |
| @@ -63,7 +63,7 @@ · 62 unmodified lines | ||
| 63 | 63 | #define TSC_MAX_NUM 3 |
| 64 | 64 | |
| 65 | 65 | /* default THCODE values if FUSEs are missing */ |
| 66 | −static const int thcode[TSC_MAX_NUM][3] = { | |
| 66 | +static const int thcodes[TSC_MAX_NUM][3] = { | |
| 67 | 67 | { 3397, 2800, 2221 }, |
| 68 | 68 | { 3393, 2795, 2216 }, |
| 69 | 69 | { 3389, 2805, 2237 }, |
| @@ -172,7 +172,7 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp) · 102 unmodified lines | ||
| 172 | 172 | /* Read register and convert to mili Celsius */ |
| 173 | 173 | reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK; |
| 174 | 174 | |
| 175 | − if (reg <= thcode[tsc->id][1]) | |
| 175 | + if (reg <= thcodes[tsc->id][1]) | |
| 176 | 176 | val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, |
| 177 | 177 | tsc->coef.a1); |
| 178 | 178 | else |
| @@ -314,6 +314,10 @@ static const struct of_device_id rcar_gen3_thermal_dt_ids[] = { · 135 unmodified lines | ||
| 314 | 314 | .compatible = "renesas,r8a774b1-thermal", |
| 315 | 315 | .data = &rcar_gen3_ths_tj_1, |
| 316 | 316 | }, |
| 317 | + { | |
| 318 | + .compatible = "renesas,r8a774e1-thermal", | |
| 319 | + .data = &rcar_gen3_ths_tj_1, | |
| 320 | + }, | |
| 317 | 321 | { |
| 318 | 322 | .compatible = "renesas,r8a7795-thermal", |
| 319 | 323 | .data = &rcar_gen3_ths_tj_1, |
| @@ -430,7 +434,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) · 110 unmodified lines | ||
| 430 | 434 | priv->tscs[i] = tsc; |
| 431 | 435 | |
| 432 | 436 | priv->thermal_init(tsc); |
| 433 | − rcar_gen3_thermal_calc_coefs(tsc, ptat, thcode[i], | |
| 437 | + rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], | |
| 434 | 438 | *rcar_gen3_ths_tj_1); |
| 435 | 439 | |
| 436 | 440 | zone = devm_thermal_zone_of_sensor_register(dev, i, tsc, |
| @@ -550,12 +550,19 @@ static int rcar_thermal_probe(struct platform_device *pdev) · 549 unmodified lines | ||
| 550 | 550 | priv->zone = devm_thermal_zone_of_sensor_register( |
| 551 | 551 | dev, i, priv, |
| 552 | 552 | &rcar_thermal_zone_of_ops); |
| 553 | − else | |
| 553 | + else { | |
| 554 | 554 | priv->zone = thermal_zone_device_register( |
| 555 | 555 | "rcar_thermal", |
| 556 | 556 | 1, 0, priv, |
| 557 | 557 | &rcar_thermal_zone_ops, NULL, 0, |
| 558 | 558 | idle); |
| 559 | + | |
| 560 | + ret = thermal_zone_device_enable(priv->zone); | |
| 561 | + if (ret) { | |
| 562 | + thermal_zone_device_unregister(priv->zone); | |
| 563 | + priv->zone = ERR_PTR(ret); | |
| 564 | + } | |
| 565 | + } | |
| 559 | 566 | if (IS_ERR(priv->zone)) { |
| 560 | 567 | dev_err(dev, "can't register thermal zone\n"); |
| 561 | 568 | ret = PTR_ERR(priv->zone); |
| @@ -1068,8 +1068,10 @@ rockchip_thermal_toggle_sensor(struct rockchip_thermal_sensor *sensor, bool on) · 1067 unmodified lines | ||
| 1068 | 1068 | { |
| 1069 | 1069 | struct thermal_zone_device *tzd = sensor->tzd; |
| 1070 | 1070 | |
| 1071 | − tzd->ops->set_mode(tzd, | |
| 1072 | − on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED); | |
| 1071 | + if (on) | |
| 1072 | + thermal_zone_device_enable(tzd); | |
| 1073 | + else | |
| 1074 | + thermal_zone_device_disable(tzd); | |
| 1073 | 1075 | } |
| 1074 | 1076 | |
| 1075 | 1077 | static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev) |
| @@ -131,6 +131,11 @@ static int spear_thermal_probe(struct platform_device *pdev) · 130 unmodified lines | ||
| 131 | 131 | ret = PTR_ERR(spear_thermal); |
| 132 | 132 | goto disable_clk; |
| 133 | 133 | } |
| 134 | + ret = thermal_zone_device_enable(spear_thermal); | |
| 135 | + if (ret) { | |
| 136 | + dev_err(&pdev->dev, "Cannot enable thermal zone\n"); | |
| 137 | + goto unregister_tzd; | |
| 138 | + } | |
| 134 | 139 | |
| 135 | 140 | platform_set_drvdata(pdev, spear_thermal); |
| 136 | 141 | |
| @@ -139,6 +144,8 @@ static int spear_thermal_probe(struct platform_device *pdev) · 2 unmodified lines | ||
| 139 | 144 | |
| 140 | 145 | return 0; |
| 141 | 146 | |
| 147 | +unregister_tzd: | |
| 148 | + thermal_zone_device_unregister(spear_thermal); | |
| 142 | 149 | disable_clk: |
| 143 | 150 | clk_disable(stdev->clk); |
| 144 | 151 | |
| @@ -322,8 +322,10 @@ static void sprd_thm_toggle_sensor(struct sprd_thermal_sensor *sen, bool on) · 321 unmodified lines | ||
| 322 | 322 | { |
| 323 | 323 | struct thermal_zone_device *tzd = sen->tzd; |
| 324 | 324 | |
| 325 | − tzd->ops->set_mode(tzd, | |
| 326 | − on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED); | |
| 325 | + if (on) | |
| 326 | + thermal_zone_device_enable(tzd); | |
| 327 | + else | |
| 328 | + thermal_zone_device_disable(tzd); | |
| 327 | 329 | } |
| 328 | 330 | |
| 329 | 331 | static int sprd_thm_probe(struct platform_device *pdev) |
| @@ -246,11 +246,16 @@ int st_thermal_register(struct platform_device *pdev, · 245 unmodified lines | ||
| 246 | 246 | ret = PTR_ERR(sensor->thermal_dev); |
| 247 | 247 | goto sensor_off; |
| 248 | 248 | } |
| 249 | + ret = thermal_zone_device_enable(sensor->thermal_dev); | |
| 250 | + if (ret) | |
| 251 | + goto tzd_unregister; | |
| 249 | 252 | |
| 250 | 253 | platform_set_drvdata(pdev, sensor); |
| 251 | 254 | |
| 252 | 255 | return 0; |
| 253 | 256 | |
| 257 | +tzd_unregister: | |
| 258 | + thermal_zone_device_unregister(sensor->thermal_dev); | |
| 254 | 259 | sensor_off: |
| 255 | 260 | st_thermal_sensor_off(sensor); |
| 256 | 261 | |
| @@ -215,6 +215,8 @@ exit: · 214 unmodified lines | ||
| 215 | 215 | mutex_unlock(&tz->lock); |
| 216 | 216 | mutex_unlock(&thermal_governor_lock); |
| 217 | 217 | |
| 218 | + thermal_notify_tz_gov_change(tz->id, policy); | |
| 219 | + | |
| 218 | 220 | return ret; |
| 219 | 221 | } |
| 220 | 222 | |
| @@ -301,13 +303,22 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz, · 80 unmodified lines | ||
| 301 | 303 | cancel_delayed_work(&tz->poll_queue); |
| 302 | 304 | } |
| 303 | 305 | |
| 306 | +static inline bool should_stop_polling(struct thermal_zone_device *tz) | |
| 307 | +{ | |
| 308 | + return !thermal_zone_device_is_enabled(tz); | |
| 309 | +} | |
| 310 | + | |
| 304 | 311 | static void monitor_thermal_zone(struct thermal_zone_device *tz) |
| 305 | 312 | { |
| 313 | + bool stop; | |
| 314 | + | |
| 315 | + stop = should_stop_polling(tz); | |
| 316 | + | |
| 306 | 317 | mutex_lock(&tz->lock); |
| 307 | 318 | |
| 308 | − if (tz->passive) | |
| 319 | + if (!stop && tz->passive) | |
| 309 | 320 | thermal_zone_device_set_polling(tz, tz->passive_delay); |
| 310 | − else if (tz->polling_delay) | |
| 321 | + else if (!stop && tz->polling_delay) | |
| 311 | 322 | thermal_zone_device_set_polling(tz, tz->polling_delay); |
| 312 | 323 | else |
| 313 | 324 | thermal_zone_device_set_polling(tz, 0); |
| @@ -406,12 +417,25 @@ static void handle_critical_trips(struct thermal_zone_device *tz, · 92 unmodified lines | ||
| 406 | 417 | static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) |
| 407 | 418 | { |
| 408 | 419 | enum thermal_trip_type type; |
| 420 | + int trip_temp, hyst = 0; | |
| 409 | 421 | |
| 410 | 422 | /* Ignore disabled trip points */ |
| 411 | 423 | if (test_bit(trip, &tz->trips_disabled)) |
| 412 | 424 | return; |
| 413 | 425 | |
| 426 | + tz->ops->get_trip_temp(tz, trip, &trip_temp); | |
| 414 | 427 | tz->ops->get_trip_type(tz, trip, &type); |
| 428 | + if (tz->ops->get_trip_hyst) | |
| 429 | + tz->ops->get_trip_hyst(tz, trip, &hyst); | |
| 430 | + | |
| 431 | + if (tz->last_temperature != THERMAL_TEMP_INVALID) { | |
| 432 | + if (tz->last_temperature < trip_temp && | |
| 433 | + tz->temperature >= trip_temp) | |
| 434 | + thermal_notify_tz_trip_up(tz->id, trip); | |
| 435 | + if (tz->last_temperature >= trip_temp && | |
| 436 | + tz->temperature < (trip_temp - hyst)) | |
| 437 | + thermal_notify_tz_trip_down(tz->id, trip); | |
| 438 | + } | |
| 415 | 439 | |
| 416 | 440 | if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT) |
| 417 | 441 | handle_critical_trips(tz, trip, type); |
| @@ -443,6 +467,8 @@ static void update_temperature(struct thermal_zone_device *tz) · 25 unmodified lines | ||
| 443 | 467 | mutex_unlock(&tz->lock); |
| 444 | 468 | |
| 445 | 469 | trace_thermal_temperature(tz); |
| 470 | + | |
| 471 | + thermal_genl_sampling_temp(tz->id, temp); | |
| 446 | 472 | } |
| 447 | 473 | |
| 448 | 474 | static void thermal_zone_device_init(struct thermal_zone_device *tz) |
| @@ -459,11 +485,71 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz) · 10 unmodified lines | ||
| 459 | 485 | thermal_zone_device_init(tz); |
| 460 | 486 | } |
| 461 | 487 | |
| 488 | +static int thermal_zone_device_set_mode(struct thermal_zone_device *tz, | |
| 489 | + enum thermal_device_mode mode) | |
| 490 | +{ | |
| 491 | + int ret = 0; | |
| 492 | + | |
| 493 | + mutex_lock(&tz->lock); | |
| 494 | + | |
| 495 | + /* do nothing if mode isn't changing */ | |
| 496 | + if (mode == tz->mode) { | |
| 497 | + mutex_unlock(&tz->lock); | |
| 498 | + | |
| 499 | + return ret; | |
| 500 | + } | |
| 501 | + | |
| 502 | + if (tz->ops->change_mode) | |
| 503 | + ret = tz->ops->change_mode(tz, mode); | |
| 504 | + | |
| 505 | + if (!ret) | |
| 506 | + tz->mode = mode; | |
| 507 | + | |
| 508 | + mutex_unlock(&tz->lock); | |
| 509 | + | |
| 510 | + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); | |
| 511 | + | |
| 512 | + if (mode == THERMAL_DEVICE_ENABLED) | |
| 513 | + thermal_notify_tz_enable(tz->id); | |
| 514 | + else | |
| 515 | + thermal_notify_tz_disable(tz->id); | |
| 516 | + | |
| 517 | + return ret; | |
| 518 | +} | |
| 519 | + | |
| 520 | +int thermal_zone_device_enable(struct thermal_zone_device *tz) | |
| 521 | +{ | |
| 522 | + return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED); | |
| 523 | +} | |
| 524 | +EXPORT_SYMBOL_GPL(thermal_zone_device_enable); | |
| 525 | + | |
| 526 | +int thermal_zone_device_disable(struct thermal_zone_device *tz) | |
| 527 | +{ | |
| 528 | + return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED); | |
| 529 | +} | |
| 530 | +EXPORT_SYMBOL_GPL(thermal_zone_device_disable); | |
| 531 | + | |
| 532 | +int thermal_zone_device_is_enabled(struct thermal_zone_device *tz) | |
| 533 | +{ | |
| 534 | + enum thermal_device_mode mode; | |
| 535 | + | |
| 536 | + mutex_lock(&tz->lock); | |
| 537 | + | |
| 538 | + mode = tz->mode; | |
| 539 | + | |
| 540 | + mutex_unlock(&tz->lock); | |
| 541 | + | |
| 542 | + return mode == THERMAL_DEVICE_ENABLED; | |
| 543 | +} | |
| 544 | + | |
| 462 | 545 | void thermal_zone_device_update(struct thermal_zone_device *tz, |
| 463 | 546 | enum thermal_notify_event event) |
| 464 | 547 | { |
| 465 | 548 | int count; |
| 466 | 549 | |
| 550 | + if (should_stop_polling(tz)) | |
| 551 | + return; | |
| 552 | + | |
| 467 | 553 | if (atomic_read(&in_suspend)) |
| 468 | 554 | return; |
| 469 | 555 | |
| @@ -617,6 +703,73 @@ void thermal_zone_device_rebind_exception(struct thermal_zone_device *tz, · 147 unmodified lines | ||
| 617 | 703 | mutex_unlock(&thermal_list_lock); |
| 618 | 704 | } |
| 619 | 705 | |
| 706 | +int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *), | |
| 707 | + void *data) | |
| 708 | +{ | |
| 709 | + struct thermal_governor *gov; | |
| 710 | + int ret = 0; | |
| 711 | + | |
| 712 | + mutex_lock(&thermal_governor_lock); | |
| 713 | + list_for_each_entry(gov, &thermal_governor_list, governor_list) { | |
| 714 | + ret = cb(gov, data); | |
| 715 | + if (ret) | |
| 716 | + break; | |
| 717 | + } | |
| 718 | + mutex_unlock(&thermal_governor_lock); | |
| 719 | + | |
| 720 | + return ret; | |
| 721 | +} | |
| 722 | + | |
| 723 | +int for_each_thermal_cooling_device(int (*cb)(struct thermal_cooling_device *, | |
| 724 | + void *), void *data) | |
| 725 | +{ | |
| 726 | + struct thermal_cooling_device *cdev; | |
| 727 | + int ret = 0; | |
| 728 | + | |
| 729 | + mutex_lock(&thermal_list_lock); | |
| 730 | + list_for_each_entry(cdev, &thermal_cdev_list, node) { | |
| 731 | + ret = cb(cdev, data); | |
| 732 | + if (ret) | |
| 733 | + break; | |
| 734 | + } | |
| 735 | + mutex_unlock(&thermal_list_lock); | |
| 736 | + | |
| 737 | + return ret; | |
| 738 | +} | |
| 739 | + | |
| 740 | +int for_each_thermal_zone(int (*cb)(struct thermal_zone_device *, void *), | |
| 741 | + void *data) | |
| 742 | +{ | |
| 743 | + struct thermal_zone_device *tz; | |
| 744 | + int ret = 0; | |
| 745 | + | |
| 746 | + mutex_lock(&thermal_list_lock); | |
| 747 | + list_for_each_entry(tz, &thermal_tz_list, node) { | |
| 748 | + ret = cb(tz, data); | |
| 749 | + if (ret) | |
| 750 | + break; | |
| 751 | + } | |
| 752 | + mutex_unlock(&thermal_list_lock); | |
| 753 | + | |
| 754 | + return ret; | |
| 755 | +} | |
| 756 | + | |
| 757 | +struct thermal_zone_device *thermal_zone_get_by_id(int id) | |
| 758 | +{ | |
| 759 | + struct thermal_zone_device *tz, *match = NULL; | |
| 760 | + | |
| 761 | + mutex_lock(&thermal_list_lock); | |
| 762 | + list_for_each_entry(tz, &thermal_tz_list, node) { | |
| 763 | + if (tz->id == id) { | |
| 764 | + match = tz; | |
| 765 | + break; | |
| 766 | + } | |
| 767 | + } | |
| 768 | + mutex_unlock(&thermal_list_lock); | |
| 769 | + | |
| 770 | + return match; | |
| 771 | +} | |
| 772 | + | |
| 620 | 773 | void thermal_zone_device_unbind_exception(struct thermal_zone_device *tz, |
| 621 | 774 | const char *cdev_type, size_t size) |
| 622 | 775 | { |
| @@ -1340,6 +1493,8 @@ thermal_zone_device_register(const char *type, int trips, int mask, · 717 unmodified lines | ||
| 1340 | 1493 | if (atomic_cmpxchg(&tz->need_update, 1, 0)) |
| 1341 | 1494 | thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); |
| 1342 | 1495 | |
| 1496 | + thermal_notify_tz_create(tz->id, tz->type); | |
| 1497 | + | |
| 1343 | 1498 | return tz; |
| 1344 | 1499 | |
| 1345 | 1500 | unregister: |
| @@ -1411,6 +1566,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) · 65 unmodified lines | ||
| 1411 | 1566 | ida_destroy(&tz->ida); |
| 1412 | 1567 | mutex_destroy(&tz->lock); |
| 1413 | 1568 | device_unregister(&tz->device); |
| 1569 | + | |
| 1570 | + thermal_notify_tz_delete(tz->id); | |
| 1414 | 1571 | } |
| 1415 | 1572 | EXPORT_SYMBOL_GPL(thermal_zone_device_unregister); |
| 1416 | 1573 | |
| @@ -1456,7 +1613,6 @@ static int thermal_pm_notify(struct notifier_block *nb, · 39 unmodified lines | ||
| 1456 | 1613 | unsigned long mode, void *_unused) |
| 1457 | 1614 | { |
| 1458 | 1615 | struct thermal_zone_device *tz; |
| 1459 | − enum thermal_device_mode tz_mode; | |
| 1460 | 1616 | |
| 1461 | 1617 | switch (mode) { |
| 1462 | 1618 | case PM_HIBERNATION_PREPARE: |
| @@ -1469,11 +1625,7 @@ static int thermal_pm_notify(struct notifier_block *nb, · 6 unmodified lines | ||
| 1469 | 1625 | case PM_POST_SUSPEND: |
| 1470 | 1626 | atomic_set(&in_suspend, 0); |
| 1471 | 1627 | list_for_each_entry(tz, &thermal_tz_list, node) { |
| 1472 | − tz_mode = THERMAL_DEVICE_ENABLED; | |
| 1473 | − if (tz->ops->get_mode) | |
| 1474 | − tz->ops->get_mode(tz, &tz_mode); | |
| 1475 | − | |
| 1476 | − if (tz_mode == THERMAL_DEVICE_DISABLED) | |
| 1628 | + if (!thermal_zone_device_is_enabled(tz)) | |
| 1477 | 1629 | continue; |
| 1478 | 1630 | |
| 1479 | 1631 | thermal_zone_device_init(tz); |
| @@ -1495,6 +1647,10 @@ static int __init thermal_init(void) · 15 unmodified lines | ||
| 1495 | 1647 | { |
| 1496 | 1648 | int result; |
| 1497 | 1649 | |
| 1650 | + result = thermal_netlink_init(); | |
| 1651 | + if (result) | |
| 1652 | + goto error; | |
| 1653 | + | |
| 1498 | 1654 | mutex_init(&poweroff_lock); |
| 1499 | 1655 | result = thermal_register_governors(); |
| 1500 | 1656 | if (result) |
| @@ -1527,4 +1683,4 @@ error: · 26 unmodified lines | ||
| 1527 | 1683 | mutex_destroy(&poweroff_lock); |
| 1528 | 1684 | return result; |
| 1529 | 1685 | } |
| 1530 | −core_initcall(thermal_init); | |
| 1686 | +postcore_initcall(thermal_init); | |
| @@ -12,6 +12,8 @@ · 11 unmodified lines | ||
| 12 | 12 | #include <linux/device.h> |
| 13 | 13 | #include <linux/thermal.h> |
| 14 | 14 | |
| 15 | +#include "thermal_netlink.h" | |
| 16 | + | |
| 15 | 17 | /* Default Thermal Governor */ |
| 16 | 18 | #if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE) |
| 17 | 19 | #define DEFAULT_THERMAL_GOVERNOR "step_wise" |
| @@ -41,6 +43,17 @@ extern struct thermal_governor *__governor_thermal_table_end[]; · 23 unmodified lines | ||
| 41 | 43 | __governor < __governor_thermal_table_end; \ |
| 42 | 44 | __governor++) |
| 43 | 45 | |
| 46 | +int for_each_thermal_zone(int (*cb)(struct thermal_zone_device *, void *), | |
| 47 | + void *); | |
| 48 | + | |
| 49 | +int for_each_thermal_cooling_device(int (*cb)(struct thermal_cooling_device *, | |
| 50 | + void *), void *); | |
| 51 | + | |
| 52 | +int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *), | |
| 53 | + void *thermal_governor); | |
| 54 | + | |
| 55 | +struct thermal_zone_device *thermal_zone_get_by_id(int id); | |
| 56 | + | |
| 44 | 57 | struct thermal_attr { |
| 45 | 58 | struct device_attribute attr; |
| 46 | 59 | char name[THERMAL_NAME_LENGTH]; |
| @@ -166,4 +179,6 @@ of_thermal_get_trip_points(struct thermal_zone_device *tz) · 119 unmodified lines | ||
| 166 | 179 | } |
| 167 | 180 | #endif |
| 168 | 181 | |
| 182 | +int thermal_zone_device_is_enabled(struct thermal_zone_device *tz); | |
| 183 | + | |
| 169 | 184 | #endif /* __THERMAL_CORE_H__ */ |
| @@ -175,6 +175,16 @@ exit: · 174 unmodified lines | ||
| 175 | 175 | mutex_unlock(&tz->lock); |
| 176 | 176 | } |
| 177 | 177 | |
| 178 | +static void thermal_cdev_set_cur_state(struct thermal_cooling_device *cdev, | |
| 179 | + int target) | |
| 180 | +{ | |
| 181 | + if (cdev->ops->set_cur_state(cdev, target)) | |
| 182 | + return; | |
| 183 | + | |
| 184 | + thermal_notify_cdev_state_update(cdev->id, target); | |
| 185 | + thermal_cooling_device_stats_update(cdev, target); | |
| 186 | +} | |
| 187 | + | |
| 178 | 188 | void thermal_cdev_update(struct thermal_cooling_device *cdev) |
| 179 | 189 | { |
| 180 | 190 | struct thermal_instance *instance; |
| @@ -197,8 +207,7 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev) · 16 unmodified lines | ||
| 197 | 207 | target = instance->target; |
| 198 | 208 | } |
| 199 | 209 | |
| 200 | − if (!cdev->ops->set_cur_state(cdev, target)) | |
| 201 | − thermal_cooling_device_stats_update(cdev, target); | |
| 210 | + thermal_cdev_set_cur_state(cdev, target); | |
| 202 | 211 | |
| 203 | 212 | cdev->updated = true; |
| 204 | 213 | mutex_unlock(&cdev->lock); |
| @@ -0,0 +1,647 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Copyright 2020 Linaro Limited | |
| 4 | + * | |
| 5 | + * Author: Daniel Lezcano <daniel.lezcano@linaro.org> | |
| 6 | + * | |
| 7 | + * Generic netlink for thermal management framework | |
| 8 | + */ | |
| 9 | +#include <linux/module.h> | |
| 10 | +#include <linux/kernel.h> | |
| 11 | +#include <net/genetlink.h> | |
| 12 | +#include <uapi/linux/thermal.h> | |
| 13 | + | |
| 14 | +#include "thermal_core.h" | |
| 15 | + | |
| 16 | +static const struct genl_multicast_group thermal_genl_mcgrps[] = { | |
| 17 | + { .name = THERMAL_GENL_SAMPLING_GROUP_NAME, }, | |
| 18 | + { .name = THERMAL_GENL_EVENT_GROUP_NAME, }, | |
| 19 | +}; | |
| 20 | + | |
| 21 | +static const struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = { | |
| 22 | + /* Thermal zone */ | |
| 23 | + [THERMAL_GENL_ATTR_TZ] = { .type = NLA_NESTED }, | |
| 24 | + [THERMAL_GENL_ATTR_TZ_ID] = { .type = NLA_U32 }, | |
| 25 | + [THERMAL_GENL_ATTR_TZ_TEMP] = { .type = NLA_U32 }, | |
| 26 | + [THERMAL_GENL_ATTR_TZ_TRIP] = { .type = NLA_NESTED }, | |
| 27 | + [THERMAL_GENL_ATTR_TZ_TRIP_ID] = { .type = NLA_U32 }, | |
| 28 | + [THERMAL_GENL_ATTR_TZ_TRIP_TEMP] = { .type = NLA_U32 }, | |
| 29 | + [THERMAL_GENL_ATTR_TZ_TRIP_TYPE] = { .type = NLA_U32 }, | |
| 30 | + [THERMAL_GENL_ATTR_TZ_TRIP_HYST] = { .type = NLA_U32 }, | |
| 31 | + [THERMAL_GENL_ATTR_TZ_MODE] = { .type = NLA_U32 }, | |
| 32 | + [THERMAL_GENL_ATTR_TZ_CDEV_WEIGHT] = { .type = NLA_U32 }, | |
| 33 | + [THERMAL_GENL_ATTR_TZ_NAME] = { .type = NLA_STRING, | |
| 34 | + .len = THERMAL_NAME_LENGTH }, | |
| 35 | + /* Governor(s) */ | |
| 36 | + [THERMAL_GENL_ATTR_TZ_GOV] = { .type = NLA_NESTED }, | |
| 37 | + [THERMAL_GENL_ATTR_TZ_GOV_NAME] = { .type = NLA_STRING, | |
| 38 | + .len = THERMAL_NAME_LENGTH }, | |
| 39 | + /* Cooling devices */ | |
| 40 | + [THERMAL_GENL_ATTR_CDEV] = { .type = NLA_NESTED }, | |
| 41 | + [THERMAL_GENL_ATTR_CDEV_ID] = { .type = NLA_U32 }, | |
| 42 | + [THERMAL_GENL_ATTR_CDEV_CUR_STATE] = { .type = NLA_U32 }, | |
| 43 | + [THERMAL_GENL_ATTR_CDEV_MAX_STATE] = { .type = NLA_U32 }, | |
| 44 | + [THERMAL_GENL_ATTR_CDEV_NAME] = { .type = NLA_STRING, | |
| 45 | + .len = THERMAL_NAME_LENGTH }, | |
| 46 | +}; | |
| 47 | + | |
| 48 | +struct param { | |
| 49 | + struct nlattr **attrs; | |
| 50 | + struct sk_buff *msg; | |
| 51 | + const char *name; | |
| 52 | + int tz_id; | |
| 53 | + int cdev_id; | |
| 54 | + int trip_id; | |
| 55 | + int trip_temp; | |
| 56 | + int trip_type; | |
| 57 | + int trip_hyst; | |
| 58 | + int temp; | |
| 59 | + int cdev_state; | |
| 60 | + int cdev_max_state; | |
| 61 | +}; | |
| 62 | + | |
| 63 | +typedef int (*cb_t)(struct param *); | |
| 64 | + | |
| 65 | +static struct genl_family thermal_gnl_family; | |
| 66 | + | |
| 67 | +/************************** Sampling encoding *******************************/ | |
| 68 | + | |
| 69 | +int thermal_genl_sampling_temp(int id, int temp) | |
| 70 | +{ | |
| 71 | + struct sk_buff *skb; | |
| 72 | + void *hdr; | |
| 73 | + | |
| 74 | + skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | |
| 75 | + if (!skb) | |
| 76 | + return -ENOMEM; | |
| 77 | + | |
| 78 | + hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, | |
| 79 | + THERMAL_GENL_SAMPLING_TEMP); | |
| 80 | + if (!hdr) | |
| 81 | + return -EMSGSIZE; | |
| 82 | + | |
| 83 | + if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_ID, id)) | |
| 84 | + goto out_cancel; | |
| 85 | + | |
| 86 | + if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_TEMP, temp)) | |
| 87 | + goto out_cancel; | |
| 88 | + | |
| 89 | + genlmsg_end(skb, hdr); | |
| 90 | + | |
| 91 | + genlmsg_multicast(&thermal_gnl_family, skb, 0, 0, GFP_KERNEL); | |
| 92 | + | |
| 93 | + return 0; | |
| 94 | +out_cancel: | |
| 95 | + genlmsg_cancel(skb, hdr); | |
| 96 | + nlmsg_free(skb); | |
| 97 | + | |
| 98 | + return -EMSGSIZE; | |
| 99 | +} | |
| 100 | + | |
| 101 | +/**************************** Event encoding *********************************/ | |
| 102 | + | |
| 103 | +static int thermal_genl_event_tz_create(struct param *p) | |
| 104 | +{ | |
| 105 | + if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || | |
| 106 | + nla_put_string(p->msg, THERMAL_GENL_ATTR_TZ_NAME, p->name)) | |
| 107 | + return -EMSGSIZE; | |
| 108 | + | |
| 109 | + return 0; | |
| 110 | +} | |
| 111 | + | |
| 112 | +static int thermal_genl_event_tz(struct param *p) | |
| 113 | +{ | |
| 114 | + if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id)) | |
| 115 | + return -EMSGSIZE; | |
| 116 | + | |
| 117 | + return 0; | |
| 118 | +} | |
| 119 | + | |
| 120 | +static int thermal_genl_event_tz_trip_up(struct param *p) | |
| 121 | +{ | |
| 122 | + if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || | |
| 123 | + nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id)) | |
| 124 | + return -EMSGSIZE; | |
| 125 | + | |
| 126 | + return 0; | |
| 127 | +} | |
| 128 | + | |
| 129 | +static int thermal_genl_event_tz_trip_add(struct param *p) | |
| 130 | +{ | |
| 131 | + if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || | |
| 132 | + nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) || | |
| 133 | + nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, p->trip_type) || | |
| 134 | + nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, p->trip_temp) || | |
| 135 | + nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, p->trip_hyst)) | |
| 136 | + return -EMSGSIZE; | |
| 137 | + | |
| 138 | + return 0; | |
| 139 | +} | |
| 140 | + | |
| 141 | +static int thermal_genl_event_tz_trip_delete(struct param *p) | |
| 142 | +{ | |
| 143 | + if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || | |
| 144 | + nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id)) | |
| 145 | + return -EMSGSIZE; | |
| 146 | + | |
| 147 | + return 0; | |
| 148 | +} | |
| 149 | + | |
| 150 | +static int thermal_genl_event_cdev_add(struct param *p) | |
| 151 | +{ | |
| 152 | + if (nla_put_string(p->msg, THERMAL_GENL_ATTR_CDEV_NAME, | |
| 153 | + p->name) || | |
| 154 | + nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, | |
| 155 | + p->cdev_id) || | |
| 156 | + nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_MAX_STATE, | |
| 157 | + p->cdev_max_state)) | |
| 158 | + return -EMSGSIZE; | |
| 159 | + | |
| 160 | + return 0; | |
| 161 | +} | |
| 162 | + | |
| 163 | +static int thermal_genl_event_cdev_delete(struct param *p) | |
| 164 | +{ | |
| 165 | + if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, p->cdev_id)) | |
| 166 | + return -EMSGSIZE; | |
| 167 | + | |
| 168 | + return 0; | |
| 169 | +} | |
| 170 | + | |
| 171 | +static int thermal_genl_event_cdev_state_update(struct param *p) | |
| 172 | +{ | |
| 173 | + if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, | |
| 174 | + p->cdev_id) || | |
| 175 | + nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_CUR_STATE, | |
| 176 | + p->cdev_state)) | |
| 177 | + return -EMSGSIZE; | |
| 178 | + | |
| 179 | + return 0; | |
| 180 | +} | |
| 181 | + | |
| 182 | +static int thermal_genl_event_gov_change(struct param *p) | |
| 183 | +{ | |
| 184 | + if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || | |
| 185 | + nla_put_string(p->msg, THERMAL_GENL_ATTR_GOV_NAME, p->name)) | |
| 186 | + return -EMSGSIZE; | |
| 187 | + | |
| 188 | + return 0; | |
| 189 | +} | |
| 190 | + | |
| 191 | +int thermal_genl_event_tz_delete(struct param *p) | |
| 192 | + __attribute__((alias("thermal_genl_event_tz"))); | |
| 193 | + | |
| 194 | +int thermal_genl_event_tz_enable(struct param *p) | |
| 195 | + __attribute__((alias("thermal_genl_event_tz"))); | |
| 196 | + | |
| 197 | +int thermal_genl_event_tz_disable(struct param *p) | |
| 198 | + __attribute__((alias("thermal_genl_event_tz"))); | |
| 199 | + | |
| 200 | +int thermal_genl_event_tz_trip_down(struct param *p) | |
| 201 | + __attribute__((alias("thermal_genl_event_tz_trip_up"))); | |
| 202 | + | |
| 203 | +int thermal_genl_event_tz_trip_change(struct param *p) | |
| 204 | + __attribute__((alias("thermal_genl_event_tz_trip_add"))); | |
| 205 | + | |
| 206 | +static cb_t event_cb[] = { | |
| 207 | + [THERMAL_GENL_EVENT_TZ_CREATE] = thermal_genl_event_tz_create, | |
| 208 | + [THERMAL_GENL_EVENT_TZ_DELETE] = thermal_genl_event_tz_delete, | |
| 209 | + [THERMAL_GENL_EVENT_TZ_ENABLE] = thermal_genl_event_tz_enable, | |
| 210 | + [THERMAL_GENL_EVENT_TZ_DISABLE] = thermal_genl_event_tz_disable, | |
| 211 | + [THERMAL_GENL_EVENT_TZ_TRIP_UP] = thermal_genl_event_tz_trip_up, | |
| 212 | + [THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = thermal_genl_event_tz_trip_down, | |
| 213 | + [THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = thermal_genl_event_tz_trip_change, | |
| 214 | + [THERMAL_GENL_EVENT_TZ_TRIP_ADD] = thermal_genl_event_tz_trip_add, | |
| 215 | + [THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = thermal_genl_event_tz_trip_delete, | |
| 216 | + [THERMAL_GENL_EVENT_CDEV_ADD] = thermal_genl_event_cdev_add, | |
| 217 | + [THERMAL_GENL_EVENT_CDEV_DELETE] = thermal_genl_event_cdev_delete, | |
| 218 | + [THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = thermal_genl_event_cdev_state_update, | |
| 219 | + [THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = thermal_genl_event_gov_change, | |
| 220 | +}; | |
| 221 | + | |
| 222 | +/* | |
| 223 | + * Generic netlink event encoding | |
| 224 | + */ | |
| 225 | +static int thermal_genl_send_event(enum thermal_genl_event event, | |
| 226 | + struct param *p) | |
| 227 | +{ | |
| 228 | + struct sk_buff *msg; | |
| 229 | + int ret = -EMSGSIZE; | |
| 230 | + void *hdr; | |
| 231 | + | |
| 232 | + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | |
| 233 | + if (!msg) | |
| 234 | + return -ENOMEM; | |
| 235 | + p->msg = msg; | |
| 236 | + | |
| 237 | + hdr = genlmsg_put(msg, 0, 0, &thermal_gnl_family, 0, event); | |
| 238 | + if (!hdr) | |
| 239 | + goto out_free_msg; | |
| 240 | + | |
| 241 | + ret = event_cb[event](p); | |
| 242 | + if (ret) | |
| 243 | + goto out_cancel_msg; | |
| 244 | + | |
| 245 | + genlmsg_end(msg, hdr); | |
| 246 | + | |
| 247 | + genlmsg_multicast(&thermal_gnl_family, msg, 0, 1, GFP_KERNEL); | |
| 248 | + | |
| 249 | + return 0; | |
| 250 | + | |
| 251 | +out_cancel_msg: | |
| 252 | + genlmsg_cancel(msg, hdr); | |
| 253 | +out_free_msg: | |
| 254 | + nlmsg_free(msg); | |
| 255 | + | |
| 256 | + return ret; | |
| 257 | +} | |
| 258 | + | |
| 259 | +int thermal_notify_tz_create(int tz_id, const char *name) | |
| 260 | +{ | |
| 261 | + struct param p = { .tz_id = tz_id, .name = name }; | |
| 262 | + | |
| 263 | + return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_CREATE, &p); | |
| 264 | +} | |
| 265 | + | |
| 266 | +int thermal_notify_tz_delete(int tz_id) | |
| 267 | +{ | |
| 268 | + struct param p = { .tz_id = tz_id }; | |
| 269 | + | |
| 270 | + return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DELETE, &p); | |
| 271 | +} | |
| 272 | + | |
| 273 | +int thermal_notify_tz_enable(int tz_id) | |
| 274 | +{ | |
| 275 | + struct param p = { .tz_id = tz_id }; | |
| 276 | + | |
| 277 | + return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_ENABLE, &p); | |
| 278 | +} | |
| 279 | + | |
| 280 | +int thermal_notify_tz_disable(int tz_id) | |
| 281 | +{ | |
| 282 | + struct param p = { .tz_id = tz_id }; | |
| 283 | + | |
| 284 | + return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE, &p); | |
| 285 | +} | |
| 286 | + | |
| 287 | +int thermal_notify_tz_trip_down(int tz_id, int trip_id) | |
| 288 | +{ | |
| 289 | + struct param p = { .tz_id = tz_id, .trip_id = trip_id }; | |
| 290 | + | |
| 291 | + return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN, &p); | |
| 292 | +} | |
| 293 | + | |
| 294 | +int thermal_notify_tz_trip_up(int tz_id, int trip_id) | |
| 295 | +{ | |
| 296 | + struct param p = { .tz_id = tz_id, .trip_id = trip_id }; | |
| 297 | + | |
| 298 | + return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP, &p); | |
| 299 | +} | |
| 300 | + | |
| 301 | +int thermal_notify_tz_trip_add(int tz_id, int trip_id, int trip_type, | |
| 302 | + int trip_temp, int trip_hyst) | |
| 303 | +{ | |
| 304 | + struct param p = { .tz_id = tz_id, .trip_id = trip_id, | |
| 305 | + .trip_type = trip_type, .trip_temp = trip_temp, | |
| 306 | + .trip_hyst = trip_hyst }; | |
| 307 | + | |
| 308 | + return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_ADD, &p); | |
| 309 | +} | |
| 310 | + | |
| 311 | +int thermal_notify_tz_trip_delete(int tz_id, int trip_id) | |
| 312 | +{ | |
| 313 | + struct param p = { .tz_id = tz_id, .trip_id = trip_id }; | |
| 314 | + | |
| 315 | + return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DELETE, &p); | |
| 316 | +} | |
| 317 | + | |
| 318 | +int thermal_notify_tz_trip_change(int tz_id, int trip_id, int trip_type, | |
| 319 | + int trip_temp, int trip_hyst) | |
| 320 | +{ | |
| 321 | + struct param p = { .tz_id = tz_id, .trip_id = trip_id, | |
| 322 | + .trip_type = trip_type, .trip_temp = trip_temp, | |
| 323 | + .trip_hyst = trip_hyst }; | |
| 324 | + | |
| 325 | + return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_CHANGE, &p); | |
| 326 | +} | |
| 327 | + | |
| 328 | +int thermal_notify_cdev_state_update(int cdev_id, int cdev_state) | |
| 329 | +{ | |
| 330 | + struct param p = { .cdev_id = cdev_id, .cdev_state = cdev_state }; | |
| 331 | + | |
| 332 | + return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, &p); | |
| 333 | +} | |
| 334 | + | |
| 335 | +int thermal_notify_cdev_add(int cdev_id, const char *name, int cdev_max_state) | |
| 336 | +{ | |
| 337 | + struct param p = { .cdev_id = cdev_id, .name = name, | |
| 338 | + .cdev_max_state = cdev_max_state }; | |
| 339 | + | |
| 340 | + return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_ADD, &p); | |
| 341 | +} | |
| 342 | + | |
| 343 | +int thermal_notify_cdev_delete(int cdev_id) | |
| 344 | +{ | |
| 345 | + struct param p = { .cdev_id = cdev_id }; | |
| 346 | + | |
| 347 | + return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_DELETE, &p); | |
| 348 | +} | |
| 349 | + | |
| 350 | +int thermal_notify_tz_gov_change(int tz_id, const char *name) | |
| 351 | +{ | |
| 352 | + struct param p = { .tz_id = tz_id, .name = name }; | |
| 353 | + | |
| 354 | + return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_GOV_CHANGE, &p); | |
| 355 | +} | |
| 356 | + | |
| 357 | +/*************************** Command encoding ********************************/ | |
| 358 | + | |
| 359 | +static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device *tz, | |
| 360 | + void *data) | |
| 361 | +{ | |
| 362 | + struct sk_buff *msg = data; | |
| 363 | + | |
| 364 | + if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, tz->id) || | |
| 365 | + nla_put_string(msg, THERMAL_GENL_ATTR_TZ_NAME, tz->type)) | |
| 366 | + return -EMSGSIZE; | |
| 367 | + | |
| 368 | + return 0; | |
| 369 | +} | |
| 370 | + | |
| 371 | +static int thermal_genl_cmd_tz_get_id(struct param *p) | |
| 372 | +{ | |
| 373 | + struct sk_buff *msg = p->msg; | |
| 374 | + struct nlattr *start_tz; | |
| 375 | + int ret; | |
| 376 | + | |
| 377 | + start_tz = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ); | |
| 378 | + if (!start_tz) | |
| 379 | + return -EMSGSIZE; | |
| 380 | + | |
| 381 | + ret = for_each_thermal_zone(__thermal_genl_cmd_tz_get_id, msg); | |
| 382 | + if (ret) | |
| 383 | + goto out_cancel_nest; | |
| 384 | + | |
| 385 | + nla_nest_end(msg, start_tz); | |
| 386 | + | |
| 387 | + return 0; | |
| 388 | + | |
| 389 | +out_cancel_nest: | |
| 390 | + nla_nest_cancel(msg, start_tz); | |
| 391 | + | |
| 392 | + return ret; | |
| 393 | +} | |
| 394 | + | |
| 395 | +static int thermal_genl_cmd_tz_get_trip(struct param *p) | |
| 396 | +{ | |
| 397 | + struct sk_buff *msg = p->msg; | |
| 398 | + struct thermal_zone_device *tz; | |
| 399 | + struct nlattr *start_trip; | |
| 400 | + int i, id; | |
| 401 | + | |
| 402 | + if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) | |
| 403 | + return -EINVAL; | |
| 404 | + | |
| 405 | + id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); | |
| 406 | + | |
| 407 | + tz = thermal_zone_get_by_id(id); | |
| 408 | + if (!tz) | |
| 409 | + return -EINVAL; | |
| 410 | + | |
| 411 | + start_trip = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ_TRIP); | |
| 412 | + if (!start_trip) | |
| 413 | + return -EMSGSIZE; | |
| 414 | + | |
| 415 | + mutex_lock(&tz->lock); | |
| 416 | + | |
| 417 | + for (i = 0; i < tz->trips; i++) { | |
| 418 | + | |
| 419 | + enum thermal_trip_type type; | |
| 420 | + int temp, hyst; | |
| 421 | + | |
| 422 | + tz->ops->get_trip_type(tz, i, &type); | |
| 423 | + tz->ops->get_trip_temp(tz, i, &temp); | |
| 424 | + tz->ops->get_trip_hyst(tz, i, &hyst); | |
| 425 | + | |
| 426 | + if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, i) || | |
| 427 | + nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, type) || | |
| 428 | + nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, temp) || | |
| 429 | + nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, hyst)) | |
| 430 | + goto out_cancel_nest; | |
| 431 | + } | |
| 432 | + | |
| 433 | + mutex_unlock(&tz->lock); | |
| 434 | + | |
| 435 | + nla_nest_end(msg, start_trip); | |
| 436 | + | |
| 437 | + return 0; | |
| 438 | + | |
| 439 | +out_cancel_nest: | |
| 440 | + mutex_unlock(&tz->lock); | |
| 441 | + | |
| 442 | + return -EMSGSIZE; | |
| 443 | +} | |
| 444 | + | |
| 445 | +static int thermal_genl_cmd_tz_get_temp(struct param *p) | |
| 446 | +{ | |
| 447 | + struct sk_buff *msg = p->msg; | |
| 448 | + struct thermal_zone_device *tz; | |
| 449 | + int temp, ret, id; | |
| 450 | + | |
| 451 | + if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) | |
| 452 | + return -EINVAL; | |
| 453 | + | |
| 454 | + id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); | |
| 455 | + | |
| 456 | + tz = thermal_zone_get_by_id(id); | |
| 457 | + if (!tz) | |
| 458 | + return -EINVAL; | |
| 459 | + | |
| 460 | + ret = thermal_zone_get_temp(tz, &temp); | |
| 461 | + if (ret) | |
| 462 | + return ret; | |
| 463 | + | |
| 464 | + if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) || | |
| 465 | + nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TEMP, temp)) | |
| 466 | + return -EMSGSIZE; | |
| 467 | + | |
| 468 | + return 0; | |
| 469 | +} | |
| 470 | + | |
| 471 | +static int thermal_genl_cmd_tz_get_gov(struct param *p) | |
| 472 | +{ | |
| 473 | + struct sk_buff *msg = p->msg; | |
| 474 | + struct thermal_zone_device *tz; | |
| 475 | + int id, ret = 0; | |
| 476 | + | |
| 477 | + if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) | |
| 478 | + return -EINVAL; | |
| 479 | + | |
| 480 | + id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); | |
| 481 | + | |
| 482 | + tz = thermal_zone_get_by_id(id); | |
| 483 | + if (!tz) | |
| 484 | + return -EINVAL; | |
| 485 | + | |
| 486 | + mutex_lock(&tz->lock); | |
| 487 | + | |
| 488 | + if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) || | |
| 489 | + nla_put_string(msg, THERMAL_GENL_ATTR_TZ_GOV_NAME, | |
| 490 | + tz->governor->name)) | |
| 491 | + ret = -EMSGSIZE; | |
| 492 | + | |
| 493 | + mutex_unlock(&tz->lock); | |
| 494 | + | |
| 495 | + return ret; | |
| 496 | +} | |
| 497 | + | |
| 498 | +static int __thermal_genl_cmd_cdev_get(struct thermal_cooling_device *cdev, | |
| 499 | + void *data) | |
| 500 | +{ | |
| 501 | + struct sk_buff *msg = data; | |
| 502 | + | |
| 503 | + if (nla_put_u32(msg, THERMAL_GENL_ATTR_CDEV_ID, cdev->id)) | |
| 504 | + return -EMSGSIZE; | |
| 505 | + | |
| 506 | + if (nla_put_string(msg, THERMAL_GENL_ATTR_CDEV_NAME, cdev->type)) | |
| 507 | + return -EMSGSIZE; | |
| 508 | + | |
| 509 | + return 0; | |
| 510 | +} | |
| 511 | + | |
| 512 | +static int thermal_genl_cmd_cdev_get(struct param *p) | |
| 513 | +{ | |
| 514 | + struct sk_buff *msg = p->msg; | |
| 515 | + struct nlattr *start_cdev; | |
| 516 | + int ret; | |
| 517 | + | |
| 518 | + start_cdev = nla_nest_start(msg, THERMAL_GENL_ATTR_CDEV); | |
| 519 | + if (!start_cdev) | |
| 520 | + return -EMSGSIZE; | |
| 521 | + | |
| 522 | + ret = for_each_thermal_cooling_device(__thermal_genl_cmd_cdev_get, msg); | |
| 523 | + if (ret) | |
| 524 | + goto out_cancel_nest; | |
| 525 | + | |
| 526 | + nla_nest_end(msg, start_cdev); | |
| 527 | + | |
| 528 | + return 0; | |
| 529 | +out_cancel_nest: | |
| 530 | + nla_nest_cancel(msg, start_cdev); | |
| 531 | + | |
| 532 | + return ret; | |
| 533 | +} | |
| 534 | + | |
| 535 | +static cb_t cmd_cb[] = { | |
| 536 | + [THERMAL_GENL_CMD_TZ_GET_ID] = thermal_genl_cmd_tz_get_id, | |
| 537 | + [THERMAL_GENL_CMD_TZ_GET_TRIP] = thermal_genl_cmd_tz_get_trip, | |
| 538 | + [THERMAL_GENL_CMD_TZ_GET_TEMP] = thermal_genl_cmd_tz_get_temp, | |
| 539 | + [THERMAL_GENL_CMD_TZ_GET_GOV] = thermal_genl_cmd_tz_get_gov, | |
| 540 | + [THERMAL_GENL_CMD_CDEV_GET] = thermal_genl_cmd_cdev_get, | |
| 541 | +}; | |
| 542 | + | |
| 543 | +static int thermal_genl_cmd_dumpit(struct sk_buff *skb, | |
| 544 | + struct netlink_callback *cb) | |
| 545 | +{ | |
| 546 | + struct param p = { .msg = skb }; | |
| 547 | + const struct genl_dumpit_info *info = genl_dumpit_info(cb); | |
| 548 | + int cmd = info->ops->cmd; | |
| 549 | + int ret; | |
| 550 | + void *hdr; | |
| 551 | + | |
| 552 | + hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, cmd); | |
| 553 | + if (!hdr) | |
| 554 | + return -EMSGSIZE; | |
| 555 | + | |
| 556 | + ret = cmd_cb[cmd](&p); | |
| 557 | + if (ret) | |
| 558 | + goto out_cancel_msg; | |
| 559 | + | |
| 560 | + genlmsg_end(skb, hdr); | |
| 561 | + | |
| 562 | + return 0; | |
| 563 | + | |
| 564 | +out_cancel_msg: | |
| 565 | + genlmsg_cancel(skb, hdr); | |
| 566 | + | |
| 567 | + return ret; | |
| 568 | +} | |
| 569 | + | |
| 570 | +static int thermal_genl_cmd_doit(struct sk_buff *skb, | |
| 571 | + struct genl_info *info) | |
| 572 | +{ | |
| 573 | + struct param p = { .attrs = info->attrs }; | |
| 574 | + struct sk_buff *msg; | |
| 575 | + void *hdr; | |
| 576 | + int cmd = info->genlhdr->cmd; | |
| 577 | + int ret = -EMSGSIZE; | |
| 578 | + | |
| 579 | + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | |
| 580 | + if (!msg) | |
| 581 | + return -ENOMEM; | |
| 582 | + p.msg = msg; | |
| 583 | + | |
| 584 | + hdr = genlmsg_put_reply(msg, info, &thermal_gnl_family, 0, cmd); | |
| 585 | + if (!hdr) | |
| 586 | + goto out_free_msg; | |
| 587 | + | |
| 588 | + ret = cmd_cb[cmd](&p); | |
| 589 | + if (ret) | |
| 590 | + goto out_cancel_msg; | |
| 591 | + | |
| 592 | + genlmsg_end(msg, hdr); | |
| 593 | + | |
| 594 | + return genlmsg_reply(msg, info); | |
| 595 | + | |
| 596 | +out_cancel_msg: | |
| 597 | + genlmsg_cancel(msg, hdr); | |
| 598 | +out_free_msg: | |
| 599 | + nlmsg_free(msg); | |
| 600 | + | |
| 601 | + return ret; | |
| 602 | +} | |
| 603 | + | |
| 604 | +static const struct genl_ops thermal_genl_ops[] = { | |
| 605 | + { | |
| 606 | + .cmd = THERMAL_GENL_CMD_TZ_GET_ID, | |
| 607 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, | |
| 608 | + .dumpit = thermal_genl_cmd_dumpit, | |
| 609 | + }, | |
| 610 | + { | |
| 611 | + .cmd = THERMAL_GENL_CMD_TZ_GET_TRIP, | |
| 612 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, | |
| 613 | + .doit = thermal_genl_cmd_doit, | |
| 614 | + }, | |
| 615 | + { | |
| 616 | + .cmd = THERMAL_GENL_CMD_TZ_GET_TEMP, | |
| 617 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, | |
| 618 | + .doit = thermal_genl_cmd_doit, | |
| 619 | + }, | |
| 620 | + { | |
| 621 | + .cmd = THERMAL_GENL_CMD_TZ_GET_GOV, | |
| 622 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, | |
| 623 | + .doit = thermal_genl_cmd_doit, | |
| 624 | + }, | |
| 625 | + { | |
| 626 | + .cmd = THERMAL_GENL_CMD_CDEV_GET, | |
| 627 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, | |
| 628 | + .dumpit = thermal_genl_cmd_dumpit, | |
| 629 | + }, | |
| 630 | +}; | |
| 631 | + | |
| 632 | +static struct genl_family thermal_gnl_family __ro_after_init = { | |
| 633 | + .hdrsize = 0, | |
| 634 | + .name = THERMAL_GENL_FAMILY_NAME, | |
| 635 | + .version = THERMAL_GENL_VERSION, | |
| 636 | + .maxattr = THERMAL_GENL_ATTR_MAX, | |
| 637 | + .policy = thermal_genl_policy, | |
| 638 | + .ops = thermal_genl_ops, | |
| 639 | + .n_ops = ARRAY_SIZE(thermal_genl_ops), | |
| 640 | + .mcgrps = thermal_genl_mcgrps, | |
| 641 | + .n_mcgrps = ARRAY_SIZE(thermal_genl_mcgrps), | |
| 642 | +}; | |
| 643 | + | |
| 644 | +int __init thermal_netlink_init(void) | |
| 645 | +{ | |
| 646 | + return genl_register_family(&thermal_gnl_family); | |
| 647 | +} | |
| @@ -0,0 +1,104 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | +/* | |
| 3 | + * Copyright (C) Linaro Ltd 2020 | |
| 4 | + * Author: Daniel Lezcano <daniel.lezcano@linaro.org> | |
| 5 | + */ | |
| 6 | + | |
| 7 | +/* Netlink notification function */ | |
| 8 | +#ifdef CONFIG_THERMAL_NETLINK | |
| 9 | +int __init thermal_netlink_init(void); | |
| 10 | +int thermal_notify_tz_create(int tz_id, const char *name); | |
| 11 | +int thermal_notify_tz_delete(int tz_id); | |
| 12 | +int thermal_notify_tz_enable(int tz_id); | |
| 13 | +int thermal_notify_tz_disable(int tz_id); | |
| 14 | +int thermal_notify_tz_trip_down(int tz_id, int id); | |
| 15 | +int thermal_notify_tz_trip_up(int tz_id, int id); | |
| 16 | +int thermal_notify_tz_trip_delete(int tz_id, int id); | |
| 17 | +int thermal_notify_tz_trip_add(int tz_id, int id, int type, | |
| 18 | + int temp, int hyst); | |
| 19 | +int thermal_notify_tz_trip_change(int tz_id, int id, int type, | |
| 20 | + int temp, int hyst); | |
| 21 | +int thermal_notify_cdev_state_update(int cdev_id, int state); | |
| 22 | +int thermal_notify_cdev_add(int cdev_id, const char *name, int max_state); | |
| 23 | +int thermal_notify_cdev_delete(int cdev_id); | |
| 24 | +int thermal_notify_tz_gov_change(int tz_id, const char *name); | |
| 25 | +int thermal_genl_sampling_temp(int id, int temp); | |
| 26 | +#else | |
| 27 | +static inline int thermal_netlink_init(void) | |
| 28 | +{ | |
| 29 | + return 0; | |
| 30 | +} | |
| 31 | + | |
| 32 | +static inline int thermal_notify_tz_create(int tz_id, const char *name) | |
| 33 | +{ | |
| 34 | + return 0; | |
| 35 | +} | |
| 36 | + | |
| 37 | +static inline int thermal_notify_tz_delete(int tz_id) | |
| 38 | +{ | |
| 39 | + return 0; | |
| 40 | +} | |
| 41 | + | |
| 42 | +static inline int thermal_notify_tz_enable(int tz_id) | |
| 43 | +{ | |
| 44 | + return 0; | |
| 45 | +} | |
| 46 | + | |
| 47 | +static inline int thermal_notify_tz_disable(int tz_id) | |
| 48 | +{ | |
| 49 | + return 0; | |
| 50 | +} | |
| 51 | + | |
| 52 | +static inline int thermal_notify_tz_trip_down(int tz_id, int id) | |
| 53 | +{ | |
| 54 | + return 0; | |
| 55 | +} | |
| 56 | + | |
| 57 | +static inline int thermal_notify_tz_trip_up(int tz_id, int id) | |
| 58 | +{ | |
| 59 | + return 0; | |
| 60 | +} | |
| 61 | + | |
| 62 | +static inline int thermal_notify_tz_trip_delete(int tz_id, int id) | |
| 63 | +{ | |
| 64 | + return 0; | |
| 65 | +} | |
| 66 | + | |
| 67 | +static inline int thermal_notify_tz_trip_add(int tz_id, int id, int type, | |
| 68 | + int temp, int hyst) | |
| 69 | +{ | |
| 70 | + return 0; | |
| 71 | +} | |
| 72 | + | |
| 73 | +static inline int thermal_notify_tz_trip_change(int tz_id, int id, int type, | |
| 74 | + int temp, int hyst) | |
| 75 | +{ | |
| 76 | + return 0; | |
| 77 | +} | |
| 78 | + | |
| 79 | +static inline int thermal_notify_cdev_state_update(int cdev_id, int state) | |
| 80 | +{ | |
| 81 | + return 0; | |
| 82 | +} | |
| 83 | + | |
| 84 | +static inline int thermal_notify_cdev_add(int cdev_id, const char *name, | |
| 85 | + int max_state) | |
| 86 | +{ | |
| 87 | + return 0; | |
| 88 | +} | |
| 89 | + | |
| 90 | +static inline int thermal_notify_cdev_delete(int cdev_id) | |
| 91 | +{ | |
| 92 | + return 0; | |
| 93 | +} | |
| 94 | + | |
| 95 | +static inline int thermal_notify_tz_gov_change(int tz_id, const char *name) | |
| 96 | +{ | |
| 97 | + return 0; | |
| 98 | +} | |
| 99 | + | |
| 100 | +static inline int thermal_genl_sampling_temp(int id, int temp) | |
| 101 | +{ | |
| 102 | + return 0; | |
| 103 | +} | |
| 104 | +#endif /* CONFIG_THERMAL_NETLINK */ | |
| @@ -51,7 +51,6 @@ struct __thermal_bind_params { · 50 unmodified lines | ||
| 51 | 51 | |
| 52 | 52 | /** |
| 53 | 53 | * struct __thermal_zone - internal representation of a thermal zone |
| 54 | − * @mode: current thermal zone device mode (enabled/disabled) | |
| 55 | 54 | * @passive_delay: polling interval while passive cooling is activated |
| 56 | 55 | * @polling_delay: zone polling interval |
| 57 | 56 | * @slope: slope of the temperature adjustment curve |
| @@ -65,7 +64,6 @@ struct __thermal_bind_params { · 7 unmodified lines | ||
| 65 | 64 | */ |
| 66 | 65 | |
| 67 | 66 | struct __thermal_zone { |
| 68 | − enum thermal_device_mode mode; | |
| 69 | 67 | int passive_delay; |
| 70 | 68 | int polling_delay; |
| 71 | 69 | int slope; |
| @@ -269,39 +267,6 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal, · 197 unmodified lines | ||
| 269 | 267 | return 0; |
| 270 | 268 | } |
| 271 | 269 | |
| 272 | −static int of_thermal_get_mode(struct thermal_zone_device *tz, | |
| 273 | − enum thermal_device_mode *mode) | |
| 274 | −{ | |
| 275 | − struct __thermal_zone *data = tz->devdata; | |
| 276 | − | |
| 277 | − *mode = data->mode; | |
| 278 | − | |
| 279 | − return 0; | |
| 280 | −} | |
| 281 | − | |
| 282 | −static int of_thermal_set_mode(struct thermal_zone_device *tz, | |
| 283 | − enum thermal_device_mode mode) | |
| 284 | −{ | |
| 285 | − struct __thermal_zone *data = tz->devdata; | |
| 286 | − | |
| 287 | − mutex_lock(&tz->lock); | |
| 288 | − | |
| 289 | − if (mode == THERMAL_DEVICE_ENABLED) { | |
| 290 | − tz->polling_delay = data->polling_delay; | |
| 291 | − tz->passive_delay = data->passive_delay; | |
| 292 | − } else { | |
| 293 | − tz->polling_delay = 0; | |
| 294 | − tz->passive_delay = 0; | |
| 295 | − } | |
| 296 | − | |
| 297 | − mutex_unlock(&tz->lock); | |
| 298 | − | |
| 299 | − data->mode = mode; | |
| 300 | − thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); | |
| 301 | − | |
| 302 | − return 0; | |
| 303 | −} | |
| 304 | − | |
| 305 | 270 | static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip, |
| 306 | 271 | enum thermal_trip_type *type) |
| 307 | 272 | { |
| @@ -393,9 +358,6 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz, · 85 unmodified lines | ||
| 393 | 358 | } |
| 394 | 359 | |
| 395 | 360 | static struct thermal_zone_device_ops of_thermal_ops = { |
| 396 | − .get_mode = of_thermal_get_mode, | |
| 397 | − .set_mode = of_thermal_set_mode, | |
| 398 | − | |
| 399 | 361 | .get_trip_type = of_thermal_get_trip_type, |
| 400 | 362 | .get_trip_temp = of_thermal_get_trip_temp, |
| 401 | 363 | .set_trip_temp = of_thermal_set_trip_temp, |
| @@ -554,7 +516,7 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data, · 152 unmodified lines | ||
| 554 | 516 | tzd = thermal_zone_of_add_sensor(child, sensor_np, |
| 555 | 517 | data, ops); |
| 556 | 518 | if (!IS_ERR(tzd)) |
| 557 | − tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED); | |
| 519 | + thermal_zone_device_enable(tzd); | |
| 558 | 520 | |
| 559 | 521 | of_node_put(child); |
| 560 | 522 | goto exit; |
| @@ -979,7 +941,6 @@ __init *thermal_of_build_thermal_zone(struct device_node *np) · 418 unmodified lines | ||
| 979 | 941 | |
| 980 | 942 | finish: |
| 981 | 943 | of_node_put(child); |
| 982 | − tz->mode = THERMAL_DEVICE_DISABLED; | |
| 983 | 944 | |
| 984 | 945 | return tz; |
| 985 | 946 | |
| @@ -49,18 +49,9 @@ static ssize_t · 48 unmodified lines | ||
| 49 | 49 | mode_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 50 | 50 | { |
| 51 | 51 | struct thermal_zone_device *tz = to_thermal_zone(dev); |
| 52 | − enum thermal_device_mode mode; | |
| 53 | − int result; | |
| 54 | − | |
| 55 | − if (!tz->ops->get_mode) | |
| 56 | − return -EPERM; | |
| 52 | + int enabled = thermal_zone_device_is_enabled(tz); | |
| 57 | 53 | |
| 58 | − result = tz->ops->get_mode(tz, &mode); | |
| 59 | − if (result) | |
| 60 | − return result; | |
| 61 | − | |
| 62 | − return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled" | |
| 63 | − : "disabled"); | |
| 54 | + return sprintf(buf, "%s\n", enabled ? "enabled" : "disabled"); | |
| 64 | 55 | } |
| 65 | 56 | |
| 66 | 57 | static ssize_t |
| @@ -70,13 +61,10 @@ mode_store(struct device *dev, struct device_attribute *attr, · 3 unmodified lines | ||
| 70 | 61 | struct thermal_zone_device *tz = to_thermal_zone(dev); |
| 71 | 62 | int result; |
| 72 | 63 | |
| 73 | − if (!tz->ops->set_mode) | |
| 74 | − return -EPERM; | |
| 75 | − | |
| 76 | 64 | if (!strncmp(buf, "enabled", sizeof("enabled") - 1)) |
| 77 | − result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED); | |
| 65 | + result = thermal_zone_device_enable(tz); | |
| 78 | 66 | else if (!strncmp(buf, "disabled", sizeof("disabled") - 1)) |
| 79 | − result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED); | |
| 67 | + result = thermal_zone_device_disable(tz); | |
| 80 | 68 | else |
| 81 | 69 | result = -EINVAL; |
| 82 | 70 | |
| @@ -124,7 +112,8 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr, · 41 unmodified lines | ||
| 124 | 112 | { |
| 125 | 113 | struct thermal_zone_device *tz = to_thermal_zone(dev); |
| 126 | 114 | int trip, ret; |
| 127 | − int temperature; | |
| 115 | + int temperature, hyst = 0; | |
| 116 | + enum thermal_trip_type type; | |
| 128 | 117 | |
| 129 | 118 | if (!tz->ops->set_trip_temp) |
| 130 | 119 | return -EPERM; |
| @@ -139,6 +128,18 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr, · 8 unmodified lines | ||
| 139 | 128 | if (ret) |
| 140 | 129 | return ret; |
| 141 | 130 | |
| 131 | + if (tz->ops->get_trip_hyst) { | |
| 132 | + ret = tz->ops->get_trip_hyst(tz, trip, &hyst); | |
| 133 | + if (ret) | |
| 134 | + return ret; | |
| 135 | + } | |
| 136 | + | |
| 137 | + ret = tz->ops->get_trip_type(tz, trip, &type); | |
| 138 | + if (ret) | |
| 139 | + return ret; | |
| 140 | + | |
| 141 | + thermal_notify_tz_trip_change(tz->id, trip, type, temperature, hyst); | |
| 142 | + | |
| 142 | 143 | thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); |
| 143 | 144 | |
| 144 | 145 | return count; |
| @@ -428,30 +429,13 @@ static struct attribute_group thermal_zone_attribute_group = { · 283 unmodified lines | ||
| 428 | 429 | .attrs = thermal_zone_dev_attrs, |
| 429 | 430 | }; |
| 430 | 431 | |
| 431 | −/* We expose mode only if .get_mode is present */ | |
| 432 | 432 | static struct attribute *thermal_zone_mode_attrs[] = { |
| 433 | 433 | &dev_attr_mode.attr, |
| 434 | 434 | NULL, |
| 435 | 435 | }; |
| 436 | 436 | |
| 437 | −static umode_t thermal_zone_mode_is_visible(struct kobject *kobj, | |
| 438 | − struct attribute *attr, | |
| 439 | − int attrno) | |
| 440 | −{ | |
| 441 | − struct device *dev = container_of(kobj, struct device, kobj); | |
| 442 | − struct thermal_zone_device *tz; | |
| 443 | − | |
| 444 | − tz = container_of(dev, struct thermal_zone_device, device); | |
| 445 | − | |
| 446 | − if (tz->ops->get_mode) | |
| 447 | − return attr->mode; | |
| 448 | − | |
| 449 | − return 0; | |
| 450 | −} | |
| 451 | − | |
| 452 | 437 | static struct attribute_group thermal_zone_mode_attribute_group = { |
| 453 | 438 | .attrs = thermal_zone_mode_attrs, |
| 454 | − .is_visible = thermal_zone_mode_is_visible, | |
| 455 | 439 | }; |
| 456 | 440 | |
| 457 | 441 | /* We expose passive only if passive trips are present */ |
| @@ -169,7 +169,7 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, · 168 unmodified lines | ||
| 169 | 169 | |
| 170 | 170 | data = ti_bandgap_get_sensor_data(bgp, id); |
| 171 | 171 | |
| 172 | − if (!IS_ERR_OR_NULL(data)) | |
| 172 | + if (IS_ERR_OR_NULL(data)) | |
| 173 | 173 | data = ti_thermal_build_data(bgp, id); |
| 174 | 174 | |
| 175 | 175 | if (!data) |
| @@ -1,57 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | −/* | |
| 3 | − * linux/include/linux/clock_cooling.h | |
| 4 | − * | |
| 5 | − * Copyright (C) 2014 Eduardo Valentin <edubezval@gmail.com> | |
| 6 | − * | |
| 7 | − * Copyright (C) 2013 Texas Instruments Inc. | |
| 8 | − * Contact: Eduardo Valentin <eduardo.valentin@ti.com> | |
| 9 | − * | |
| 10 | − * Highly based on cpufreq_cooling.c. | |
| 11 | − * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com) | |
| 12 | − * Copyright (C) 2012 Amit Daniel <amit.kachhap@linaro.org> | |
| 13 | − */ | |
| 14 | − | |
| 15 | −#ifndef __CPU_COOLING_H__ | |
| 16 | −#define __CPU_COOLING_H__ | |
| 17 | − | |
| 18 | −#include <linux/of.h> | |
| 19 | −#include <linux/thermal.h> | |
| 20 | −#include <linux/cpumask.h> | |
| 21 | − | |
| 22 | −#ifdef CONFIG_CLOCK_THERMAL | |
| 23 | −/** | |
| 24 | − * clock_cooling_register - function to create clock cooling device. | |
| 25 | − * @dev: struct device pointer to the device used as clock cooling device. | |
| 26 | − * @clock_name: string containing the clock used as cooling mechanism. | |
| 27 | − */ | |
| 28 | −struct thermal_cooling_device * | |
| 29 | −clock_cooling_register(struct device *dev, const char *clock_name); | |
| 30 | − | |
| 31 | −/** | |
| 32 | − * clock_cooling_unregister - function to remove clock cooling device. | |
| 33 | − * @cdev: thermal cooling device pointer. | |
| 34 | − */ | |
| 35 | −void clock_cooling_unregister(struct thermal_cooling_device *cdev); | |
| 36 | − | |
| 37 | −unsigned long clock_cooling_get_level(struct thermal_cooling_device *cdev, | |
| 38 | − unsigned long freq); | |
| 39 | −#else /* !CONFIG_CLOCK_THERMAL */ | |
| 40 | −static inline struct thermal_cooling_device * | |
| 41 | −clock_cooling_register(struct device *dev, const char *clock_name) | |
| 42 | −{ | |
| 43 | − return NULL; | |
| 44 | −} | |
| 45 | −static inline | |
| 46 | −void clock_cooling_unregister(struct thermal_cooling_device *cdev) | |
| 47 | −{ | |
| 48 | −} | |
| 49 | −static inline | |
| 50 | −unsigned long clock_cooling_get_level(struct thermal_cooling_device *cdev, | |
| 51 | − unsigned long freq) | |
| 52 | −{ | |
| 53 | − return THERMAL_CSTATE_INVALID; | |
| 54 | −} | |
| 55 | −#endif /* CONFIG_CLOCK_THERMAL */ | |
| 56 | − | |
| 57 | −#endif /* __CPU_COOLING_H__ */ | |
| @@ -1,17 +1,10 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 1 | 2 | /* |
| 2 | 3 | * devfreq_cooling: Thermal cooling device implementation for devices using |
| 3 | 4 | * devfreq |
| 4 | 5 | * |
| 5 | 6 | * Copyright (C) 2014-2015 ARM Limited |
| 6 | 7 | * |
| 7 | − * This program is free software; you can redistribute it and/or modify | |
| 8 | − * it under the terms of the GNU General Public License version 2 as | |
| 9 | − * published by the Free Software Foundation. | |
| 10 | − * | |
| 11 | − * This program is distributed "as is" WITHOUT ANY WARRANTY of any | |
| 12 | − * kind, whether express or implied; without even the implied warranty | |
| 13 | − * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | − * GNU General Public License for more details. | |
| 15 | 8 | */ |
| 16 | 9 | |
| 17 | 10 | #ifndef __DEVFREQ_COOLING_H__ |
| @@ -37,18 +37,6 @@ struct thermal_cooling_device; · 36 unmodified lines | ||
| 37 | 37 | struct thermal_instance; |
| 38 | 38 | struct thermal_attr; |
| 39 | 39 | |
| 40 | −enum thermal_device_mode { | |
| 41 | − THERMAL_DEVICE_DISABLED = 0, | |
| 42 | − THERMAL_DEVICE_ENABLED, | |
| 43 | −}; | |
| 44 | − | |
| 45 | −enum thermal_trip_type { | |
| 46 | − THERMAL_TRIP_ACTIVE = 0, | |
| 47 | − THERMAL_TRIP_PASSIVE, | |
| 48 | − THERMAL_TRIP_HOT, | |
| 49 | − THERMAL_TRIP_CRITICAL, | |
| 50 | −}; | |
| 51 | − | |
| 52 | 40 | enum thermal_trend { |
| 53 | 41 | THERMAL_TREND_STABLE, /* temperature is stable */ |
| 54 | 42 | THERMAL_TREND_RAISING, /* temperature is raising */ |
| @@ -76,9 +64,7 @@ struct thermal_zone_device_ops { · 21 unmodified lines | ||
| 76 | 64 | struct thermal_cooling_device *); |
| 77 | 65 | int (*get_temp) (struct thermal_zone_device *, int *); |
| 78 | 66 | int (*set_trips) (struct thermal_zone_device *, int, int); |
| 79 | − int (*get_mode) (struct thermal_zone_device *, | |
| 80 | − enum thermal_device_mode *); | |
| 81 | − int (*set_mode) (struct thermal_zone_device *, | |
| 67 | + int (*change_mode) (struct thermal_zone_device *, | |
| 82 | 68 | enum thermal_device_mode); |
| 83 | 69 | int (*get_trip_type) (struct thermal_zone_device *, int, |
| 84 | 70 | enum thermal_trip_type *); |
| @@ -128,6 +114,7 @@ struct thermal_cooling_device { · 43 unmodified lines | ||
| 128 | 114 | * @trip_temp_attrs: attributes for trip points for sysfs: trip temperature |
| 129 | 115 | * @trip_type_attrs: attributes for trip points for sysfs: trip type |
| 130 | 116 | * @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis |
| 117 | + * @mode: current mode of this thermal zone | |
| 131 | 118 | * @devdata: private pointer for device private data |
| 132 | 119 | * @trips: number of trip points the thermal zone supports |
| 133 | 120 | * @trips_disabled; bitmap for disabled trips |
| @@ -170,6 +157,7 @@ struct thermal_zone_device { · 36 unmodified lines | ||
| 170 | 157 | struct thermal_attr *trip_temp_attrs; |
| 171 | 158 | struct thermal_attr *trip_type_attrs; |
| 172 | 159 | struct thermal_attr *trip_hyst_attrs; |
| 160 | + enum thermal_device_mode mode; | |
| 173 | 161 | void *devdata; |
| 174 | 162 | int trips; |
| 175 | 163 | unsigned long trips_disabled; /* bitmap for disabled trips */ |
| @@ -303,11 +291,6 @@ struct thermal_zone_params { · 127 unmodified lines | ||
| 303 | 291 | int offset; |
| 304 | 292 | }; |
| 305 | 293 | |
| 306 | −struct thermal_genl_event { | |
| 307 | − u32 orig; | |
| 308 | − enum events event; | |
| 309 | −}; | |
| 310 | − | |
| 311 | 294 | /** |
| 312 | 295 | * struct thermal_zone_of_device_ops - scallbacks for handling DT based zones |
| 313 | 296 | * |
| @@ -416,6 +399,8 @@ int thermal_zone_get_offset(struct thermal_zone_device *tz); · 102 unmodified lines | ||
| 416 | 399 | |
| 417 | 400 | void thermal_cdev_update(struct thermal_cooling_device *); |
| 418 | 401 | void thermal_notify_framework(struct thermal_zone_device *, int); |
| 402 | +int thermal_zone_device_enable(struct thermal_zone_device *tz); | |
| 403 | +int thermal_zone_device_disable(struct thermal_zone_device *tz); | |
| 419 | 404 | #else |
| 420 | 405 | static inline struct thermal_zone_device *thermal_zone_device_register( |
| 421 | 406 | const char *type, int trips, int mask, void *devdata, |
| @@ -463,6 +448,12 @@ static inline void thermal_cdev_update(struct thermal_cooling_device *cdev) · 41 unmodified lines | ||
| 463 | 448 | static inline void thermal_notify_framework(struct thermal_zone_device *tz, |
| 464 | 449 | int trip) |
| 465 | 450 | { } |
| 451 | + | |
| 452 | +static inline int thermal_zone_device_enable(struct thermal_zone_device *tz) | |
| 453 | +{ return -ENODEV; } | |
| 454 | + | |
| 455 | +static inline int thermal_zone_device_disable(struct thermal_zone_device *tz) | |
| 456 | +{ return -ENODEV; } | |
| 466 | 457 | #endif /* CONFIG_THERMAL */ |
| 467 | 458 | |
| 468 | 459 | #endif /* __THERMAL_H__ */ |
| @@ -4,31 +4,86 @@ · 3 unmodified lines | ||
| 4 | 4 | |
| 5 | 5 | #define THERMAL_NAME_LENGTH 20 |
| 6 | 6 | |
| 7 | −/* Adding event notification support elements */ | |
| 8 | −#define THERMAL_GENL_FAMILY_NAME "thermal_event" | |
| 9 | −#define THERMAL_GENL_VERSION 0x01 | |
| 10 | −#define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_grp" | |
| 11 | − | |
| 12 | −/* Events supported by Thermal Netlink */ | |
| 13 | −enum events { | |
| 14 | − THERMAL_AUX0, | |
| 15 | − THERMAL_AUX1, | |
| 16 | − THERMAL_CRITICAL, | |
| 17 | − THERMAL_DEV_FAULT, | |
| 7 | +enum thermal_device_mode { | |
| 8 | + THERMAL_DEVICE_DISABLED = 0, | |
| 9 | + THERMAL_DEVICE_ENABLED, | |
| 10 | +}; | |
| 11 | + | |
| 12 | +enum thermal_trip_type { | |
| 13 | + THERMAL_TRIP_ACTIVE = 0, | |
| 14 | + THERMAL_TRIP_PASSIVE, | |
| 15 | + THERMAL_TRIP_HOT, | |
| 16 | + THERMAL_TRIP_CRITICAL, | |
| 18 | 17 | }; |
| 19 | 18 | |
| 20 | −/* attributes of thermal_genl_family */ | |
| 21 | −enum { | |
| 19 | +/* Adding event notification support elements */ | |
| 20 | +#define THERMAL_GENL_FAMILY_NAME "thermal" | |
| 21 | +#define THERMAL_GENL_VERSION 0x01 | |
| 22 | +#define THERMAL_GENL_SAMPLING_GROUP_NAME "sampling" | |
| 23 | +#define THERMAL_GENL_EVENT_GROUP_NAME "event" | |
| 24 | + | |
| 25 | +/* Attributes of thermal_genl_family */ | |
| 26 | +enum thermal_genl_attr { | |
| 22 | 27 | THERMAL_GENL_ATTR_UNSPEC, |
| 23 | − THERMAL_GENL_ATTR_EVENT, | |
| 28 | + THERMAL_GENL_ATTR_TZ, | |
| 29 | + THERMAL_GENL_ATTR_TZ_ID, | |
| 30 | + THERMAL_GENL_ATTR_TZ_TEMP, | |
| 31 | + THERMAL_GENL_ATTR_TZ_TRIP, | |
| 32 | + THERMAL_GENL_ATTR_TZ_TRIP_ID, | |
| 33 | + THERMAL_GENL_ATTR_TZ_TRIP_TYPE, | |
| 34 | + THERMAL_GENL_ATTR_TZ_TRIP_TEMP, | |
| 35 | + THERMAL_GENL_ATTR_TZ_TRIP_HYST, | |
| 36 | + THERMAL_GENL_ATTR_TZ_MODE, | |
| 37 | + THERMAL_GENL_ATTR_TZ_NAME, | |
| 38 | + THERMAL_GENL_ATTR_TZ_CDEV_WEIGHT, | |
| 39 | + THERMAL_GENL_ATTR_TZ_GOV, | |
| 40 | + THERMAL_GENL_ATTR_TZ_GOV_NAME, | |
| 41 | + THERMAL_GENL_ATTR_CDEV, | |
| 42 | + THERMAL_GENL_ATTR_CDEV_ID, | |
| 43 | + THERMAL_GENL_ATTR_CDEV_CUR_STATE, | |
| 44 | + THERMAL_GENL_ATTR_CDEV_MAX_STATE, | |
| 45 | + THERMAL_GENL_ATTR_CDEV_NAME, | |
| 46 | + THERMAL_GENL_ATTR_GOV_NAME, | |
| 47 | + | |
| 24 | 48 | __THERMAL_GENL_ATTR_MAX, |
| 25 | 49 | }; |
| 26 | 50 | #define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1) |
| 27 | 51 | |
| 28 | −/* commands supported by the thermal_genl_family */ | |
| 29 | −enum { | |
| 52 | +enum thermal_genl_sampling { | |
| 53 | + THERMAL_GENL_SAMPLING_TEMP, | |
| 54 | + __THERMAL_GENL_SAMPLING_MAX, | |
| 55 | +}; | |
| 56 | +#define THERMAL_GENL_SAMPLING_MAX (__THERMAL_GENL_SAMPLING_MAX - 1) | |
| 57 | + | |
| 58 | +/* Events of thermal_genl_family */ | |
| 59 | +enum thermal_genl_event { | |
| 60 | + THERMAL_GENL_EVENT_UNSPEC, | |
| 61 | + THERMAL_GENL_EVENT_TZ_CREATE, /* Thermal zone creation */ | |
| 62 | + THERMAL_GENL_EVENT_TZ_DELETE, /* Thermal zone deletion */ | |
| 63 | + THERMAL_GENL_EVENT_TZ_DISABLE, /* Thermal zone disabed */ | |
| 64 | + THERMAL_GENL_EVENT_TZ_ENABLE, /* Thermal zone enabled */ | |
| 65 | + THERMAL_GENL_EVENT_TZ_TRIP_UP, /* Trip point crossed the way up */ | |
| 66 | + THERMAL_GENL_EVENT_TZ_TRIP_DOWN, /* Trip point crossed the way down */ | |
| 67 | + THERMAL_GENL_EVENT_TZ_TRIP_CHANGE, /* Trip point changed */ | |
| 68 | + THERMAL_GENL_EVENT_TZ_TRIP_ADD, /* Trip point added */ | |
| 69 | + THERMAL_GENL_EVENT_TZ_TRIP_DELETE, /* Trip point deleted */ | |
| 70 | + THERMAL_GENL_EVENT_CDEV_ADD, /* Cdev bound to the thermal zone */ | |
| 71 | + THERMAL_GENL_EVENT_CDEV_DELETE, /* Cdev unbound */ | |
| 72 | + THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, /* Cdev state updated */ | |
| 73 | + THERMAL_GENL_EVENT_TZ_GOV_CHANGE, /* Governor policy changed */ | |
| 74 | + __THERMAL_GENL_EVENT_MAX, | |
| 75 | +}; | |
| 76 | +#define THERMAL_GENL_EVENT_MAX (__THERMAL_GENL_EVENT_MAX - 1) | |
| 77 | + | |
| 78 | +/* Commands supported by the thermal_genl_family */ | |
| 79 | +enum thermal_genl_cmd { | |
| 30 | 80 | THERMAL_GENL_CMD_UNSPEC, |
| 31 | − THERMAL_GENL_CMD_EVENT, | |
| 81 | + THERMAL_GENL_CMD_TZ_GET_ID, /* List of thermal zones id */ | |
| 82 | + THERMAL_GENL_CMD_TZ_GET_TRIP, /* List of thermal trips */ | |
| 83 | + THERMAL_GENL_CMD_TZ_GET_TEMP, /* Get the thermal zone temperature */ | |
| 84 | + THERMAL_GENL_CMD_TZ_GET_GOV, /* Get the thermal zone governor */ | |
| 85 | + THERMAL_GENL_CMD_TZ_GET_MODE, /* Get the thermal zone mode */ | |
| 86 | + THERMAL_GENL_CMD_CDEV_GET, /* List of cdev id */ | |
| 32 | 87 | __THERMAL_GENL_CMD_MAX, |
| 33 | 88 | }; |
| 34 | 89 | #define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1) |
| @@ -1192,7 +1192,7 @@ problem: · 1191 unmodified lines | ||
| 1192 | 1192 | panic("GENL: Cannot register controller: %d\n", err); |
| 1193 | 1193 | } |
| 1194 | 1194 | |
| 1195 | −subsys_initcall(genl_init); | |
| 1195 | +core_initcall(genl_init); | |
| 1196 | 1196 | |
| 1197 | 1197 | static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group, |
| 1198 | 1198 | gfp_t flags) |