Pull thermal updates from Daniel Lezcano: - Remove duplicate error message for the amlogic driver (Tang Bin) - Fix spellos in comments for the tegra and sun8i (Bhaskar Chowdhury) - Add the missing fifth node on the rcar_gen3 sensor (Niklas Söderlund) - Remove duplicate include in ti-bandgap (Zhang Yunkai) - Assign error code in the error path in the function thermal_of_populate_bind_params() (Jia-Ju Bai) - Fix spelling mistake in a comment 'disabed' -> 'disabled' (Colin Ian King) - Use the device name instead of auto-numbering for a better identification of the cooling device (Daniel Lezcano) - Improve a bit the division accuracy in the power allocator governor (Jeson Gao) - Enable the missing third sensor on msm8976 (Konrad Dybcio) - Add QCom tsens driver co-maintainer (Thara Gopinath) - Fix memory leak and use after free errors in the core code (Daniel Lezcano) - Add the MDM9607 compatible bindings (Konrad Dybcio) - Fix trivial spello in the copyright name for Hisilicon (Hao Fang) - Fix negative index array access when converting the frequency to power in the energy model (Brian-sy Yang) - Add support for Gen2 new PMIC support for Qcom SPMI (David Collins) - Update maintainer file for CPU cooling device section (Lukasz Luba) - Fix missing put_device on error in the Qcom tsens driver (Guangqing Zhu) - Add compatible DT binding for sm8350 (Robert Foss) - Add support for the MDM9607's tsens driver (Konrad Dybcio) - Remove duplicate error messages in thermal_mmio and the bcm2835 driver (Ruiqi Gong) - Add the Thermal Temperature Cooling driver (Zhang Rui) - Remove duplicate error messages in the Hisilicon sensor driver (Ye Bin) - Use the devm_platform_ioremap_resource_byname() function instead of a couple of corresponding calls (dingsenjie) - Sort the headers alphabetically in the ti-bandgap driver (Zhen Lei) - Add missing property in the DT thermal sensor binding (Rafał Miłecki) - Remove dead code in the ti-bandgap sensor driver (Lin Ruizhe) - Convert the BRCM DT bindings to the yaml schema (Rafał Miłecki) - Replace the thermal_notify_framework() call by a call to the thermal_zone_device_update() function. Remove the function as well as the corresponding documentation (Thara Gopinath) - Add support for the ipq8064-tsens sensor along with a set of cleanups and code preparation (Ansuel Smith) - Add a lockless __thermal_cdev_update() function to improve the locking scheme in the core code and governors (Lukasz Luba) - Fix multiple cooling device notification changes (Lukasz Luba) - Remove unneeded variable initialization (Colin Ian King) * tag 'thermal-v5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux: (55 commits) thermal/drivers/mtk_thermal: Remove redundant initializations of several variables thermal/core/power allocator: Use the lockless __thermal_cdev_update() function thermal/core/fair share: Use the lockless __thermal_cdev_update() function thermal/core/fair share: Lock the thermal zone while looping over instances thermal/core/power_allocator: Update once cooling devices when temp is low thermal/core/power_allocator: Maintain the device statistics from going stale thermal/core: Create a helper __thermal_cdev_update() without a lock dt-bindings: thermal: tsens: Document ipq8064 bindings thermal/drivers/tsens: Add support for ipq8064-tsens thermal/drivers/tsens: Drop unused define for msm8960 thermal/drivers/tsens: Replace custom 8960 apis with generic apis thermal/drivers/tsens: Fix bug in sensor enable for msm8960 thermal/drivers/tsens: Use init_common for msm8960 thermal/drivers/tsens: Add VER_0 tsens version thermal/drivers/tsens: Convert msm8960 to reg_field thermal/drivers/tsens: Don't hardcode sensor slope Documentation: driver-api: thermal: Remove thermal_notify_framework from documentation thermal/core: Remove thermal_notify_framework iwlwifi: mvm: tt: Replace thermal_notify_framework dt-bindings: thermal: brcm,ns-thermal: Convert to the json-schema ...
Unified · Split
| @@ -1,37 +0,0 @@ | ||
| 1 | −* Broadcom Northstar Thermal | |
| 2 | − | |
| 3 | −This binding describes thermal sensor that is part of Northstar's DMU (Device | |
| 4 | −Management Unit). | |
| 5 | − | |
| 6 | −Required properties: | |
| 7 | −- compatible : Must be "brcm,ns-thermal" | |
| 8 | −- reg : iomem address range of PVTMON registers | |
| 9 | −- #thermal-sensor-cells : Should be <0> | |
| 10 | − | |
| 11 | −Example: | |
| 12 | − | |
| 13 | −thermal: thermal@1800c2c0 { | |
| 14 | − compatible = "brcm,ns-thermal"; | |
| 15 | − reg = <0x1800c2c0 0x10>; | |
| 16 | − #thermal-sensor-cells = <0>; | |
| 17 | −}; | |
| 18 | − | |
| 19 | −thermal-zones { | |
| 20 | − cpu_thermal: cpu-thermal { | |
| 21 | − polling-delay-passive = <0>; | |
| 22 | − polling-delay = <1000>; | |
| 23 | − coefficients = <(-556) 418000>; | |
| 24 | − thermal-sensors = <&thermal>; | |
| 25 | − | |
| 26 | − trips { | |
| 27 | − cpu-crit { | |
| 28 | − temperature = <125000>; | |
| 29 | − hysteresis = <0>; | |
| 30 | − type = "critical"; | |
| 31 | − }; | |
| 32 | − }; | |
| 33 | − | |
| 34 | − cooling-maps { | |
| 35 | − }; | |
| 36 | − }; | |
| 37 | −}; | |
| @@ -0,0 +1,60 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/thermal/brcm,ns-thermal.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Broadcom Northstar Thermal | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Rafał Miłecki <rafal@milecki.pl> | |
| 11 | + | |
| 12 | +description: | |
| 13 | + Thermal sensor that is part of Northstar's DMU (Device Management Unit). | |
| 14 | + | |
| 15 | +allOf: | |
| 16 | + - $ref: thermal-sensor.yaml# | |
| 17 | + | |
| 18 | +properties: | |
| 19 | + compatible: | |
| 20 | + const: brcm,ns-thermal | |
| 21 | + | |
| 22 | + reg: | |
| 23 | + description: PVTMON registers range | |
| 24 | + maxItems: 1 | |
| 25 | + | |
| 26 | + "#thermal-sensor-cells": | |
| 27 | + const: 0 | |
| 28 | + | |
| 29 | +unevaluatedProperties: false | |
| 30 | + | |
| 31 | +required: | |
| 32 | + - reg | |
| 33 | + | |
| 34 | +examples: | |
| 35 | + - | | |
| 36 | + thermal: thermal@1800c2c0 { | |
| 37 | + compatible = "brcm,ns-thermal"; | |
| 38 | + reg = <0x1800c2c0 0x10>; | |
| 39 | + #thermal-sensor-cells = <0>; | |
| 40 | + }; | |
| 41 | + | |
| 42 | + thermal-zones { | |
| 43 | + cpu-thermal { | |
| 44 | + polling-delay-passive = <0>; | |
| 45 | + polling-delay = <1000>; | |
| 46 | + coefficients = <(-556) 418000>; | |
| 47 | + thermal-sensors = <&thermal>; | |
| 48 | + | |
| 49 | + trips { | |
| 50 | + cpu-crit { | |
| 51 | + temperature = <125000>; | |
| 52 | + hysteresis = <0>; | |
| 53 | + type = "critical"; | |
| 54 | + }; | |
| 55 | + }; | |
| 56 | + | |
| 57 | + cooling-maps { | |
| 58 | + }; | |
| 59 | + }; | |
| 60 | + }; | |
| @@ -19,9 +19,15 @@ description: | · 18 unmodified lines | ||
| 19 | 19 | properties: |
| 20 | 20 | compatible: |
| 21 | 21 | oneOf: |
| 22 | + - description: msm9860 TSENS based | |
| 23 | + items: | |
| 24 | + - enum: | |
| 25 | + - qcom,ipq8064-tsens | |
| 26 | + | |
| 22 | 27 | - description: v0.1 of TSENS |
| 23 | 28 | items: |
| 24 | 29 | - enum: |
| 30 | + - qcom,mdm9607-tsens | |
| 25 | 31 | - qcom,msm8916-tsens |
| 26 | 32 | - qcom,msm8939-tsens |
| 27 | 33 | - qcom,msm8974-tsens |
| @@ -43,6 +49,7 @@ properties: · 15 unmodified lines | ||
| 43 | 49 | - qcom,sdm845-tsens |
| 44 | 50 | - qcom,sm8150-tsens |
| 45 | 51 | - qcom,sm8250-tsens |
| 52 | + - qcom,sm8350-tsens | |
| 46 | 53 | - const: qcom,tsens-v2 |
| 47 | 54 | |
| 48 | 55 | reg: |
| @@ -73,7 +80,9 @@ properties: · 24 unmodified lines | ||
| 73 | 80 | maxItems: 2 |
| 74 | 81 | items: |
| 75 | 82 | - const: calib |
| 76 | − - const: calib_sel | |
| 83 | + - enum: | |
| 84 | + - calib_backup | |
| 85 | + - calib_sel | |
| 77 | 86 | |
| 78 | 87 | "#qcom,sensors": |
| 79 | 88 | description: |
| @@ -88,12 +97,21 @@ properties: · 8 unmodified lines | ||
| 88 | 97 | Number of cells required to uniquely identify the thermal sensors. Since |
| 89 | 98 | we have multiple sensors this is set to 1 |
| 90 | 99 | |
| 100 | +required: | |
| 101 | + - compatible | |
| 102 | + - interrupts | |
| 103 | + - interrupt-names | |
| 104 | + - "#thermal-sensor-cells" | |
| 105 | + - "#qcom,sensors" | |
| 106 | + | |
| 91 | 107 | allOf: |
| 92 | 108 | - if: |
| 93 | 109 | properties: |
| 94 | 110 | compatible: |
| 95 | 111 | contains: |
| 96 | 112 | enum: |
| 113 | + - qcom,ipq8064-tsens | |
| 114 | + - qcom,mdm9607-tsens | |
| 97 | 115 | - qcom,msm8916-tsens |
| 98 | 116 | - qcom,msm8974-tsens |
| 99 | 117 | - qcom,msm8976-tsens |
| @@ -114,17 +132,42 @@ allOf: · 14 unmodified lines | ||
| 114 | 132 | interrupt-names: |
| 115 | 133 | minItems: 2 |
| 116 | 134 | |
| 117 | −required: | |
| 118 | − - compatible | |
| 119 | − - reg | |
| 120 | − - "#qcom,sensors" | |
| 121 | − - interrupts | |
| 122 | − - interrupt-names | |
| 123 | − - "#thermal-sensor-cells" | |
| 135 | + - if: | |
| 136 | + properties: | |
| 137 | + compatible: | |
| 138 | + contains: | |
| 139 | + enum: | |
| 140 | + - qcom,tsens-v0_1 | |
| 141 | + - qcom,tsens-v1 | |
| 142 | + - qcom,tsens-v2 | |
| 143 | + | |
| 144 | + then: | |
| 145 | + required: | |
| 146 | + - reg | |
| 124 | 147 | |
| 125 | 148 | additionalProperties: false |
| 126 | 149 | |
| 127 | 150 | examples: |
| 151 | + - | | |
| 152 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 153 | + // Example msm9860 based SoC (ipq8064): | |
| 154 | + gcc: clock-controller { | |
| 155 | + | |
| 156 | + /* ... */ | |
| 157 | + | |
| 158 | + tsens: thermal-sensor { | |
| 159 | + compatible = "qcom,ipq8064-tsens"; | |
| 160 | + | |
| 161 | + nvmem-cells = <&tsens_calib>, <&tsens_calib_backup>; | |
| 162 | + nvmem-cell-names = "calib", "calib_backup"; | |
| 163 | + interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>; | |
| 164 | + interrupt-names = "uplow"; | |
| 165 | + | |
| 166 | + #qcom,sensors = <11>; | |
| 167 | + #thermal-sensor-cells = <1>; | |
| 168 | + }; | |
| 169 | + }; | |
| 170 | + | |
| 128 | 171 | - | |
| 129 | 172 | #include <dt-bindings/interrupt-controller/arm-gic.h> |
| 130 | 173 | // Example 1 (legacy: for pre v1 IP): |
| @@ -28,14 +28,7 @@ properties: · 27 unmodified lines | ||
| 28 | 28 | - renesas,r8a77980-thermal # R-Car V3H |
| 29 | 29 | - renesas,r8a779a0-thermal # R-Car V3U |
| 30 | 30 | |
| 31 | − reg: | |
| 32 | − minItems: 2 | |
| 33 | − maxItems: 4 | |
| 34 | − items: | |
| 35 | − - description: TSC1 registers | |
| 36 | − - description: TSC2 registers | |
| 37 | − - description: TSC3 registers | |
| 38 | − - description: TSC4 registers | |
| 31 | + reg: true | |
| 39 | 32 | |
| 40 | 33 | interrupts: |
| 41 | 34 | items: |
| @@ -71,8 +64,25 @@ if: · 29 unmodified lines | ||
| 71 | 64 | enum: |
| 72 | 65 | - renesas,r8a779a0-thermal |
| 73 | 66 | then: |
| 67 | + properties: | |
| 68 | + reg: | |
| 69 | + minItems: 2 | |
| 70 | + maxItems: 3 | |
| 71 | + items: | |
| 72 | + - description: TSC1 registers | |
| 73 | + - description: TSC2 registers | |
| 74 | + - description: TSC3 registers | |
| 74 | 75 | required: |
| 75 | 76 | - interrupts |
| 77 | +else: | |
| 78 | + properties: | |
| 79 | + reg: | |
| 80 | + items: | |
| 81 | + - description: TSC0 registers | |
| 82 | + - description: TSC1 registers | |
| 83 | + - description: TSC2 registers | |
| 84 | + - description: TSC3 registers | |
| 85 | + - description: TSC4 registers | |
| 76 | 86 | |
| 77 | 87 | additionalProperties: false |
| 78 | 88 | |
| @@ -111,3 +121,20 @@ examples: · 32 unmodified lines | ||
| 111 | 121 | }; |
| 112 | 122 | }; |
| 113 | 123 | }; |
| 124 | + - | | |
| 125 | + #include <dt-bindings/clock/r8a779a0-cpg-mssr.h> | |
| 126 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 127 | + #include <dt-bindings/power/r8a779a0-sysc.h> | |
| 128 | + | |
| 129 | + tsc_r8a779a0: thermal@e6190000 { | |
| 130 | + compatible = "renesas,r8a779a0-thermal"; | |
| 131 | + reg = <0xe6190000 0x200>, | |
| 132 | + <0xe6198000 0x200>, | |
| 133 | + <0xe61a0000 0x200>, | |
| 134 | + <0xe61a8000 0x200>, | |
| 135 | + <0xe61b0000 0x200>; | |
| 136 | + clocks = <&cpg CPG_MOD 919>; | |
| 137 | + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; | |
| 138 | + resets = <&cpg 919>; | |
| 139 | + #thermal-sensor-cells = <1>; | |
| 140 | + }; | |
| @@ -36,6 +36,9 @@ properties: · 35 unmodified lines | ||
| 36 | 36 | containing several internal sensors. |
| 37 | 37 | enum: [0, 1] |
| 38 | 38 | |
| 39 | +required: | |
| 40 | + - "#thermal-sensor-cells" | |
| 41 | + | |
| 39 | 42 | additionalProperties: true |
| 40 | 43 | |
| 41 | 44 | examples: |
| @@ -730,17 +730,7 @@ This function returns the thermal_instance corresponding to a given · 729 unmodified lines | ||
| 730 | 730 | {thermal_zone, cooling_device, trip_point} combination. Returns NULL |
| 731 | 731 | if such an instance does not exist. |
| 732 | 732 | |
| 733 | −4.3. thermal_notify_framework | |
| 734 | −----------------------------- | |
| 735 | − | |
| 736 | −This function handles the trip events from sensor drivers. It starts | |
| 737 | −throttling the cooling devices according to the policy configured. | |
| 738 | −For CRITICAL and HOT trip points, this notifies the respective drivers, | |
| 739 | −and does actual throttling for other trip points i.e ACTIVE and PASSIVE. | |
| 740 | −The throttling policy is based on the configured platform data; if no | |
| 741 | −platform data is provided, this uses the step_wise throttling policy. | |
| 742 | − | |
| 743 | −4.4. thermal_cdev_update | |
| 733 | +4.3. thermal_cdev_update | |
| 744 | 734 | ------------------------ |
| 745 | 735 | |
| 746 | 736 | This function serves as an arbitrator to set the state of a cooling |
| @@ -15197,6 +15197,7 @@ F: include/linux/if_rmnet.h · 15196 unmodified lines | ||
| 15197 | 15197 | |
| 15198 | 15198 | QUALCOMM TSENS THERMAL DRIVER |
| 15199 | 15199 | M: Amit Kucheria <amitk@kernel.org> |
| 15200 | +M: Thara Gopinath <thara.gopinath@linaro.org> | |
| 15200 | 15201 | L: linux-pm@vger.kernel.org |
| 15201 | 15202 | L: linux-arm-msm@vger.kernel.org |
| 15202 | 15203 | S: Maintained |
| @@ -18101,7 +18102,7 @@ THERMAL/CPU_COOLING · 2898 unmodified lines | ||
| 18101 | 18102 | M: Amit Daniel Kachhap <amit.kachhap@gmail.com> |
| 18102 | 18103 | M: Daniel Lezcano <daniel.lezcano@linaro.org> |
| 18103 | 18104 | M: Viresh Kumar <viresh.kumar@linaro.org> |
| 18104 | −M: Javi Merino <javi.merino@kernel.org> | |
| 18105 | +R: Lukasz Luba <lukasz.luba@arm.com> | |
| 18105 | 18106 | L: linux-pm@vger.kernel.org |
| 18106 | 18107 | S: Supported |
| 18107 | 18108 | F: Documentation/driver-api/thermal/cpu-cooling-api.rst |
| @@ -132,7 +132,7 @@ static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal, · 131 unmodified lines | ||
| 132 | 132 | /* Allow mlxsw thermal zone binding to an external cooling device */ |
| 133 | 133 | for (i = 0; i < ARRAY_SIZE(mlxsw_thermal_external_allowed_cdev); i++) { |
| 134 | 134 | if (strnstr(cdev->type, mlxsw_thermal_external_allowed_cdev[i], |
| 135 | − sizeof(cdev->type))) | |
| 135 | + strlen(cdev->type))) | |
| 136 | 136 | return 0; |
| 137 | 137 | } |
| 138 | 138 | |
| @@ -146,8 +146,8 @@ void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) · 145 unmodified lines | ||
| 146 | 146 | if (mvm->tz_device.tzone) { |
| 147 | 147 | struct iwl_mvm_thermal_device *tz_dev = &mvm->tz_device; |
| 148 | 148 | |
| 149 | − thermal_notify_framework(tz_dev->tzone, | |
| 150 | − tz_dev->fw_trips_index[ths_crossed]); | |
| 149 | + thermal_zone_device_update(tz_dev->tzone, | |
| 150 | + THERMAL_TRIP_VIOLATED); | |
| 151 | 151 | } |
| 152 | 152 | #endif /* CONFIG_THERMAL */ |
| 153 | 153 | } |
| @@ -254,10 +254,8 @@ static int amlogic_thermal_probe(struct platform_device *pdev) · 253 unmodified lines | ||
| 254 | 254 | platform_set_drvdata(pdev, pdata); |
| 255 | 255 | |
| 256 | 256 | base = devm_platform_ioremap_resource(pdev, 0); |
| 257 | − if (IS_ERR(base)) { | |
| 258 | − dev_err(dev, "failed to get io address\n"); | |
| 257 | + if (IS_ERR(base)) | |
| 259 | 258 | return PTR_ERR(base); |
| 260 | − } | |
| 261 | 259 | |
| 262 | 260 | pdata->regmap = devm_regmap_init_mmio(dev, base, |
| 263 | 261 | pdata->data->regmap_config); |
| @@ -184,7 +184,6 @@ static int bcm2835_thermal_probe(struct platform_device *pdev) · 183 unmodified lines | ||
| 184 | 184 | data->regs = devm_ioremap_resource(&pdev->dev, res); |
| 185 | 185 | if (IS_ERR(data->regs)) { |
| 186 | 186 | err = PTR_ERR(data->regs); |
| 187 | − dev_err(&pdev->dev, "Could not get registers: %d\n", err); | |
| 188 | 187 | return err; |
| 189 | 188 | } |
| 190 | 189 | |
| @@ -13,10 +13,10 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <linux/cpu.h> |
| 14 | 14 | #include <linux/cpufreq.h> |
| 15 | 15 | #include <linux/cpu_cooling.h> |
| 16 | +#include <linux/device.h> | |
| 16 | 17 | #include <linux/energy_model.h> |
| 17 | 18 | #include <linux/err.h> |
| 18 | 19 | #include <linux/export.h> |
| 19 | −#include <linux/idr.h> | |
| 20 | 20 | #include <linux/pm_opp.h> |
| 21 | 21 | #include <linux/pm_qos.h> |
| 22 | 22 | #include <linux/slab.h> |
| @@ -50,8 +50,6 @@ struct time_in_idle { · 27 unmodified lines | ||
| 50 | 50 | |
| 51 | 51 | /** |
| 52 | 52 | * struct cpufreq_cooling_device - data for cooling device with cpufreq |
| 53 | − * @id: unique integer value corresponding to each cpufreq_cooling_device | |
| 54 | − * registered. | |
| 55 | 53 | * @last_load: load measured by the latest call to cpufreq_get_requested_power() |
| 56 | 54 | * @cpufreq_state: integer value representing the current state of cpufreq |
| 57 | 55 | * cooling devices. |
| @@ -61,7 +59,6 @@ struct time_in_idle { · 3 unmodified lines | ||
| 61 | 59 | * @cdev: thermal_cooling_device pointer to keep track of the |
| 62 | 60 | * registered cooling device. |
| 63 | 61 | * @policy: cpufreq policy. |
| 64 | − * @node: list_head to link all cpufreq_cooling_device together. | |
| 65 | 62 | * @idle_time: idle time stats |
| 66 | 63 | * @qos_req: PM QoS contraint to apply |
| 67 | 64 | * |
| @@ -69,23 +66,17 @@ struct time_in_idle { · 1 unmodified line | ||
| 69 | 66 | * cpufreq_cooling_device. |
| 70 | 67 | */ |
| 71 | 68 | struct cpufreq_cooling_device { |
| 72 | − int id; | |
| 73 | 69 | u32 last_load; |
| 74 | 70 | unsigned int cpufreq_state; |
| 75 | 71 | unsigned int max_level; |
| 76 | 72 | struct em_perf_domain *em; |
| 77 | 73 | struct cpufreq_policy *policy; |
| 78 | − struct list_head node; | |
| 79 | 74 | #ifndef CONFIG_SMP |
| 80 | 75 | struct time_in_idle *idle_time; |
| 81 | 76 | #endif |
| 82 | 77 | struct freq_qos_request qos_req; |
| 83 | 78 | }; |
| 84 | 79 | |
| 85 | −static DEFINE_IDA(cpufreq_ida); | |
| 86 | −static DEFINE_MUTEX(cooling_list_lock); | |
| 87 | −static LIST_HEAD(cpufreq_cdev_list); | |
| 88 | − | |
| 89 | 80 | #ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR |
| 90 | 81 | /** |
| 91 | 82 | * get_level: Find the level for a particular frequency |
| @@ -125,7 +116,7 @@ static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev, · 33 unmodified lines | ||
| 125 | 116 | { |
| 126 | 117 | int i; |
| 127 | 118 | |
| 128 | − for (i = cpufreq_cdev->max_level; i >= 0; i--) { | |
| 119 | + for (i = cpufreq_cdev->max_level; i > 0; i--) { | |
| 129 | 120 | if (power >= cpufreq_cdev->em->table[i].power) |
| 130 | 121 | break; |
| 131 | 122 | } |
| @@ -528,11 +519,11 @@ __cpufreq_cooling_register(struct device_node *np, · 396 unmodified lines | ||
| 528 | 519 | { |
| 529 | 520 | struct thermal_cooling_device *cdev; |
| 530 | 521 | struct cpufreq_cooling_device *cpufreq_cdev; |
| 531 | − char dev_name[THERMAL_NAME_LENGTH]; | |
| 532 | 522 | unsigned int i; |
| 533 | 523 | struct device *dev; |
| 534 | 524 | int ret; |
| 535 | 525 | struct thermal_cooling_device_ops *cooling_ops; |
| 526 | + char *name; | |
| 536 | 527 | |
| 537 | 528 | dev = get_cpu_device(policy->cpu); |
| 538 | 529 | if (unlikely(!dev)) { |
| @@ -567,16 +558,6 @@ __cpufreq_cooling_register(struct device_node *np, · 28 unmodified lines | ||
| 567 | 558 | /* max_level is an index, not a counter */ |
| 568 | 559 | cpufreq_cdev->max_level = i - 1; |
| 569 | 560 | |
| 570 | − ret = ida_simple_get(&cpufreq_ida, 0, 0, GFP_KERNEL); | |
| 571 | − if (ret < 0) { | |
| 572 | − cdev = ERR_PTR(ret); | |
| 573 | − goto free_idle_time; | |
| 574 | − } | |
| 575 | − cpufreq_cdev->id = ret; | |
| 576 | − | |
| 577 | − snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", | |
| 578 | − cpufreq_cdev->id); | |
| 579 | − | |
| 580 | 561 | cooling_ops = &cpufreq_cooling_ops; |
| 581 | 562 | |
| 582 | 563 | #ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR |
| @@ -591,7 +572,7 @@ __cpufreq_cooling_register(struct device_node *np, · 8 unmodified lines | ||
| 591 | 572 | pr_err("%s: unsorted frequency tables are not supported\n", |
| 592 | 573 | __func__); |
| 593 | 574 | cdev = ERR_PTR(-EINVAL); |
| 594 | − goto remove_ida; | |
| 575 | + goto free_idle_time; | |
| 595 | 576 | } |
| 596 | 577 | |
| 597 | 578 | ret = freq_qos_add_request(&policy->constraints, |
| @@ -601,24 +582,25 @@ __cpufreq_cooling_register(struct device_node *np, · 3 unmodified lines | ||
| 601 | 582 | pr_err("%s: Failed to add freq constraint (%d)\n", __func__, |
| 602 | 583 | ret); |
| 603 | 584 | cdev = ERR_PTR(ret); |
| 604 | − goto remove_ida; | |
| 585 | + goto free_idle_time; | |
| 605 | 586 | } |
| 606 | 587 | |
| 607 | − cdev = thermal_of_cooling_device_register(np, dev_name, cpufreq_cdev, | |
| 588 | + cdev = ERR_PTR(-ENOMEM); | |
| 589 | + name = kasprintf(GFP_KERNEL, "cpufreq-%s", dev_name(dev)); | |
| 590 | + if (!name) | |
| 591 | + goto remove_qos_req; | |
| 592 | + | |
| 593 | + cdev = thermal_of_cooling_device_register(np, name, cpufreq_cdev, | |
| 608 | 594 | cooling_ops); |
| 595 | + kfree(name); | |
| 596 | + | |
| 609 | 597 | if (IS_ERR(cdev)) |
| 610 | 598 | goto remove_qos_req; |
| 611 | 599 | |
| 612 | − mutex_lock(&cooling_list_lock); | |
| 613 | − list_add(&cpufreq_cdev->node, &cpufreq_cdev_list); | |
| 614 | − mutex_unlock(&cooling_list_lock); | |
| 615 | − | |
| 616 | 600 | return cdev; |
| 617 | 601 | |
| 618 | 602 | remove_qos_req: |
| 619 | 603 | freq_qos_remove_request(&cpufreq_cdev->qos_req); |
| 620 | −remove_ida: | |
| 621 | − ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id); | |
| 622 | 604 | free_idle_time: |
| 623 | 605 | free_idle_time(cpufreq_cdev); |
| 624 | 606 | free_cdev: |
| @@ -706,13 +688,8 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) · 81 unmodified lines | ||
| 706 | 688 | |
| 707 | 689 | cpufreq_cdev = cdev->devdata; |
| 708 | 690 | |
| 709 | − mutex_lock(&cooling_list_lock); | |
| 710 | − list_del(&cpufreq_cdev->node); | |
| 711 | − mutex_unlock(&cooling_list_lock); | |
| 712 | − | |
| 713 | 691 | thermal_cooling_device_unregister(cdev); |
| 714 | 692 | freq_qos_remove_request(&cpufreq_cdev->qos_req); |
| 715 | − ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id); | |
| 716 | 693 | free_idle_time(cpufreq_cdev); |
| 717 | 694 | kfree(cpufreq_cdev); |
| 718 | 695 | } |
| @@ -9,9 +9,9 @@ · 8 unmodified lines | ||
| 9 | 9 | |
| 10 | 10 | #include <linux/cpu_cooling.h> |
| 11 | 11 | #include <linux/cpuidle.h> |
| 12 | +#include <linux/device.h> | |
| 12 | 13 | #include <linux/err.h> |
| 13 | 14 | #include <linux/idle_inject.h> |
| 14 | −#include <linux/idr.h> | |
| 15 | 15 | #include <linux/of_device.h> |
| 16 | 16 | #include <linux/slab.h> |
| 17 | 17 | #include <linux/thermal.h> |
| @@ -26,8 +26,6 @@ struct cpuidle_cooling_device { · 8 unmodified lines | ||
| 26 | 26 | unsigned long state; |
| 27 | 27 | }; |
| 28 | 28 | |
| 29 | −static DEFINE_IDA(cpuidle_ida); | |
| 30 | − | |
| 31 | 29 | /** |
| 32 | 30 | * cpuidle_cooling_runtime - Running time computation |
| 33 | 31 | * @idle_duration_us: CPU idle time to inject in microseconds |
| @@ -174,10 +172,11 @@ static int __cpuidle_cooling_register(struct device_node *np, · 140 unmodified lines | ||
| 174 | 172 | struct idle_inject_device *ii_dev; |
| 175 | 173 | struct cpuidle_cooling_device *idle_cdev; |
| 176 | 174 | struct thermal_cooling_device *cdev; |
| 175 | + struct device *dev; | |
| 177 | 176 | unsigned int idle_duration_us = TICK_USEC; |
| 178 | 177 | unsigned int latency_us = UINT_MAX; |
| 179 | − char dev_name[THERMAL_NAME_LENGTH]; | |
| 180 | − int id, ret; | |
| 178 | + char *name; | |
| 179 | + int ret; | |
| 181 | 180 | |
| 182 | 181 | idle_cdev = kzalloc(sizeof(*idle_cdev), GFP_KERNEL); |
| 183 | 182 | if (!idle_cdev) { |
| @@ -185,16 +184,10 @@ static int __cpuidle_cooling_register(struct device_node *np, · 1 unmodified line | ||
| 185 | 184 | goto out; |
| 186 | 185 | } |
| 187 | 186 | |
| 188 | − id = ida_simple_get(&cpuidle_ida, 0, 0, GFP_KERNEL); | |
| 189 | − if (id < 0) { | |
| 190 | − ret = id; | |
| 191 | − goto out_kfree; | |
| 192 | − } | |
| 193 | − | |
| 194 | 187 | ii_dev = idle_inject_register(drv->cpumask); |
| 195 | 188 | if (!ii_dev) { |
| 196 | 189 | ret = -EINVAL; |
| 197 | − goto out_id; | |
| 190 | + goto out_kfree; | |
| 198 | 191 | } |
| 199 | 192 | |
| 200 | 193 | of_property_read_u32(np, "duration-us", &idle_duration_us); |
| @@ -205,24 +198,32 @@ static int __cpuidle_cooling_register(struct device_node *np, · 4 unmodified lines | ||
| 205 | 198 | |
| 206 | 199 | idle_cdev->ii_dev = ii_dev; |
| 207 | 200 | |
| 208 | − snprintf(dev_name, sizeof(dev_name), "thermal-idle-%d", id); | |
| 201 | + dev = get_cpu_device(cpumask_first(drv->cpumask)); | |
| 209 | 202 | |
| 210 | − cdev = thermal_of_cooling_device_register(np, dev_name, idle_cdev, | |
| 203 | + name = kasprintf(GFP_KERNEL, "idle-%s", dev_name(dev)); | |
| 204 | + if (!name) { | |
| 205 | + ret = -ENOMEM; | |
| 206 | + goto out_unregister; | |
| 207 | + } | |
| 208 | + | |
| 209 | + cdev = thermal_of_cooling_device_register(np, name, idle_cdev, | |
| 211 | 210 | &cpuidle_cooling_ops); |
| 212 | 211 | if (IS_ERR(cdev)) { |
| 213 | 212 | ret = PTR_ERR(cdev); |
| 214 | − goto out_unregister; | |
| 213 | + goto out_kfree_name; | |
| 215 | 214 | } |
| 216 | 215 | |
| 217 | 216 | pr_debug("%s: Idle injection set with idle duration=%u, latency=%u\n", |
| 218 | − dev_name, idle_duration_us, latency_us); | |
| 217 | + name, idle_duration_us, latency_us); | |
| 218 | + | |
| 219 | + kfree(name); | |
| 219 | 220 | |
| 220 | 221 | return 0; |
| 221 | 222 | |
| 223 | +out_kfree_name: | |
| 224 | + kfree(name); | |
| 222 | 225 | out_unregister: |
| 223 | 226 | idle_inject_unregister(ii_dev); |
| 224 | −out_id: | |
| 225 | − ida_simple_remove(&cpuidle_ida, id); | |
| 226 | 227 | out_kfree: |
| 227 | 228 | kfree(idle_cdev); |
| 228 | 229 | out: |
| @@ -14,7 +14,6 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/devfreq_cooling.h> |
| 15 | 15 | #include <linux/energy_model.h> |
| 16 | 16 | #include <linux/export.h> |
| 17 | −#include <linux/idr.h> | |
| 18 | 17 | #include <linux/slab.h> |
| 19 | 18 | #include <linux/pm_opp.h> |
| 20 | 19 | #include <linux/pm_qos.h> |
| @@ -25,11 +24,8 @@ · 4 unmodified lines | ||
| 25 | 24 | #define HZ_PER_KHZ 1000 |
| 26 | 25 | #define SCALE_ERROR_MITIGATION 100 |
| 27 | 26 | |
| 28 | −static DEFINE_IDA(devfreq_ida); | |
| 29 | − | |
| 30 | 27 | /** |
| 31 | 28 | * struct devfreq_cooling_device - Devfreq cooling device |
| 32 | − * @id: unique integer value corresponding to each | |
| 33 | 29 | * devfreq_cooling_device registered. |
| 34 | 30 | * @cdev: Pointer to associated thermal cooling device. |
| 35 | 31 | * @devfreq: Pointer to associated devfreq device. |
| @@ -51,7 +47,6 @@ static DEFINE_IDA(devfreq_ida); · 15 unmodified lines | ||
| 51 | 47 | * @em_pd: Energy Model for the associated Devfreq device |
| 52 | 48 | */ |
| 53 | 49 | struct devfreq_cooling_device { |
| 54 | − int id; | |
| 55 | 50 | struct thermal_cooling_device *cdev; |
| 56 | 51 | struct devfreq *devfreq; |
| 57 | 52 | unsigned long cooling_state; |
| @@ -363,7 +358,7 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df, · 305 unmodified lines | ||
| 363 | 358 | struct thermal_cooling_device *cdev; |
| 364 | 359 | struct device *dev = df->dev.parent; |
| 365 | 360 | struct devfreq_cooling_device *dfc; |
| 366 | − char dev_name[THERMAL_NAME_LENGTH]; | |
| 361 | + char *name; | |
| 367 | 362 | int err, num_opps; |
| 368 | 363 | |
| 369 | 364 | dfc = kzalloc(sizeof(*dfc), GFP_KERNEL); |
| @@ -407,30 +402,27 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df, · 37 unmodified lines | ||
| 407 | 402 | if (err < 0) |
| 408 | 403 | goto free_table; |
| 409 | 404 | |
| 410 | − err = ida_simple_get(&devfreq_ida, 0, 0, GFP_KERNEL); | |
| 411 | − if (err < 0) | |
| 405 | + err = -ENOMEM; | |
| 406 | + name = kasprintf(GFP_KERNEL, "devfreq-%s", dev_name(dev)); | |
| 407 | + if (!name) | |
| 412 | 408 | goto remove_qos_req; |
| 413 | 409 | |
| 414 | − dfc->id = err; | |
| 415 | − | |
| 416 | − snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id); | |
| 417 | − | |
| 418 | − cdev = thermal_of_cooling_device_register(np, dev_name, dfc, | |
| 410 | + cdev = thermal_of_cooling_device_register(np, name, dfc, | |
| 419 | 411 | &devfreq_cooling_ops); |
| 412 | + kfree(name); | |
| 413 | + | |
| 420 | 414 | if (IS_ERR(cdev)) { |
| 421 | 415 | err = PTR_ERR(cdev); |
| 422 | 416 | dev_err(dev, |
| 423 | 417 | "Failed to register devfreq cooling device (%d)\n", |
| 424 | 418 | err); |
| 425 | − goto release_ida; | |
| 419 | + goto remove_qos_req; | |
| 426 | 420 | } |
| 427 | 421 | |
| 428 | 422 | dfc->cdev = cdev; |
| 429 | 423 | |
| 430 | 424 | return cdev; |
| 431 | 425 | |
| 432 | −release_ida: | |
| 433 | − ida_simple_remove(&devfreq_ida, dfc->id); | |
| 434 | 426 | remove_qos_req: |
| 435 | 427 | dev_pm_qos_remove_request(&dfc->req_max_freq); |
| 436 | 428 | free_table: |
| @@ -527,7 +519,6 @@ void devfreq_cooling_unregister(struct thermal_cooling_device *cdev) · 90 unmodified lines | ||
| 527 | 519 | dev = dfc->devfreq->dev.parent; |
| 528 | 520 | |
| 529 | 521 | thermal_cooling_device_unregister(dfc->cdev); |
| 530 | − ida_simple_remove(&devfreq_ida, dfc->id); | |
| 531 | 522 | dev_pm_qos_remove_request(&dfc->req_max_freq); |
| 532 | 523 | |
| 533 | 524 | em_dev_unregister_perf_domain(dev); |
| @@ -82,6 +82,8 @@ static int fair_share_throttle(struct thermal_zone_device *tz, int trip) · 81 unmodified lines | ||
| 82 | 82 | int total_instance = 0; |
| 83 | 83 | int cur_trip_level = get_trip_level(tz); |
| 84 | 84 | |
| 85 | + mutex_lock(&tz->lock); | |
| 86 | + | |
| 85 | 87 | list_for_each_entry(instance, &tz->thermal_instances, tz_node) { |
| 86 | 88 | if (instance->trip != trip) |
| 87 | 89 | continue; |
| @@ -105,11 +107,12 @@ static int fair_share_throttle(struct thermal_zone_device *tz, int trip) · 17 unmodified lines | ||
| 105 | 107 | instance->target = get_target_state(tz, cdev, percentage, |
| 106 | 108 | cur_trip_level); |
| 107 | 109 | |
| 108 | − mutex_lock(&instance->cdev->lock); | |
| 109 | − instance->cdev->updated = false; | |
| 110 | − mutex_unlock(&instance->cdev->lock); | |
| 111 | − thermal_cdev_update(cdev); | |
| 110 | + mutex_lock(&cdev->lock); | |
| 111 | + __thermal_cdev_update(cdev); | |
| 112 | + mutex_unlock(&cdev->lock); | |
| 112 | 113 | } |
| 114 | + | |
| 115 | + mutex_unlock(&tz->lock); | |
| 113 | 116 | return 0; |
| 114 | 117 | } |
| 115 | 118 | |
| @@ -301,9 +301,8 @@ power_actor_set_power(struct thermal_cooling_device *cdev, · 300 unmodified lines | ||
| 301 | 301 | |
| 302 | 302 | instance->target = clamp_val(state, instance->lower, instance->upper); |
| 303 | 303 | mutex_lock(&cdev->lock); |
| 304 | − cdev->updated = false; | |
| 304 | + __thermal_cdev_update(cdev); | |
| 305 | 305 | mutex_unlock(&cdev->lock); |
| 306 | − thermal_cdev_update(cdev); | |
| 307 | 306 | |
| 308 | 307 | return 0; |
| 309 | 308 | } |
| @@ -374,9 +373,11 @@ static void divvy_up_power(u32 *req_power, u32 *max_power, int num_actors, · 64 unmodified lines | ||
| 374 | 373 | */ |
| 375 | 374 | extra_power = min(extra_power, capped_extra_power); |
| 376 | 375 | if (capped_extra_power > 0) |
| 377 | − for (i = 0; i < num_actors; i++) | |
| 378 | − granted_power[i] += (extra_actor_power[i] * | |
| 379 | − extra_power) / capped_extra_power; | |
| 376 | + for (i = 0; i < num_actors; i++) { | |
| 377 | + u64 extra_range = (u64)extra_actor_power[i] * extra_power; | |
| 378 | + granted_power[i] += DIV_ROUND_CLOSEST_ULL(extra_range, | |
| 379 | + capped_extra_power); | |
| 380 | + } | |
| 380 | 381 | } |
| 381 | 382 | |
| 382 | 383 | static int allocate_power(struct thermal_zone_device *tz, |
| @@ -569,22 +570,33 @@ static void reset_pid_controller(struct power_allocator_params *params) · 186 unmodified lines | ||
| 569 | 570 | params->prev_err = 0; |
| 570 | 571 | } |
| 571 | 572 | |
| 572 | −static void allow_maximum_power(struct thermal_zone_device *tz) | |
| 573 | +static void allow_maximum_power(struct thermal_zone_device *tz, bool update) | |
| 573 | 574 | { |
| 574 | 575 | struct thermal_instance *instance; |
| 575 | 576 | struct power_allocator_params *params = tz->governor_data; |
| 577 | + u32 req_power; | |
| 576 | 578 | |
| 577 | 579 | mutex_lock(&tz->lock); |
| 578 | 580 | list_for_each_entry(instance, &tz->thermal_instances, tz_node) { |
| 581 | + struct thermal_cooling_device *cdev = instance->cdev; | |
| 582 | + | |
| 579 | 583 | if ((instance->trip != params->trip_max_desired_temperature) || |
| 580 | 584 | (!cdev_is_power_actor(instance->cdev))) |
| 581 | 585 | continue; |
| 582 | 586 | |
| 583 | 587 | instance->target = 0; |
| 584 | 588 | mutex_lock(&instance->cdev->lock); |
| 585 | − instance->cdev->updated = false; | |
| 589 | + /* | |
| 590 | + * Call for updating the cooling devices local stats and avoid | |
| 591 | + * periods of dozen of seconds when those have not been | |
| 592 | + * maintained. | |
| 593 | + */ | |
| 594 | + cdev->ops->get_requested_power(cdev, &req_power); | |
| 595 | + | |
| 596 | + if (update) | |
| 597 | + __thermal_cdev_update(instance->cdev); | |
| 598 | + | |
| 586 | 599 | mutex_unlock(&instance->cdev->lock); |
| 587 | − thermal_cdev_update(instance->cdev); | |
| 588 | 600 | } |
| 589 | 601 | mutex_unlock(&tz->lock); |
| 590 | 602 | } |
| @@ -698,6 +710,7 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip) · 107 unmodified lines | ||
| 698 | 710 | int ret; |
| 699 | 711 | int switch_on_temp, control_temp; |
| 700 | 712 | struct power_allocator_params *params = tz->governor_data; |
| 713 | + bool update; | |
| 701 | 714 | |
| 702 | 715 | /* |
| 703 | 716 | * We get called for every trip point but we only need to do |
| @@ -709,9 +722,10 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip) · 5 unmodified lines | ||
| 709 | 722 | ret = tz->ops->get_trip_temp(tz, params->trip_switch_on, |
| 710 | 723 | &switch_on_temp); |
| 711 | 724 | if (!ret && (tz->temperature < switch_on_temp)) { |
| 725 | + update = (tz->last_temperature >= switch_on_temp); | |
| 712 | 726 | tz->passive = 0; |
| 713 | 727 | reset_pid_controller(params); |
| 714 | − allow_maximum_power(tz); | |
| 728 | + allow_maximum_power(tz, update); | |
| 715 | 729 | return 0; |
| 716 | 730 | } |
| 717 | 731 | |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | /* |
| 2 | − * Hisilicon thermal sensor driver | |
| 2 | + * HiSilicon thermal sensor driver | |
| 3 | 3 | * |
| 4 | − * Copyright (c) 2014-2015 Hisilicon Limited. | |
| 4 | + * Copyright (c) 2014-2015 HiSilicon Limited. | |
| 5 | 5 | * Copyright (c) 2014-2015 Linaro Limited. |
| 6 | 6 | * |
| 7 | 7 | * Xinwei Kong <kong.kongxinwei@hisilicon.com> |
| @@ -572,10 +572,8 @@ static int hisi_thermal_probe(struct platform_device *pdev) · 564 unmodified lines | ||
| 572 | 572 | |
| 573 | 573 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 574 | 574 | data->regs = devm_ioremap_resource(dev, res); |
| 575 | − if (IS_ERR(data->regs)) { | |
| 576 | − dev_err(dev, "failed to get io address\n"); | |
| 575 | + if (IS_ERR(data->regs)) | |
| 577 | 576 | return PTR_ERR(data->regs); |
| 578 | − } | |
| 579 | 577 | |
| 580 | 578 | ret = data->ops->probe(data); |
| 581 | 579 | if (ret) |
| @@ -672,5 +670,5 @@ module_platform_driver(hisi_thermal_driver); · 90 unmodified lines | ||
| 672 | 670 | |
| 673 | 671 | MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>"); |
| 674 | 672 | MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>"); |
| 675 | −MODULE_DESCRIPTION("Hisilicon thermal driver"); | |
| 673 | +MODULE_DESCRIPTION("HiSilicon thermal driver"); | |
| 676 | 674 | MODULE_LICENSE("GPL v2"); |
| @@ -79,3 +79,14 @@ config INTEL_PCH_THERMAL · 78 unmodified lines | ||
| 79 | 79 | Enable this to support thermal reporting on certain intel PCHs. |
| 80 | 80 | Thermal reporting device will provide temperature reading, |
| 81 | 81 | programmable trip points and other information. |
| 82 | + | |
| 83 | +config INTEL_TCC_COOLING | |
| 84 | + tristate "Intel TCC offset cooling Driver" | |
| 85 | + depends on X86 | |
| 86 | + help | |
| 87 | + Enable this to support system cooling by adjusting the effective TCC | |
| 88 | + activation temperature via the TCC Offset register, which is widely | |
| 89 | + supported on modern Intel platforms. | |
| 90 | + Note that, on different platforms, the behavior might be different | |
| 91 | + on how fast the setting takes effect, and how much the CPU frequency | |
| 92 | + is reduced. | |
| @@ -10,4 +10,5 @@ obj-$(CONFIG_INTEL_QUARK_DTS_THERMAL) += intel_quark_dts_thermal.o · 9 unmodified lines | ||
| 10 | 10 | obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ |
| 11 | 11 | obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o |
| 12 | 12 | obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o |
| 13 | +obj-$(CONFIG_INTEL_TCC_COOLING) += intel_tcc_cooling.o | |
| 13 | 14 | obj-$(CONFIG_X86_THERMAL_VECTOR) += therm_throt.o |
| @@ -0,0 +1,129 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | +/* | |
| 3 | + * cooling device driver that activates the processor throttling by | |
| 4 | + * programming the TCC Offset register. | |
| 5 | + * Copyright (c) 2021, Intel Corporation. | |
| 6 | + */ | |
| 7 | +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 8 | + | |
| 9 | +#include <linux/device.h> | |
| 10 | +#include <linux/module.h> | |
| 11 | +#include <linux/thermal.h> | |
| 12 | +#include <asm/cpu_device_id.h> | |
| 13 | + | |
| 14 | +#define TCC_SHIFT 24 | |
| 15 | +#define TCC_MASK (0x3fULL<<24) | |
| 16 | +#define TCC_PROGRAMMABLE BIT(30) | |
| 17 | + | |
| 18 | +static struct thermal_cooling_device *tcc_cdev; | |
| 19 | + | |
| 20 | +static int tcc_get_max_state(struct thermal_cooling_device *cdev, unsigned long | |
| 21 | + *state) | |
| 22 | +{ | |
| 23 | + *state = TCC_MASK >> TCC_SHIFT; | |
| 24 | + return 0; | |
| 25 | +} | |
| 26 | + | |
| 27 | +static int tcc_offset_update(int tcc) | |
| 28 | +{ | |
| 29 | + u64 val; | |
| 30 | + int err; | |
| 31 | + | |
| 32 | + err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val); | |
| 33 | + if (err) | |
| 34 | + return err; | |
| 35 | + | |
| 36 | + val &= ~TCC_MASK; | |
| 37 | + val |= tcc << TCC_SHIFT; | |
| 38 | + | |
| 39 | + err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val); | |
| 40 | + if (err) | |
| 41 | + return err; | |
| 42 | + | |
| 43 | + return 0; | |
| 44 | +} | |
| 45 | + | |
| 46 | +static int tcc_get_cur_state(struct thermal_cooling_device *cdev, unsigned long | |
| 47 | + *state) | |
| 48 | +{ | |
| 49 | + u64 val; | |
| 50 | + int err; | |
| 51 | + | |
| 52 | + err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val); | |
| 53 | + if (err) | |
| 54 | + return err; | |
| 55 | + | |
| 56 | + *state = (val & TCC_MASK) >> TCC_SHIFT; | |
| 57 | + return 0; | |
| 58 | +} | |
| 59 | + | |
| 60 | +static int tcc_set_cur_state(struct thermal_cooling_device *cdev, unsigned long | |
| 61 | + state) | |
| 62 | +{ | |
| 63 | + return tcc_offset_update(state); | |
| 64 | +} | |
| 65 | + | |
| 66 | +static const struct thermal_cooling_device_ops tcc_cooling_ops = { | |
| 67 | + .get_max_state = tcc_get_max_state, | |
| 68 | + .get_cur_state = tcc_get_cur_state, | |
| 69 | + .set_cur_state = tcc_set_cur_state, | |
| 70 | +}; | |
| 71 | + | |
| 72 | +static const struct x86_cpu_id tcc_ids[] __initconst = { | |
| 73 | + X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, NULL), | |
| 74 | + X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, NULL), | |
| 75 | + X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, NULL), | |
| 76 | + X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, NULL), | |
| 77 | + X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, NULL), | |
| 78 | + X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, NULL), | |
| 79 | + X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL), | |
| 80 | + X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL), | |
| 81 | + X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL), | |
| 82 | + {} | |
| 83 | +}; | |
| 84 | + | |
| 85 | +MODULE_DEVICE_TABLE(x86cpu, tcc_ids); | |
| 86 | + | |
| 87 | +static int __init tcc_cooling_init(void) | |
| 88 | +{ | |
| 89 | + int ret; | |
| 90 | + u64 val; | |
| 91 | + const struct x86_cpu_id *id; | |
| 92 | + | |
| 93 | + int err; | |
| 94 | + | |
| 95 | + id = x86_match_cpu(tcc_ids); | |
| 96 | + if (!id) | |
| 97 | + return -ENODEV; | |
| 98 | + | |
| 99 | + err = rdmsrl_safe(MSR_PLATFORM_INFO, &val); | |
| 100 | + if (err) | |
| 101 | + return err; | |
| 102 | + | |
| 103 | + if (!(val & TCC_PROGRAMMABLE)) | |
| 104 | + return -ENODEV; | |
| 105 | + | |
| 106 | + pr_info("Programmable TCC Offset detected\n"); | |
| 107 | + | |
| 108 | + tcc_cdev = | |
| 109 | + thermal_cooling_device_register("TCC Offset", NULL, | |
| 110 | + &tcc_cooling_ops); | |
| 111 | + if (IS_ERR(tcc_cdev)) { | |
| 112 | + ret = PTR_ERR(tcc_cdev); | |
| 113 | + return ret; | |
| 114 | + } | |
| 115 | + return 0; | |
| 116 | +} | |
| 117 | + | |
| 118 | +module_init(tcc_cooling_init) | |
| 119 | + | |
| 120 | +static void __exit tcc_cooling_exit(void) | |
| 121 | +{ | |
| 122 | + thermal_cooling_device_unregister(tcc_cdev); | |
| 123 | +} | |
| 124 | + | |
| 125 | +module_exit(tcc_cooling_exit) | |
| 126 | + | |
| 127 | +MODULE_DESCRIPTION("TCC offset cooling device Driver"); | |
| 128 | +MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>"); | |
| 129 | +MODULE_LICENSE("GPL v2"); | |
| @@ -573,12 +573,12 @@ static int raw_to_mcelsius_v1(struct mtk_thermal *mt, int sensno, s32 raw) · 572 unmodified lines | ||
| 573 | 573 | |
| 574 | 574 | static int raw_to_mcelsius_v2(struct mtk_thermal *mt, int sensno, s32 raw) |
| 575 | 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; | |
| 576 | + s32 format_1; | |
| 577 | + s32 format_2; | |
| 578 | + s32 g_oe; | |
| 579 | + s32 g_gain; | |
| 580 | + s32 g_x_roomt; | |
| 581 | + s32 tmp; | |
| 582 | 582 | |
| 583 | 583 | if (raw == 0) |
| 584 | 584 | return 0; |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | #include "../thermal_core.h" |
| 19 | 19 | |
| 20 | +#define QPNP_TM_REG_DIG_MAJOR 0x01 | |
| 20 | 21 | #define QPNP_TM_REG_TYPE 0x04 |
| 21 | 22 | #define QPNP_TM_REG_SUBTYPE 0x05 |
| 22 | 23 | #define QPNP_TM_REG_STATUS 0x08 |
| @@ -38,26 +39,30 @@ · 15 unmodified lines | ||
| 38 | 39 | |
| 39 | 40 | #define ALARM_CTRL_FORCE_ENABLE BIT(7) |
| 40 | 41 | |
| 41 | −/* | |
| 42 | − * Trip point values based on threshold control | |
| 43 | − * 0 = {105 C, 125 C, 145 C} | |
| 44 | − * 1 = {110 C, 130 C, 150 C} | |
| 45 | − * 2 = {115 C, 135 C, 155 C} | |
| 46 | − * 3 = {120 C, 140 C, 160 C} | |
| 47 | −*/ | |
| 48 | −#define TEMP_STAGE_STEP 20000 /* Stage step: 20.000 C */ | |
| 49 | −#define TEMP_STAGE_HYSTERESIS 2000 | |
| 42 | +#define THRESH_COUNT 4 | |
| 43 | +#define STAGE_COUNT 3 | |
| 44 | + | |
| 45 | +/* Over-temperature trip point values in mC */ | |
| 46 | +static const long temp_map_gen1[THRESH_COUNT][STAGE_COUNT] = { | |
| 47 | + { 105000, 125000, 145000 }, | |
| 48 | + { 110000, 130000, 150000 }, | |
| 49 | + { 115000, 135000, 155000 }, | |
| 50 | + { 120000, 140000, 160000 }, | |
| 51 | +}; | |
| 52 | + | |
| 53 | +static const long temp_map_gen2_v1[THRESH_COUNT][STAGE_COUNT] = { | |
| 54 | + { 90000, 110000, 140000 }, | |
| 55 | + { 95000, 115000, 145000 }, | |
| 56 | + { 100000, 120000, 150000 }, | |
| 57 | + { 105000, 125000, 155000 }, | |
| 58 | +}; | |
| 50 | 59 | |
| 51 | −#define TEMP_THRESH_MIN 105000 /* Threshold Min: 105 C */ | |
| 52 | −#define TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */ | |
| 60 | +#define TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */ | |
| 53 | 61 | |
| 54 | 62 | #define THRESH_MIN 0 |
| 55 | 63 | #define THRESH_MAX 3 |
| 56 | 64 | |
| 57 | −/* Stage 2 Threshold Min: 125 C */ | |
| 58 | −#define STAGE2_THRESHOLD_MIN 125000 | |
| 59 | −/* Stage 2 Threshold Max: 140 C */ | |
| 60 | −#define STAGE2_THRESHOLD_MAX 140000 | |
| 65 | +#define TEMP_STAGE_HYSTERESIS 2000 | |
| 61 | 66 | |
| 62 | 67 | /* Temperature in Milli Celsius reported during stage 0 if no ADC is present */ |
| 63 | 68 | #define DEFAULT_TEMP 37000 |
| @@ -77,6 +82,7 @@ struct qpnp_tm_chip { · 13 unmodified lines | ||
| 77 | 82 | bool initialized; |
| 78 | 83 | |
| 79 | 84 | struct iio_channel *adc; |
| 85 | + const long (*temp_map)[THRESH_COUNT][STAGE_COUNT]; | |
| 80 | 86 | }; |
| 81 | 87 | |
| 82 | 88 | /* This array maps from GEN2 alarm state to GEN1 alarm stage */ |
| @@ -100,6 +106,23 @@ static int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 data) · 17 unmodified lines | ||
| 100 | 106 | return regmap_write(chip->map, chip->base + addr, data); |
| 101 | 107 | } |
| 102 | 108 | |
| 109 | +/** | |
| 110 | + * qpnp_tm_decode_temp() - return temperature in mC corresponding to the | |
| 111 | + * specified over-temperature stage | |
| 112 | + * @chip: Pointer to the qpnp_tm chip | |
| 113 | + * @stage: Over-temperature stage | |
| 114 | + * | |
| 115 | + * Return: temperature in mC | |
| 116 | + */ | |
| 117 | +static long qpnp_tm_decode_temp(struct qpnp_tm_chip *chip, unsigned int stage) | |
| 118 | +{ | |
| 119 | + if (!chip->temp_map || chip->thresh >= THRESH_COUNT || stage == 0 || | |
| 120 | + stage > STAGE_COUNT) | |
| 121 | + return 0; | |
| 122 | + | |
| 123 | + return (*chip->temp_map)[chip->thresh][stage - 1]; | |
| 124 | +} | |
| 125 | + | |
| 103 | 126 | /** |
| 104 | 127 | * qpnp_tm_get_temp_stage() - return over-temperature stage |
| 105 | 128 | * @chip: Pointer to the qpnp_tm chip |
| @@ -149,14 +172,12 @@ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip) · 43 unmodified lines | ||
| 149 | 172 | |
| 150 | 173 | if (stage_new > stage_old) { |
| 151 | 174 | /* increasing stage, use lower bound */ |
| 152 | − chip->temp = (stage_new - 1) * TEMP_STAGE_STEP + | |
| 153 | − chip->thresh * TEMP_THRESH_STEP + | |
| 154 | − TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN; | |
| 175 | + chip->temp = qpnp_tm_decode_temp(chip, stage_new) | |
| 176 | + + TEMP_STAGE_HYSTERESIS; | |
| 155 | 177 | } else if (stage_new < stage_old) { |
| 156 | 178 | /* decreasing stage, use upper bound */ |
| 157 | − chip->temp = stage_new * TEMP_STAGE_STEP + | |
| 158 | − chip->thresh * TEMP_THRESH_STEP - | |
| 159 | − TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN; | |
| 179 | + chip->temp = qpnp_tm_decode_temp(chip, stage_new + 1) | |
| 180 | + - TEMP_STAGE_HYSTERESIS; | |
| 160 | 181 | } |
| 161 | 182 | |
| 162 | 183 | chip->stage = stage; |
| @@ -199,26 +220,28 @@ static int qpnp_tm_get_temp(void *data, int *temp) · 36 unmodified lines | ||
| 199 | 220 | static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip, |
| 200 | 221 | int temp) |
| 201 | 222 | { |
| 202 | − u8 reg; | |
| 223 | + long stage2_threshold_min = (*chip->temp_map)[THRESH_MIN][1]; | |
| 224 | + long stage2_threshold_max = (*chip->temp_map)[THRESH_MAX][1]; | |
| 203 | 225 | bool disable_s2_shutdown = false; |
| 226 | + u8 reg; | |
| 204 | 227 | |
| 205 | 228 | WARN_ON(!mutex_is_locked(&chip->lock)); |
| 206 | 229 | |
| 207 | 230 | /* |
| 208 | 231 | * Default: S2 and S3 shutdown enabled, thresholds at |
| 209 | − * 105C/125C/145C, monitoring at 25Hz | |
| 232 | + * lowest threshold set, monitoring at 25Hz | |
| 210 | 233 | */ |
| 211 | 234 | reg = SHUTDOWN_CTRL1_RATE_25HZ; |
| 212 | 235 | |
| 213 | 236 | if (temp == THERMAL_TEMP_INVALID || |
| 214 | − temp < STAGE2_THRESHOLD_MIN) { | |
| 237 | + temp < stage2_threshold_min) { | |
| 215 | 238 | chip->thresh = THRESH_MIN; |
| 216 | 239 | goto skip; |
| 217 | 240 | } |
| 218 | 241 | |
| 219 | − if (temp <= STAGE2_THRESHOLD_MAX) { | |
| 242 | + if (temp <= stage2_threshold_max) { | |
| 220 | 243 | chip->thresh = THRESH_MAX - |
| 221 | − ((STAGE2_THRESHOLD_MAX - temp) / | |
| 244 | + ((stage2_threshold_max - temp) / | |
| 222 | 245 | TEMP_THRESH_STEP); |
| 223 | 246 | disable_s2_shutdown = true; |
| 224 | 247 | } else { |
| @@ -326,9 +349,7 @@ static int qpnp_tm_init(struct qpnp_tm_chip *chip) · 101 unmodified lines | ||
| 326 | 349 | ? chip->stage : alarm_state_map[chip->stage]; |
| 327 | 350 | |
| 328 | 351 | if (stage) |
| 329 | − chip->temp = chip->thresh * TEMP_THRESH_STEP + | |
| 330 | − (stage - 1) * TEMP_STAGE_STEP + | |
| 331 | − TEMP_THRESH_MIN; | |
| 352 | + chip->temp = qpnp_tm_decode_temp(chip, stage); | |
| 332 | 353 | |
| 333 | 354 | crit_temp = qpnp_tm_get_critical_trip_temp(chip); |
| 334 | 355 | ret = qpnp_tm_update_critical_trip_temp(chip, crit_temp); |
| @@ -350,7 +371,7 @@ static int qpnp_tm_probe(struct platform_device *pdev) · 15 unmodified lines | ||
| 350 | 371 | { |
| 351 | 372 | struct qpnp_tm_chip *chip; |
| 352 | 373 | struct device_node *node; |
| 353 | − u8 type, subtype; | |
| 374 | + u8 type, subtype, dig_major; | |
| 354 | 375 | u32 res; |
| 355 | 376 | int ret, irq; |
| 356 | 377 | |
| @@ -400,6 +421,12 @@ static int qpnp_tm_probe(struct platform_device *pdev) · 43 unmodified lines | ||
| 400 | 421 | return ret; |
| 401 | 422 | } |
| 402 | 423 | |
| 424 | + ret = qpnp_tm_read(chip, QPNP_TM_REG_DIG_MAJOR, &dig_major); | |
| 425 | + if (ret < 0) { | |
| 426 | + dev_err(&pdev->dev, "could not read dig_major\n"); | |
| 427 | + return ret; | |
| 428 | + } | |
| 429 | + | |
| 403 | 430 | if (type != QPNP_TM_TYPE || (subtype != QPNP_TM_SUBTYPE_GEN1 |
| 404 | 431 | && subtype != QPNP_TM_SUBTYPE_GEN2)) { |
| 405 | 432 | dev_err(&pdev->dev, "invalid type 0x%02x or subtype 0x%02x\n", |
| @@ -408,6 +435,10 @@ static int qpnp_tm_probe(struct platform_device *pdev) · 2 unmodified lines | ||
| 408 | 435 | } |
| 409 | 436 | |
| 410 | 437 | chip->subtype = subtype; |
| 438 | + if (subtype == QPNP_TM_SUBTYPE_GEN2 && dig_major >= 1) | |
| 439 | + chip->temp_map = &temp_map_gen2_v1; | |
| 440 | + else | |
| 441 | + chip->temp_map = &temp_map_gen1; | |
| 411 | 442 | |
| 412 | 443 | /* |
| 413 | 444 | * Register the sensor before initializing the hardware to be able to |
| @@ -10,8 +10,6 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/thermal.h> |
| 11 | 11 | #include "tsens.h" |
| 12 | 12 | |
| 13 | −#define CAL_MDEGC 30000 | |
| 14 | − | |
| 15 | 13 | #define CONFIG_ADDR 0x3640 |
| 16 | 14 | #define CONFIG_ADDR_8660 0x3620 |
| 17 | 15 | /* CONFIG_ADDR bitmasks */ |
| @@ -21,40 +19,38 @@ · 3 unmodified lines | ||
| 21 | 19 | #define CONFIG_SHIFT_8660 28 |
| 22 | 20 | #define CONFIG_MASK_8660 (3 << CONFIG_SHIFT_8660) |
| 23 | 21 | |
| 24 | −#define STATUS_CNTL_ADDR_8064 0x3660 | |
| 25 | 22 | #define CNTL_ADDR 0x3620 |
| 26 | 23 | /* CNTL_ADDR bitmasks */ |
| 27 | 24 | #define EN BIT(0) |
| 28 | 25 | #define SW_RST BIT(1) |
| 29 | −#define SENSOR0_EN BIT(3) | |
| 26 | + | |
| 27 | +#define MEASURE_PERIOD BIT(18) | |
| 30 | 28 | #define SLP_CLK_ENA BIT(26) |
| 31 | 29 | #define SLP_CLK_ENA_8660 BIT(24) |
| 32 | −#define MEASURE_PERIOD 1 | |
| 33 | 30 | #define SENSOR0_SHIFT 3 |
| 34 | 31 | |
| 35 | −/* INT_STATUS_ADDR bitmasks */ | |
| 36 | −#define MIN_STATUS_MASK BIT(0) | |
| 37 | −#define LOWER_STATUS_CLR BIT(1) | |
| 38 | −#define UPPER_STATUS_CLR BIT(2) | |
| 39 | −#define MAX_STATUS_MASK BIT(3) | |
| 40 | − | |
| 41 | 32 | #define THRESHOLD_ADDR 0x3624 |
| 42 | −/* THRESHOLD_ADDR bitmasks */ | |
| 43 | −#define THRESHOLD_MAX_LIMIT_SHIFT 24 | |
| 44 | −#define THRESHOLD_MIN_LIMIT_SHIFT 16 | |
| 45 | −#define THRESHOLD_UPPER_LIMIT_SHIFT 8 | |
| 46 | −#define THRESHOLD_LOWER_LIMIT_SHIFT 0 | |
| 47 | − | |
| 48 | −/* Initial temperature threshold values */ | |
| 49 | −#define LOWER_LIMIT_TH 0x50 | |
| 50 | −#define UPPER_LIMIT_TH 0xdf | |
| 51 | −#define MIN_LIMIT_TH 0x0 | |
| 52 | −#define MAX_LIMIT_TH 0xff | |
| 53 | − | |
| 54 | −#define S0_STATUS_ADDR 0x3628 | |
| 33 | + | |
| 55 | 34 | #define INT_STATUS_ADDR 0x363c |
| 56 | −#define TRDY_MASK BIT(7) | |
| 57 | −#define TIMEOUT_US 100 | |
| 35 | + | |
| 36 | +#define S0_STATUS_OFF 0x3628 | |
| 37 | +#define S1_STATUS_OFF 0x362c | |
| 38 | +#define S2_STATUS_OFF 0x3630 | |
| 39 | +#define S3_STATUS_OFF 0x3634 | |
| 40 | +#define S4_STATUS_OFF 0x3638 | |
| 41 | +#define S5_STATUS_OFF 0x3664 /* Sensors 5-10 found on apq8064/msm8960 */ | |
| 42 | +#define S6_STATUS_OFF 0x3668 | |
| 43 | +#define S7_STATUS_OFF 0x366c | |
| 44 | +#define S8_STATUS_OFF 0x3670 | |
| 45 | +#define S9_STATUS_OFF 0x3674 | |
| 46 | +#define S10_STATUS_OFF 0x3678 | |
| 47 | + | |
| 48 | +/* Original slope - 350 to compensate mC to C inaccuracy */ | |
| 49 | +static u32 tsens_msm8960_slope[] = { | |
| 50 | + 826, 826, 804, 826, | |
| 51 | + 761, 782, 782, 849, | |
| 52 | + 782, 849, 782 | |
| 53 | + }; | |
| 58 | 54 | |
| 59 | 55 | static int suspend_8960(struct tsens_priv *priv) |
| 60 | 56 | { |
| @@ -115,17 +111,34 @@ static int resume_8960(struct tsens_priv *priv) · 54 unmodified lines | ||
| 115 | 111 | static int enable_8960(struct tsens_priv *priv, int id) |
| 116 | 112 | { |
| 117 | 113 | int ret; |
| 118 | − u32 reg, mask; | |
| 114 | + u32 reg, mask = BIT(id); | |
| 119 | 115 | |
| 120 | 116 | ret = regmap_read(priv->tm_map, CNTL_ADDR, ®); |
| 121 | 117 | if (ret) |
| 122 | 118 | return ret; |
| 123 | 119 | |
| 124 | − mask = BIT(id + SENSOR0_SHIFT); | |
| 120 | + /* HARDWARE BUG: | |
| 121 | + * On platforms with more than 6 sensors, all remaining sensors | |
| 122 | + * must be enabled together, otherwise undefined results are expected. | |
| 123 | + * (Sensor 6-7 disabled, Sensor 3 disabled...) In the original driver, | |
| 124 | + * all the sensors are enabled in one step hence this bug is not | |
| 125 | + * triggered. | |
| 126 | + */ | |
| 127 | + if (id > 5) | |
| 128 | + mask = GENMASK(10, 6); | |
| 129 | + | |
| 130 | + mask <<= SENSOR0_SHIFT; | |
| 131 | + | |
| 132 | + /* Sensors already enabled. Skip. */ | |
| 133 | + if ((reg & mask) == mask) | |
| 134 | + return 0; | |
| 135 | + | |
| 125 | 136 | ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST); |
| 126 | 137 | if (ret) |
| 127 | 138 | return ret; |
| 128 | 139 | |
| 140 | + reg |= MEASURE_PERIOD; | |
| 141 | + | |
| 129 | 142 | if (priv->num_sensors > 1) |
| 130 | 143 | reg |= mask | SLP_CLK_ENA | EN; |
| 131 | 144 | else |
| @@ -162,63 +175,11 @@ static void disable_8960(struct tsens_priv *priv) · 30 unmodified lines | ||
| 162 | 175 | regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); |
| 163 | 176 | } |
| 164 | 177 | |
| 165 | −static int init_8960(struct tsens_priv *priv) | |
| 166 | −{ | |
| 167 | − int ret, i; | |
| 168 | − u32 reg_cntl; | |
| 169 | − | |
| 170 | − priv->tm_map = dev_get_regmap(priv->dev, NULL); | |
| 171 | − if (!priv->tm_map) | |
| 172 | − return -ENODEV; | |
| 173 | − | |
| 174 | − /* | |
| 175 | − * The status registers for each sensor are discontiguous | |
| 176 | − * because some SoCs have 5 sensors while others have more | |
| 177 | − * but the control registers stay in the same place, i.e | |
| 178 | − * directly after the first 5 status registers. | |
| 179 | − */ | |
| 180 | − for (i = 0; i < priv->num_sensors; i++) { | |
| 181 | − if (i >= 5) | |
| 182 | − priv->sensor[i].status = S0_STATUS_ADDR + 40; | |
| 183 | − priv->sensor[i].status += i * 4; | |
| 184 | − } | |
| 185 | − | |
| 186 | − reg_cntl = SW_RST; | |
| 187 | − ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl); | |
| 188 | − if (ret) | |
| 189 | − return ret; | |
| 190 | − | |
| 191 | − if (priv->num_sensors > 1) { | |
| 192 | − reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18); | |
| 193 | − reg_cntl &= ~SW_RST; | |
| 194 | − ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR, | |
| 195 | − CONFIG_MASK, CONFIG); | |
| 196 | − } else { | |
| 197 | − reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16); | |
| 198 | − reg_cntl &= ~CONFIG_MASK_8660; | |
| 199 | − reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660; | |
| 200 | − } | |
| 201 | − | |
| 202 | − reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT; | |
| 203 | − ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); | |
| 204 | − if (ret) | |
| 205 | − return ret; | |
| 206 | − | |
| 207 | − reg_cntl |= EN; | |
| 208 | − ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); | |
| 209 | − if (ret) | |
| 210 | − return ret; | |
| 211 | − | |
| 212 | − return 0; | |
| 213 | −} | |
| 214 | − | |
| 215 | 178 | static int calibrate_8960(struct tsens_priv *priv) |
| 216 | 179 | { |
| 217 | 180 | int i; |
| 218 | 181 | char *data; |
| 219 | − | |
| 220 | − ssize_t num_read = priv->num_sensors; | |
| 221 | − struct tsens_sensor *s = priv->sensor; | |
| 182 | + u32 p1[11]; | |
| 222 | 183 | |
| 223 | 184 | data = qfprom_read(priv->dev, "calib"); |
| 224 | 185 | if (IS_ERR(data)) |
| @@ -226,60 +187,96 @@ static int calibrate_8960(struct tsens_priv *priv) · 1 unmodified line | ||
| 226 | 187 | if (IS_ERR(data)) |
| 227 | 188 | return PTR_ERR(data); |
| 228 | 189 | |
| 229 | − for (i = 0; i < num_read; i++, s++) | |
| 230 | − s->offset = data[i]; | |
| 190 | + for (i = 0; i < priv->num_sensors; i++) { | |
| 191 | + p1[i] = data[i]; | |
| 192 | + priv->sensor[i].slope = tsens_msm8960_slope[i]; | |
| 193 | + } | |
| 194 | + | |
| 195 | + compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB); | |
| 231 | 196 | |
| 232 | 197 | kfree(data); |
| 233 | 198 | |
| 234 | 199 | return 0; |
| 235 | 200 | } |
| 236 | 201 | |
| 237 | −/* Temperature on y axis and ADC-code on x-axis */ | |
| 238 | −static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s) | |
| 239 | −{ | |
| 240 | − int slope, offset; | |
| 241 | − | |
| 242 | − slope = thermal_zone_get_slope(s->tzd); | |
| 243 | − offset = CAL_MDEGC - slope * s->offset; | |
| 244 | − | |
| 245 | − return adc_code * slope + offset; | |
| 246 | −} | |
| 247 | − | |
| 248 | −static int get_temp_8960(const struct tsens_sensor *s, int *temp) | |
| 249 | −{ | |
| 250 | − int ret; | |
| 251 | − u32 code, trdy; | |
| 252 | − struct tsens_priv *priv = s->priv; | |
| 253 | − unsigned long timeout; | |
| 254 | − | |
| 255 | − timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); | |
| 256 | − do { | |
| 257 | − ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy); | |
| 258 | − if (ret) | |
| 259 | − return ret; | |
| 260 | − if (!(trdy & TRDY_MASK)) | |
| 261 | − continue; | |
| 262 | − ret = regmap_read(priv->tm_map, s->status, &code); | |
| 263 | − if (ret) | |
| 264 | − return ret; | |
| 265 | − *temp = code_to_mdegC(code, s); | |
| 266 | − return 0; | |
| 267 | − } while (time_before(jiffies, timeout)); | |
| 268 | − | |
| 269 | − return -ETIMEDOUT; | |
| 270 | −} | |
| 202 | +static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = { | |
| 203 | + /* ----- SROT ------ */ | |
| 204 | + /* No VERSION information */ | |
| 205 | + | |
| 206 | + /* CNTL */ | |
| 207 | + [TSENS_EN] = REG_FIELD(CNTL_ADDR, 0, 0), | |
| 208 | + [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR, 1, 1), | |
| 209 | + /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */ | |
| 210 | + [SENSOR_EN] = REG_FIELD(CNTL_ADDR, 3, 7), | |
| 211 | + | |
| 212 | + /* ----- TM ------ */ | |
| 213 | + /* INTERRUPT ENABLE */ | |
| 214 | + /* NO INTERRUPT ENABLE */ | |
| 215 | + | |
| 216 | + /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */ | |
| 217 | + [LOW_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 0, 7), | |
| 218 | + [UP_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 8, 15), | |
| 219 | + /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield | |
| 220 | + * Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded temp | |
| 221 | + * MIN_THRESH_0 -> CRIT_THRESH_1 | |
| 222 | + * MAX_THRESH_0 -> CRIT_THRESH_0 | |
| 223 | + */ | |
| 224 | + [CRIT_THRESH_1] = REG_FIELD(THRESHOLD_ADDR, 16, 23), | |
| 225 | + [CRIT_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 24, 31), | |
| 226 | + | |
| 227 | + /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */ | |
| 228 | + /* 1 == clear, 0 == normal operation */ | |
| 229 | + [LOW_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 9, 9), | |
| 230 | + [UP_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 10, 10), | |
| 231 | + | |
| 232 | + /* NO CRITICAL INTERRUPT SUPPORT on 8960 */ | |
| 233 | + | |
| 234 | + /* Sn_STATUS */ | |
| 235 | + [LAST_TEMP_0] = REG_FIELD(S0_STATUS_OFF, 0, 7), | |
| 236 | + [LAST_TEMP_1] = REG_FIELD(S1_STATUS_OFF, 0, 7), | |
| 237 | + [LAST_TEMP_2] = REG_FIELD(S2_STATUS_OFF, 0, 7), | |
| 238 | + [LAST_TEMP_3] = REG_FIELD(S3_STATUS_OFF, 0, 7), | |
| 239 | + [LAST_TEMP_4] = REG_FIELD(S4_STATUS_OFF, 0, 7), | |
| 240 | + [LAST_TEMP_5] = REG_FIELD(S5_STATUS_OFF, 0, 7), | |
| 241 | + [LAST_TEMP_6] = REG_FIELD(S6_STATUS_OFF, 0, 7), | |
| 242 | + [LAST_TEMP_7] = REG_FIELD(S7_STATUS_OFF, 0, 7), | |
| 243 | + [LAST_TEMP_8] = REG_FIELD(S8_STATUS_OFF, 0, 7), | |
| 244 | + [LAST_TEMP_9] = REG_FIELD(S9_STATUS_OFF, 0, 7), | |
| 245 | + [LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0, 7), | |
| 246 | + | |
| 247 | + /* No VALID field on 8960 */ | |
| 248 | + /* TSENS_INT_STATUS bits: 1 == threshold violated */ | |
| 249 | + [MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0), | |
| 250 | + [LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1), | |
| 251 | + [UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2), | |
| 252 | + /* No CRITICAL field on 8960 */ | |
| 253 | + [MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3), | |
| 254 | + | |
| 255 | + /* TRDY: 1=ready, 0=in progress */ | |
| 256 | + [TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7), | |
| 257 | +}; | |
| 271 | 258 | |
| 272 | 259 | static const struct tsens_ops ops_8960 = { |
| 273 | − .init = init_8960, | |
| 260 | + .init = init_common, | |
| 274 | 261 | .calibrate = calibrate_8960, |
| 275 | − .get_temp = get_temp_8960, | |
| 262 | + .get_temp = get_temp_common, | |
| 276 | 263 | .enable = enable_8960, |
| 277 | 264 | .disable = disable_8960, |
| 278 | 265 | .suspend = suspend_8960, |
| 279 | 266 | .resume = resume_8960, |
| 280 | 267 | }; |
| 281 | 268 | |
| 269 | +static struct tsens_features tsens_8960_feat = { | |
| 270 | + .ver_major = VER_0, | |
| 271 | + .crit_int = 0, | |
| 272 | + .adc = 1, | |
| 273 | + .srot_split = 0, | |
| 274 | + .max_sensors = 11, | |
| 275 | +}; | |
| 276 | + | |
| 282 | 277 | struct tsens_plat_data data_8960 = { |
| 283 | 278 | .num_sensors = 11, |
| 284 | 279 | .ops = &ops_8960, |
| 280 | + .feat = &tsens_8960_feat, | |
| 281 | + .fields = tsens_8960_regfields, | |
| 285 | 282 | }; |
| @@ -190,6 +190,39 @@ · 189 unmodified lines | ||
| 190 | 190 | |
| 191 | 191 | #define BIT_APPEND 0x3 |
| 192 | 192 | |
| 193 | +/* eeprom layout data for mdm9607 */ | |
| 194 | +#define MDM9607_BASE0_MASK 0x000000ff | |
| 195 | +#define MDM9607_BASE1_MASK 0x000ff000 | |
| 196 | +#define MDM9607_BASE0_SHIFT 0 | |
| 197 | +#define MDM9607_BASE1_SHIFT 12 | |
| 198 | + | |
| 199 | +#define MDM9607_S0_P1_MASK 0x00003f00 | |
| 200 | +#define MDM9607_S1_P1_MASK 0x03f00000 | |
| 201 | +#define MDM9607_S2_P1_MASK 0x0000003f | |
| 202 | +#define MDM9607_S3_P1_MASK 0x0003f000 | |
| 203 | +#define MDM9607_S4_P1_MASK 0x0000003f | |
| 204 | + | |
| 205 | +#define MDM9607_S0_P2_MASK 0x000fc000 | |
| 206 | +#define MDM9607_S1_P2_MASK 0xfc000000 | |
| 207 | +#define MDM9607_S2_P2_MASK 0x00000fc0 | |
| 208 | +#define MDM9607_S3_P2_MASK 0x00fc0000 | |
| 209 | +#define MDM9607_S4_P2_MASK 0x00000fc0 | |
| 210 | + | |
| 211 | +#define MDM9607_S0_P1_SHIFT 8 | |
| 212 | +#define MDM9607_S1_P1_SHIFT 20 | |
| 213 | +#define MDM9607_S2_P1_SHIFT 0 | |
| 214 | +#define MDM9607_S3_P1_SHIFT 12 | |
| 215 | +#define MDM9607_S4_P1_SHIFT 0 | |
| 216 | + | |
| 217 | +#define MDM9607_S0_P2_SHIFT 14 | |
| 218 | +#define MDM9607_S1_P2_SHIFT 26 | |
| 219 | +#define MDM9607_S2_P2_SHIFT 6 | |
| 220 | +#define MDM9607_S3_P2_SHIFT 18 | |
| 221 | +#define MDM9607_S4_P2_SHIFT 6 | |
| 222 | + | |
| 223 | +#define MDM9607_CAL_SEL_MASK 0x00700000 | |
| 224 | +#define MDM9607_CAL_SEL_SHIFT 20 | |
| 225 | + | |
| 193 | 226 | static int calibrate_8916(struct tsens_priv *priv) |
| 194 | 227 | { |
| 195 | 228 | int base0 = 0, base1 = 0, i; |
| @@ -452,7 +485,56 @@ static int calibrate_8974(struct tsens_priv *priv) · 256 unmodified lines | ||
| 452 | 485 | return 0; |
| 453 | 486 | } |
| 454 | 487 | |
| 455 | −/* v0.1: 8916, 8939, 8974 */ | |
| 488 | +static int calibrate_9607(struct tsens_priv *priv) | |
| 489 | +{ | |
| 490 | + int base, i; | |
| 491 | + u32 p1[5], p2[5]; | |
| 492 | + int mode = 0; | |
| 493 | + u32 *qfprom_cdata; | |
| 494 | + | |
| 495 | + qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib"); | |
| 496 | + if (IS_ERR(qfprom_cdata)) | |
| 497 | + return PTR_ERR(qfprom_cdata); | |
| 498 | + | |
| 499 | + mode = (qfprom_cdata[2] & MDM9607_CAL_SEL_MASK) >> MDM9607_CAL_SEL_SHIFT; | |
| 500 | + dev_dbg(priv->dev, "calibration mode is %d\n", mode); | |
| 501 | + | |
| 502 | + switch (mode) { | |
| 503 | + case TWO_PT_CALIB: | |
| 504 | + base = (qfprom_cdata[2] & MDM9607_BASE1_MASK) >> MDM9607_BASE1_SHIFT; | |
| 505 | + p2[0] = (qfprom_cdata[0] & MDM9607_S0_P2_MASK) >> MDM9607_S0_P2_SHIFT; | |
| 506 | + p2[1] = (qfprom_cdata[0] & MDM9607_S1_P2_MASK) >> MDM9607_S1_P2_SHIFT; | |
| 507 | + p2[2] = (qfprom_cdata[1] & MDM9607_S2_P2_MASK) >> MDM9607_S2_P2_SHIFT; | |
| 508 | + p2[3] = (qfprom_cdata[1] & MDM9607_S3_P2_MASK) >> MDM9607_S3_P2_SHIFT; | |
| 509 | + p2[4] = (qfprom_cdata[2] & MDM9607_S4_P2_MASK) >> MDM9607_S4_P2_SHIFT; | |
| 510 | + for (i = 0; i < priv->num_sensors; i++) | |
| 511 | + p2[i] = ((base + p2[i]) << 2); | |
| 512 | + fallthrough; | |
| 513 | + case ONE_PT_CALIB2: | |
| 514 | + base = (qfprom_cdata[0] & MDM9607_BASE0_MASK); | |
| 515 | + p1[0] = (qfprom_cdata[0] & MDM9607_S0_P1_MASK) >> MDM9607_S0_P1_SHIFT; | |
| 516 | + p1[1] = (qfprom_cdata[0] & MDM9607_S1_P1_MASK) >> MDM9607_S1_P1_SHIFT; | |
| 517 | + p1[2] = (qfprom_cdata[1] & MDM9607_S2_P1_MASK) >> MDM9607_S2_P1_SHIFT; | |
| 518 | + p1[3] = (qfprom_cdata[1] & MDM9607_S3_P1_MASK) >> MDM9607_S3_P1_SHIFT; | |
| 519 | + p1[4] = (qfprom_cdata[2] & MDM9607_S4_P1_MASK) >> MDM9607_S4_P1_SHIFT; | |
| 520 | + for (i = 0; i < priv->num_sensors; i++) | |
| 521 | + p1[i] = ((base + p1[i]) << 2); | |
| 522 | + break; | |
| 523 | + default: | |
| 524 | + for (i = 0; i < priv->num_sensors; i++) { | |
| 525 | + p1[i] = 500; | |
| 526 | + p2[i] = 780; | |
| 527 | + } | |
| 528 | + break; | |
| 529 | + } | |
| 530 | + | |
| 531 | + compute_intercept_slope(priv, p1, p2, mode); | |
| 532 | + kfree(qfprom_cdata); | |
| 533 | + | |
| 534 | + return 0; | |
| 535 | +} | |
| 536 | + | |
| 537 | +/* v0.1: 8916, 8939, 8974, 9607 */ | |
| 456 | 538 | |
| 457 | 539 | static struct tsens_features tsens_v0_1_feat = { |
| 458 | 540 | .ver_major = VER_0_1, |
| @@ -540,3 +622,17 @@ struct tsens_plat_data data_8974 = { · 81 unmodified lines | ||
| 540 | 622 | .feat = &tsens_v0_1_feat, |
| 541 | 623 | .fields = tsens_v0_1_regfields, |
| 542 | 624 | }; |
| 625 | + | |
| 626 | +static const struct tsens_ops ops_9607 = { | |
| 627 | + .init = init_common, | |
| 628 | + .calibrate = calibrate_9607, | |
| 629 | + .get_temp = get_temp_common, | |
| 630 | +}; | |
| 631 | + | |
| 632 | +struct tsens_plat_data data_9607 = { | |
| 633 | + .num_sensors = 5, | |
| 634 | + .ops = &ops_9607, | |
| 635 | + .hw_ids = (unsigned int []){ 0, 1, 2, 3, 4 }, | |
| 636 | + .feat = &tsens_v0_1_feat, | |
| 637 | + .fields = tsens_v0_1_regfields, | |
| 638 | +}; | |
| @@ -380,11 +380,11 @@ static const struct tsens_ops ops_8976 = { · 379 unmodified lines | ||
| 380 | 380 | .get_temp = get_temp_tsens_valid, |
| 381 | 381 | }; |
| 382 | 382 | |
| 383 | −/* Valid for both MSM8956 and MSM8976. Sensor ID 3 is unused. */ | |
| 383 | +/* Valid for both MSM8956 and MSM8976. */ | |
| 384 | 384 | struct tsens_plat_data data_8976 = { |
| 385 | 385 | .num_sensors = 11, |
| 386 | 386 | .ops = &ops_8976, |
| 387 | − .hw_ids = (unsigned int[]){0, 1, 2, 4, 5, 6, 7, 8, 9, 10}, | |
| 387 | + .hw_ids = (unsigned int[]){0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, | |
| 388 | 388 | .feat = &tsens_v1_feat, |
| 389 | 389 | .fields = tsens_v1_regfields, |
| 390 | 390 | }; |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | ||
| 12 | 12 | #include <linux/of.h> |
| 13 | 13 | #include <linux/of_address.h> |
| 14 | 14 | #include <linux/of_platform.h> |
| 15 | +#include <linux/mfd/syscon.h> | |
| 15 | 16 | #include <linux/platform_device.h> |
| 16 | 17 | #include <linux/pm.h> |
| 17 | 18 | #include <linux/regmap.h> |
| @@ -85,7 +86,8 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1, · 67 unmodified lines | ||
| 85 | 86 | "%s: sensor%d - data_point1:%#x data_point2:%#x\n", |
| 86 | 87 | __func__, i, p1[i], p2[i]); |
| 87 | 88 | |
| 88 | − priv->sensor[i].slope = SLOPE_DEFAULT; | |
| 89 | + if (!priv->sensor[i].slope) | |
| 90 | + priv->sensor[i].slope = SLOPE_DEFAULT; | |
| 89 | 91 | if (mode == TWO_PT_CALIB) { |
| 90 | 92 | /* |
| 91 | 93 | * slope (m) = adc_code2 - adc_code1 (y2 - y1)/ |
| @@ -515,6 +517,15 @@ static irqreturn_t tsens_irq_thread(int irq, void *data) · 423 unmodified lines | ||
| 515 | 517 | dev_dbg(priv->dev, "[%u] %s: no violation: %d\n", |
| 516 | 518 | hw_id, __func__, temp); |
| 517 | 519 | } |
| 520 | + | |
| 521 | + if (tsens_version(priv) < VER_0_1) { | |
| 522 | + /* Constraint: There is only 1 interrupt control register for all | |
| 523 | + * 11 temperature sensor. So monitoring more than 1 sensor based | |
| 524 | + * on interrupts will yield inconsistent result. To overcome this | |
| 525 | + * issue we will monitor only sensor 0 which is the master sensor. | |
| 526 | + */ | |
| 527 | + break; | |
| 528 | + } | |
| 518 | 529 | } |
| 519 | 530 | |
| 520 | 531 | return IRQ_HANDLED; |
| @@ -530,6 +541,13 @@ static int tsens_set_trips(void *_sensor, int low, int high) · 9 unmodified lines | ||
| 530 | 541 | int high_val, low_val, cl_high, cl_low; |
| 531 | 542 | u32 hw_id = s->hw_id; |
| 532 | 543 | |
| 544 | + if (tsens_version(priv) < VER_0_1) { | |
| 545 | + /* Pre v0.1 IP had a single register for each type of interrupt | |
| 546 | + * and thresholds | |
| 547 | + */ | |
| 548 | + hw_id = 0; | |
| 549 | + } | |
| 550 | + | |
| 533 | 551 | dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n", |
| 534 | 552 | hw_id, __func__, low, high); |
| 535 | 553 | |
| @@ -584,18 +602,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp) · 48 unmodified lines | ||
| 584 | 602 | u32 valid; |
| 585 | 603 | int ret; |
| 586 | 604 | |
| 587 | − ret = regmap_field_read(priv->rf[valid_idx], &valid); | |
| 588 | − if (ret) | |
| 589 | − return ret; | |
| 590 | − while (!valid) { | |
| 591 | − /* Valid bit is 0 for 6 AHB clock cycles. | |
| 592 | − * At 19.2MHz, 1 AHB clock is ~60ns. | |
| 593 | − * We should enter this loop very, very rarely. | |
| 594 | − */ | |
| 595 | − ndelay(400); | |
| 605 | + /* VER_0 doesn't have VALID bit */ | |
| 606 | + if (tsens_version(priv) >= VER_0_1) { | |
| 596 | 607 | ret = regmap_field_read(priv->rf[valid_idx], &valid); |
| 597 | 608 | if (ret) |
| 598 | 609 | return ret; |
| 610 | + while (!valid) { | |
| 611 | + /* Valid bit is 0 for 6 AHB clock cycles. | |
| 612 | + * At 19.2MHz, 1 AHB clock is ~60ns. | |
| 613 | + * We should enter this loop very, very rarely. | |
| 614 | + */ | |
| 615 | + ndelay(400); | |
| 616 | + ret = regmap_field_read(priv->rf[valid_idx], &valid); | |
| 617 | + if (ret) | |
| 618 | + return ret; | |
| 619 | + } | |
| 599 | 620 | } |
| 600 | 621 | |
| 601 | 622 | /* Valid bit is set, OK to read the temperature */ |
| @@ -608,15 +629,29 @@ int get_temp_common(const struct tsens_sensor *s, int *temp) · 6 unmodified lines | ||
| 608 | 629 | { |
| 609 | 630 | struct tsens_priv *priv = s->priv; |
| 610 | 631 | int hw_id = s->hw_id; |
| 611 | − int last_temp = 0, ret; | |
| 632 | + int last_temp = 0, ret, trdy; | |
| 633 | + unsigned long timeout; | |
| 612 | 634 | |
| 613 | − ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp); | |
| 614 | − if (ret) | |
| 615 | − return ret; | |
| 635 | + timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); | |
| 636 | + do { | |
| 637 | + if (tsens_version(priv) == VER_0) { | |
| 638 | + ret = regmap_field_read(priv->rf[TRDY], &trdy); | |
| 639 | + if (ret) | |
| 640 | + return ret; | |
| 641 | + if (!trdy) | |
| 642 | + continue; | |
| 643 | + } | |
| 616 | 644 | |
| 617 | − *temp = code_to_degc(last_temp, s) * 1000; | |
| 645 | + ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp); | |
| 646 | + if (ret) | |
| 647 | + return ret; | |
| 618 | 648 | |
| 619 | − return 0; | |
| 649 | + *temp = code_to_degc(last_temp, s) * 1000; | |
| 650 | + | |
| 651 | + return 0; | |
| 652 | + } while (time_before(jiffies, timeout)); | |
| 653 | + | |
| 654 | + return -ETIMEDOUT; | |
| 620 | 655 | } |
| 621 | 656 | |
| 622 | 657 | #ifdef CONFIG_DEBUG_FS |
| @@ -738,25 +773,42 @@ int __init init_common(struct tsens_priv *priv) · 115 unmodified lines | ||
| 738 | 773 | priv->tm_offset = 0x1000; |
| 739 | 774 | } |
| 740 | 775 | |
| 741 | − res = platform_get_resource(op, IORESOURCE_MEM, 0); | |
| 742 | − tm_base = devm_ioremap_resource(dev, res); | |
| 743 | − if (IS_ERR(tm_base)) { | |
| 744 | − ret = PTR_ERR(tm_base); | |
| 745 | − goto err_put_device; | |
| 776 | + if (tsens_version(priv) >= VER_0_1) { | |
| 777 | + res = platform_get_resource(op, IORESOURCE_MEM, 0); | |
| 778 | + tm_base = devm_ioremap_resource(dev, res); | |
| 779 | + if (IS_ERR(tm_base)) { | |
| 780 | + ret = PTR_ERR(tm_base); | |
| 781 | + goto err_put_device; | |
| 782 | + } | |
| 783 | + | |
| 784 | + priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config); | |
| 785 | + } else { /* VER_0 share the same gcc regs using a syscon */ | |
| 786 | + struct device *parent = priv->dev->parent; | |
| 787 | + | |
| 788 | + if (parent) | |
| 789 | + priv->tm_map = syscon_node_to_regmap(parent->of_node); | |
| 746 | 790 | } |
| 747 | 791 | |
| 748 | − priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config); | |
| 749 | − if (IS_ERR(priv->tm_map)) { | |
| 750 | − ret = PTR_ERR(priv->tm_map); | |
| 792 | + if (IS_ERR_OR_NULL(priv->tm_map)) { | |
| 793 | + if (!priv->tm_map) | |
| 794 | + ret = -ENODEV; | |
| 795 | + else | |
| 796 | + ret = PTR_ERR(priv->tm_map); | |
| 751 | 797 | goto err_put_device; |
| 752 | 798 | } |
| 753 | 799 | |
| 800 | + /* VER_0 have only tm_map */ | |
| 801 | + if (!priv->srot_map) | |
| 802 | + priv->srot_map = priv->tm_map; | |
| 803 | + | |
| 754 | 804 | if (tsens_version(priv) > VER_0_1) { |
| 755 | 805 | for (i = VER_MAJOR; i <= VER_STEP; i++) { |
| 756 | 806 | priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map, |
| 757 | 807 | priv->fields[i]); |
| 758 | − if (IS_ERR(priv->rf[i])) | |
| 759 | − return PTR_ERR(priv->rf[i]); | |
| 808 | + if (IS_ERR(priv->rf[i])) { | |
| 809 | + ret = PTR_ERR(priv->rf[i]); | |
| 810 | + goto err_put_device; | |
| 811 | + } | |
| 760 | 812 | } |
| 761 | 813 | ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor); |
| 762 | 814 | if (ret) |
| @@ -769,6 +821,10 @@ int __init init_common(struct tsens_priv *priv) · 6 unmodified lines | ||
| 769 | 821 | ret = PTR_ERR(priv->rf[TSENS_EN]); |
| 770 | 822 | goto err_put_device; |
| 771 | 823 | } |
| 824 | + /* in VER_0 TSENS need to be explicitly enabled */ | |
| 825 | + if (tsens_version(priv) == VER_0) | |
| 826 | + regmap_field_write(priv->rf[TSENS_EN], 1); | |
| 827 | + | |
| 772 | 828 | ret = regmap_field_read(priv->rf[TSENS_EN], &enabled); |
| 773 | 829 | if (ret) |
| 774 | 830 | goto err_put_device; |
| @@ -791,6 +847,19 @@ int __init init_common(struct tsens_priv *priv) · 16 unmodified lines | ||
| 791 | 847 | goto err_put_device; |
| 792 | 848 | } |
| 793 | 849 | |
| 850 | + priv->rf[TSENS_SW_RST] = | |
| 851 | + devm_regmap_field_alloc(dev, priv->srot_map, priv->fields[TSENS_SW_RST]); | |
| 852 | + if (IS_ERR(priv->rf[TSENS_SW_RST])) { | |
| 853 | + ret = PTR_ERR(priv->rf[TSENS_SW_RST]); | |
| 854 | + goto err_put_device; | |
| 855 | + } | |
| 856 | + | |
| 857 | + priv->rf[TRDY] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[TRDY]); | |
| 858 | + if (IS_ERR(priv->rf[TRDY])) { | |
| 859 | + ret = PTR_ERR(priv->rf[TRDY]); | |
| 860 | + goto err_put_device; | |
| 861 | + } | |
| 862 | + | |
| 794 | 863 | /* This loop might need changes if enum regfield_ids is reordered */ |
| 795 | 864 | for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) { |
| 796 | 865 | for (i = 0; i < priv->feat->max_sensors; i++) { |
| @@ -806,7 +875,7 @@ int __init init_common(struct tsens_priv *priv) · 9 unmodified lines | ||
| 806 | 875 | } |
| 807 | 876 | } |
| 808 | 877 | |
| 809 | − if (priv->feat->crit_int) { | |
| 878 | + if (priv->feat->crit_int || tsens_version(priv) < VER_0_1) { | |
| 810 | 879 | /* Loop might need changes if enum regfield_ids is reordered */ |
| 811 | 880 | for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) { |
| 812 | 881 | for (i = 0; i < priv->feat->max_sensors; i++) { |
| @@ -844,7 +913,11 @@ int __init init_common(struct tsens_priv *priv) · 31 unmodified lines | ||
| 844 | 913 | } |
| 845 | 914 | |
| 846 | 915 | spin_lock_init(&priv->ul_lock); |
| 847 | − tsens_enable_irq(priv); | |
| 916 | + | |
| 917 | + /* VER_0 interrupt doesn't need to be enabled */ | |
| 918 | + if (tsens_version(priv) >= VER_0_1) | |
| 919 | + tsens_enable_irq(priv); | |
| 920 | + | |
| 848 | 921 | tsens_debug_init(op); |
| 849 | 922 | |
| 850 | 923 | err_put_device: |
| @@ -895,6 +968,12 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume); · 44 unmodified lines | ||
| 895 | 968 | |
| 896 | 969 | static const struct of_device_id tsens_table[] = { |
| 897 | 970 | { |
| 971 | + .compatible = "qcom,ipq8064-tsens", | |
| 972 | + .data = &data_8960, | |
| 973 | + }, { | |
| 974 | + .compatible = "qcom,mdm9607-tsens", | |
| 975 | + .data = &data_9607, | |
| 976 | + }, { | |
| 898 | 977 | .compatible = "qcom,msm8916-tsens", |
| 899 | 978 | .data = &data_8916, |
| 900 | 979 | }, { |
| @@ -943,10 +1022,19 @@ static int tsens_register_irq(struct tsens_priv *priv, char *irqname, · 42 unmodified lines | ||
| 943 | 1022 | if (irq == -ENXIO) |
| 944 | 1023 | ret = 0; |
| 945 | 1024 | } else { |
| 946 | − ret = devm_request_threaded_irq(&pdev->dev, irq, | |
| 947 | − NULL, thread_fn, | |
| 948 | − IRQF_ONESHOT, | |
| 949 | − dev_name(&pdev->dev), priv); | |
| 1025 | + /* VER_0 interrupt is TRIGGER_RISING, VER_0_1 and up is ONESHOT */ | |
| 1026 | + if (tsens_version(priv) == VER_0) | |
| 1027 | + ret = devm_request_threaded_irq(&pdev->dev, irq, | |
| 1028 | + thread_fn, NULL, | |
| 1029 | + IRQF_TRIGGER_RISING, | |
| 1030 | + dev_name(&pdev->dev), | |
| 1031 | + priv); | |
| 1032 | + else | |
| 1033 | + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, | |
| 1034 | + thread_fn, IRQF_ONESHOT, | |
| 1035 | + dev_name(&pdev->dev), | |
| 1036 | + priv); | |
| 1037 | + | |
| 950 | 1038 | if (ret) |
| 951 | 1039 | dev_err(&pdev->dev, "%s: failed to get irq\n", |
| 952 | 1040 | __func__); |
| @@ -975,6 +1063,19 @@ static int tsens_register(struct tsens_priv *priv) · 22 unmodified lines | ||
| 975 | 1063 | priv->ops->enable(priv, i); |
| 976 | 1064 | } |
| 977 | 1065 | |
| 1066 | + /* VER_0 require to set MIN and MAX THRESH | |
| 1067 | + * These 2 regs are set using the: | |
| 1068 | + * - CRIT_THRESH_0 for MAX THRESH hardcoded to 120°C | |
| 1069 | + * - CRIT_THRESH_1 for MIN THRESH hardcoded to 0°C | |
| 1070 | + */ | |
| 1071 | + if (tsens_version(priv) < VER_0_1) { | |
| 1072 | + regmap_field_write(priv->rf[CRIT_THRESH_0], | |
| 1073 | + tsens_mC_to_hw(priv->sensor, 120000)); | |
| 1074 | + | |
| 1075 | + regmap_field_write(priv->rf[CRIT_THRESH_1], | |
| 1076 | + tsens_mC_to_hw(priv->sensor, 0)); | |
| 1077 | + } | |
| 1078 | + | |
| 978 | 1079 | ret = tsens_register_irq(priv, "uplow", tsens_irq_thread); |
| 979 | 1080 | if (ret < 0) |
| 980 | 1081 | return ret; |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | #define CAL_DEGC_PT2 120 |
| 14 | 14 | #define SLOPE_FACTOR 1000 |
| 15 | 15 | #define SLOPE_DEFAULT 3200 |
| 16 | +#define TIMEOUT_US 100 | |
| 16 | 17 | #define THRESHOLD_MAX_ADC_CODE 0x3ff |
| 17 | 18 | #define THRESHOLD_MIN_ADC_CODE 0x0 |
| 18 | 19 | |
| @@ -25,7 +26,8 @@ struct tsens_priv; · 6 unmodified lines | ||
| 25 | 26 | |
| 26 | 27 | /* IP version numbers in ascending order */ |
| 27 | 28 | enum tsens_ver { |
| 28 | − VER_0_1 = 0, | |
| 29 | + VER_0 = 0, | |
| 30 | + VER_0_1, | |
| 29 | 31 | VER_1_X, |
| 30 | 32 | VER_2_X, |
| 31 | 33 | }; |
| @@ -585,7 +587,7 @@ int get_temp_common(const struct tsens_sensor *s, int *temp); · 553 unmodified lines | ||
| 585 | 587 | extern struct tsens_plat_data data_8960; |
| 586 | 588 | |
| 587 | 589 | /* TSENS v0.1 targets */ |
| 588 | −extern struct tsens_plat_data data_8916, data_8939, data_8974; | |
| 590 | +extern struct tsens_plat_data data_8916, data_8939, data_8974, data_9607; | |
| 589 | 591 | |
| 590 | 592 | /* TSENS v1 targets */ |
| 591 | 593 | extern struct tsens_plat_data data_tsens_v1, data_8976; |
| @@ -60,7 +60,7 @@ · 59 unmodified lines | ||
| 60 | 60 | #define MCELSIUS(temp) ((temp) * 1000) |
| 61 | 61 | #define GEN3_FUSE_MASK 0xFFF |
| 62 | 62 | |
| 63 | −#define TSC_MAX_NUM 4 | |
| 63 | +#define TSC_MAX_NUM 5 | |
| 64 | 64 | |
| 65 | 65 | /* default THCODE values if FUSEs are missing */ |
| 66 | 66 | static const int thcodes[TSC_MAX_NUM][3] = { |
| @@ -68,6 +68,7 @@ static const int thcodes[TSC_MAX_NUM][3] = { · 1 unmodified line | ||
| 68 | 68 | { 3393, 2795, 2216 }, |
| 69 | 69 | { 3389, 2805, 2237 }, |
| 70 | 70 | { 3415, 2694, 2195 }, |
| 71 | + { 3356, 2724, 2244 }, | |
| 71 | 72 | }; |
| 72 | 73 | |
| 73 | 74 | /* Structure for thermal temperature calculation */ |
| @@ -300,7 +300,7 @@ static int sun8i_ths_calibrate(struct ths_device *tmdev) · 299 unmodified lines | ||
| 300 | 300 | * or 0x8xx, so they won't be away from the default value |
| 301 | 301 | * for a lot. |
| 302 | 302 | * |
| 303 | − * So here we do not return error if the calibartion data is | |
| 303 | + * So here we do not return error if the calibration data is | |
| 304 | 304 | * not available, except the probe needs deferring. |
| 305 | 305 | */ |
| 306 | 306 | goto out; |
| @@ -418,7 +418,7 @@ static int sun8i_h3_thermal_init(struct ths_device *tmdev) · 111 unmodified lines | ||
| 418 | 418 | } |
| 419 | 419 | |
| 420 | 420 | /* |
| 421 | − * Without this undocummented value, the returned temperatures would | |
| 421 | + * Without this undocumented value, the returned temperatures would | |
| 422 | 422 | * be higher than real ones by about 20C. |
| 423 | 423 | */ |
| 424 | 424 | #define SUN50I_H6_CTRL0_UNK 0x0000002f |
| @@ -2118,7 +2118,6 @@ static int tegra_soctherm_probe(struct platform_device *pdev) · 2117 unmodified lines | ||
| 2118 | 2118 | struct tegra_soctherm *tegra; |
| 2119 | 2119 | struct thermal_zone_device *z; |
| 2120 | 2120 | struct tsensor_shared_calib shared_calib; |
| 2121 | − struct resource *res; | |
| 2122 | 2121 | struct tegra_soctherm_soc *soc; |
| 2123 | 2122 | unsigned int i; |
| 2124 | 2123 | int err; |
| @@ -2140,26 +2139,20 @@ static int tegra_soctherm_probe(struct platform_device *pdev) · 15 unmodified lines | ||
| 2140 | 2139 | |
| 2141 | 2140 | tegra->soc = soc; |
| 2142 | 2141 | |
| 2143 | − res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | |
| 2144 | − "soctherm-reg"); | |
| 2145 | − tegra->regs = devm_ioremap_resource(&pdev->dev, res); | |
| 2142 | + tegra->regs = devm_platform_ioremap_resource_byname(pdev, "soctherm-reg"); | |
| 2146 | 2143 | if (IS_ERR(tegra->regs)) { |
| 2147 | 2144 | dev_err(&pdev->dev, "can't get soctherm registers"); |
| 2148 | 2145 | return PTR_ERR(tegra->regs); |
| 2149 | 2146 | } |
| 2150 | 2147 | |
| 2151 | 2148 | if (!tegra->soc->use_ccroc) { |
| 2152 | − res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | |
| 2153 | − "car-reg"); | |
| 2154 | − tegra->clk_regs = devm_ioremap_resource(&pdev->dev, res); | |
| 2149 | + tegra->clk_regs = devm_platform_ioremap_resource_byname(pdev, "car-reg"); | |
| 2155 | 2150 | if (IS_ERR(tegra->clk_regs)) { |
| 2156 | 2151 | dev_err(&pdev->dev, "can't get car clk registers"); |
| 2157 | 2152 | return PTR_ERR(tegra->clk_regs); |
| 2158 | 2153 | } |
| 2159 | 2154 | } else { |
| 2160 | − res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | |
| 2161 | − "ccroc-reg"); | |
| 2162 | − tegra->ccroc_regs = devm_ioremap_resource(&pdev->dev, res); | |
| 2155 | + tegra->ccroc_regs = devm_platform_ioremap_resource_byname(pdev, "ccroc-reg"); | |
| 2163 | 2156 | if (IS_ERR(tegra->ccroc_regs)) { |
| 2164 | 2157 | dev_err(&pdev->dev, "can't get ccroc registers"); |
| 2165 | 2158 | return PTR_ERR(tegra->ccroc_regs); |
| @@ -2195,7 +2188,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev) · 29 unmodified lines | ||
| 2195 | 2188 | if (err) |
| 2196 | 2189 | return err; |
| 2197 | 2190 | |
| 2198 | − /* calculate tsensor calibaration data */ | |
| 2191 | + /* calculate tsensor calibration data */ | |
| 2199 | 2192 | for (i = 0; i < soc->num_tsensors; ++i) { |
| 2200 | 2193 | err = tegra_calc_tsensor_calib(&soc->tsensors[i], |
| 2201 | 2194 | &shared_calib, |
| @@ -561,24 +561,6 @@ void thermal_zone_device_update(struct thermal_zone_device *tz, · 560 unmodified lines | ||
| 561 | 561 | } |
| 562 | 562 | EXPORT_SYMBOL_GPL(thermal_zone_device_update); |
| 563 | 563 | |
| 564 | −/** | |
| 565 | − * thermal_notify_framework - Sensor drivers use this API to notify framework | |
| 566 | − * @tz: thermal zone device | |
| 567 | − * @trip: indicates which trip point has been crossed | |
| 568 | − * | |
| 569 | − * This function handles the trip events from sensor drivers. It starts | |
| 570 | − * throttling the cooling devices according to the policy configured. | |
| 571 | − * For CRITICAL and HOT trip points, this notifies the respective drivers, | |
| 572 | − * and does actual throttling for other trip points i.e ACTIVE and PASSIVE. | |
| 573 | − * The throttling policy is based on the configured platform data; if no | |
| 574 | − * platform data is provided, this uses the step_wise throttling policy. | |
| 575 | − */ | |
| 576 | −void thermal_notify_framework(struct thermal_zone_device *tz, int trip) | |
| 577 | −{ | |
| 578 | − handle_thermal_trip(tz, trip); | |
| 579 | −} | |
| 580 | −EXPORT_SYMBOL_GPL(thermal_notify_framework); | |
| 581 | − | |
| 582 | 564 | static void thermal_zone_device_check(struct work_struct *work) |
| 583 | 565 | { |
| 584 | 566 | struct thermal_zone_device *tz = container_of(work, struct |
| @@ -960,10 +942,7 @@ __thermal_cooling_device_register(struct device_node *np, · 375 unmodified lines | ||
| 960 | 942 | { |
| 961 | 943 | struct thermal_cooling_device *cdev; |
| 962 | 944 | struct thermal_zone_device *pos = NULL; |
| 963 | − int result; | |
| 964 | − | |
| 965 | − if (type && strlen(type) >= THERMAL_NAME_LENGTH) | |
| 966 | − return ERR_PTR(-EINVAL); | |
| 945 | + int ret; | |
| 967 | 946 | |
| 968 | 947 | if (!ops || !ops->get_max_state || !ops->get_cur_state || |
| 969 | 948 | !ops->set_cur_state) |
| @@ -973,14 +952,17 @@ __thermal_cooling_device_register(struct device_node *np, · 3 unmodified lines | ||
| 973 | 952 | if (!cdev) |
| 974 | 953 | return ERR_PTR(-ENOMEM); |
| 975 | 954 | |
| 976 | − result = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL); | |
| 977 | − if (result < 0) { | |
| 978 | − kfree(cdev); | |
| 979 | − return ERR_PTR(result); | |
| 955 | + ret = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL); | |
| 956 | + if (ret < 0) | |
| 957 | + goto out_kfree_cdev; | |
| 958 | + cdev->id = ret; | |
| 959 | + | |
| 960 | + cdev->type = kstrdup(type ? type : "", GFP_KERNEL); | |
| 961 | + if (!cdev->type) { | |
| 962 | + ret = -ENOMEM; | |
| 963 | + goto out_ida_remove; | |
| 980 | 964 | } |
| 981 | 965 | |
| 982 | − cdev->id = result; | |
| 983 | − strlcpy(cdev->type, type ? : "", sizeof(cdev->type)); | |
| 984 | 966 | mutex_init(&cdev->lock); |
| 985 | 967 | INIT_LIST_HEAD(&cdev->thermal_instances); |
| 986 | 968 | cdev->np = np; |
| @@ -990,12 +972,9 @@ __thermal_cooling_device_register(struct device_node *np, · 3 unmodified lines | ||
| 990 | 972 | cdev->devdata = devdata; |
| 991 | 973 | thermal_cooling_device_setup_sysfs(cdev); |
| 992 | 974 | dev_set_name(&cdev->device, "cooling_device%d", cdev->id); |
| 993 | − result = device_register(&cdev->device); | |
| 994 | − if (result) { | |
| 995 | − ida_simple_remove(&thermal_cdev_ida, cdev->id); | |
| 996 | − put_device(&cdev->device); | |
| 997 | − return ERR_PTR(result); | |
| 998 | − } | |
| 975 | + ret = device_register(&cdev->device); | |
| 976 | + if (ret) | |
| 977 | + goto out_kfree_type; | |
| 999 | 978 | |
| 1000 | 979 | /* Add 'this' new cdev to the global cdev list */ |
| 1001 | 980 | mutex_lock(&thermal_list_lock); |
| @@ -1013,6 +992,15 @@ __thermal_cooling_device_register(struct device_node *np, · 11 unmodified lines | ||
| 1013 | 992 | mutex_unlock(&thermal_list_lock); |
| 1014 | 993 | |
| 1015 | 994 | return cdev; |
| 995 | + | |
| 996 | +out_kfree_type: | |
| 997 | + kfree(cdev->type); | |
| 998 | + put_device(&cdev->device); | |
| 999 | +out_ida_remove: | |
| 1000 | + ida_simple_remove(&thermal_cdev_ida, cdev->id); | |
| 1001 | +out_kfree_cdev: | |
| 1002 | + kfree(cdev); | |
| 1003 | + return ERR_PTR(ret); | |
| 1016 | 1004 | } |
| 1017 | 1005 | |
| 1018 | 1006 | /** |
| @@ -1171,6 +1159,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev) · 152 unmodified lines | ||
| 1171 | 1159 | ida_simple_remove(&thermal_cdev_ida, cdev->id); |
| 1172 | 1160 | device_del(&cdev->device); |
| 1173 | 1161 | thermal_cooling_device_destroy_sysfs(cdev); |
| 1162 | + kfree(cdev->type); | |
| 1174 | 1163 | put_device(&cdev->device); |
| 1175 | 1164 | } |
| 1176 | 1165 | EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister); |
| @@ -66,6 +66,7 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev) · 65 unmodified lines | ||
| 66 | 66 | } |
| 67 | 67 | |
| 68 | 68 | void thermal_cdev_update(struct thermal_cooling_device *); |
| 69 | +void __thermal_cdev_update(struct thermal_cooling_device *cdev); | |
| 69 | 70 | |
| 70 | 71 | /** |
| 71 | 72 | * struct thermal_trip - representation of a point in temperature domain |
| @@ -192,18 +192,11 @@ static void thermal_cdev_set_cur_state(struct thermal_cooling_device *cdev, · 191 unmodified lines | ||
| 192 | 192 | thermal_cooling_device_stats_update(cdev, target); |
| 193 | 193 | } |
| 194 | 194 | |
| 195 | −void thermal_cdev_update(struct thermal_cooling_device *cdev) | |
| 195 | +void __thermal_cdev_update(struct thermal_cooling_device *cdev) | |
| 196 | 196 | { |
| 197 | 197 | struct thermal_instance *instance; |
| 198 | 198 | unsigned long target = 0; |
| 199 | 199 | |
| 200 | − mutex_lock(&cdev->lock); | |
| 201 | − /* cooling device is updated*/ | |
| 202 | − if (cdev->updated) { | |
| 203 | − mutex_unlock(&cdev->lock); | |
| 204 | − return; | |
| 205 | − } | |
| 206 | − | |
| 207 | 200 | /* Make sure cdev enters the deepest cooling state */ |
| 208 | 201 | list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) { |
| 209 | 202 | dev_dbg(&cdev->device, "zone%d->target=%lu\n", |
| @@ -216,11 +209,25 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev) · 6 unmodified lines | ||
| 216 | 209 | |
| 217 | 210 | thermal_cdev_set_cur_state(cdev, target); |
| 218 | 211 | |
| 219 | − cdev->updated = true; | |
| 220 | − mutex_unlock(&cdev->lock); | |
| 221 | 212 | trace_cdev_update(cdev, target); |
| 222 | 213 | dev_dbg(&cdev->device, "set to state %lu\n", target); |
| 223 | 214 | } |
| 215 | + | |
| 216 | +/** | |
| 217 | + * thermal_cdev_update - update cooling device state if needed | |
| 218 | + * @cdev: pointer to struct thermal_cooling_device | |
| 219 | + * | |
| 220 | + * Update the cooling device state if there is a need. | |
| 221 | + */ | |
| 222 | +void thermal_cdev_update(struct thermal_cooling_device *cdev) | |
| 223 | +{ | |
| 224 | + mutex_lock(&cdev->lock); | |
| 225 | + if (!cdev->updated) { | |
| 226 | + __thermal_cdev_update(cdev); | |
| 227 | + cdev->updated = true; | |
| 228 | + } | |
| 229 | + mutex_unlock(&cdev->lock); | |
| 230 | +} | |
| 224 | 231 | EXPORT_SYMBOL(thermal_cdev_update); |
| 225 | 232 | |
| 226 | 233 | /** |
| @@ -54,11 +54,8 @@ static int thermal_mmio_probe(struct platform_device *pdev) · 53 unmodified lines | ||
| 54 | 54 | |
| 55 | 55 | resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 56 | 56 | sensor->mmio_base = devm_ioremap_resource(&pdev->dev, resource); |
| 57 | − if (IS_ERR(sensor->mmio_base)) { | |
| 58 | − dev_err(&pdev->dev, "failed to ioremap memory (%ld)\n", | |
| 59 | − PTR_ERR(sensor->mmio_base)); | |
| 57 | + if (IS_ERR(sensor->mmio_base)) | |
| 60 | 58 | return PTR_ERR(sensor->mmio_base); |
| 61 | − } | |
| 62 | 59 | |
| 63 | 60 | sensor_init_func = device_get_match_data(&pdev->dev); |
| 64 | 61 | if (sensor_init_func) { |
| @@ -704,14 +704,17 @@ static int thermal_of_populate_bind_params(struct device_node *np, · 703 unmodified lines | ||
| 704 | 704 | |
| 705 | 705 | count = of_count_phandle_with_args(np, "cooling-device", |
| 706 | 706 | "#cooling-cells"); |
| 707 | − if (!count) { | |
| 707 | + if (count <= 0) { | |
| 708 | 708 | pr_err("Add a cooling_device property with at least one device\n"); |
| 709 | + ret = -ENOENT; | |
| 709 | 710 | goto end; |
| 710 | 711 | } |
| 711 | 712 | |
| 712 | 713 | __tcbp = kcalloc(count, sizeof(*__tcbp), GFP_KERNEL); |
| 713 | − if (!__tcbp) | |
| 714 | + if (!__tcbp) { | |
| 715 | + ret = -ENOMEM; | |
| 714 | 716 | goto end; |
| 717 | + } | |
| 715 | 718 | |
| 716 | 719 | for (i = 0; i < count; i++) { |
| 717 | 720 | ret = of_parse_phandle_with_args(np, "cooling-device", |
| @@ -9,30 +9,29 @@ · 8 unmodified lines | ||
| 9 | 9 | * Eduardo Valentin <eduardo.valentin@ti.com> |
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | −#include <linux/module.h> | |
| 12 | +#include <linux/clk.h> | |
| 13 | +#include <linux/cpu_pm.h> | |
| 14 | +#include <linux/device.h> | |
| 15 | +#include <linux/err.h> | |
| 13 | 16 | #include <linux/export.h> |
| 17 | +#include <linux/gpio/consumer.h> | |
| 14 | 18 | #include <linux/init.h> |
| 15 | −#include <linux/kernel.h> | |
| 16 | 19 | #include <linux/interrupt.h> |
| 17 | −#include <linux/clk.h> | |
| 18 | −#include <linux/gpio/consumer.h> | |
| 19 | −#include <linux/platform_device.h> | |
| 20 | −#include <linux/err.h> | |
| 21 | −#include <linux/types.h> | |
| 22 | −#include <linux/spinlock.h> | |
| 23 | −#include <linux/sys_soc.h> | |
| 24 | −#include <linux/reboot.h> | |
| 25 | −#include <linux/of_device.h> | |
| 26 | −#include <linux/of_platform.h> | |
| 27 | −#include <linux/of_irq.h> | |
| 28 | 20 | #include <linux/io.h> |
| 29 | 21 | #include <linux/iopoll.h> |
| 30 | −#include <linux/cpu_pm.h> | |
| 31 | −#include <linux/device.h> | |
| 32 | −#include <linux/pm_runtime.h> | |
| 33 | −#include <linux/pm.h> | |
| 22 | +#include <linux/kernel.h> | |
| 23 | +#include <linux/module.h> | |
| 34 | 24 | #include <linux/of.h> |
| 35 | 25 | #include <linux/of_device.h> |
| 26 | +#include <linux/of_irq.h> | |
| 27 | +#include <linux/of_platform.h> | |
| 28 | +#include <linux/platform_device.h> | |
| 29 | +#include <linux/pm.h> | |
| 30 | +#include <linux/pm_runtime.h> | |
| 31 | +#include <linux/reboot.h> | |
| 32 | +#include <linux/spinlock.h> | |
| 33 | +#include <linux/sys_soc.h> | |
| 34 | +#include <linux/types.h> | |
| 36 | 35 | |
| 37 | 36 | #include "ti-bandgap.h" |
| 38 | 37 | |
| @@ -1143,14 +1142,10 @@ static int ti_bandgap_restore_ctxt(struct ti_bandgap *bgp) · 1104 unmodified lines | ||
| 1143 | 1142 | for (i = 0; i < bgp->conf->sensor_count; i++) { |
| 1144 | 1143 | struct temp_sensor_registers *tsr; |
| 1145 | 1144 | struct temp_sensor_regval *rval; |
| 1146 | − u32 val = 0; | |
| 1147 | 1145 | |
| 1148 | 1146 | rval = &bgp->regval[i]; |
| 1149 | 1147 | tsr = bgp->conf->sensors[i].registers; |
| 1150 | 1148 | |
| 1151 | − if (TI_BANDGAP_HAS(bgp, COUNTER)) | |
| 1152 | − val = ti_bandgap_readl(bgp, tsr->bgap_counter); | |
| 1153 | − | |
| 1154 | 1149 | if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) |
| 1155 | 1150 | ti_bandgap_writel(bgp, rval->tshut_threshold, |
| 1156 | 1151 | tsr->tshut_threshold); |
| @@ -91,7 +91,7 @@ struct thermal_cooling_device_ops { · 90 unmodified lines | ||
| 91 | 91 | |
| 92 | 92 | struct thermal_cooling_device { |
| 93 | 93 | int id; |
| 94 | − char type[THERMAL_NAME_LENGTH]; | |
| 94 | + char *type; | |
| 95 | 95 | struct device device; |
| 96 | 96 | struct device_node *np; |
| 97 | 97 | void *devdata; |
| @@ -390,7 +390,6 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp); · 292 unmodified lines | ||
| 390 | 390 | int thermal_zone_get_slope(struct thermal_zone_device *tz); |
| 391 | 391 | int thermal_zone_get_offset(struct thermal_zone_device *tz); |
| 392 | 392 | |
| 393 | −void thermal_notify_framework(struct thermal_zone_device *, int); | |
| 394 | 393 | int thermal_zone_device_enable(struct thermal_zone_device *tz); |
| 395 | 394 | int thermal_zone_device_disable(struct thermal_zone_device *tz); |
| 396 | 395 | void thermal_zone_device_critical(struct thermal_zone_device *tz); |
| @@ -436,10 +435,6 @@ static inline int thermal_zone_get_offset( · 39 unmodified lines | ||
| 436 | 435 | struct thermal_zone_device *tz) |
| 437 | 436 | { return -ENODEV; } |
| 438 | 437 | |
| 439 | −static inline void thermal_notify_framework(struct thermal_zone_device *tz, | |
| 440 | − int trip) | |
| 441 | −{ } | |
| 442 | − | |
| 443 | 438 | static inline int thermal_zone_device_enable(struct thermal_zone_device *tz) |
| 444 | 439 | { return -ENODEV; } |
| 445 | 440 | |
| @@ -60,7 +60,7 @@ enum thermal_genl_event { · 59 unmodified lines | ||
| 60 | 60 | THERMAL_GENL_EVENT_UNSPEC, |
| 61 | 61 | THERMAL_GENL_EVENT_TZ_CREATE, /* Thermal zone creation */ |
| 62 | 62 | THERMAL_GENL_EVENT_TZ_DELETE, /* Thermal zone deletion */ |
| 63 | − THERMAL_GENL_EVENT_TZ_DISABLE, /* Thermal zone disabed */ | |
| 63 | + THERMAL_GENL_EVENT_TZ_DISABLE, /* Thermal zone disabled */ | |
| 64 | 64 | THERMAL_GENL_EVENT_TZ_ENABLE, /* Thermal zone enabled */ |
| 65 | 65 | THERMAL_GENL_EVENT_TZ_TRIP_UP, /* Trip point crossed the way up */ |
| 66 | 66 | THERMAL_GENL_EVENT_TZ_TRIP_DOWN, /* Trip point crossed the way down */ |