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 | [0] http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/index.html | 102 | [0] http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/index.html |
| 103 | [1] Documentation/devicetree/bindings/clock/clock-bindings.txt | 103 | [1] Documentation/devicetree/bindings/clock/clock-bindings.txt |
| 104 | [2] Documentation/devicetree/bindings/power/power-domain.yaml | 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 | [4] Documentation/devicetree/bindings/sram/sram.yaml | 106 | [4] Documentation/devicetree/bindings/sram/sram.yaml |
| 107 | [5] Documentation/devicetree/bindings/reset/reset.txt | 107 | [5] Documentation/devicetree/bindings/reset/reset.txt |
| 108 | 108 | ||
| @@ -108,7 +108,7 @@ Required properties: · 107 unmodified lines | |||
| 108 | 108 | ||
| 109 | [0] http://infocenter.arm.com/help/topic/com.arm.doc.dui0922b/index.html | 109 | [0] http://infocenter.arm.com/help/topic/com.arm.doc.dui0922b/index.html |
| 110 | [1] Documentation/devicetree/bindings/clock/clock-bindings.txt | 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 | [3] Documentation/devicetree/bindings/sram/sram.yaml | 112 | [3] Documentation/devicetree/bindings/sram/sram.yaml |
| 113 | [4] Documentation/devicetree/bindings/power/power-domain.yaml | 113 | [4] Documentation/devicetree/bindings/power/power-domain.yaml |
| 114 | 114 | ||
| @@ -176,7 +176,7 @@ Required properties: · 175 unmodified lines | |||
| 176 | "fsl,imx8qxp-sc-thermal" | 176 | "fsl,imx8qxp-sc-thermal" |
| 177 | followed by "fsl,imx-sc-thermal"; | 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 | for a description. | 180 | for a description. |
| 181 | 181 | ||
| 182 | Example (imx8qxp): | 182 | Example (imx8qxp): |
| @@ -111,7 +111,7 @@ Thermal: · 110 unmodified lines | |||
| 111 | -------- | 111 | -------- |
| 112 | 112 | ||
| 113 | For common binding part and usage, refer to | 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 | The thermal IP can probe the temperature all around the processor. It | 116 | The thermal IP can probe the temperature all around the processor. It |
| 117 | may feature several channels, each of them wired to one sensor. | 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 | critical point to any subnode of the thermal-zone node. | 203 | critical point to any subnode of the thermal-zone node. |
| 204 | 204 | ||
| 205 | For common binding part and usage, refer to | 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 | Required properties: | 208 | Required properties: |
| 209 | - compatible: must be one of: | 209 | - compatible: must be one of: |
| @@ -18,7 +18,8 @@ Optional properties: · 17 unmodified lines | |||
| 18 | in unit of nanoseconds. | 18 | in unit of nanoseconds. |
| 19 | - voltage-tolerance: Specify the CPU voltage tolerance in percentage. | 19 | - voltage-tolerance: Specify the CPU voltage tolerance in percentage. |
| 20 | - #cooling-cells: | 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 | Examples: | 24 | Examples: |
| 24 | 25 | ||
| @@ -21,8 +21,8 @@ Optional properties: · 20 unmodified lines | |||
| 21 | flow is handled by hardware, hence no software "voltage tracking" is | 21 | flow is handled by hardware, hence no software "voltage tracking" is |
| 22 | needed. | 22 | needed. |
| 23 | - #cooling-cells: | 23 | - #cooling-cells: |
| 24 | Please refer to Documentation/devicetree/bindings/thermal/thermal.txt | 24 | For details, please refer to |
| 25 | for detail. | 25 | Documentation/devicetree/bindings/thermal/thermal-cooling-devices.yaml |
| 26 | 26 | ||
| 27 | Example 1 (MT7623 SoC): | 27 | Example 1 (MT7623 SoC): |
| 28 | 28 | ||
| @@ -5,7 +5,7 @@ Required properties: · 4 unmodified lines | |||
| 5 | - clocks: Must contain an entry for the CPU clock. | 5 | - clocks: Must contain an entry for the CPU clock. |
| 6 | See ../clocks/clock-bindings.txt for details. | 6 | See ../clocks/clock-bindings.txt for details. |
| 7 | - operating-points-v2: See ../bindings/opp/opp.txt for details. | 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 | For each opp entry in 'operating-points-v2' table: | 10 | For each opp entry in 'operating-points-v2' table: |
| 11 | - opp-supported-hw: Two bitfields indicating: | 11 | - opp-supported-hw: Two bitfields indicating: |
| @@ -12,7 +12,8 @@ Optional properties: · 11 unmodified lines | |||
| 12 | - alarm-gpios: This pin going active indicates something is wrong with | 12 | - alarm-gpios: This pin going active indicates something is wrong with |
| 13 | the fan, and a udev event will be fired. | 13 | the fan, and a udev event will be fired. |
| 14 | - #cooling-cells: If used as a cooling device, must be <2> | 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 | min and max states are derived from the speed-map of the fan. | 17 | min and max states are derived from the speed-map of the fan. |
| 17 | 18 | ||
| 18 | Note: At least one the "gpios" or "alarm-gpios" properties must be set. | 19 | Note: At least one the "gpios" or "alarm-gpios" properties must be set. |
| @@ -34,8 +34,8 @@ Optional properties: · 33 unmodified lines | |||
| 34 | LM90 "-ALERT" pin output. | 34 | LM90 "-ALERT" pin output. |
| 35 | See interrupt-controller/interrupts.txt for the format. | 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 | 37 | - #thermal-sensor-cells: should be set to 1. See thermal/thermal-sensor.yaml |
| 38 | details. See <include/dt-bindings/thermal/lm90.h> for the | 38 | for details. See <include/dt-bindings/thermal/lm90.h> for the |
| 39 | definition of the local, remote and 2nd remote sensor index | 39 | definition of the local, remote and 2nd remote sensor index |
| 40 | constants. | 40 | constants. |
| 41 | 41 | ||
| @@ -50,7 +50,7 @@ properties: · 49 unmodified lines | |||
| 50 | nvmem-cell-names: | 50 | nvmem-cell-names: |
| 51 | const: calibration | 51 | const: calibration |
| 52 | 52 | ||
| 53 | # See ./thermal.txt for details | 53 | # See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for details |
| 54 | "#thermal-sensor-cells": | 54 | "#thermal-sensor-cells": |
| 55 | enum: | 55 | enum: |
| 56 | - 0 | 56 | - 0 |
| @@ -6,7 +6,7 @@ transaction. · 5 unmodified lines | |||
| 6 | Required properties: | 6 | Required properties: |
| 7 | - compatible: "amazon,al-thermal". | 7 | - compatible: "amazon,al-thermal". |
| 8 | - reg: The physical base address and length of the sensor's registers. | 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 | Example: | 11 | Example: |
| 12 | thermal: thermal { | 12 | thermal: thermal { |
| @@ -23,7 +23,7 @@ properties: · 22 unmodified lines | |||
| 23 | compatible: | 23 | compatible: |
| 24 | const: brcm,bcm2711-thermal | 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 | "#thermal-sensor-cells": | 27 | "#thermal-sensor-cells": |
| 28 | const: 0 | 28 | const: 0 |
| 29 | 29 | ||
| @@ -7,7 +7,7 @@ compatible: should be one of: "brcm,bcm2835-thermal", · 6 unmodified lines | |||
| 7 | "brcm,bcm2836-thermal" or "brcm,bcm2837-thermal" | 7 | "brcm,bcm2836-thermal" or "brcm,bcm2837-thermal" |
| 8 | reg: Address range of the thermal registers. | 8 | reg: Address range of the thermal registers. |
| 9 | clocks: Phandle of the clock used by the thermal sensor. | 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 | Example: | 12 | Example: |
| 13 | 13 | ||
| @@ -9,7 +9,7 @@ · 8 unmodified lines | |||
| 9 | by /SOCTHERM/tsensor. | 9 | by /SOCTHERM/tsensor. |
| 10 | - clock-names: Input clock name, should be 'thermal_clk'. | 10 | - clock-names: Input clock name, should be 'thermal_clk'. |
| 11 | - clocks: phandles for clock specified in "clock-names" property. | 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 | Example : | 14 | Example : |
| 15 | 15 | ||
| @@ -8,12 +8,12 @@ below threshold level. · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | Required properties: | 9 | Required properties: |
| 10 | ------------------- | 10 | ------------------- |
| 11 | #thermal-sensor-cells: Please refer <devicetree/bindings/thermal/thermal.txt> | 11 | #thermal-sensor-cells: For more details, please refer to |
| 12 | for more details. | 12 | <devicetree/bindings/thermal/thermal-sensor.yaml> |
| 13 | The value must be 0. | 13 | The value must be 0. |
| 14 | 14 | ||
| 15 | For more details, please refer generic thermal DT binding document | 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 | Please refer <devicetree/bindings/mfd/max77620.txt> for mfd DT binding | 18 | Please refer <devicetree/bindings/mfd/max77620.txt> for mfd DT binding |
| 19 | document for the MAX77620. | 19 | document for the MAX77620. |
| @@ -23,7 +23,7 @@ Required properties: · 22 unmodified lines | |||
| 23 | - resets: Reference to the reset controller controlling the thermal controller. | 23 | - resets: Reference to the reset controller controlling the thermal controller. |
| 24 | - mediatek,auxadc: A phandle to the AUXADC which the thermal controller uses | 24 | - mediatek,auxadc: A phandle to the AUXADC which the thermal controller uses |
| 25 | - mediatek,apmixedsys: A phandle to the APMIXEDSYS controller. | 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 | Optional properties: | 28 | Optional properties: |
| 29 | - nvmem-cells: A phandle to the calibration data provided by a nvmem device. If | 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 | See ../reset/reset.txt for details. | 28 | See ../reset/reset.txt for details. |
| 29 | - reset-names : Must include the following entries: | 29 | - reset-names : Must include the following entries: |
| 30 | - soctherm | 30 | - soctherm |
| 31 | - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description | 31 | - #thermal-sensor-cells : Should be 1. For a description of this property, see |
| 32 | of this property. See <dt-bindings/thermal/tegra124-soctherm.h> for a | 32 | Documentation/devicetree/bindings/thermal/thermal-sensor.yaml. |
| 33 | list of valid values when referring to thermal sensors. | 33 | See <dt-bindings/thermal/tegra124-soctherm.h> for a list of valid values |
| 34 | when referring to thermal sensors. | ||
| 34 | - throttle-cfgs: A sub-node which is a container of configuration for each | 35 | - throttle-cfgs: A sub-node which is a container of configuration for each |
| 35 | hardware throttle events. These events can be set as cooling devices. | 36 | hardware throttle events. These events can be set as cooling devices. |
| 36 | * throttle events: Sub-nodes must be named as "light" or "heavy". | 37 | * throttle events: Sub-nodes must be named as "light" or "heavy". |
| @@ -62,7 +63,8 @@ Required properties : · 25 unmodified lines | |||
| 62 | TEGRA_SOCTHERM_THROT_LEVEL_MED (75%), | 63 | TEGRA_SOCTHERM_THROT_LEVEL_MED (75%), |
| 63 | TEGRA_SOCTHERM_THROT_LEVEL_HIGH (85%). | 64 | TEGRA_SOCTHERM_THROT_LEVEL_HIGH (85%). |
| 64 | - #cooling-cells: Should be 1. This cooling device only support on/off state. | 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 | Optional properties: The following properties are T210 specific and | 69 | Optional properties: The following properties are T210 specific and |
| 68 | valid only for OCx throttle events. | 70 | valid only for OCx throttle events. |
| @@ -8,7 +8,7 @@ exposed by BPMP. · 7 unmodified lines | |||
| 8 | The BPMP thermal node must be located directly inside the main BPMP node. See | 8 | The BPMP thermal node must be located directly inside the main BPMP node. See |
| 9 | ../firmware/nvidia,tegra186-bpmp.txt for details of the BPMP binding. | 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 | core thermal binding. | 12 | core thermal binding. |
| 13 | 13 | ||
| 14 | Required properties: | 14 | Required properties: |
| @@ -8,7 +8,7 @@ Required properties: · 7 unmodified lines | |||
| 8 | - compatible: Should contain "qcom,spmi-temp-alarm". | 8 | - compatible: Should contain "qcom,spmi-temp-alarm". |
| 9 | - reg: Specifies the SPMI address. | 9 | - reg: Specifies the SPMI address. |
| 10 | - interrupts: PMIC temperature alarm interrupt. | 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 | Optional properties: | 13 | Optional properties: |
| 14 | - io-channels: Should contain IIO channel specifier for the ADC channel, | 14 | - io-channels: Should contain IIO channel specifier for the ADC channel, |
| @@ -23,6 +23,7 @@ properties: · 22 unmodified lines | |||
| 23 | items: | 23 | items: |
| 24 | - enum: | 24 | - enum: |
| 25 | - qcom,msm8916-tsens | 25 | - qcom,msm8916-tsens |
| 26 | - qcom,msm8939-tsens | ||
| 26 | - qcom,msm8974-tsens | 27 | - qcom,msm8974-tsens |
| 27 | - const: qcom,tsens-v0_1 | 28 | - const: qcom,tsens-v0_1 |
| 28 | 29 | ||
| @@ -24,7 +24,7 @@ Required properties: · 23 unmodified lines | |||
| 24 | - pinctrl-1 : The "default" pinctrl state, it will be set after reset the | 24 | - pinctrl-1 : The "default" pinctrl state, it will be set after reset the |
| 25 | TSADC controller. | 25 | TSADC controller. |
| 26 | - pinctrl-2 : The "sleep" pinctrl state, it will be in for suspend. | 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 | Optional properties: | 29 | Optional properties: |
| 30 | - rockchip,hw-tshut-temp : The hardware-controlled shutdown temperature value. | 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 | (in the CPU, video decoder, and PCIe controller). | 4 | (in the CPU, video decoder, and PCIe controller). |
| 5 | 5 | ||
| 6 | Required properties: | 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 | - compatible: "sigma,smp8758-thermal" | 8 | - compatible: "sigma,smp8758-thermal" |
| 9 | - reg: Address range of the thermal registers | 9 | - reg: Address range of the thermal registers |
| 10 | 10 | ||
| @@ -8,7 +8,7 @@ temperature using voltage-temperature lookup table. · 7 unmodified lines | |||
| 8 | Required properties: | 8 | Required properties: |
| 9 | =================== | 9 | =================== |
| 10 | - compatible: Must be "generic-adc-thermal". | 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 | of this property. | 12 | of this property. |
| 13 | Optional properties: | 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 | F: drivers/thermal/cpuidle_cooling.c | 17086 | F: drivers/thermal/cpuidle_cooling.c |
| 17087 | F: include/linux/cpu_cooling.h | 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 | THINKPAD ACPI EXTRAS DRIVER | 17097 | THINKPAD ACPI EXTRAS DRIVER |
| 17090 | M: Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br> | 17098 | M: Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br> |
| 17091 | L: ibm-acpi-devel@lists.sourceforge.net | 17099 | L: ibm-acpi-devel@lists.sourceforge.net |
| @@ -172,7 +172,6 @@ struct acpi_thermal { · 171 unmodified lines | |||
| 172 | struct acpi_thermal_trips trips; | 172 | struct acpi_thermal_trips trips; |
| 173 | struct acpi_handle_list devices; | 173 | struct acpi_handle_list devices; |
| 174 | struct thermal_zone_device *thermal_zone; | 174 | struct thermal_zone_device *thermal_zone; |
| 175 | int tz_enabled; | ||
| 176 | int kelvin_offset; /* in millidegrees */ | 175 | int kelvin_offset; /* in millidegrees */ |
| 177 | struct work_struct thermal_check_work; | 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 | struct acpi_thermal *tz = data; | 500 | struct acpi_thermal *tz = data; |
| 502 | 501 | ||
| 503 | if (!tz->tz_enabled) | ||
| 504 | return; | ||
| 505 | |||
| 506 | thermal_zone_device_update(tz->thermal_zone, | 502 | thermal_zone_device_update(tz->thermal_zone, |
| 507 | THERMAL_EVENT_UNSPECIFIED); | 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 | return 0; | 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 | static int thermal_get_trip_type(struct thermal_zone_device *thermal, | 525 | static int thermal_get_trip_type(struct thermal_zone_device *thermal, |
| 574 | int trip, enum thermal_trip_type *type) | 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 | .bind = acpi_thermal_bind_cooling_device, | 808 | .bind = acpi_thermal_bind_cooling_device, |
| 857 | .unbind = acpi_thermal_unbind_cooling_device, | 809 | .unbind = acpi_thermal_unbind_cooling_device, |
| 858 | .get_temp = thermal_get_temp, | 810 | .get_temp = thermal_get_temp, |
| 859 | .get_mode = thermal_get_mode, | ||
| 860 | .set_mode = thermal_set_mode, | ||
| 861 | .get_trip_type = thermal_get_trip_type, | 811 | .get_trip_type = thermal_get_trip_type, |
| 862 | .get_trip_temp = thermal_get_trip_temp, | 812 | .get_trip_temp = thermal_get_trip_temp, |
| 863 | .get_crit_temp = thermal_get_crit_temp, | 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 | result = sysfs_create_link(&tz->device->dev.kobj, | 851 | result = sysfs_create_link(&tz->device->dev.kobj, |
| 902 | &tz->thermal_zone->device.kobj, "thermal_zone"); | 852 | &tz->thermal_zone->device.kobj, "thermal_zone"); |
| 903 | if (result) | 853 | if (result) |
| 904 | return result; | 854 | goto unregister_tzd; |
| 905 | 855 | ||
| 906 | result = sysfs_create_link(&tz->thermal_zone->device.kobj, | 856 | result = sysfs_create_link(&tz->thermal_zone->device.kobj, |
| 907 | &tz->device->dev.kobj, "device"); | 857 | &tz->device->dev.kobj, "device"); |
| 908 | if (result) | 858 | if (result) |
| 909 | return result; | 859 | goto remove_tz_link; |
| 910 | 860 | ||
| 911 | status = acpi_bus_attach_private_data(tz->device->handle, | 861 | status = acpi_bus_attach_private_data(tz->device->handle, |
| 912 | tz->thermal_zone); | 862 | tz->thermal_zone); |
| 913 | if (ACPI_FAILURE(status)) | 863 | if (ACPI_FAILURE(status)) { |
| 914 | return -ENODEV; | 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 | dev_info(&tz->device->dev, "registered as thermal_zone%d\n", | 872 | dev_info(&tz->device->dev, "registered as thermal_zone%d\n", |
| 919 | tz->thermal_zone->id); | 873 | tz->thermal_zone->id); |
| 874 | |||
| 920 | return 0; | 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 | static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) | 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 | ch_thermal->tzdev = NULL; | 92 | ch_thermal->tzdev = NULL; |
| 93 | return ret; | 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 | return 0; | 103 | return 0; |
| 96 | } | 104 | } |
| 97 | 105 | ||
| @@ -98,7 +98,6 @@ struct mlxsw_thermal_module { · 97 unmodified lines | |||
| 98 | struct mlxsw_thermal *parent; | 98 | struct mlxsw_thermal *parent; |
| 99 | struct thermal_zone_device *tzdev; | 99 | struct thermal_zone_device *tzdev; |
| 100 | struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; | 100 | struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; |
| 101 | enum thermal_device_mode mode; | ||
| 102 | int module; /* Module or gearbox number */ | 101 | int module; /* Module or gearbox number */ |
| 103 | }; | 102 | }; |
| 104 | 103 | ||
| @@ -110,7 +109,6 @@ struct mlxsw_thermal { · 5 unmodified lines | |||
| 110 | struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX]; | 109 | struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX]; |
| 111 | u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1]; | 110 | u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1]; |
| 112 | struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; | 111 | struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; |
| 113 | enum thermal_device_mode mode; | ||
| 114 | struct mlxsw_thermal_module *tz_module_arr; | 112 | struct mlxsw_thermal_module *tz_module_arr; |
| 115 | u8 tz_module_num; | 113 | u8 tz_module_num; |
| 116 | struct mlxsw_thermal_module *tz_gearbox_arr; | 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 | return 0; | 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 | static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, | 278 | static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, |
| 311 | int *p_temp) | 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 | static struct thermal_zone_device_ops mlxsw_thermal_ops = { | 374 | static struct thermal_zone_device_ops mlxsw_thermal_ops = { |
| 407 | .bind = mlxsw_thermal_bind, | 375 | .bind = mlxsw_thermal_bind, |
| 408 | .unbind = mlxsw_thermal_unbind, | 376 | .unbind = mlxsw_thermal_unbind, |
| 409 | .get_mode = mlxsw_thermal_get_mode, | ||
| 410 | .set_mode = mlxsw_thermal_set_mode, | ||
| 411 | .get_temp = mlxsw_thermal_get_temp, | 377 | .get_temp = mlxsw_thermal_get_temp, |
| 412 | .get_trip_type = mlxsw_thermal_get_trip_type, | 378 | .get_trip_type = mlxsw_thermal_get_trip_type, |
| 413 | .get_trip_temp = mlxsw_thermal_get_trip_temp, | 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 | return err; | 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 | static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, | 434 | static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, |
| 500 | int *p_temp) | 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 | static struct thermal_zone_device_ops mlxsw_thermal_module_ops = { | 546 | static struct thermal_zone_device_ops mlxsw_thermal_module_ops = { |
| 612 | .bind = mlxsw_thermal_module_bind, | 547 | .bind = mlxsw_thermal_module_bind, |
| 613 | .unbind = mlxsw_thermal_module_unbind, | 548 | .unbind = mlxsw_thermal_module_unbind, |
| 614 | .get_mode = mlxsw_thermal_module_mode_get, | ||
| 615 | .set_mode = mlxsw_thermal_module_mode_set, | ||
| 616 | .get_temp = mlxsw_thermal_module_temp_get, | 549 | .get_temp = mlxsw_thermal_module_temp_get, |
| 617 | .get_trip_type = mlxsw_thermal_module_trip_type_get, | 550 | .get_trip_type = mlxsw_thermal_module_trip_type_get, |
| 618 | .get_trip_temp = mlxsw_thermal_module_trip_temp_get, | 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 | static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = { | 583 | static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = { |
| 651 | .bind = mlxsw_thermal_module_bind, | 584 | .bind = mlxsw_thermal_module_bind, |
| 652 | .unbind = mlxsw_thermal_module_unbind, | 585 | .unbind = mlxsw_thermal_module_unbind, |
| 653 | .get_mode = mlxsw_thermal_module_mode_get, | ||
| 654 | .set_mode = mlxsw_thermal_module_mode_set, | ||
| 655 | .get_temp = mlxsw_thermal_gearbox_temp_get, | 586 | .get_temp = mlxsw_thermal_gearbox_temp_get, |
| 656 | .get_trip_type = mlxsw_thermal_module_trip_type_get, | 587 | .get_trip_type = mlxsw_thermal_module_trip_type_get, |
| 657 | .get_trip_temp = mlxsw_thermal_module_trip_temp_get, | 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 | return err; | 711 | return err; |
| 781 | } | 712 | } |
| 782 | 713 | ||
| 783 | module_tz->mode = THERMAL_DEVICE_ENABLED; | 714 | err = thermal_zone_device_enable(module_tz->tzdev); |
| 784 | return 0; | 715 | if (err) |
| 716 | thermal_zone_device_unregister(module_tz->tzdev); | ||
| 717 | |||
| 718 | return err; | ||
| 785 | } | 719 | } |
| 786 | 720 | ||
| 787 | static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev) | 721 | static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev) |
| @@ -884,6 +818,7 @@ static int · 96 unmodified lines | |||
| 884 | mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) | 818 | mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) |
| 885 | { | 819 | { |
| 886 | char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME]; | 820 | char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME]; |
| 821 | int ret; | ||
| 887 | 822 | ||
| 888 | snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d", | 823 | snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d", |
| 889 | gearbox_tz->module + 1); | 824 | gearbox_tz->module + 1); |
| @@ -896,8 +831,11 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) · 6 unmodified lines | |||
| 896 | if (IS_ERR(gearbox_tz->tzdev)) | 831 | if (IS_ERR(gearbox_tz->tzdev)) |
| 897 | return PTR_ERR(gearbox_tz->tzdev); | 832 | return PTR_ERR(gearbox_tz->tzdev); |
| 898 | 833 | ||
| 899 | gearbox_tz->mode = THERMAL_DEVICE_ENABLED; | 834 | ret = thermal_zone_device_enable(gearbox_tz->tzdev); |
| 900 | return 0; | 835 | if (ret) |
| 836 | thermal_zone_device_unregister(gearbox_tz->tzdev); | ||
| 837 | |||
| 838 | return ret; | ||
| 901 | } | 839 | } |
| 902 | 840 | ||
| 903 | static void | 841 | static void |
| @@ -1065,10 +1003,15 @@ int mlxsw_thermal_init(struct mlxsw_core *core, · 161 unmodified lines | |||
| 1065 | if (err) | 1003 | if (err) |
| 1066 | goto err_unreg_modules_tzdev; | 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 | *p_thermal = thermal; | 1010 | *p_thermal = thermal; |
| 1070 | return 0; | 1011 | return 0; |
| 1071 | 1012 | ||
| 1013 | err_unreg_gearboxes: | ||
| 1014 | mlxsw_thermal_gearboxes_fini(thermal); | ||
| 1072 | err_unreg_modules_tzdev: | 1015 | err_unreg_modules_tzdev: |
| 1073 | mlxsw_thermal_modules_fini(thermal); | 1016 | mlxsw_thermal_modules_fini(thermal); |
| 1074 | err_unreg_tzdev: | 1017 | err_unreg_tzdev: |
| @@ -733,7 +733,7 @@ static struct thermal_zone_device_ops tzone_ops = { · 732 unmodified lines | |||
| 733 | 733 | ||
| 734 | static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm) | 734 | static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm) |
| 735 | { | 735 | { |
| 736 | int i; | 736 | int i, ret; |
| 737 | char name[16]; | 737 | char name[16]; |
| 738 | static atomic_t counter = ATOMIC_INIT(0); | 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 | return; | 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 | /* 0 is a valid temperature, | 769 | /* 0 is a valid temperature, |
| 763 | * so initialize the array with S16_MIN which invalid temperature | 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 | acerhdf_change_fanstate(ACERHDF_FAN_AUTO); | 398 | acerhdf_change_fanstate(ACERHDF_FAN_AUTO); |
| 399 | kernelmode = 0; | 399 | kernelmode = 0; |
| 400 | if (thz_dev) | 400 | |
| 401 | thz_dev->polling_delay = 0; | ||
| 402 | pr_notice("kernel mode fan control OFF\n"); | 401 | pr_notice("kernel mode fan control OFF\n"); |
| 403 | } | 402 | } |
| 404 | static inline void acerhdf_enable_kernelmode(void) | 403 | static inline void acerhdf_enable_kernelmode(void) |
| 405 | { | 404 | { |
| 406 | kernelmode = 1; | 405 | kernelmode = 1; |
| 407 | 406 | ||
| 408 | thz_dev->polling_delay = interval*1000; | ||
| 409 | thermal_zone_device_update(thz_dev, THERMAL_EVENT_UNSPECIFIED); | ||
| 410 | pr_notice("kernel mode fan control ON\n"); | 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 | * set operation mode; | 411 | * set operation mode; |
| 427 | * enabled: the thermal layer of the kernel takes care about | 412 | * enabled: the thermal layer of the kernel takes care about |
| 428 | * the temperature and the fan. | 413 | * the temperature and the fan. |
| 429 | * disabled: the BIOS takes control of the fan. | 414 | * disabled: the BIOS takes control of the fan. |
| 430 | */ | 415 | */ |
| 431 | static int acerhdf_set_mode(struct thermal_zone_device *thermal, | 416 | static int acerhdf_change_mode(struct thermal_zone_device *thermal, |
| 432 | enum thermal_device_mode mode) | 417 | enum thermal_device_mode mode) |
| 433 | { | 418 | { |
| 434 | if (mode == THERMAL_DEVICE_DISABLED && kernelmode) | 419 | if (mode == THERMAL_DEVICE_DISABLED && kernelmode) |
| 435 | acerhdf_revert_to_bios_mode(); | 420 | acerhdf_revert_to_bios_mode(); |
| @@ -488,8 +473,7 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = { · 52 unmodified lines | |||
| 488 | .bind = acerhdf_bind, | 473 | .bind = acerhdf_bind, |
| 489 | .unbind = acerhdf_unbind, | 474 | .unbind = acerhdf_unbind, |
| 490 | .get_temp = acerhdf_get_ec_temp, | 475 | .get_temp = acerhdf_get_ec_temp, |
| 491 | .get_mode = acerhdf_get_mode, | 476 | .change_mode = acerhdf_change_mode, |
| 492 | .set_mode = acerhdf_set_mode, | ||
| 493 | .get_trip_type = acerhdf_get_trip_type, | 477 | .get_trip_type = acerhdf_get_trip_type, |
| 494 | .get_trip_hyst = acerhdf_get_trip_hyst, | 478 | .get_trip_hyst = acerhdf_get_trip_hyst, |
| 495 | .get_trip_temp = acerhdf_get_trip_temp, | 479 | .get_trip_temp = acerhdf_get_trip_temp, |
| @@ -733,6 +717,8 @@ static void acerhdf_unregister_platform(void) · 237 unmodified lines | |||
| 733 | 717 | ||
| 734 | static int __init acerhdf_register_thermal(void) | 718 | static int __init acerhdf_register_thermal(void) |
| 735 | { | 719 | { |
| 720 | int ret; | ||
| 721 | |||
| 736 | cl_dev = thermal_cooling_device_register("acerhdf-fan", NULL, | 722 | cl_dev = thermal_cooling_device_register("acerhdf-fan", NULL, |
| 737 | &acerhdf_cooling_ops); | 723 | &acerhdf_cooling_ops); |
| 738 | 724 | ||
| @@ -746,6 +732,13 @@ static int __init acerhdf_register_thermal(void) · 7 unmodified lines | |||
| 746 | if (IS_ERR(thz_dev)) | 732 | if (IS_ERR(thz_dev)) |
| 747 | return -EINVAL; | 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 | if (strcmp(thz_dev->governor->name, | 742 | if (strcmp(thz_dev->governor->name, |
| 750 | acerhdf_zone_params.governor_name)) { | 743 | acerhdf_zone_params.governor_name)) { |
| 751 | pr_err("Didn't get thermal governor %s, perhaps not compiled into thermal subsystem.\n", | 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 | ret = PTR_ERR(pinfo->tzd[i]); | 493 | ret = PTR_ERR(pinfo->tzd[i]); |
| 494 | goto err; | 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 | pinfo->pdev = pdev; | 504 | pinfo->pdev = pdev; |
| @@ -939,7 +939,7 @@ static struct thermal_zone_device_ops psy_tzd_ops = { · 938 unmodified lines | |||
| 939 | 939 | ||
| 940 | static int psy_register_thermal(struct power_supply *psy) | 940 | static int psy_register_thermal(struct power_supply *psy) |
| 941 | { | 941 | { |
| 942 | int i; | 942 | int i, ret; |
| 943 | 943 | ||
| 944 | if (psy->desc->no_thermal) | 944 | if (psy->desc->no_thermal) |
| 945 | return 0; | 945 | return 0; |
| @@ -949,7 +949,12 @@ static int psy_register_thermal(struct power_supply *psy) · 3 unmodified lines | |||
| 949 | if (psy->desc->properties[i] == POWER_SUPPLY_PROP_TEMP) { | 949 | if (psy->desc->properties[i] == POWER_SUPPLY_PROP_TEMP) { |
| 950 | psy->tzd = thermal_zone_device_register(psy->desc->name, | 950 | psy->tzd = thermal_zone_device_register(psy->desc->name, |
| 951 | 0, 0, psy, &psy_tzd_ops, NULL, 0, 0); | 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 | return 0; | 960 | return 0; |
| @@ -17,6 +17,16 @@ menuconfig THERMAL · 16 unmodified lines | |||
| 17 | 17 | ||
| 18 | if THERMAL | 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 | config THERMAL_STATISTICS | 30 | config THERMAL_STATISTICS |
| 21 | bool "Thermal state transition statistics" | 31 | bool "Thermal state transition statistics" |
| 22 | help | 32 | help |
| @@ -180,16 +190,6 @@ config CPU_IDLE_THERMAL · 157 unmodified lines | |||
| 180 | idle cycle. | 190 | idle cycle. |
| 181 | endif | 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 | config DEVFREQ_THERMAL | 193 | config DEVFREQ_THERMAL |
| 194 | bool "Generic device cooling support" | 194 | bool "Generic device cooling support" |
| 195 | depends on PM_DEVFREQ | 195 | depends on PM_DEVFREQ |
| @@ -7,6 +7,9 @@ obj-$(CONFIG_THERMAL) += thermal_sys.o · 6 unmodified lines | |||
| 7 | thermal_sys-y += thermal_core.o thermal_sysfs.o \ | 7 | thermal_sys-y += thermal_core.o thermal_sysfs.o \ |
| 8 | thermal_helpers.o | 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 | # interface to/from other layers providing sensors | 13 | # interface to/from other layers providing sensors |
| 11 | thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o | 14 | thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o |
| 12 | thermal_sys-$(CONFIG_THERMAL_OF) += thermal_of.o | 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 | thermal_sys-$(CONFIG_CPU_FREQ_THERMAL) += cpufreq_cooling.o | 25 | thermal_sys-$(CONFIG_CPU_FREQ_THERMAL) += cpufreq_cooling.o |
| 23 | thermal_sys-$(CONFIG_CPU_IDLE_THERMAL) += cpuidle_cooling.o | 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 | # devfreq cooling | 28 | # devfreq cooling |
| 29 | thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o | 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 | return PTR_ERR(tz); | 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 | drvdata->type = LEGACY; | 883 | drvdata->type = LEGACY; |
| 878 | drvdata->data.tz = tz; | 884 | drvdata->data.tz = tz; |
| 879 | platform_set_drvdata(pdev, drvdata); | 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 | struct da9062 *hw; | 49 | struct da9062 *hw; |
| 50 | struct delayed_work work; | 50 | struct delayed_work work; |
| 51 | struct thermal_zone_device *zone; | 51 | struct thermal_zone_device *zone; |
| 52 | enum thermal_device_mode mode; | ||
| 53 | struct mutex lock; /* protection for da9062_thermal temperature */ | 52 | struct mutex lock; /* protection for da9062_thermal temperature */ |
| 54 | int temperature; | 53 | int temperature; |
| 55 | int irq; | 54 | int irq; |
| @@ -121,14 +120,6 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data) · 65 unmodified lines | |||
| 121 | return IRQ_HANDLED; | 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 | static int da9062_thermal_get_trip_type(struct thermal_zone_device *z, | 123 | static int da9062_thermal_get_trip_type(struct thermal_zone_device *z, |
| 133 | int trip, | 124 | int trip, |
| 134 | enum thermal_trip_type *type) | 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 | static struct thermal_zone_device_ops da9062_thermal_ops = { | 173 | static struct thermal_zone_device_ops da9062_thermal_ops = { |
| 183 | .get_temp = da9062_thermal_get_temp, | 174 | .get_temp = da9062_thermal_get_temp, |
| 184 | .get_mode = da9062_thermal_get_mode, | ||
| 185 | .get_trip_type = da9062_thermal_get_trip_type, | 175 | .get_trip_type = da9062_thermal_get_trip_type, |
| 186 | .get_trip_temp = da9062_thermal_get_trip_temp, | 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 | thermal->config = match->data; | 224 | thermal->config = match->data; |
| 235 | thermal->hw = chip; | 225 | thermal->hw = chip; |
| 236 | thermal->mode = THERMAL_DEVICE_ENABLED; | ||
| 237 | thermal->dev = &pdev->dev; | 226 | thermal->dev = &pdev->dev; |
| 238 | 227 | ||
| 239 | INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on); | 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 | ret = PTR_ERR(thermal->zone); | 237 | ret = PTR_ERR(thermal->zone); |
| 249 | goto err; | 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 | dev_dbg(&pdev->dev, | 246 | dev_dbg(&pdev->dev, |
| 253 | "TJUNC temperature polling period set at %d ms\n", | 247 | "TJUNC temperature polling period set at %d ms\n", |
| @@ -1,18 +1,10 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 1 | /* | 2 | /* |
| 2 | * devfreq_cooling: Thermal cooling device implementation for devices using | 3 | * devfreq_cooling: Thermal cooling device implementation for devices using |
| 3 | * devfreq | 4 | * devfreq |
| 4 | * | 5 | * |
| 5 | * Copyright (C) 2014-2015 ARM Limited | 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 | * TODO: | 8 | * TODO: |
| 17 | * - If OPPs are added or removed after devfreq cooling has | 9 | * - If OPPs are added or removed after devfreq cooling has |
| 18 | * registered, the devfreq cooling won't react to it. | 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 | return PTR_ERR(thermal); | 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 | platform_set_drvdata(pdev, thermal); | 162 | platform_set_drvdata(pdev, thermal); |
| 157 | 163 | ||
| 158 | return 0; | 164 | return 0; |
| @@ -1,16 +1,9 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 1 | /* | 2 | /* |
| 2 | * A power allocator to manage temperature | 3 | * A power allocator to manage temperature |
| 3 | * | 4 | * |
| 4 | * Copyright (C) 2014 ARM Ltd. | 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 | #define pr_fmt(fmt) "Power allocator: " fmt | 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 | struct thermal_zone_device *tzd = sensor->tzd; | 550 | struct thermal_zone_device *tzd = sensor->tzd; |
| 551 | 551 | ||
| 552 | tzd->ops->set_mode(tzd, | 552 | if (on) |
| 553 | on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED); | 553 | thermal_zone_device_enable(tzd); |
| 554 | else | ||
| 555 | thermal_zone_device_disable(tzd); | ||
| 554 | } | 556 | } |
| 555 | 557 | ||
| 556 | static int hisi_thermal_probe(struct platform_device *pdev) | 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 | { .compatible = "fsl,imx8mp-tmu", .data = &imx8mp_tmu_data, }, | 220 | { .compatible = "fsl,imx8mp-tmu", .data = &imx8mp_tmu_data, }, |
| 221 | { }, | 221 | { }, |
| 222 | }; | 222 | }; |
| 223 | MODULE_DEVICE_TABLE(of, imx8mm_tmu_table); | ||
| 223 | 224 | ||
| 224 | static struct platform_driver imx8mm_tmu = { | 225 | static struct platform_driver imx8mm_tmu = { |
| 225 | .driver = { | 226 | .driver = { |
| @@ -197,7 +197,6 @@ struct imx_thermal_data { · 196 unmodified lines | |||
| 197 | struct cpufreq_policy *policy; | 197 | struct cpufreq_policy *policy; |
| 198 | struct thermal_zone_device *tz; | 198 | struct thermal_zone_device *tz; |
| 199 | struct thermal_cooling_device *cdev; | 199 | struct thermal_cooling_device *cdev; |
| 200 | enum thermal_device_mode mode; | ||
| 201 | struct regmap *tempmon; | 200 | struct regmap *tempmon; |
| 202 | u32 c1, c2; /* See formula in imx_init_calib() */ | 201 | u32 c1, c2; /* See formula in imx_init_calib() */ |
| 203 | int temp_passive; | 202 | int temp_passive; |
| @@ -253,10 +252,11 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp) · 49 unmodified lines | |||
| 253 | const struct thermal_soc_data *soc_data = data->socdata; | 252 | const struct thermal_soc_data *soc_data = data->socdata; |
| 254 | struct regmap *map = data->tempmon; | 253 | struct regmap *map = data->tempmon; |
| 255 | unsigned int n_meas; | 254 | unsigned int n_meas; |
| 256 | bool wait; | 255 | bool wait, run_measurement; |
| 257 | u32 val; | 256 | u32 val; |
| 258 | 257 | ||
| 259 | if (data->mode == THERMAL_DEVICE_ENABLED) { | 258 | run_measurement = !data->irq_enabled; |
| 259 | if (!run_measurement) { | ||
| 260 | /* Check if a measurement is currently in progress */ | 260 | /* Check if a measurement is currently in progress */ |
| 261 | regmap_read(map, soc_data->temp_data, &val); | 261 | regmap_read(map, soc_data->temp_data, &val); |
| 262 | wait = !(val & soc_data->temp_valid_mask); | 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 | regmap_read(map, soc_data->temp_data, &val); | 284 | regmap_read(map, soc_data->temp_data, &val); |
| 285 | 285 | ||
| 286 | if (data->mode != THERMAL_DEVICE_ENABLED) { | 286 | if (run_measurement) { |
| 287 | regmap_write(map, soc_data->sensor_ctrl + REG_CLR, | 287 | regmap_write(map, soc_data->sensor_ctrl + REG_CLR, |
| 288 | soc_data->measure_temp_mask); | 288 | soc_data->measure_temp_mask); |
| 289 | regmap_write(map, soc_data->sensor_ctrl + REG_SET, | 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 | return 0; | 331 | return 0; |
| 332 | } | 332 | } |
| 333 | 333 | ||
| 334 | static int imx_get_mode(struct thermal_zone_device *tz, | 334 | static int imx_change_mode(struct thermal_zone_device *tz, |
| 335 | enum thermal_device_mode *mode) | 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) | ||
| 346 | { | 336 | { |
| 347 | struct imx_thermal_data *data = tz->devdata; | 337 | struct imx_thermal_data *data = tz->devdata; |
| 348 | struct regmap *map = data->tempmon; | 338 | struct regmap *map = data->tempmon; |
| 349 | const struct thermal_soc_data *soc_data = data->socdata; | 339 | const struct thermal_soc_data *soc_data = data->socdata; |
| 350 | 340 | ||
| 351 | if (mode == THERMAL_DEVICE_ENABLED) { | 341 | if (mode == THERMAL_DEVICE_ENABLED) { |
| 352 | tz->polling_delay = IMX_POLLING_DELAY; | ||
| 353 | tz->passive_delay = IMX_PASSIVE_DELAY; | ||
| 354 | |||
| 355 | regmap_write(map, soc_data->sensor_ctrl + REG_CLR, | 342 | regmap_write(map, soc_data->sensor_ctrl + REG_CLR, |
| 356 | soc_data->power_down_mask); | 343 | soc_data->power_down_mask); |
| 357 | regmap_write(map, soc_data->sensor_ctrl + REG_SET, | 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 | regmap_write(map, soc_data->sensor_ctrl + REG_SET, | 354 | regmap_write(map, soc_data->sensor_ctrl + REG_SET, |
| 368 | soc_data->power_down_mask); | 355 | soc_data->power_down_mask); |
| 369 | 356 | ||
| 370 | tz->polling_delay = 0; | ||
| 371 | tz->passive_delay = 0; | ||
| 372 | |||
| 373 | if (data->irq_enabled) { | 357 | if (data->irq_enabled) { |
| 374 | disable_irq(data->irq); | 358 | disable_irq(data->irq); |
| 375 | data->irq_enabled = false; | 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 | return 0; | 363 | return 0; |
| 383 | } | 364 | } |
| 384 | 365 | ||
| @@ -467,8 +448,7 @@ static struct thermal_zone_device_ops imx_tz_ops = { · 82 unmodified lines | |||
| 467 | .bind = imx_bind, | 448 | .bind = imx_bind, |
| 468 | .unbind = imx_unbind, | 449 | .unbind = imx_unbind, |
| 469 | .get_temp = imx_get_temp, | 450 | .get_temp = imx_get_temp, |
| 470 | .get_mode = imx_get_mode, | 451 | .change_mode = imx_change_mode, |
| 471 | .set_mode = imx_set_mode, | ||
| 472 | .get_trip_type = imx_get_trip_type, | 452 | .get_trip_type = imx_get_trip_type, |
| 473 | .get_trip_temp = imx_get_trip_temp, | 453 | .get_trip_temp = imx_get_trip_temp, |
| 474 | .get_crit_temp = imx_get_crit_temp, | 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 | data->socdata->measure_temp_mask); | 812 | data->socdata->measure_temp_mask); |
| 833 | 813 | ||
| 834 | data->irq_enabled = true; | 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 | ret = devm_request_threaded_irq(&pdev->dev, data->irq, | 819 | ret = devm_request_threaded_irq(&pdev->dev, data->irq, |
| 838 | imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread, | 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 | static int __maybe_unused imx_thermal_suspend(struct device *dev) | 856 | static int __maybe_unused imx_thermal_suspend(struct device *dev) |
| 875 | { | 857 | { |
| 876 | struct imx_thermal_data *data = dev_get_drvdata(dev); | 858 | struct imx_thermal_data *data = dev_get_drvdata(dev); |
| 877 | struct regmap *map = data->tempmon; | 859 | int ret; |
| 878 | 860 | ||
| 879 | /* | 861 | /* |
| 880 | * Need to disable thermal sensor, otherwise, when thermal core | 862 | * Need to disable thermal sensor, otherwise, when thermal core |
| 881 | * try to get temperature before thermal sensor resume, a wrong | 863 | * try to get temperature before thermal sensor resume, a wrong |
| 882 | * temperature will be read as the thermal sensor is powered | 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, | 868 | ret = thermal_zone_device_disable(data->tz); |
| 886 | data->socdata->measure_temp_mask); | 869 | if (ret) |
| 887 | regmap_write(map, data->socdata->sensor_ctrl + REG_SET, | 870 | return ret; |
| 888 | data->socdata->power_down_mask); | ||
| 889 | data->mode = THERMAL_DEVICE_DISABLED; | ||
| 890 | clk_disable_unprepare(data->thermal_clk); | 871 | clk_disable_unprepare(data->thermal_clk); |
| 891 | 872 | ||
| 892 | return 0; | 873 | return 0; |
| @@ -895,18 +876,15 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev) · 2 unmodified lines | |||
| 895 | static int __maybe_unused imx_thermal_resume(struct device *dev) | 876 | static int __maybe_unused imx_thermal_resume(struct device *dev) |
| 896 | { | 877 | { |
| 897 | struct imx_thermal_data *data = dev_get_drvdata(dev); | 878 | struct imx_thermal_data *data = dev_get_drvdata(dev); |
| 898 | struct regmap *map = data->tempmon; | ||
| 899 | int ret; | 879 | int ret; |
| 900 | 880 | ||
| 901 | ret = clk_prepare_enable(data->thermal_clk); | 881 | ret = clk_prepare_enable(data->thermal_clk); |
| 902 | if (ret) | 882 | if (ret) |
| 903 | return ret; | 883 | return ret; |
| 904 | /* Enabled thermal sensor after resume */ | 884 | /* Enabled thermal sensor after resume */ |
| 905 | regmap_write(map, data->socdata->sensor_ctrl + REG_CLR, | 885 | ret = thermal_zone_device_enable(data->tz); |
| 906 | data->socdata->power_down_mask); | 886 | if (ret) |
| 907 | regmap_write(map, data->socdata->sensor_ctrl + REG_SET, | 887 | return ret; |
| 908 | data->socdata->measure_temp_mask); | ||
| 909 | data->mode = THERMAL_DEVICE_ENABLED; | ||
| 910 | 888 | ||
| 911 | return 0; | 889 | return 0; |
| 912 | } | 890 | } |
| @@ -48,7 +48,6 @@ struct int3400_thermal_priv { · 47 unmodified lines | |||
| 48 | struct acpi_device *adev; | 48 | struct acpi_device *adev; |
| 49 | struct platform_device *pdev; | 49 | struct platform_device *pdev; |
| 50 | struct thermal_zone_device *thermal; | 50 | struct thermal_zone_device *thermal; |
| 51 | int mode; | ||
| 52 | int art_count; | 51 | int art_count; |
| 53 | struct art *arts; | 52 | struct art *arts; |
| 54 | int trt_count; | 53 | int trt_count; |
| @@ -383,42 +382,20 @@ static int int3400_thermal_get_temp(struct thermal_zone_device *thermal, · 328 unmodified lines | |||
| 383 | return 0; | 382 | return 0; |
| 384 | } | 383 | } |
| 385 | 384 | ||
| 386 | static int int3400_thermal_get_mode(struct thermal_zone_device *thermal, | 385 | static int int3400_thermal_change_mode(struct thermal_zone_device *thermal, |
| 387 | enum thermal_device_mode *mode) | 386 | enum thermal_device_mode mode) |
| 388 | { | 387 | { |
| 389 | struct int3400_thermal_priv *priv = thermal->devdata; | 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 | int result = 0; | 389 | int result = 0; |
| 405 | 390 | ||
| 406 | if (!priv) | 391 | if (!priv) |
| 407 | return -EINVAL; | 392 | return -EINVAL; |
| 408 | 393 | ||
| 409 | if (mode == THERMAL_DEVICE_ENABLED) | 394 | if (mode != thermal->mode) |
| 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; | ||
| 418 | result = int3400_thermal_run_osc(priv->adev->handle, | 395 | result = int3400_thermal_run_osc(priv->adev->handle, |
| 419 | priv->current_uuid_index, | 396 | priv->current_uuid_index, |
| 420 | enable); | 397 | mode == THERMAL_DEVICE_ENABLED); |
| 421 | } | 398 | |
| 422 | 399 | ||
| 423 | evaluate_odvp(priv); | 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 | static struct thermal_zone_device_ops int3400_thermal_ops = { | 405 | static struct thermal_zone_device_ops int3400_thermal_ops = { |
| 429 | .get_temp = int3400_thermal_get_temp, | 406 | .get_temp = int3400_thermal_get_temp, |
| 430 | .get_mode = int3400_thermal_get_mode, | 407 | .change_mode = int3400_thermal_change_mode, |
| 431 | .set_mode = int3400_thermal_set_mode, | ||
| 432 | }; | 408 | }; |
| 433 | 409 | ||
| 434 | static struct thermal_zone_params int3400_thermal_params = { | 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 | ret = PTR_ERR(int34x_thermal_zone->zone); | 259 | ret = PTR_ERR(int34x_thermal_zone->zone); |
| 260 | goto err_thermal_zone; | 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 | return int34x_thermal_zone; | 266 | return int34x_thermal_zone; |
| 264 | 267 | ||
| 268 | err_enable: | ||
| 269 | thermal_zone_device_unregister(int34x_thermal_zone->zone); | ||
| 265 | err_thermal_zone: | 270 | err_thermal_zone: |
| 266 | acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); | 271 | acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); |
| 267 | kfree(int34x_thermal_zone->aux_trips); | 272 | kfree(int34x_thermal_zone->aux_trips); |
| @@ -43,7 +43,7 @@ · 42 unmodified lines | |||
| 43 | #define PCI_DEVICE_ID_PROC_ICL_THERMAL 0x8a03 | 43 | #define PCI_DEVICE_ID_PROC_ICL_THERMAL 0x8a03 |
| 44 | 44 | ||
| 45 | /* JasperLake thermal reporting device */ | 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 | /* TigerLake thermal reporting device */ | 48 | /* TigerLake thermal reporting device */ |
| 49 | #define PCI_DEVICE_ID_PROC_TGL_THERMAL 0x9A03 | 49 | #define PCI_DEVICE_ID_PROC_TGL_THERMAL 0x9A03 |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | |||
| 24 | #define PCH_THERMAL_DID_SKL_H 0xA131 /* Skylake PCH 100 series */ | 24 | #define PCH_THERMAL_DID_SKL_H 0xA131 /* Skylake PCH 100 series */ |
| 25 | #define PCH_THERMAL_DID_CNL 0x9Df9 /* CNL PCH */ | 25 | #define PCH_THERMAL_DID_CNL 0x9Df9 /* CNL PCH */ |
| 26 | #define PCH_THERMAL_DID_CNL_H 0xA379 /* CNL-H PCH */ | 26 | #define PCH_THERMAL_DID_CNL_H 0xA379 /* CNL-H PCH */ |
| 27 | #define PCH_THERMAL_DID_CNL_LP 0x02F9 /* CNL-LP PCH */ | ||
| 27 | #define PCH_THERMAL_DID_CML_H 0X06F9 /* CML-H PCH */ | 28 | #define PCH_THERMAL_DID_CML_H 0X06F9 /* CML-H PCH */ |
| 28 | 29 | ||
| 29 | /* Wildcat Point-LP PCH Thermal registers */ | 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 | err = PTR_ERR(ptd->tzd); | 353 | err = PTR_ERR(ptd->tzd); |
| 353 | goto error_cleanup; | 354 | goto error_cleanup; |
| 354 | } | 355 | } |
| 356 | err = thermal_zone_device_enable(ptd->tzd); | ||
| 357 | if (err) | ||
| 358 | goto err_unregister; | ||
| 355 | 359 | ||
| 356 | return 0; | 360 | return 0; |
| 357 | 361 | ||
| 362 | err_unregister: | ||
| 363 | thermal_zone_device_unregister(ptd->tzd); | ||
| 358 | error_cleanup: | 364 | error_cleanup: |
| 359 | iounmap(ptd->hw_base); | 365 | iounmap(ptd->hw_base); |
| 360 | error_release: | 366 | error_release: |
| @@ -405,6 +411,8 @@ static const struct pci_device_id intel_pch_thermal_id[] = { · 44 unmodified lines | |||
| 405 | .driver_data = board_cnl, }, | 411 | .driver_data = board_cnl, }, |
| 406 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL_H), | 412 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL_H), |
| 407 | .driver_data = board_cnl, }, | 413 | .driver_data = board_cnl, }, |
| 414 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL_LP), | ||
| 415 | .driver_data = board_cnl, }, | ||
| 408 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CML_H), | 416 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CML_H), |
| 409 | .driver_data = board_cml, }, | 417 | .driver_data = board_cml, }, |
| 410 | { 0, }, | 418 | { 0, }, |
| @@ -103,7 +103,6 @@ struct soc_sensor_entry { · 102 unmodified lines | |||
| 103 | bool locked; | 103 | bool locked; |
| 104 | u32 store_ptps; | 104 | u32 store_ptps; |
| 105 | u32 store_dts_enable; | 105 | u32 store_dts_enable; |
| 106 | enum thermal_device_mode mode; | ||
| 107 | struct thermal_zone_device *tzone; | 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 | if (ret) | 126 | if (ret) |
| 128 | return ret; | 127 | return ret; |
| 129 | 128 | ||
| 130 | if (out & QRK_DTS_ENABLE_BIT) { | 129 | if (out & QRK_DTS_ENABLE_BIT) |
| 131 | aux_entry->mode = THERMAL_DEVICE_ENABLED; | ||
| 132 | return 0; | 130 | return 0; |
| 133 | } | ||
| 134 | 131 | ||
| 135 | if (!aux_entry->locked) { | 132 | if (!aux_entry->locked) { |
| 136 | out |= QRK_DTS_ENABLE_BIT; | 133 | out |= QRK_DTS_ENABLE_BIT; |
| @@ -138,10 +135,7 @@ static int soc_dts_enable(struct thermal_zone_device *tzd) · 1 unmodified line | |||
| 138 | QRK_DTS_REG_OFFSET_ENABLE, out); | 135 | QRK_DTS_REG_OFFSET_ENABLE, out); |
| 139 | if (ret) | 136 | if (ret) |
| 140 | return ret; | 137 | return ret; |
| 141 | |||
| 142 | aux_entry->mode = THERMAL_DEVICE_ENABLED; | ||
| 143 | } else { | 138 | } else { |
| 144 | aux_entry->mode = THERMAL_DEVICE_DISABLED; | ||
| 145 | pr_info("DTS is locked. Cannot enable DTS\n"); | 139 | pr_info("DTS is locked. Cannot enable DTS\n"); |
| 146 | ret = -EPERM; | 140 | ret = -EPERM; |
| 147 | } | 141 | } |
| @@ -160,10 +154,8 @@ static int soc_dts_disable(struct thermal_zone_device *tzd) · 12 unmodified lines | |||
| 160 | if (ret) | 154 | if (ret) |
| 161 | return ret; | 155 | return ret; |
| 162 | 156 | ||
| 163 | if (!(out & QRK_DTS_ENABLE_BIT)) { | 157 | if (!(out & QRK_DTS_ENABLE_BIT)) |
| 164 | aux_entry->mode = THERMAL_DEVICE_DISABLED; | ||
| 165 | return 0; | 158 | return 0; |
| 166 | } | ||
| 167 | 159 | ||
| 168 | if (!aux_entry->locked) { | 160 | if (!aux_entry->locked) { |
| 169 | out &= ~QRK_DTS_ENABLE_BIT; | 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 | if (ret) | 165 | if (ret) |
| 174 | return ret; | 166 | return ret; |
| 175 | |||
| 176 | aux_entry->mode = THERMAL_DEVICE_DISABLED; | ||
| 177 | } else { | 167 | } else { |
| 178 | aux_entry->mode = THERMAL_DEVICE_ENABLED; | ||
| 179 | pr_info("DTS is locked. Cannot disable DTS\n"); | 168 | pr_info("DTS is locked. Cannot disable DTS\n"); |
| 180 | ret = -EPERM; | 169 | ret = -EPERM; |
| 181 | } | 170 | } |
| @@ -309,16 +298,8 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, · 127 unmodified lines | |||
| 309 | return 0; | 298 | return 0; |
| 310 | } | 299 | } |
| 311 | 300 | ||
| 312 | static int sys_get_mode(struct thermal_zone_device *tzd, | 301 | static int sys_change_mode(struct thermal_zone_device *tzd, |
| 313 | enum thermal_device_mode *mode) | 302 | 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) | ||
| 322 | { | 303 | { |
| 323 | int ret; | 304 | int ret; |
| 324 | 305 | ||
| @@ -338,8 +319,7 @@ static struct thermal_zone_device_ops tzone_ops = { · 13 unmodified lines | |||
| 338 | .get_trip_type = sys_get_trip_type, | 319 | .get_trip_type = sys_get_trip_type, |
| 339 | .set_trip_temp = sys_set_trip_temp, | 320 | .set_trip_temp = sys_set_trip_temp, |
| 340 | .get_crit_temp = sys_get_crit_temp, | 321 | .get_crit_temp = sys_get_crit_temp, |
| 341 | .get_mode = sys_get_mode, | 322 | .change_mode = sys_change_mode, |
| 342 | .set_mode = sys_set_mode, | ||
| 343 | }; | 323 | }; |
| 344 | 324 | ||
| 345 | static void free_soc_dts(struct soc_sensor_entry *aux_entry) | 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 | goto err_ret; | 394 | goto err_ret; |
| 415 | } | 395 | } |
| 416 | 396 | ||
| 417 | mutex_lock(&dts_update_mutex); | 397 | err = thermal_zone_device_enable(aux_entry->tzone); |
| 418 | err = soc_dts_enable(aux_entry->tzone); | ||
| 419 | mutex_unlock(&dts_update_mutex); | ||
| 420 | if (err) | 398 | if (err) |
| 421 | goto err_aux_status; | 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 | ret = PTR_ERR(dts->tzone); | 329 | ret = PTR_ERR(dts->tzone); |
| 330 | goto err_ret; | 330 | goto err_ret; |
| 331 | } | 331 | } |
| 332 | ret = thermal_zone_device_enable(dts->tzone); | ||
| 333 | if (ret) | ||
| 334 | goto err_enable; | ||
| 332 | 335 | ||
| 333 | ret = soc_dts_enable(id); | 336 | ret = soc_dts_enable(id); |
| 334 | if (ret) | 337 | if (ret) |
| @@ -363,6 +363,12 @@ static int pkg_temp_thermal_device_add(unsigned int cpu) · 362 unmodified lines | |||
| 363 | kfree(zonedev); | 363 | kfree(zonedev); |
| 364 | return err; | 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 | /* Store MSR value for package thermal interrupt, to restore at exit */ | 372 | /* Store MSR value for package thermal interrupt, to restore at exit */ |
| 367 | rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, zonedev->msr_pkg_therm_low, | 373 | rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, zonedev->msr_pkg_therm_low, |
| 368 | zonedev->msr_pkg_therm_high); | 374 | zonedev->msr_pkg_therm_high); |
| @@ -65,6 +65,7 @@ static int kirkwood_thermal_probe(struct platform_device *pdev) · 64 unmodified lines | |||
| 65 | struct thermal_zone_device *thermal = NULL; | 65 | struct thermal_zone_device *thermal = NULL; |
| 66 | struct kirkwood_thermal_priv *priv; | 66 | struct kirkwood_thermal_priv *priv; |
| 67 | struct resource *res; | 67 | struct resource *res; |
| 68 | int ret; | ||
| 68 | 69 | ||
| 69 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | 70 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); |
| 70 | if (!priv) | 71 | if (!priv) |
| @@ -82,6 +83,12 @@ static int kirkwood_thermal_probe(struct platform_device *pdev) · 11 unmodified lines | |||
| 82 | "Failed to register thermal zone device\n"); | 83 | "Failed to register thermal zone device\n"); |
| 83 | return PTR_ERR(thermal); | 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 | platform_set_drvdata(pdev, thermal); | 93 | platform_set_drvdata(pdev, thermal); |
| 87 | 94 | ||
| @@ -38,6 +38,7 @@ · 37 unmodified lines | |||
| 38 | #define TEMP_MONIDET0 0x014 | 38 | #define TEMP_MONIDET0 0x014 |
| 39 | #define TEMP_MONIDET1 0x018 | 39 | #define TEMP_MONIDET1 0x018 |
| 40 | #define TEMP_MSRCTL0 0x038 | 40 | #define TEMP_MSRCTL0 0x038 |
| 41 | #define TEMP_MSRCTL1 0x03c | ||
| 41 | #define TEMP_AHBPOLL 0x040 | 42 | #define TEMP_AHBPOLL 0x040 |
| 42 | #define TEMP_AHBTO 0x044 | 43 | #define TEMP_AHBTO 0x044 |
| 43 | #define TEMP_ADCPNP0 0x048 | 44 | #define TEMP_ADCPNP0 0x048 |
| @@ -120,18 +121,32 @@ · 76 unmodified lines | |||
| 120 | * MT2701 has 3 sensors and needs 3 VTS calibration data. | 121 | * MT2701 has 3 sensors and needs 3 VTS calibration data. |
| 121 | * MT2712 has 4 sensors and needs 4 VTS calibration data. | 122 | * MT2712 has 4 sensors and needs 4 VTS calibration data. |
| 122 | */ | 123 | */ |
| 123 | #define CALIB_BUF0_VALID BIT(0) | 124 | #define CALIB_BUF0_VALID_V1 BIT(0) |
| 124 | #define CALIB_BUF1_ADC_GE(x) (((x) >> 22) & 0x3ff) | 125 | #define CALIB_BUF1_ADC_GE_V1(x) (((x) >> 22) & 0x3ff) |
| 125 | #define CALIB_BUF0_VTS_TS1(x) (((x) >> 17) & 0x1ff) | 126 | #define CALIB_BUF0_VTS_TS1_V1(x) (((x) >> 17) & 0x1ff) |
| 126 | #define CALIB_BUF0_VTS_TS2(x) (((x) >> 8) & 0x1ff) | 127 | #define CALIB_BUF0_VTS_TS2_V1(x) (((x) >> 8) & 0x1ff) |
| 127 | #define CALIB_BUF1_VTS_TS3(x) (((x) >> 0) & 0x1ff) | 128 | #define CALIB_BUF1_VTS_TS3_V1(x) (((x) >> 0) & 0x1ff) |
| 128 | #define CALIB_BUF2_VTS_TS4(x) (((x) >> 23) & 0x1ff) | 129 | #define CALIB_BUF2_VTS_TS4_V1(x) (((x) >> 23) & 0x1ff) |
| 129 | #define CALIB_BUF2_VTS_TS5(x) (((x) >> 5) & 0x1ff) | 130 | #define CALIB_BUF2_VTS_TS5_V1(x) (((x) >> 5) & 0x1ff) |
| 130 | #define CALIB_BUF2_VTS_TSABB(x) (((x) >> 14) & 0x1ff) | 131 | #define CALIB_BUF2_VTS_TSABB_V1(x) (((x) >> 14) & 0x1ff) |
| 131 | #define CALIB_BUF0_DEGC_CALI(x) (((x) >> 1) & 0x3f) | 132 | #define CALIB_BUF0_DEGC_CALI_V1(x) (((x) >> 1) & 0x3f) |
| 132 | #define CALIB_BUF0_O_SLOPE(x) (((x) >> 26) & 0x3f) | 133 | #define CALIB_BUF0_O_SLOPE_V1(x) (((x) >> 26) & 0x3f) |
| 133 | #define CALIB_BUF0_O_SLOPE_SIGN(x) (((x) >> 7) & 0x1) | 134 | #define CALIB_BUF0_O_SLOPE_SIGN_V1(x) (((x) >> 7) & 0x1) |
| 134 | #define CALIB_BUF1_ID(x) (((x) >> 9) & 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 | enum { | 151 | enum { |
| 137 | VTS1, | 152 | VTS1, |
| @@ -143,6 +158,11 @@ enum { · 5 unmodified lines | |||
| 143 | MAX_NUM_VTS, | 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 | /* MT2701 thermal sensors */ | 166 | /* MT2701 thermal sensors */ |
| 147 | #define MT2701_TS1 0 | 167 | #define MT2701_TS1 0 |
| 148 | #define MT2701_TS2 1 | 168 | #define MT2701_TS2 1 |
| @@ -248,6 +268,7 @@ struct mtk_thermal_data { · 99 unmodified lines | |||
| 248 | const int *controller_offset; | 268 | const int *controller_offset; |
| 249 | bool need_switch_bank; | 269 | bool need_switch_bank; |
| 250 | struct thermal_bank_cfg bank_data[MAX_NUM_ZONES]; | 270 | struct thermal_bank_cfg bank_data[MAX_NUM_ZONES]; |
| 271 | enum mtk_thermal_version version; | ||
| 251 | }; | 272 | }; |
| 252 | 273 | ||
| 253 | struct mtk_thermal { | 274 | struct mtk_thermal { |
| @@ -261,8 +282,10 @@ struct mtk_thermal { · 7 unmodified lines | |||
| 261 | 282 | ||
| 262 | /* Calibration values */ | 283 | /* Calibration values */ |
| 263 | s32 adc_ge; | 284 | s32 adc_ge; |
| 285 | s32 adc_oe; | ||
| 264 | s32 degc_cali; | 286 | s32 degc_cali; |
| 265 | s32 o_slope; | 287 | s32 o_slope; |
| 288 | s32 o_slope_sign; | ||
| 266 | s32 vts[MAX_NUM_VTS]; | 289 | s32 vts[MAX_NUM_VTS]; |
| 267 | 290 | ||
| 268 | const struct mtk_thermal_data *conf; | 291 | const struct mtk_thermal_data *conf; |
| @@ -401,6 +424,7 @@ static const struct mtk_thermal_data mt8173_thermal_data = { · 132 unmodified lines | |||
| 401 | .msr = mt8173_msr, | 424 | .msr = mt8173_msr, |
| 402 | .adcpnp = mt8173_adcpnp, | 425 | .adcpnp = mt8173_adcpnp, |
| 403 | .sensor_mux_values = mt8173_mux_values, | 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 | .msr = mt2701_msr, | 455 | .msr = mt2701_msr, |
| 432 | .adcpnp = mt2701_adcpnp, | 456 | .adcpnp = mt2701_adcpnp, |
| 433 | .sensor_mux_values = mt2701_mux_values, | 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 | .msr = mt2712_msr, | 486 | .msr = mt2712_msr, |
| 462 | .adcpnp = mt2712_adcpnp, | 487 | .adcpnp = mt2712_adcpnp, |
| 463 | .sensor_mux_values = mt2712_mux_values, | 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 | .msr = mt7622_msr, | 511 | .msr = mt7622_msr, |
| 486 | .adcpnp = mt7622_adcpnp, | 512 | .adcpnp = mt7622_adcpnp, |
| 487 | .sensor_mux_values = mt7622_mux_values, | 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 | .msr = mt8183_msr, | 544 | .msr = mt8183_msr, |
| 518 | .adcpnp = mt8183_adcpnp, | 545 | .adcpnp = mt8183_adcpnp, |
| 519 | .sensor_mux_values = mt8183_mux_values, | 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 | * This converts the raw ADC value to mcelsius using the SoC specific | 556 | * This converts the raw ADC value to mcelsius using the SoC specific |
| 529 | * calibration constants | 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 | s32 tmp; | 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 | return mt->degc_cali * 500 - tmp; | 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 | * mtk_thermal_get_bank - get bank | 605 | * mtk_thermal_get_bank - get bank |
| 548 | * @bank: The bank | 606 | * @bank: The bank |
| @@ -596,9 +654,13 @@ static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank) · 47 unmodified lines | |||
| 596 | for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) { | 654 | for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) { |
| 597 | raw = readl(mt->thermal_base + conf->msr[i]); | 655 | raw = readl(mt->thermal_base + conf->msr[i]); |
| 598 | 656 | ||
| 599 | temp = raw_to_mcelsius(mt, | 657 | if (mt->conf->version == MTK_THERMAL_V1) { |
| 600 | conf->bank_data[bank->id].sensors[i], | 658 | temp = raw_to_mcelsius_v1( |
| 601 | raw); | 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 | * The first read of a sensor often contains very high bogus | 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 | writel(auxadc_phys_base + AUXADC_CON1_CLR_V, | 762 | writel(auxadc_phys_base + AUXADC_CON1_CLR_V, |
| 701 | controller_base + TEMP_ADCMUXADDR); | 763 | controller_base + TEMP_ADCMUXADDR); |
| 702 | 764 | ||
| 703 | /* AHB address for pnp sensor mux selection */ | 765 | if (mt->conf->version == MTK_THERMAL_V1) { |
| 704 | writel(apmixed_phys_base + APMIXED_SYS_TS_CON1, | 766 | /* AHB address for pnp sensor mux selection */ |
| 705 | controller_base + TEMP_PNPMUXADDR); | 767 | writel(apmixed_phys_base + APMIXED_SYS_TS_CON1, |
| 768 | controller_base + TEMP_PNPMUXADDR); | ||
| 769 | } | ||
| 706 | 770 | ||
| 707 | /* AHB value for auxadc enable */ | 771 | /* AHB value for auxadc enable */ |
| 708 | writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCEN); | 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 | return of_translate_address(np, regaddr_p); | 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 | static int mtk_thermal_get_calibration_data(struct device *dev, | 888 | static int mtk_thermal_get_calibration_data(struct device *dev, |
| 763 | struct mtk_thermal *mt) | 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 | goto out; | 920 | goto out; |
| 795 | } | 921 | } |
| 796 | 922 | ||
| 797 | if (buf[0] & CALIB_BUF0_VALID) { | 923 | if (mt->conf->version == MTK_THERMAL_V1) |
| 798 | mt->adc_ge = CALIB_BUF1_ADC_GE(buf[1]); | 924 | ret = mtk_thermal_extract_efuse_v1(mt, buf); |
| 799 | 925 | else | |
| 800 | for (i = 0; i < mt->conf->num_sensors; i++) { | 926 | ret = mtk_thermal_extract_efuse_v2(mt, buf); |
| 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 | } | ||
| 824 | 927 | ||
| 825 | mt->degc_cali = CALIB_BUF0_DEGC_CALI(buf[0]); | 928 | if (ret) { |
| 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 { | ||
| 832 | dev_info(dev, "Device not calibrated, using default calibration values\n"); | 929 | dev_info(dev, "Device not calibrated, using default calibration values\n"); |
| 930 | ret = 0; | ||
| 833 | } | 931 | } |
| 834 | 932 | ||
| 835 | out: | 933 | out: |
| @@ -863,6 +961,28 @@ static const struct of_device_id mtk_thermal_of_match[] = { · 27 unmodified lines | |||
| 863 | }; | 961 | }; |
| 864 | MODULE_DEVICE_TABLE(of, mtk_thermal_of_match); | 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 | static int mtk_thermal_probe(struct platform_device *pdev) | 986 | static int mtk_thermal_probe(struct platform_device *pdev) |
| 867 | { | 987 | { |
| 868 | int ret, i, ctrl_id; | 988 | int ret, i, ctrl_id; |
| @@ -871,6 +991,7 @@ static int mtk_thermal_probe(struct platform_device *pdev) · 2 unmodified lines | |||
| 871 | struct resource *res; | 991 | struct resource *res; |
| 872 | u64 auxadc_phys_base, apmixed_phys_base; | 992 | u64 auxadc_phys_base, apmixed_phys_base; |
| 873 | struct thermal_zone_device *tzdev; | 993 | struct thermal_zone_device *tzdev; |
| 994 | void __iomem *apmixed_base, *auxadc_base; | ||
| 874 | 995 | ||
| 875 | mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL); | 996 | mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL); |
| 876 | if (!mt) | 997 | if (!mt) |
| @@ -905,6 +1026,7 @@ static int mtk_thermal_probe(struct platform_device *pdev) · 28 unmodified lines | |||
| 905 | return -ENODEV; | 1026 | return -ENODEV; |
| 906 | } | 1027 | } |
| 907 | 1028 | ||
| 1029 | auxadc_base = of_iomap(auxadc, 0); | ||
| 908 | auxadc_phys_base = of_get_phys_base(auxadc); | 1030 | auxadc_phys_base = of_get_phys_base(auxadc); |
| 909 | 1031 | ||
| 910 | of_node_put(auxadc); | 1032 | of_node_put(auxadc); |
| @@ -920,6 +1042,7 @@ static int mtk_thermal_probe(struct platform_device *pdev) · 9 unmodified lines | |||
| 920 | return -ENODEV; | 1042 | return -ENODEV; |
| 921 | } | 1043 | } |
| 922 | 1044 | ||
| 1045 | apmixed_base = of_iomap(apmixedsys, 0); | ||
| 923 | apmixed_phys_base = of_get_phys_base(apmixedsys); | 1046 | apmixed_phys_base = of_get_phys_base(apmixedsys); |
| 924 | 1047 | ||
| 925 | of_node_put(apmixedsys); | 1048 | of_node_put(apmixedsys); |
| @@ -945,6 +1068,11 @@ static int mtk_thermal_probe(struct platform_device *pdev) · 19 unmodified lines | |||
| 945 | goto err_disable_clk_auxadc; | 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 | for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++) | 1076 | for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++) |
| 949 | for (i = 0; i < mt->conf->num_banks; i++) | 1077 | for (i = 0; i < mt->conf->num_banks; i++) |
| 950 | mtk_thermal_init_bank(mt, i, apmixed_phys_base, | 1078 | mtk_thermal_init_bank(mt, i, apmixed_phys_base, |
| @@ -48,6 +48,63 @@ · 47 unmodified lines | |||
| 48 | #define MSM8916_CAL_SEL_MASK 0xe0000000 | 48 | #define MSM8916_CAL_SEL_MASK 0xe0000000 |
| 49 | #define MSM8916_CAL_SEL_SHIFT 29 | 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 | /* eeprom layout data for 8974 */ | 108 | /* eeprom layout data for 8974 */ |
| 52 | #define BASE1_MASK 0xff | 109 | #define BASE1_MASK 0xff |
| 53 | #define S0_P1_MASK 0x3f00 | 110 | #define S0_P1_MASK 0x3f00 |
| @@ -189,6 +246,76 @@ static int calibrate_8916(struct tsens_priv *priv) · 135 unmodified lines | |||
| 189 | return 0; | 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 | static int calibrate_8974(struct tsens_priv *priv) | 319 | static int calibrate_8974(struct tsens_priv *priv) |
| 193 | { | 320 | { |
| 194 | int base1 = 0, base2 = 0, i; | 321 | int base1 = 0, base2 = 0, i; |
| @@ -325,7 +452,7 @@ static int calibrate_8974(struct tsens_priv *priv) · 130 unmodified lines | |||
| 325 | return 0; | 452 | return 0; |
| 326 | } | 453 | } |
| 327 | 454 | ||
| 328 | /* v0.1: 8916, 8974 */ | 455 | /* v0.1: 8916, 8939, 8974 */ |
| 329 | 456 | ||
| 330 | static struct tsens_features tsens_v0_1_feat = { | 457 | static struct tsens_features tsens_v0_1_feat = { |
| 331 | .ver_major = VER_0_1, | 458 | .ver_major = VER_0_1, |
| @@ -386,6 +513,21 @@ struct tsens_plat_data data_8916 = { · 54 unmodified lines | |||
| 386 | .fields = tsens_v0_1_regfields, | 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 | static const struct tsens_ops ops_8974 = { | 531 | static const struct tsens_ops ops_8974 = { |
| 390 | .init = init_common, | 532 | .init = init_common, |
| 391 | .calibrate = calibrate_8974, | 533 | .calibrate = calibrate_8974, |
| @@ -897,6 +897,9 @@ static const struct of_device_id tsens_table[] = { · 896 unmodified lines | |||
| 897 | { | 897 | { |
| 898 | .compatible = "qcom,msm8916-tsens", | 898 | .compatible = "qcom,msm8916-tsens", |
| 899 | .data = &data_8916, | 899 | .data = &data_8916, |
| 900 | }, { | ||
| 901 | .compatible = "qcom,msm8939-tsens", | ||
| 902 | .data = &data_8939, | ||
| 900 | }, { | 903 | }, { |
| 901 | .compatible = "qcom,msm8974-tsens", | 904 | .compatible = "qcom,msm8974-tsens", |
| 902 | .data = &data_8974, | 905 | .data = &data_8974, |
| @@ -585,7 +585,7 @@ int get_temp_common(const struct tsens_sensor *s, int *temp); · 584 unmodified lines | |||
| 585 | extern struct tsens_plat_data data_8960; | 585 | extern struct tsens_plat_data data_8960; |
| 586 | 586 | ||
| 587 | /* TSENS v0.1 targets */ | 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 | /* TSENS v1 targets */ | 590 | /* TSENS v1 targets */ |
| 591 | extern struct tsens_plat_data data_tsens_v1, data_8976; | 591 | extern struct tsens_plat_data data_tsens_v1, data_8976; |
| @@ -63,7 +63,7 @@ · 62 unmodified lines | |||
| 63 | #define TSC_MAX_NUM 3 | 63 | #define TSC_MAX_NUM 3 |
| 64 | 64 | ||
| 65 | /* default THCODE values if FUSEs are missing */ | 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 | { 3397, 2800, 2221 }, | 67 | { 3397, 2800, 2221 }, |
| 68 | { 3393, 2795, 2216 }, | 68 | { 3393, 2795, 2216 }, |
| 69 | { 3389, 2805, 2237 }, | 69 | { 3389, 2805, 2237 }, |
| @@ -172,7 +172,7 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp) · 102 unmodified lines | |||
| 172 | /* Read register and convert to mili Celsius */ | 172 | /* Read register and convert to mili Celsius */ |
| 173 | reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK; | 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 | val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, | 176 | val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, |
| 177 | tsc->coef.a1); | 177 | tsc->coef.a1); |
| 178 | else | 178 | else |
| @@ -314,6 +314,10 @@ static const struct of_device_id rcar_gen3_thermal_dt_ids[] = { · 135 unmodified lines | |||
| 314 | .compatible = "renesas,r8a774b1-thermal", | 314 | .compatible = "renesas,r8a774b1-thermal", |
| 315 | .data = &rcar_gen3_ths_tj_1, | 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 | .compatible = "renesas,r8a7795-thermal", | 322 | .compatible = "renesas,r8a7795-thermal", |
| 319 | .data = &rcar_gen3_ths_tj_1, | 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 | priv->tscs[i] = tsc; | 434 | priv->tscs[i] = tsc; |
| 431 | 435 | ||
| 432 | priv->thermal_init(tsc); | 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 | *rcar_gen3_ths_tj_1); | 438 | *rcar_gen3_ths_tj_1); |
| 435 | 439 | ||
| 436 | zone = devm_thermal_zone_of_sensor_register(dev, i, tsc, | 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 | priv->zone = devm_thermal_zone_of_sensor_register( | 550 | priv->zone = devm_thermal_zone_of_sensor_register( |
| 551 | dev, i, priv, | 551 | dev, i, priv, |
| 552 | &rcar_thermal_zone_of_ops); | 552 | &rcar_thermal_zone_of_ops); |
| 553 | else | 553 | else { |
| 554 | priv->zone = thermal_zone_device_register( | 554 | priv->zone = thermal_zone_device_register( |
| 555 | "rcar_thermal", | 555 | "rcar_thermal", |
| 556 | 1, 0, priv, | 556 | 1, 0, priv, |
| 557 | &rcar_thermal_zone_ops, NULL, 0, | 557 | &rcar_thermal_zone_ops, NULL, 0, |
| 558 | idle); | 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 | if (IS_ERR(priv->zone)) { | 566 | if (IS_ERR(priv->zone)) { |
| 560 | dev_err(dev, "can't register thermal zone\n"); | 567 | dev_err(dev, "can't register thermal zone\n"); |
| 561 | ret = PTR_ERR(priv->zone); | 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 | struct thermal_zone_device *tzd = sensor->tzd; | 1069 | struct thermal_zone_device *tzd = sensor->tzd; |
| 1070 | 1070 | ||
| 1071 | tzd->ops->set_mode(tzd, | 1071 | if (on) |
| 1072 | on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED); | 1072 | thermal_zone_device_enable(tzd); |
| 1073 | else | ||
| 1074 | thermal_zone_device_disable(tzd); | ||
| 1073 | } | 1075 | } |
| 1074 | 1076 | ||
| 1075 | static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev) | 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 | ret = PTR_ERR(spear_thermal); | 131 | ret = PTR_ERR(spear_thermal); |
| 132 | goto disable_clk; | 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 | platform_set_drvdata(pdev, spear_thermal); | 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 | return 0; | 145 | return 0; |
| 141 | 146 | ||
| 147 | unregister_tzd: | ||
| 148 | thermal_zone_device_unregister(spear_thermal); | ||
| 142 | disable_clk: | 149 | disable_clk: |
| 143 | clk_disable(stdev->clk); | 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 | struct thermal_zone_device *tzd = sen->tzd; | 323 | struct thermal_zone_device *tzd = sen->tzd; |
| 324 | 324 | ||
| 325 | tzd->ops->set_mode(tzd, | 325 | if (on) |
| 326 | on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED); | 326 | thermal_zone_device_enable(tzd); |
| 327 | else | ||
| 328 | thermal_zone_device_disable(tzd); | ||
| 327 | } | 329 | } |
| 328 | 330 | ||
| 329 | static int sprd_thm_probe(struct platform_device *pdev) | 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 | ret = PTR_ERR(sensor->thermal_dev); | 246 | ret = PTR_ERR(sensor->thermal_dev); |
| 247 | goto sensor_off; | 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 | platform_set_drvdata(pdev, sensor); | 253 | platform_set_drvdata(pdev, sensor); |
| 251 | 254 | ||
| 252 | return 0; | 255 | return 0; |
| 253 | 256 | ||
| 257 | tzd_unregister: | ||
| 258 | thermal_zone_device_unregister(sensor->thermal_dev); | ||
| 254 | sensor_off: | 259 | sensor_off: |
| 255 | st_thermal_sensor_off(sensor); | 260 | st_thermal_sensor_off(sensor); |
| 256 | 261 | ||
| @@ -215,6 +215,8 @@ exit: · 214 unmodified lines | |||
| 215 | mutex_unlock(&tz->lock); | 215 | mutex_unlock(&tz->lock); |
| 216 | mutex_unlock(&thermal_governor_lock); | 216 | mutex_unlock(&thermal_governor_lock); |
| 217 | 217 | ||
| 218 | thermal_notify_tz_gov_change(tz->id, policy); | ||
| 219 | |||
| 218 | return ret; | 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 | cancel_delayed_work(&tz->poll_queue); | 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 | static void monitor_thermal_zone(struct thermal_zone_device *tz) | 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 | mutex_lock(&tz->lock); | 317 | mutex_lock(&tz->lock); |
| 307 | 318 | ||
| 308 | if (tz->passive) | 319 | if (!stop && tz->passive) |
| 309 | thermal_zone_device_set_polling(tz, tz->passive_delay); | 320 | thermal_zone_device_set_polling(tz, tz->passive_delay); |
| 310 | else if (tz->polling_delay) | 321 | else if (!stop && tz->polling_delay) |
| 311 | thermal_zone_device_set_polling(tz, tz->polling_delay); | 322 | thermal_zone_device_set_polling(tz, tz->polling_delay); |
| 312 | else | 323 | else |
| 313 | thermal_zone_device_set_polling(tz, 0); | 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 | static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) | 417 | static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) |
| 407 | { | 418 | { |
| 408 | enum thermal_trip_type type; | 419 | enum thermal_trip_type type; |
| 420 | int trip_temp, hyst = 0; | ||
| 409 | 421 | ||
| 410 | /* Ignore disabled trip points */ | 422 | /* Ignore disabled trip points */ |
| 411 | if (test_bit(trip, &tz->trips_disabled)) | 423 | if (test_bit(trip, &tz->trips_disabled)) |
| 412 | return; | 424 | return; |
| 413 | 425 | ||
| 426 | tz->ops->get_trip_temp(tz, trip, &trip_temp); | ||
| 414 | tz->ops->get_trip_type(tz, trip, &type); | 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 | if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT) | 440 | if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT) |
| 417 | handle_critical_trips(tz, trip, type); | 441 | handle_critical_trips(tz, trip, type); |
| @@ -443,6 +467,8 @@ static void update_temperature(struct thermal_zone_device *tz) · 25 unmodified lines | |||
| 443 | mutex_unlock(&tz->lock); | 467 | mutex_unlock(&tz->lock); |
| 444 | 468 | ||
| 445 | trace_thermal_temperature(tz); | 469 | trace_thermal_temperature(tz); |
| 470 | |||
| 471 | thermal_genl_sampling_temp(tz->id, temp); | ||
| 446 | } | 472 | } |
| 447 | 473 | ||
| 448 | static void thermal_zone_device_init(struct thermal_zone_device *tz) | 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 | thermal_zone_device_init(tz); | 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 | void thermal_zone_device_update(struct thermal_zone_device *tz, | 545 | void thermal_zone_device_update(struct thermal_zone_device *tz, |
| 463 | enum thermal_notify_event event) | 546 | enum thermal_notify_event event) |
| 464 | { | 547 | { |
| 465 | int count; | 548 | int count; |
| 466 | 549 | ||
| 550 | if (should_stop_polling(tz)) | ||
| 551 | return; | ||
| 552 | |||
| 467 | if (atomic_read(&in_suspend)) | 553 | if (atomic_read(&in_suspend)) |
| 468 | return; | 554 | return; |
| 469 | 555 | ||
| @@ -617,6 +703,73 @@ void thermal_zone_device_rebind_exception(struct thermal_zone_device *tz, · 147 unmodified lines | |||
| 617 | mutex_unlock(&thermal_list_lock); | 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 | void thermal_zone_device_unbind_exception(struct thermal_zone_device *tz, | 773 | void thermal_zone_device_unbind_exception(struct thermal_zone_device *tz, |
| 621 | const char *cdev_type, size_t size) | 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 | if (atomic_cmpxchg(&tz->need_update, 1, 0)) | 1493 | if (atomic_cmpxchg(&tz->need_update, 1, 0)) |
| 1341 | thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); | 1494 | thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); |
| 1342 | 1495 | ||
| 1496 | thermal_notify_tz_create(tz->id, tz->type); | ||
| 1497 | |||
| 1343 | return tz; | 1498 | return tz; |
| 1344 | 1499 | ||
| 1345 | unregister: | 1500 | unregister: |
| @@ -1411,6 +1566,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) · 65 unmodified lines | |||
| 1411 | ida_destroy(&tz->ida); | 1566 | ida_destroy(&tz->ida); |
| 1412 | mutex_destroy(&tz->lock); | 1567 | mutex_destroy(&tz->lock); |
| 1413 | device_unregister(&tz->device); | 1568 | device_unregister(&tz->device); |
| 1569 | |||
| 1570 | thermal_notify_tz_delete(tz->id); | ||
| 1414 | } | 1571 | } |
| 1415 | EXPORT_SYMBOL_GPL(thermal_zone_device_unregister); | 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 | unsigned long mode, void *_unused) | 1613 | unsigned long mode, void *_unused) |
| 1457 | { | 1614 | { |
| 1458 | struct thermal_zone_device *tz; | 1615 | struct thermal_zone_device *tz; |
| 1459 | enum thermal_device_mode tz_mode; | ||
| 1460 | 1616 | ||
| 1461 | switch (mode) { | 1617 | switch (mode) { |
| 1462 | case PM_HIBERNATION_PREPARE: | 1618 | case PM_HIBERNATION_PREPARE: |
| @@ -1469,11 +1625,7 @@ static int thermal_pm_notify(struct notifier_block *nb, · 6 unmodified lines | |||
| 1469 | case PM_POST_SUSPEND: | 1625 | case PM_POST_SUSPEND: |
| 1470 | atomic_set(&in_suspend, 0); | 1626 | atomic_set(&in_suspend, 0); |
| 1471 | list_for_each_entry(tz, &thermal_tz_list, node) { | 1627 | list_for_each_entry(tz, &thermal_tz_list, node) { |
| 1472 | tz_mode = THERMAL_DEVICE_ENABLED; | 1628 | if (!thermal_zone_device_is_enabled(tz)) |
| 1473 | if (tz->ops->get_mode) | ||
| 1474 | tz->ops->get_mode(tz, &tz_mode); | ||
| 1475 | |||
| 1476 | if (tz_mode == THERMAL_DEVICE_DISABLED) | ||
| 1477 | continue; | 1629 | continue; |
| 1478 | 1630 | ||
| 1479 | thermal_zone_device_init(tz); | 1631 | thermal_zone_device_init(tz); |
| @@ -1495,6 +1647,10 @@ static int __init thermal_init(void) · 15 unmodified lines | |||
| 1495 | { | 1647 | { |
| 1496 | int result; | 1648 | int result; |
| 1497 | 1649 | ||
| 1650 | result = thermal_netlink_init(); | ||
| 1651 | if (result) | ||
| 1652 | goto error; | ||
| 1653 | |||
| 1498 | mutex_init(&poweroff_lock); | 1654 | mutex_init(&poweroff_lock); |
| 1499 | result = thermal_register_governors(); | 1655 | result = thermal_register_governors(); |
| 1500 | if (result) | 1656 | if (result) |
| @@ -1527,4 +1683,4 @@ error: · 26 unmodified lines | |||
| 1527 | mutex_destroy(&poweroff_lock); | 1683 | mutex_destroy(&poweroff_lock); |
| 1528 | return result; | 1684 | return result; |
| 1529 | } | 1685 | } |
| 1530 | core_initcall(thermal_init); | 1686 | postcore_initcall(thermal_init); |
| @@ -12,6 +12,8 @@ · 11 unmodified lines | |||
| 12 | #include <linux/device.h> | 12 | #include <linux/device.h> |
| 13 | #include <linux/thermal.h> | 13 | #include <linux/thermal.h> |
| 14 | 14 | ||
| 15 | #include "thermal_netlink.h" | ||
| 16 | |||
| 15 | /* Default Thermal Governor */ | 17 | /* Default Thermal Governor */ |
| 16 | #if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE) | 18 | #if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE) |
| 17 | #define DEFAULT_THERMAL_GOVERNOR "step_wise" | 19 | #define DEFAULT_THERMAL_GOVERNOR "step_wise" |
| @@ -41,6 +43,17 @@ extern struct thermal_governor *__governor_thermal_table_end[]; · 23 unmodified lines | |||
| 41 | __governor < __governor_thermal_table_end; \ | 43 | __governor < __governor_thermal_table_end; \ |
| 42 | __governor++) | 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 | struct thermal_attr { | 57 | struct thermal_attr { |
| 45 | struct device_attribute attr; | 58 | struct device_attribute attr; |
| 46 | char name[THERMAL_NAME_LENGTH]; | 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 | #endif | 180 | #endif |
| 168 | 181 | ||
| 182 | int thermal_zone_device_is_enabled(struct thermal_zone_device *tz); | ||
| 183 | |||
| 169 | #endif /* __THERMAL_CORE_H__ */ | 184 | #endif /* __THERMAL_CORE_H__ */ |
| @@ -175,6 +175,16 @@ exit: · 174 unmodified lines | |||
| 175 | mutex_unlock(&tz->lock); | 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 | void thermal_cdev_update(struct thermal_cooling_device *cdev) | 188 | void thermal_cdev_update(struct thermal_cooling_device *cdev) |
| 179 | { | 189 | { |
| 180 | struct thermal_instance *instance; | 190 | struct thermal_instance *instance; |
| @@ -197,8 +207,7 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev) · 16 unmodified lines | |||
| 197 | target = instance->target; | 207 | target = instance->target; |
| 198 | } | 208 | } |
| 199 | 209 | ||
| 200 | if (!cdev->ops->set_cur_state(cdev, target)) | 210 | thermal_cdev_set_cur_state(cdev, target); |
| 201 | thermal_cooling_device_stats_update(cdev, target); | ||
| 202 | 211 | ||
| 203 | cdev->updated = true; | 212 | cdev->updated = true; |
| 204 | mutex_unlock(&cdev->lock); | 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 | * struct __thermal_zone - internal representation of a thermal zone | 53 | * struct __thermal_zone - internal representation of a thermal zone |
| 54 | * @mode: current thermal zone device mode (enabled/disabled) | ||
| 55 | * @passive_delay: polling interval while passive cooling is activated | 54 | * @passive_delay: polling interval while passive cooling is activated |
| 56 | * @polling_delay: zone polling interval | 55 | * @polling_delay: zone polling interval |
| 57 | * @slope: slope of the temperature adjustment curve | 56 | * @slope: slope of the temperature adjustment curve |
| @@ -65,7 +64,6 @@ struct __thermal_bind_params { · 7 unmodified lines | |||
| 65 | */ | 64 | */ |
| 66 | 65 | ||
| 67 | struct __thermal_zone { | 66 | struct __thermal_zone { |
| 68 | enum thermal_device_mode mode; | ||
| 69 | int passive_delay; | 67 | int passive_delay; |
| 70 | int polling_delay; | 68 | int polling_delay; |
| 71 | int slope; | 69 | int slope; |
| @@ -269,39 +267,6 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal, · 197 unmodified lines | |||
| 269 | return 0; | 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 | static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip, | 270 | static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip, |
| 306 | enum thermal_trip_type *type) | 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 | static struct thermal_zone_device_ops of_thermal_ops = { | 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 | .get_trip_type = of_thermal_get_trip_type, | 361 | .get_trip_type = of_thermal_get_trip_type, |
| 400 | .get_trip_temp = of_thermal_get_trip_temp, | 362 | .get_trip_temp = of_thermal_get_trip_temp, |
| 401 | .set_trip_temp = of_thermal_set_trip_temp, | 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 | tzd = thermal_zone_of_add_sensor(child, sensor_np, | 516 | tzd = thermal_zone_of_add_sensor(child, sensor_np, |
| 555 | data, ops); | 517 | data, ops); |
| 556 | if (!IS_ERR(tzd)) | 518 | if (!IS_ERR(tzd)) |
| 557 | tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED); | 519 | thermal_zone_device_enable(tzd); |
| 558 | 520 | ||
| 559 | of_node_put(child); | 521 | of_node_put(child); |
| 560 | goto exit; | 522 | goto exit; |
| @@ -979,7 +941,6 @@ __init *thermal_of_build_thermal_zone(struct device_node *np) · 418 unmodified lines | |||
| 979 | 941 | ||
| 980 | finish: | 942 | finish: |
| 981 | of_node_put(child); | 943 | of_node_put(child); |
| 982 | tz->mode = THERMAL_DEVICE_DISABLED; | ||
| 983 | 944 | ||
| 984 | return tz; | 945 | return tz; |
| 985 | 946 | ||
| @@ -49,18 +49,9 @@ static ssize_t · 48 unmodified lines | |||
| 49 | mode_show(struct device *dev, struct device_attribute *attr, char *buf) | 49 | mode_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 50 | { | 50 | { |
| 51 | struct thermal_zone_device *tz = to_thermal_zone(dev); | 51 | struct thermal_zone_device *tz = to_thermal_zone(dev); |
| 52 | enum thermal_device_mode mode; | 52 | int enabled = thermal_zone_device_is_enabled(tz); |
| 53 | int result; | ||
| 54 | |||
| 55 | if (!tz->ops->get_mode) | ||
| 56 | return -EPERM; | ||
| 57 | 53 | ||
| 58 | result = tz->ops->get_mode(tz, &mode); | 54 | return sprintf(buf, "%s\n", enabled ? "enabled" : "disabled"); |
| 59 | if (result) | ||
| 60 | return result; | ||
| 61 | |||
| 62 | return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled" | ||
| 63 | : "disabled"); | ||
| 64 | } | 55 | } |
| 65 | 56 | ||
| 66 | static ssize_t | 57 | static ssize_t |
| @@ -70,13 +61,10 @@ mode_store(struct device *dev, struct device_attribute *attr, · 3 unmodified lines | |||
| 70 | struct thermal_zone_device *tz = to_thermal_zone(dev); | 61 | struct thermal_zone_device *tz = to_thermal_zone(dev); |
| 71 | int result; | 62 | int result; |
| 72 | 63 | ||
| 73 | if (!tz->ops->set_mode) | ||
| 74 | return -EPERM; | ||
| 75 | |||
| 76 | if (!strncmp(buf, "enabled", sizeof("enabled") - 1)) | 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 | else if (!strncmp(buf, "disabled", sizeof("disabled") - 1)) | 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 | else | 68 | else |
| 81 | result = -EINVAL; | 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 | struct thermal_zone_device *tz = to_thermal_zone(dev); | 113 | struct thermal_zone_device *tz = to_thermal_zone(dev); |
| 126 | int trip, ret; | 114 | int trip, ret; |
| 127 | int temperature; | 115 | int temperature, hyst = 0; |
| 116 | enum thermal_trip_type type; | ||
| 128 | 117 | ||
| 129 | if (!tz->ops->set_trip_temp) | 118 | if (!tz->ops->set_trip_temp) |
| 130 | return -EPERM; | 119 | return -EPERM; |
| @@ -139,6 +128,18 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr, · 8 unmodified lines | |||
| 139 | if (ret) | 128 | if (ret) |
| 140 | return ret; | 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 | thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); | 143 | thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); |
| 143 | 144 | ||
| 144 | return count; | 145 | return count; |
| @@ -428,30 +429,13 @@ static struct attribute_group thermal_zone_attribute_group = { · 283 unmodified lines | |||
| 428 | .attrs = thermal_zone_dev_attrs, | 429 | .attrs = thermal_zone_dev_attrs, |
| 429 | }; | 430 | }; |
| 430 | 431 | ||
| 431 | /* We expose mode only if .get_mode is present */ | ||
| 432 | static struct attribute *thermal_zone_mode_attrs[] = { | 432 | static struct attribute *thermal_zone_mode_attrs[] = { |
| 433 | &dev_attr_mode.attr, | 433 | &dev_attr_mode.attr, |
| 434 | NULL, | 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 | static struct attribute_group thermal_zone_mode_attribute_group = { | 437 | static struct attribute_group thermal_zone_mode_attribute_group = { |
| 453 | .attrs = thermal_zone_mode_attrs, | 438 | .attrs = thermal_zone_mode_attrs, |
| 454 | .is_visible = thermal_zone_mode_is_visible, | ||
| 455 | }; | 439 | }; |
| 456 | 440 | ||
| 457 | /* We expose passive only if passive trips are present */ | 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 | data = ti_bandgap_get_sensor_data(bgp, id); | 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 | data = ti_thermal_build_data(bgp, id); | 173 | data = ti_thermal_build_data(bgp, id); |
| 174 | 174 | ||
| 175 | if (!data) | 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 | * devfreq_cooling: Thermal cooling device implementation for devices using | 3 | * devfreq_cooling: Thermal cooling device implementation for devices using |
| 3 | * devfreq | 4 | * devfreq |
| 4 | * | 5 | * |
| 5 | * Copyright (C) 2014-2015 ARM Limited | 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 | #ifndef __DEVFREQ_COOLING_H__ | 10 | #ifndef __DEVFREQ_COOLING_H__ |
| @@ -37,18 +37,6 @@ struct thermal_cooling_device; · 36 unmodified lines | |||
| 37 | struct thermal_instance; | 37 | struct thermal_instance; |
| 38 | struct thermal_attr; | 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 | enum thermal_trend { | 40 | enum thermal_trend { |
| 53 | THERMAL_TREND_STABLE, /* temperature is stable */ | 41 | THERMAL_TREND_STABLE, /* temperature is stable */ |
| 54 | THERMAL_TREND_RAISING, /* temperature is raising */ | 42 | THERMAL_TREND_RAISING, /* temperature is raising */ |
| @@ -76,9 +64,7 @@ struct thermal_zone_device_ops { · 21 unmodified lines | |||
| 76 | struct thermal_cooling_device *); | 64 | struct thermal_cooling_device *); |
| 77 | int (*get_temp) (struct thermal_zone_device *, int *); | 65 | int (*get_temp) (struct thermal_zone_device *, int *); |
| 78 | int (*set_trips) (struct thermal_zone_device *, int, int); | 66 | int (*set_trips) (struct thermal_zone_device *, int, int); |
| 79 | int (*get_mode) (struct thermal_zone_device *, | 67 | int (*change_mode) (struct thermal_zone_device *, |
| 80 | enum thermal_device_mode *); | ||
| 81 | int (*set_mode) (struct thermal_zone_device *, | ||
| 82 | enum thermal_device_mode); | 68 | enum thermal_device_mode); |
| 83 | int (*get_trip_type) (struct thermal_zone_device *, int, | 69 | int (*get_trip_type) (struct thermal_zone_device *, int, |
| 84 | enum thermal_trip_type *); | 70 | enum thermal_trip_type *); |
| @@ -128,6 +114,7 @@ struct thermal_cooling_device { · 43 unmodified lines | |||
| 128 | * @trip_temp_attrs: attributes for trip points for sysfs: trip temperature | 114 | * @trip_temp_attrs: attributes for trip points for sysfs: trip temperature |
| 129 | * @trip_type_attrs: attributes for trip points for sysfs: trip type | 115 | * @trip_type_attrs: attributes for trip points for sysfs: trip type |
| 130 | * @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis | 116 | * @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis |
| 117 | * @mode: current mode of this thermal zone | ||
| 131 | * @devdata: private pointer for device private data | 118 | * @devdata: private pointer for device private data |
| 132 | * @trips: number of trip points the thermal zone supports | 119 | * @trips: number of trip points the thermal zone supports |
| 133 | * @trips_disabled; bitmap for disabled trips | 120 | * @trips_disabled; bitmap for disabled trips |
| @@ -170,6 +157,7 @@ struct thermal_zone_device { · 36 unmodified lines | |||
| 170 | struct thermal_attr *trip_temp_attrs; | 157 | struct thermal_attr *trip_temp_attrs; |
| 171 | struct thermal_attr *trip_type_attrs; | 158 | struct thermal_attr *trip_type_attrs; |
| 172 | struct thermal_attr *trip_hyst_attrs; | 159 | struct thermal_attr *trip_hyst_attrs; |
| 160 | enum thermal_device_mode mode; | ||
| 173 | void *devdata; | 161 | void *devdata; |
| 174 | int trips; | 162 | int trips; |
| 175 | unsigned long trips_disabled; /* bitmap for disabled trips */ | 163 | unsigned long trips_disabled; /* bitmap for disabled trips */ |
| @@ -303,11 +291,6 @@ struct thermal_zone_params { · 127 unmodified lines | |||
| 303 | int offset; | 291 | int offset; |
| 304 | }; | 292 | }; |
| 305 | 293 | ||
| 306 | struct thermal_genl_event { | ||
| 307 | u32 orig; | ||
| 308 | enum events event; | ||
| 309 | }; | ||
| 310 | |||
| 311 | /** | 294 | /** |
| 312 | * struct thermal_zone_of_device_ops - scallbacks for handling DT based zones | 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 | void thermal_cdev_update(struct thermal_cooling_device *); | 400 | void thermal_cdev_update(struct thermal_cooling_device *); |
| 418 | void thermal_notify_framework(struct thermal_zone_device *, int); | 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 | #else | 404 | #else |
| 420 | static inline struct thermal_zone_device *thermal_zone_device_register( | 405 | static inline struct thermal_zone_device *thermal_zone_device_register( |
| 421 | const char *type, int trips, int mask, void *devdata, | 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 | static inline void thermal_notify_framework(struct thermal_zone_device *tz, | 448 | static inline void thermal_notify_framework(struct thermal_zone_device *tz, |
| 464 | int trip) | 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 | #endif /* CONFIG_THERMAL */ | 457 | #endif /* CONFIG_THERMAL */ |
| 467 | 458 | ||
| 468 | #endif /* __THERMAL_H__ */ | 459 | #endif /* __THERMAL_H__ */ |
| @@ -4,31 +4,86 @@ · 3 unmodified lines | |||
| 4 | 4 | ||
| 5 | #define THERMAL_NAME_LENGTH 20 | 5 | #define THERMAL_NAME_LENGTH 20 |
| 6 | 6 | ||
| 7 | /* Adding event notification support elements */ | 7 | enum thermal_device_mode { |
| 8 | #define THERMAL_GENL_FAMILY_NAME "thermal_event" | 8 | THERMAL_DEVICE_DISABLED = 0, |
| 9 | #define THERMAL_GENL_VERSION 0x01 | 9 | THERMAL_DEVICE_ENABLED, |
| 10 | #define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_grp" | 10 | }; |
| 11 | 11 | ||
| 12 | /* Events supported by Thermal Netlink */ | 12 | enum thermal_trip_type { |
| 13 | enum events { | 13 | THERMAL_TRIP_ACTIVE = 0, |
| 14 | THERMAL_AUX0, | 14 | THERMAL_TRIP_PASSIVE, |
| 15 | THERMAL_AUX1, | 15 | THERMAL_TRIP_HOT, |
| 16 | THERMAL_CRITICAL, | 16 | THERMAL_TRIP_CRITICAL, |
| 17 | THERMAL_DEV_FAULT, | ||
| 18 | }; | 17 | }; |
| 19 | 18 | ||
| 20 | /* attributes of thermal_genl_family */ | 19 | /* Adding event notification support elements */ |
| 21 | enum { | 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 | THERMAL_GENL_ATTR_UNSPEC, | 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 | __THERMAL_GENL_ATTR_MAX, | 48 | __THERMAL_GENL_ATTR_MAX, |
| 25 | }; | 49 | }; |
| 26 | #define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1) | 50 | #define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1) |
| 27 | 51 | ||
| 28 | /* commands supported by the thermal_genl_family */ | 52 | enum thermal_genl_sampling { |
| 29 | enum { | 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 | THERMAL_GENL_CMD_UNSPEC, | 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 | __THERMAL_GENL_CMD_MAX, | 87 | __THERMAL_GENL_CMD_MAX, |
| 33 | }; | 88 | }; |
| 34 | #define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1) | 89 | #define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1) |
| @@ -1192,7 +1192,7 @@ problem: · 1191 unmodified lines | |||
| 1192 | panic("GENL: Cannot register controller: %d\n", err); | 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 | static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group, | 1197 | static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group, |
| 1198 | gfp_t flags) | 1198 | gfp_t flags) |