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 | properties: | 19 | properties: |
| 20 | compatible: | 20 | compatible: |
| 21 | oneOf: | 21 | oneOf: |
| 22 | - description: msm9860 TSENS based | ||
| 23 | items: | ||
| 24 | - enum: | ||
| 25 | - qcom,ipq8064-tsens | ||
| 26 | |||
| 22 | - description: v0.1 of TSENS | 27 | - description: v0.1 of TSENS |
| 23 | items: | 28 | items: |
| 24 | - enum: | 29 | - enum: |
| 30 | - qcom,mdm9607-tsens | ||
| 25 | - qcom,msm8916-tsens | 31 | - qcom,msm8916-tsens |
| 26 | - qcom,msm8939-tsens | 32 | - qcom,msm8939-tsens |
| 27 | - qcom,msm8974-tsens | 33 | - qcom,msm8974-tsens |
| @@ -43,6 +49,7 @@ properties: · 15 unmodified lines | |||
| 43 | - qcom,sdm845-tsens | 49 | - qcom,sdm845-tsens |
| 44 | - qcom,sm8150-tsens | 50 | - qcom,sm8150-tsens |
| 45 | - qcom,sm8250-tsens | 51 | - qcom,sm8250-tsens |
| 52 | - qcom,sm8350-tsens | ||
| 46 | - const: qcom,tsens-v2 | 53 | - const: qcom,tsens-v2 |
| 47 | 54 | ||
| 48 | reg: | 55 | reg: |
| @@ -73,7 +80,9 @@ properties: · 24 unmodified lines | |||
| 73 | maxItems: 2 | 80 | maxItems: 2 |
| 74 | items: | 81 | items: |
| 75 | - const: calib | 82 | - const: calib |
| 76 | - const: calib_sel | 83 | - enum: |
| 84 | - calib_backup | ||
| 85 | - calib_sel | ||
| 77 | 86 | ||
| 78 | "#qcom,sensors": | 87 | "#qcom,sensors": |
| 79 | description: | 88 | description: |
| @@ -88,12 +97,21 @@ properties: · 8 unmodified lines | |||
| 88 | Number of cells required to uniquely identify the thermal sensors. Since | 97 | Number of cells required to uniquely identify the thermal sensors. Since |
| 89 | we have multiple sensors this is set to 1 | 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 | allOf: | 107 | allOf: |
| 92 | - if: | 108 | - if: |
| 93 | properties: | 109 | properties: |
| 94 | compatible: | 110 | compatible: |
| 95 | contains: | 111 | contains: |
| 96 | enum: | 112 | enum: |
| 113 | - qcom,ipq8064-tsens | ||
| 114 | - qcom,mdm9607-tsens | ||
| 97 | - qcom,msm8916-tsens | 115 | - qcom,msm8916-tsens |
| 98 | - qcom,msm8974-tsens | 116 | - qcom,msm8974-tsens |
| 99 | - qcom,msm8976-tsens | 117 | - qcom,msm8976-tsens |
| @@ -114,17 +132,42 @@ allOf: · 14 unmodified lines | |||
| 114 | interrupt-names: | 132 | interrupt-names: |
| 115 | minItems: 2 | 133 | minItems: 2 |
| 116 | 134 | ||
| 117 | required: | 135 | - if: |
| 118 | - compatible | 136 | properties: |
| 119 | - reg | 137 | compatible: |
| 120 | - "#qcom,sensors" | 138 | contains: |
| 121 | - interrupts | 139 | enum: |
| 122 | - interrupt-names | 140 | - qcom,tsens-v0_1 |
| 123 | - "#thermal-sensor-cells" | 141 | - qcom,tsens-v1 |
| 142 | - qcom,tsens-v2 | ||
| 143 | |||
| 144 | then: | ||
| 145 | required: | ||
| 146 | - reg | ||
| 124 | 147 | ||
| 125 | additionalProperties: false | 148 | additionalProperties: false |
| 126 | 149 | ||
| 127 | examples: | 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 | #include <dt-bindings/interrupt-controller/arm-gic.h> | 172 | #include <dt-bindings/interrupt-controller/arm-gic.h> |
| 130 | // Example 1 (legacy: for pre v1 IP): | 173 | // Example 1 (legacy: for pre v1 IP): |
| @@ -28,14 +28,7 @@ properties: · 27 unmodified lines | |||
| 28 | - renesas,r8a77980-thermal # R-Car V3H | 28 | - renesas,r8a77980-thermal # R-Car V3H |
| 29 | - renesas,r8a779a0-thermal # R-Car V3U | 29 | - renesas,r8a779a0-thermal # R-Car V3U |
| 30 | 30 | ||
| 31 | reg: | 31 | reg: true |
| 32 | minItems: 2 | ||
| 33 | maxItems: 4 | ||
| 34 | items: | ||
| 35 | - description: TSC1 registers | ||
| 36 | - description: TSC2 registers | ||
| 37 | - description: TSC3 registers | ||
| 38 | - description: TSC4 registers | ||
| 39 | 32 | ||
| 40 | interrupts: | 33 | interrupts: |
| 41 | items: | 34 | items: |
| @@ -71,8 +64,25 @@ if: · 29 unmodified lines | |||
| 71 | enum: | 64 | enum: |
| 72 | - renesas,r8a779a0-thermal | 65 | - renesas,r8a779a0-thermal |
| 73 | then: | 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 | required: | 75 | required: |
| 75 | - interrupts | 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 | additionalProperties: false | 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 | containing several internal sensors. | 36 | containing several internal sensors. |
| 37 | enum: [0, 1] | 37 | enum: [0, 1] |
| 38 | 38 | ||
| 39 | required: | ||
| 40 | - "#thermal-sensor-cells" | ||
| 41 | |||
| 39 | additionalProperties: true | 42 | additionalProperties: true |
| 40 | 43 | ||
| 41 | examples: | 44 | examples: |
| @@ -730,17 +730,7 @@ This function returns the thermal_instance corresponding to a given · 729 unmodified lines | |||
| 730 | {thermal_zone, cooling_device, trip_point} combination. Returns NULL | 730 | {thermal_zone, cooling_device, trip_point} combination. Returns NULL |
| 731 | if such an instance does not exist. | 731 | if such an instance does not exist. |
| 732 | 732 | ||
| 733 | 4.3. thermal_notify_framework | 733 | 4.3. thermal_cdev_update |
| 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 | ||
| 744 | ------------------------ | 734 | ------------------------ |
| 745 | 735 | ||
| 746 | This function serves as an arbitrator to set the state of a cooling | 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 | QUALCOMM TSENS THERMAL DRIVER | 15198 | QUALCOMM TSENS THERMAL DRIVER |
| 15199 | M: Amit Kucheria <amitk@kernel.org> | 15199 | M: Amit Kucheria <amitk@kernel.org> |
| 15200 | M: Thara Gopinath <thara.gopinath@linaro.org> | ||
| 15200 | L: linux-pm@vger.kernel.org | 15201 | L: linux-pm@vger.kernel.org |
| 15201 | L: linux-arm-msm@vger.kernel.org | 15202 | L: linux-arm-msm@vger.kernel.org |
| 15202 | S: Maintained | 15203 | S: Maintained |
| @@ -18101,7 +18102,7 @@ THERMAL/CPU_COOLING · 2898 unmodified lines | |||
| 18101 | M: Amit Daniel Kachhap <amit.kachhap@gmail.com> | 18102 | M: Amit Daniel Kachhap <amit.kachhap@gmail.com> |
| 18102 | M: Daniel Lezcano <daniel.lezcano@linaro.org> | 18103 | M: Daniel Lezcano <daniel.lezcano@linaro.org> |
| 18103 | M: Viresh Kumar <viresh.kumar@linaro.org> | 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 | L: linux-pm@vger.kernel.org | 18106 | L: linux-pm@vger.kernel.org |
| 18106 | S: Supported | 18107 | S: Supported |
| 18107 | F: Documentation/driver-api/thermal/cpu-cooling-api.rst | 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 | /* Allow mlxsw thermal zone binding to an external cooling device */ | 132 | /* Allow mlxsw thermal zone binding to an external cooling device */ |
| 133 | for (i = 0; i < ARRAY_SIZE(mlxsw_thermal_external_allowed_cdev); i++) { | 133 | for (i = 0; i < ARRAY_SIZE(mlxsw_thermal_external_allowed_cdev); i++) { |
| 134 | if (strnstr(cdev->type, mlxsw_thermal_external_allowed_cdev[i], | 134 | if (strnstr(cdev->type, mlxsw_thermal_external_allowed_cdev[i], |
| 135 | sizeof(cdev->type))) | 135 | strlen(cdev->type))) |
| 136 | return 0; | 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 | if (mvm->tz_device.tzone) { | 146 | if (mvm->tz_device.tzone) { |
| 147 | struct iwl_mvm_thermal_device *tz_dev = &mvm->tz_device; | 147 | struct iwl_mvm_thermal_device *tz_dev = &mvm->tz_device; |
| 148 | 148 | ||
| 149 | thermal_notify_framework(tz_dev->tzone, | 149 | thermal_zone_device_update(tz_dev->tzone, |
| 150 | tz_dev->fw_trips_index[ths_crossed]); | 150 | THERMAL_TRIP_VIOLATED); |
| 151 | } | 151 | } |
| 152 | #endif /* CONFIG_THERMAL */ | 152 | #endif /* CONFIG_THERMAL */ |
| 153 | } | 153 | } |
| @@ -254,10 +254,8 @@ static int amlogic_thermal_probe(struct platform_device *pdev) · 253 unmodified lines | |||
| 254 | platform_set_drvdata(pdev, pdata); | 254 | platform_set_drvdata(pdev, pdata); |
| 255 | 255 | ||
| 256 | base = devm_platform_ioremap_resource(pdev, 0); | 256 | base = devm_platform_ioremap_resource(pdev, 0); |
| 257 | if (IS_ERR(base)) { | 257 | if (IS_ERR(base)) |
| 258 | dev_err(dev, "failed to get io address\n"); | ||
| 259 | return PTR_ERR(base); | 258 | return PTR_ERR(base); |
| 260 | } | ||
| 261 | 259 | ||
| 262 | pdata->regmap = devm_regmap_init_mmio(dev, base, | 260 | pdata->regmap = devm_regmap_init_mmio(dev, base, |
| 263 | pdata->data->regmap_config); | 261 | pdata->data->regmap_config); |
| @@ -184,7 +184,6 @@ static int bcm2835_thermal_probe(struct platform_device *pdev) · 183 unmodified lines | |||
| 184 | data->regs = devm_ioremap_resource(&pdev->dev, res); | 184 | data->regs = devm_ioremap_resource(&pdev->dev, res); |
| 185 | if (IS_ERR(data->regs)) { | 185 | if (IS_ERR(data->regs)) { |
| 186 | err = PTR_ERR(data->regs); | 186 | err = PTR_ERR(data->regs); |
| 187 | dev_err(&pdev->dev, "Could not get registers: %d\n", err); | ||
| 188 | return err; | 187 | return err; |
| 189 | } | 188 | } |
| 190 | 189 | ||
| @@ -13,10 +13,10 @@ · 12 unmodified lines | |||
| 13 | #include <linux/cpu.h> | 13 | #include <linux/cpu.h> |
| 14 | #include <linux/cpufreq.h> | 14 | #include <linux/cpufreq.h> |
| 15 | #include <linux/cpu_cooling.h> | 15 | #include <linux/cpu_cooling.h> |
| 16 | #include <linux/device.h> | ||
| 16 | #include <linux/energy_model.h> | 17 | #include <linux/energy_model.h> |
| 17 | #include <linux/err.h> | 18 | #include <linux/err.h> |
| 18 | #include <linux/export.h> | 19 | #include <linux/export.h> |
| 19 | #include <linux/idr.h> | ||
| 20 | #include <linux/pm_opp.h> | 20 | #include <linux/pm_opp.h> |
| 21 | #include <linux/pm_qos.h> | 21 | #include <linux/pm_qos.h> |
| 22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
| @@ -50,8 +50,6 @@ struct time_in_idle { · 27 unmodified lines | |||
| 50 | 50 | ||
| 51 | /** | 51 | /** |
| 52 | * struct cpufreq_cooling_device - data for cooling device with cpufreq | 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 | * @last_load: load measured by the latest call to cpufreq_get_requested_power() | 53 | * @last_load: load measured by the latest call to cpufreq_get_requested_power() |
| 56 | * @cpufreq_state: integer value representing the current state of cpufreq | 54 | * @cpufreq_state: integer value representing the current state of cpufreq |
| 57 | * cooling devices. | 55 | * cooling devices. |
| @@ -61,7 +59,6 @@ struct time_in_idle { · 3 unmodified lines | |||
| 61 | * @cdev: thermal_cooling_device pointer to keep track of the | 59 | * @cdev: thermal_cooling_device pointer to keep track of the |
| 62 | * registered cooling device. | 60 | * registered cooling device. |
| 63 | * @policy: cpufreq policy. | 61 | * @policy: cpufreq policy. |
| 64 | * @node: list_head to link all cpufreq_cooling_device together. | ||
| 65 | * @idle_time: idle time stats | 62 | * @idle_time: idle time stats |
| 66 | * @qos_req: PM QoS contraint to apply | 63 | * @qos_req: PM QoS contraint to apply |
| 67 | * | 64 | * |
| @@ -69,23 +66,17 @@ struct time_in_idle { · 1 unmodified line | |||
| 69 | * cpufreq_cooling_device. | 66 | * cpufreq_cooling_device. |
| 70 | */ | 67 | */ |
| 71 | struct cpufreq_cooling_device { | 68 | struct cpufreq_cooling_device { |
| 72 | int id; | ||
| 73 | u32 last_load; | 69 | u32 last_load; |
| 74 | unsigned int cpufreq_state; | 70 | unsigned int cpufreq_state; |
| 75 | unsigned int max_level; | 71 | unsigned int max_level; |
| 76 | struct em_perf_domain *em; | 72 | struct em_perf_domain *em; |
| 77 | struct cpufreq_policy *policy; | 73 | struct cpufreq_policy *policy; |
| 78 | struct list_head node; | ||
| 79 | #ifndef CONFIG_SMP | 74 | #ifndef CONFIG_SMP |
| 80 | struct time_in_idle *idle_time; | 75 | struct time_in_idle *idle_time; |
| 81 | #endif | 76 | #endif |
| 82 | struct freq_qos_request qos_req; | 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 | #ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR | 80 | #ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR |
| 90 | /** | 81 | /** |
| 91 | * get_level: Find the level for a particular frequency | 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 | int i; | 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 | if (power >= cpufreq_cdev->em->table[i].power) | 120 | if (power >= cpufreq_cdev->em->table[i].power) |
| 130 | break; | 121 | break; |
| 131 | } | 122 | } |
| @@ -528,11 +519,11 @@ __cpufreq_cooling_register(struct device_node *np, · 396 unmodified lines | |||
| 528 | { | 519 | { |
| 529 | struct thermal_cooling_device *cdev; | 520 | struct thermal_cooling_device *cdev; |
| 530 | struct cpufreq_cooling_device *cpufreq_cdev; | 521 | struct cpufreq_cooling_device *cpufreq_cdev; |
| 531 | char dev_name[THERMAL_NAME_LENGTH]; | ||
| 532 | unsigned int i; | 522 | unsigned int i; |
| 533 | struct device *dev; | 523 | struct device *dev; |
| 534 | int ret; | 524 | int ret; |
| 535 | struct thermal_cooling_device_ops *cooling_ops; | 525 | struct thermal_cooling_device_ops *cooling_ops; |
| 526 | char *name; | ||
| 536 | 527 | ||
| 537 | dev = get_cpu_device(policy->cpu); | 528 | dev = get_cpu_device(policy->cpu); |
| 538 | if (unlikely(!dev)) { | 529 | if (unlikely(!dev)) { |
| @@ -567,16 +558,6 @@ __cpufreq_cooling_register(struct device_node *np, · 28 unmodified lines | |||
| 567 | /* max_level is an index, not a counter */ | 558 | /* max_level is an index, not a counter */ |
| 568 | cpufreq_cdev->max_level = i - 1; | 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 | cooling_ops = &cpufreq_cooling_ops; | 561 | cooling_ops = &cpufreq_cooling_ops; |
| 581 | 562 | ||
| 582 | #ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR | 563 | #ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR |
| @@ -591,7 +572,7 @@ __cpufreq_cooling_register(struct device_node *np, · 8 unmodified lines | |||
| 591 | pr_err("%s: unsorted frequency tables are not supported\n", | 572 | pr_err("%s: unsorted frequency tables are not supported\n", |
| 592 | __func__); | 573 | __func__); |
| 593 | cdev = ERR_PTR(-EINVAL); | 574 | cdev = ERR_PTR(-EINVAL); |
| 594 | goto remove_ida; | 575 | goto free_idle_time; |
| 595 | } | 576 | } |
| 596 | 577 | ||
| 597 | ret = freq_qos_add_request(&policy->constraints, | 578 | ret = freq_qos_add_request(&policy->constraints, |
| @@ -601,24 +582,25 @@ __cpufreq_cooling_register(struct device_node *np, · 3 unmodified lines | |||
| 601 | pr_err("%s: Failed to add freq constraint (%d)\n", __func__, | 582 | pr_err("%s: Failed to add freq constraint (%d)\n", __func__, |
| 602 | ret); | 583 | ret); |
| 603 | cdev = ERR_PTR(ret); | 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 | cooling_ops); | 594 | cooling_ops); |
| 595 | kfree(name); | ||
| 596 | |||
| 609 | if (IS_ERR(cdev)) | 597 | if (IS_ERR(cdev)) |
| 610 | goto remove_qos_req; | 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 | return cdev; | 600 | return cdev; |
| 617 | 601 | ||
| 618 | remove_qos_req: | 602 | remove_qos_req: |
| 619 | freq_qos_remove_request(&cpufreq_cdev->qos_req); | 603 | freq_qos_remove_request(&cpufreq_cdev->qos_req); |
| 620 | remove_ida: | ||
| 621 | ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id); | ||
| 622 | free_idle_time: | 604 | free_idle_time: |
| 623 | free_idle_time(cpufreq_cdev); | 605 | free_idle_time(cpufreq_cdev); |
| 624 | free_cdev: | 606 | free_cdev: |
| @@ -706,13 +688,8 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) · 81 unmodified lines | |||
| 706 | 688 | ||
| 707 | cpufreq_cdev = cdev->devdata; | 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 | thermal_cooling_device_unregister(cdev); | 691 | thermal_cooling_device_unregister(cdev); |
| 714 | freq_qos_remove_request(&cpufreq_cdev->qos_req); | 692 | freq_qos_remove_request(&cpufreq_cdev->qos_req); |
| 715 | ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id); | ||
| 716 | free_idle_time(cpufreq_cdev); | 693 | free_idle_time(cpufreq_cdev); |
| 717 | kfree(cpufreq_cdev); | 694 | kfree(cpufreq_cdev); |
| 718 | } | 695 | } |
| @@ -9,9 +9,9 @@ · 8 unmodified lines | |||
| 9 | 9 | ||
| 10 | #include <linux/cpu_cooling.h> | 10 | #include <linux/cpu_cooling.h> |
| 11 | #include <linux/cpuidle.h> | 11 | #include <linux/cpuidle.h> |
| 12 | #include <linux/device.h> | ||
| 12 | #include <linux/err.h> | 13 | #include <linux/err.h> |
| 13 | #include <linux/idle_inject.h> | 14 | #include <linux/idle_inject.h> |
| 14 | #include <linux/idr.h> | ||
| 15 | #include <linux/of_device.h> | 15 | #include <linux/of_device.h> |
| 16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 17 | #include <linux/thermal.h> | 17 | #include <linux/thermal.h> |
| @@ -26,8 +26,6 @@ struct cpuidle_cooling_device { · 8 unmodified lines | |||
| 26 | unsigned long state; | 26 | unsigned long state; |
| 27 | }; | 27 | }; |
| 28 | 28 | ||
| 29 | static DEFINE_IDA(cpuidle_ida); | ||
| 30 | |||
| 31 | /** | 29 | /** |
| 32 | * cpuidle_cooling_runtime - Running time computation | 30 | * cpuidle_cooling_runtime - Running time computation |
| 33 | * @idle_duration_us: CPU idle time to inject in microseconds | 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 | struct idle_inject_device *ii_dev; | 172 | struct idle_inject_device *ii_dev; |
| 175 | struct cpuidle_cooling_device *idle_cdev; | 173 | struct cpuidle_cooling_device *idle_cdev; |
| 176 | struct thermal_cooling_device *cdev; | 174 | struct thermal_cooling_device *cdev; |
| 175 | struct device *dev; | ||
| 177 | unsigned int idle_duration_us = TICK_USEC; | 176 | unsigned int idle_duration_us = TICK_USEC; |
| 178 | unsigned int latency_us = UINT_MAX; | 177 | unsigned int latency_us = UINT_MAX; |
| 179 | char dev_name[THERMAL_NAME_LENGTH]; | 178 | char *name; |
| 180 | int id, ret; | 179 | int ret; |
| 181 | 180 | ||
| 182 | idle_cdev = kzalloc(sizeof(*idle_cdev), GFP_KERNEL); | 181 | idle_cdev = kzalloc(sizeof(*idle_cdev), GFP_KERNEL); |
| 183 | if (!idle_cdev) { | 182 | if (!idle_cdev) { |
| @@ -185,16 +184,10 @@ static int __cpuidle_cooling_register(struct device_node *np, · 1 unmodified line | |||
| 185 | goto out; | 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 | ii_dev = idle_inject_register(drv->cpumask); | 187 | ii_dev = idle_inject_register(drv->cpumask); |
| 195 | if (!ii_dev) { | 188 | if (!ii_dev) { |
| 196 | ret = -EINVAL; | 189 | ret = -EINVAL; |
| 197 | goto out_id; | 190 | goto out_kfree; |
| 198 | } | 191 | } |
| 199 | 192 | ||
| 200 | of_property_read_u32(np, "duration-us", &idle_duration_us); | 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 | idle_cdev->ii_dev = ii_dev; | 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 | &cpuidle_cooling_ops); | 210 | &cpuidle_cooling_ops); |
| 212 | if (IS_ERR(cdev)) { | 211 | if (IS_ERR(cdev)) { |
| 213 | ret = PTR_ERR(cdev); | 212 | ret = PTR_ERR(cdev); |
| 214 | goto out_unregister; | 213 | goto out_kfree_name; |
| 215 | } | 214 | } |
| 216 | 215 | ||
| 217 | pr_debug("%s: Idle injection set with idle duration=%u, latency=%u\n", | 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 | return 0; | 221 | return 0; |
| 221 | 222 | ||
| 223 | out_kfree_name: | ||
| 224 | kfree(name); | ||
| 222 | out_unregister: | 225 | out_unregister: |
| 223 | idle_inject_unregister(ii_dev); | 226 | idle_inject_unregister(ii_dev); |
| 224 | out_id: | ||
| 225 | ida_simple_remove(&cpuidle_ida, id); | ||
| 226 | out_kfree: | 227 | out_kfree: |
| 227 | kfree(idle_cdev); | 228 | kfree(idle_cdev); |
| 228 | out: | 229 | out: |
| @@ -14,7 +14,6 @@ · 13 unmodified lines | |||
| 14 | #include <linux/devfreq_cooling.h> | 14 | #include <linux/devfreq_cooling.h> |
| 15 | #include <linux/energy_model.h> | 15 | #include <linux/energy_model.h> |
| 16 | #include <linux/export.h> | 16 | #include <linux/export.h> |
| 17 | #include <linux/idr.h> | ||
| 18 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 19 | #include <linux/pm_opp.h> | 18 | #include <linux/pm_opp.h> |
| 20 | #include <linux/pm_qos.h> | 19 | #include <linux/pm_qos.h> |
| @@ -25,11 +24,8 @@ · 4 unmodified lines | |||
| 25 | #define HZ_PER_KHZ 1000 | 24 | #define HZ_PER_KHZ 1000 |
| 26 | #define SCALE_ERROR_MITIGATION 100 | 25 | #define SCALE_ERROR_MITIGATION 100 |
| 27 | 26 | ||
| 28 | static DEFINE_IDA(devfreq_ida); | ||
| 29 | |||
| 30 | /** | 27 | /** |
| 31 | * struct devfreq_cooling_device - Devfreq cooling device | 28 | * struct devfreq_cooling_device - Devfreq cooling device |
| 32 | * @id: unique integer value corresponding to each | ||
| 33 | * devfreq_cooling_device registered. | 29 | * devfreq_cooling_device registered. |
| 34 | * @cdev: Pointer to associated thermal cooling device. | 30 | * @cdev: Pointer to associated thermal cooling device. |
| 35 | * @devfreq: Pointer to associated devfreq device. | 31 | * @devfreq: Pointer to associated devfreq device. |
| @@ -51,7 +47,6 @@ static DEFINE_IDA(devfreq_ida); · 15 unmodified lines | |||
| 51 | * @em_pd: Energy Model for the associated Devfreq device | 47 | * @em_pd: Energy Model for the associated Devfreq device |
| 52 | */ | 48 | */ |
| 53 | struct devfreq_cooling_device { | 49 | struct devfreq_cooling_device { |
| 54 | int id; | ||
| 55 | struct thermal_cooling_device *cdev; | 50 | struct thermal_cooling_device *cdev; |
| 56 | struct devfreq *devfreq; | 51 | struct devfreq *devfreq; |
| 57 | unsigned long cooling_state; | 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 | struct thermal_cooling_device *cdev; | 358 | struct thermal_cooling_device *cdev; |
| 364 | struct device *dev = df->dev.parent; | 359 | struct device *dev = df->dev.parent; |
| 365 | struct devfreq_cooling_device *dfc; | 360 | struct devfreq_cooling_device *dfc; |
| 366 | char dev_name[THERMAL_NAME_LENGTH]; | 361 | char *name; |
| 367 | int err, num_opps; | 362 | int err, num_opps; |
| 368 | 363 | ||
| 369 | dfc = kzalloc(sizeof(*dfc), GFP_KERNEL); | 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 | if (err < 0) | 402 | if (err < 0) |
| 408 | goto free_table; | 403 | goto free_table; |
| 409 | 404 | ||
| 410 | err = ida_simple_get(&devfreq_ida, 0, 0, GFP_KERNEL); | 405 | err = -ENOMEM; |
| 411 | if (err < 0) | 406 | name = kasprintf(GFP_KERNEL, "devfreq-%s", dev_name(dev)); |
| 407 | if (!name) | ||
| 412 | goto remove_qos_req; | 408 | goto remove_qos_req; |
| 413 | 409 | ||
| 414 | dfc->id = err; | 410 | cdev = thermal_of_cooling_device_register(np, name, dfc, |
| 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, | ||
| 419 | &devfreq_cooling_ops); | 411 | &devfreq_cooling_ops); |
| 412 | kfree(name); | ||
| 413 | |||
| 420 | if (IS_ERR(cdev)) { | 414 | if (IS_ERR(cdev)) { |
| 421 | err = PTR_ERR(cdev); | 415 | err = PTR_ERR(cdev); |
| 422 | dev_err(dev, | 416 | dev_err(dev, |
| 423 | "Failed to register devfreq cooling device (%d)\n", | 417 | "Failed to register devfreq cooling device (%d)\n", |
| 424 | err); | 418 | err); |
| 425 | goto release_ida; | 419 | goto remove_qos_req; |
| 426 | } | 420 | } |
| 427 | 421 | ||
| 428 | dfc->cdev = cdev; | 422 | dfc->cdev = cdev; |
| 429 | 423 | ||
| 430 | return cdev; | 424 | return cdev; |
| 431 | 425 | ||
| 432 | release_ida: | ||
| 433 | ida_simple_remove(&devfreq_ida, dfc->id); | ||
| 434 | remove_qos_req: | 426 | remove_qos_req: |
| 435 | dev_pm_qos_remove_request(&dfc->req_max_freq); | 427 | dev_pm_qos_remove_request(&dfc->req_max_freq); |
| 436 | free_table: | 428 | free_table: |
| @@ -527,7 +519,6 @@ void devfreq_cooling_unregister(struct thermal_cooling_device *cdev) · 90 unmodified lines | |||
| 527 | dev = dfc->devfreq->dev.parent; | 519 | dev = dfc->devfreq->dev.parent; |
| 528 | 520 | ||
| 529 | thermal_cooling_device_unregister(dfc->cdev); | 521 | thermal_cooling_device_unregister(dfc->cdev); |
| 530 | ida_simple_remove(&devfreq_ida, dfc->id); | ||
| 531 | dev_pm_qos_remove_request(&dfc->req_max_freq); | 522 | dev_pm_qos_remove_request(&dfc->req_max_freq); |
| 532 | 523 | ||
| 533 | em_dev_unregister_perf_domain(dev); | 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 | int total_instance = 0; | 82 | int total_instance = 0; |
| 83 | int cur_trip_level = get_trip_level(tz); | 83 | int cur_trip_level = get_trip_level(tz); |
| 84 | 84 | ||
| 85 | mutex_lock(&tz->lock); | ||
| 86 | |||
| 85 | list_for_each_entry(instance, &tz->thermal_instances, tz_node) { | 87 | list_for_each_entry(instance, &tz->thermal_instances, tz_node) { |
| 86 | if (instance->trip != trip) | 88 | if (instance->trip != trip) |
| 87 | continue; | 89 | continue; |
| @@ -105,11 +107,12 @@ static int fair_share_throttle(struct thermal_zone_device *tz, int trip) · 17 unmodified lines | |||
| 105 | instance->target = get_target_state(tz, cdev, percentage, | 107 | instance->target = get_target_state(tz, cdev, percentage, |
| 106 | cur_trip_level); | 108 | cur_trip_level); |
| 107 | 109 | ||
| 108 | mutex_lock(&instance->cdev->lock); | 110 | mutex_lock(&cdev->lock); |
| 109 | instance->cdev->updated = false; | 111 | __thermal_cdev_update(cdev); |
| 110 | mutex_unlock(&instance->cdev->lock); | 112 | mutex_unlock(&cdev->lock); |
| 111 | thermal_cdev_update(cdev); | ||
| 112 | } | 113 | } |
| 114 | |||
| 115 | mutex_unlock(&tz->lock); | ||
| 113 | return 0; | 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 | instance->target = clamp_val(state, instance->lower, instance->upper); | 302 | instance->target = clamp_val(state, instance->lower, instance->upper); |
| 303 | mutex_lock(&cdev->lock); | 303 | mutex_lock(&cdev->lock); |
| 304 | cdev->updated = false; | 304 | __thermal_cdev_update(cdev); |
| 305 | mutex_unlock(&cdev->lock); | 305 | mutex_unlock(&cdev->lock); |
| 306 | thermal_cdev_update(cdev); | ||
| 307 | 306 | ||
| 308 | return 0; | 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 | extra_power = min(extra_power, capped_extra_power); | 374 | extra_power = min(extra_power, capped_extra_power); |
| 376 | if (capped_extra_power > 0) | 375 | if (capped_extra_power > 0) |
| 377 | for (i = 0; i < num_actors; i++) | 376 | for (i = 0; i < num_actors; i++) { |
| 378 | granted_power[i] += (extra_actor_power[i] * | 377 | u64 extra_range = (u64)extra_actor_power[i] * extra_power; |
| 379 | extra_power) / capped_extra_power; | 378 | granted_power[i] += DIV_ROUND_CLOSEST_ULL(extra_range, |
| 379 | capped_extra_power); | ||
| 380 | } | ||
| 380 | } | 381 | } |
| 381 | 382 | ||
| 382 | static int allocate_power(struct thermal_zone_device *tz, | 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 | params->prev_err = 0; | 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 | struct thermal_instance *instance; | 575 | struct thermal_instance *instance; |
| 575 | struct power_allocator_params *params = tz->governor_data; | 576 | struct power_allocator_params *params = tz->governor_data; |
| 577 | u32 req_power; | ||
| 576 | 578 | ||
| 577 | mutex_lock(&tz->lock); | 579 | mutex_lock(&tz->lock); |
| 578 | list_for_each_entry(instance, &tz->thermal_instances, tz_node) { | 580 | list_for_each_entry(instance, &tz->thermal_instances, tz_node) { |
| 581 | struct thermal_cooling_device *cdev = instance->cdev; | ||
| 582 | |||
| 579 | if ((instance->trip != params->trip_max_desired_temperature) || | 583 | if ((instance->trip != params->trip_max_desired_temperature) || |
| 580 | (!cdev_is_power_actor(instance->cdev))) | 584 | (!cdev_is_power_actor(instance->cdev))) |
| 581 | continue; | 585 | continue; |
| 582 | 586 | ||
| 583 | instance->target = 0; | 587 | instance->target = 0; |
| 584 | mutex_lock(&instance->cdev->lock); | 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 | mutex_unlock(&instance->cdev->lock); | 599 | mutex_unlock(&instance->cdev->lock); |
| 587 | thermal_cdev_update(instance->cdev); | ||
| 588 | } | 600 | } |
| 589 | mutex_unlock(&tz->lock); | 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 | int ret; | 710 | int ret; |
| 699 | int switch_on_temp, control_temp; | 711 | int switch_on_temp, control_temp; |
| 700 | struct power_allocator_params *params = tz->governor_data; | 712 | struct power_allocator_params *params = tz->governor_data; |
| 713 | bool update; | ||
| 701 | 714 | ||
| 702 | /* | 715 | /* |
| 703 | * We get called for every trip point but we only need to do | 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 | ret = tz->ops->get_trip_temp(tz, params->trip_switch_on, | 722 | ret = tz->ops->get_trip_temp(tz, params->trip_switch_on, |
| 710 | &switch_on_temp); | 723 | &switch_on_temp); |
| 711 | if (!ret && (tz->temperature < switch_on_temp)) { | 724 | if (!ret && (tz->temperature < switch_on_temp)) { |
| 725 | update = (tz->last_temperature >= switch_on_temp); | ||
| 712 | tz->passive = 0; | 726 | tz->passive = 0; |
| 713 | reset_pid_controller(params); | 727 | reset_pid_controller(params); |
| 714 | allow_maximum_power(tz); | 728 | allow_maximum_power(tz, update); |
| 715 | return 0; | 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 | * Copyright (c) 2014-2015 Linaro Limited. | 5 | * Copyright (c) 2014-2015 Linaro Limited. |
| 6 | * | 6 | * |
| 7 | * Xinwei Kong <kong.kongxinwei@hisilicon.com> | 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 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 573 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 574 | data->regs = devm_ioremap_resource(dev, res); | 574 | data->regs = devm_ioremap_resource(dev, res); |
| 575 | if (IS_ERR(data->regs)) { | 575 | if (IS_ERR(data->regs)) |
| 576 | dev_err(dev, "failed to get io address\n"); | ||
| 577 | return PTR_ERR(data->regs); | 576 | return PTR_ERR(data->regs); |
| 578 | } | ||
| 579 | 577 | ||
| 580 | ret = data->ops->probe(data); | 578 | ret = data->ops->probe(data); |
| 581 | if (ret) | 579 | if (ret) |
| @@ -672,5 +670,5 @@ module_platform_driver(hisi_thermal_driver); · 90 unmodified lines | |||
| 672 | 670 | ||
| 673 | MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>"); | 671 | MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>"); |
| 674 | MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>"); | 672 | MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>"); |
| 675 | MODULE_DESCRIPTION("Hisilicon thermal driver"); | 673 | MODULE_DESCRIPTION("HiSilicon thermal driver"); |
| 676 | MODULE_LICENSE("GPL v2"); | 674 | MODULE_LICENSE("GPL v2"); |
| @@ -79,3 +79,14 @@ config INTEL_PCH_THERMAL · 78 unmodified lines | |||
| 79 | Enable this to support thermal reporting on certain intel PCHs. | 79 | Enable this to support thermal reporting on certain intel PCHs. |
| 80 | Thermal reporting device will provide temperature reading, | 80 | Thermal reporting device will provide temperature reading, |
| 81 | programmable trip points and other information. | 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 | obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ | 10 | obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ |
| 11 | obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o | 11 | obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o |
| 12 | obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o | 12 | obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o |
| 13 | obj-$(CONFIG_INTEL_TCC_COOLING) += intel_tcc_cooling.o | ||
| 13 | obj-$(CONFIG_X86_THERMAL_VECTOR) += therm_throt.o | 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 | static int raw_to_mcelsius_v2(struct mtk_thermal *mt, int sensno, s32 raw) | 574 | static int raw_to_mcelsius_v2(struct mtk_thermal *mt, int sensno, s32 raw) |
| 575 | { | 575 | { |
| 576 | s32 format_1 = 0; | 576 | s32 format_1; |
| 577 | s32 format_2 = 0; | 577 | s32 format_2; |
| 578 | s32 g_oe = 1; | 578 | s32 g_oe; |
| 579 | s32 g_gain = 1; | 579 | s32 g_gain; |
| 580 | s32 g_x_roomt = 0; | 580 | s32 g_x_roomt; |
| 581 | s32 tmp = 0; | 581 | s32 tmp; |
| 582 | 582 | ||
| 583 | if (raw == 0) | 583 | if (raw == 0) |
| 584 | return 0; | 584 | return 0; |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | |||
| 17 | 17 | ||
| 18 | #include "../thermal_core.h" | 18 | #include "../thermal_core.h" |
| 19 | 19 | ||
| 20 | #define QPNP_TM_REG_DIG_MAJOR 0x01 | ||
| 20 | #define QPNP_TM_REG_TYPE 0x04 | 21 | #define QPNP_TM_REG_TYPE 0x04 |
| 21 | #define QPNP_TM_REG_SUBTYPE 0x05 | 22 | #define QPNP_TM_REG_SUBTYPE 0x05 |
| 22 | #define QPNP_TM_REG_STATUS 0x08 | 23 | #define QPNP_TM_REG_STATUS 0x08 |
| @@ -38,26 +39,30 @@ · 15 unmodified lines | |||
| 38 | 39 | ||
| 39 | #define ALARM_CTRL_FORCE_ENABLE BIT(7) | 40 | #define ALARM_CTRL_FORCE_ENABLE BIT(7) |
| 40 | 41 | ||
| 41 | /* | 42 | #define THRESH_COUNT 4 |
| 42 | * Trip point values based on threshold control | 43 | #define STAGE_COUNT 3 |
| 43 | * 0 = {105 C, 125 C, 145 C} | 44 | |
| 44 | * 1 = {110 C, 130 C, 150 C} | 45 | /* Over-temperature trip point values in mC */ |
| 45 | * 2 = {115 C, 135 C, 155 C} | 46 | static const long temp_map_gen1[THRESH_COUNT][STAGE_COUNT] = { |
| 46 | * 3 = {120 C, 140 C, 160 C} | 47 | { 105000, 125000, 145000 }, |
| 47 | */ | 48 | { 110000, 130000, 150000 }, |
| 48 | #define TEMP_STAGE_STEP 20000 /* Stage step: 20.000 C */ | 49 | { 115000, 135000, 155000 }, |
| 49 | #define TEMP_STAGE_HYSTERESIS 2000 | 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 */ | 60 | #define TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */ |
| 52 | #define TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */ | ||
| 53 | 61 | ||
| 54 | #define THRESH_MIN 0 | 62 | #define THRESH_MIN 0 |
| 55 | #define THRESH_MAX 3 | 63 | #define THRESH_MAX 3 |
| 56 | 64 | ||
| 57 | /* Stage 2 Threshold Min: 125 C */ | 65 | #define TEMP_STAGE_HYSTERESIS 2000 |
| 58 | #define STAGE2_THRESHOLD_MIN 125000 | ||
| 59 | /* Stage 2 Threshold Max: 140 C */ | ||
| 60 | #define STAGE2_THRESHOLD_MAX 140000 | ||
| 61 | 66 | ||
| 62 | /* Temperature in Milli Celsius reported during stage 0 if no ADC is present */ | 67 | /* Temperature in Milli Celsius reported during stage 0 if no ADC is present */ |
| 63 | #define DEFAULT_TEMP 37000 | 68 | #define DEFAULT_TEMP 37000 |
| @@ -77,6 +82,7 @@ struct qpnp_tm_chip { · 13 unmodified lines | |||
| 77 | bool initialized; | 82 | bool initialized; |
| 78 | 83 | ||
| 79 | struct iio_channel *adc; | 84 | struct iio_channel *adc; |
| 85 | const long (*temp_map)[THRESH_COUNT][STAGE_COUNT]; | ||
| 80 | }; | 86 | }; |
| 81 | 87 | ||
| 82 | /* This array maps from GEN2 alarm state to GEN1 alarm stage */ | 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 | return regmap_write(chip->map, chip->base + addr, data); | 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 | * qpnp_tm_get_temp_stage() - return over-temperature stage | 127 | * qpnp_tm_get_temp_stage() - return over-temperature stage |
| 105 | * @chip: Pointer to the qpnp_tm chip | 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 | if (stage_new > stage_old) { | 173 | if (stage_new > stage_old) { |
| 151 | /* increasing stage, use lower bound */ | 174 | /* increasing stage, use lower bound */ |
| 152 | chip->temp = (stage_new - 1) * TEMP_STAGE_STEP + | 175 | chip->temp = qpnp_tm_decode_temp(chip, stage_new) |
| 153 | chip->thresh * TEMP_THRESH_STEP + | 176 | + TEMP_STAGE_HYSTERESIS; |
| 154 | TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN; | ||
| 155 | } else if (stage_new < stage_old) { | 177 | } else if (stage_new < stage_old) { |
| 156 | /* decreasing stage, use upper bound */ | 178 | /* decreasing stage, use upper bound */ |
| 157 | chip->temp = stage_new * TEMP_STAGE_STEP + | 179 | chip->temp = qpnp_tm_decode_temp(chip, stage_new + 1) |
| 158 | chip->thresh * TEMP_THRESH_STEP - | 180 | - TEMP_STAGE_HYSTERESIS; |
| 159 | TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN; | ||
| 160 | } | 181 | } |
| 161 | 182 | ||
| 162 | chip->stage = stage; | 183 | chip->stage = stage; |
| @@ -199,26 +220,28 @@ static int qpnp_tm_get_temp(void *data, int *temp) · 36 unmodified lines | |||
| 199 | static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip, | 220 | static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip, |
| 200 | int temp) | 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 | bool disable_s2_shutdown = false; | 225 | bool disable_s2_shutdown = false; |
| 226 | u8 reg; | ||
| 204 | 227 | ||
| 205 | WARN_ON(!mutex_is_locked(&chip->lock)); | 228 | WARN_ON(!mutex_is_locked(&chip->lock)); |
| 206 | 229 | ||
| 207 | /* | 230 | /* |
| 208 | * Default: S2 and S3 shutdown enabled, thresholds at | 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 | reg = SHUTDOWN_CTRL1_RATE_25HZ; | 234 | reg = SHUTDOWN_CTRL1_RATE_25HZ; |
| 212 | 235 | ||
| 213 | if (temp == THERMAL_TEMP_INVALID || | 236 | if (temp == THERMAL_TEMP_INVALID || |
| 214 | temp < STAGE2_THRESHOLD_MIN) { | 237 | temp < stage2_threshold_min) { |
| 215 | chip->thresh = THRESH_MIN; | 238 | chip->thresh = THRESH_MIN; |
| 216 | goto skip; | 239 | goto skip; |
| 217 | } | 240 | } |
| 218 | 241 | ||
| 219 | if (temp <= STAGE2_THRESHOLD_MAX) { | 242 | if (temp <= stage2_threshold_max) { |
| 220 | chip->thresh = THRESH_MAX - | 243 | chip->thresh = THRESH_MAX - |
| 221 | ((STAGE2_THRESHOLD_MAX - temp) / | 244 | ((stage2_threshold_max - temp) / |
| 222 | TEMP_THRESH_STEP); | 245 | TEMP_THRESH_STEP); |
| 223 | disable_s2_shutdown = true; | 246 | disable_s2_shutdown = true; |
| 224 | } else { | 247 | } else { |
| @@ -326,9 +349,7 @@ static int qpnp_tm_init(struct qpnp_tm_chip *chip) · 101 unmodified lines | |||
| 326 | ? chip->stage : alarm_state_map[chip->stage]; | 349 | ? chip->stage : alarm_state_map[chip->stage]; |
| 327 | 350 | ||
| 328 | if (stage) | 351 | if (stage) |
| 329 | chip->temp = chip->thresh * TEMP_THRESH_STEP + | 352 | chip->temp = qpnp_tm_decode_temp(chip, stage); |
| 330 | (stage - 1) * TEMP_STAGE_STEP + | ||
| 331 | TEMP_THRESH_MIN; | ||
| 332 | 353 | ||
| 333 | crit_temp = qpnp_tm_get_critical_trip_temp(chip); | 354 | crit_temp = qpnp_tm_get_critical_trip_temp(chip); |
| 334 | ret = qpnp_tm_update_critical_trip_temp(chip, crit_temp); | 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 | struct qpnp_tm_chip *chip; | 372 | struct qpnp_tm_chip *chip; |
| 352 | struct device_node *node; | 373 | struct device_node *node; |
| 353 | u8 type, subtype; | 374 | u8 type, subtype, dig_major; |
| 354 | u32 res; | 375 | u32 res; |
| 355 | int ret, irq; | 376 | int ret, irq; |
| 356 | 377 | ||
| @@ -400,6 +421,12 @@ static int qpnp_tm_probe(struct platform_device *pdev) · 43 unmodified lines | |||
| 400 | return ret; | 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 | if (type != QPNP_TM_TYPE || (subtype != QPNP_TM_SUBTYPE_GEN1 | 430 | if (type != QPNP_TM_TYPE || (subtype != QPNP_TM_SUBTYPE_GEN1 |
| 404 | && subtype != QPNP_TM_SUBTYPE_GEN2)) { | 431 | && subtype != QPNP_TM_SUBTYPE_GEN2)) { |
| 405 | dev_err(&pdev->dev, "invalid type 0x%02x or subtype 0x%02x\n", | 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 | chip->subtype = subtype; | 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 | * Register the sensor before initializing the hardware to be able to | 444 | * Register the sensor before initializing the hardware to be able to |
| @@ -10,8 +10,6 @@ · 9 unmodified lines | |||
| 10 | #include <linux/thermal.h> | 10 | #include <linux/thermal.h> |
| 11 | #include "tsens.h" | 11 | #include "tsens.h" |
| 12 | 12 | ||
| 13 | #define CAL_MDEGC 30000 | ||
| 14 | |||
| 15 | #define CONFIG_ADDR 0x3640 | 13 | #define CONFIG_ADDR 0x3640 |
| 16 | #define CONFIG_ADDR_8660 0x3620 | 14 | #define CONFIG_ADDR_8660 0x3620 |
| 17 | /* CONFIG_ADDR bitmasks */ | 15 | /* CONFIG_ADDR bitmasks */ |
| @@ -21,40 +19,38 @@ · 3 unmodified lines | |||
| 21 | #define CONFIG_SHIFT_8660 28 | 19 | #define CONFIG_SHIFT_8660 28 |
| 22 | #define CONFIG_MASK_8660 (3 << CONFIG_SHIFT_8660) | 20 | #define CONFIG_MASK_8660 (3 << CONFIG_SHIFT_8660) |
| 23 | 21 | ||
| 24 | #define STATUS_CNTL_ADDR_8064 0x3660 | ||
| 25 | #define CNTL_ADDR 0x3620 | 22 | #define CNTL_ADDR 0x3620 |
| 26 | /* CNTL_ADDR bitmasks */ | 23 | /* CNTL_ADDR bitmasks */ |
| 27 | #define EN BIT(0) | 24 | #define EN BIT(0) |
| 28 | #define SW_RST BIT(1) | 25 | #define SW_RST BIT(1) |
| 29 | #define SENSOR0_EN BIT(3) | 26 | |
| 27 | #define MEASURE_PERIOD BIT(18) | ||
| 30 | #define SLP_CLK_ENA BIT(26) | 28 | #define SLP_CLK_ENA BIT(26) |
| 31 | #define SLP_CLK_ENA_8660 BIT(24) | 29 | #define SLP_CLK_ENA_8660 BIT(24) |
| 32 | #define MEASURE_PERIOD 1 | ||
| 33 | #define SENSOR0_SHIFT 3 | 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 | #define THRESHOLD_ADDR 0x3624 | 32 | #define THRESHOLD_ADDR 0x3624 |
| 42 | /* THRESHOLD_ADDR bitmasks */ | 33 | |
| 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 | ||
| 55 | #define INT_STATUS_ADDR 0x363c | 34 | #define INT_STATUS_ADDR 0x363c |
| 56 | #define TRDY_MASK BIT(7) | 35 | |
| 57 | #define TIMEOUT_US 100 | 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 | static int suspend_8960(struct tsens_priv *priv) | 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 | static int enable_8960(struct tsens_priv *priv, int id) | 111 | static int enable_8960(struct tsens_priv *priv, int id) |
| 116 | { | 112 | { |
| 117 | int ret; | 113 | int ret; |
| 118 | u32 reg, mask; | 114 | u32 reg, mask = BIT(id); |
| 119 | 115 | ||
| 120 | ret = regmap_read(priv->tm_map, CNTL_ADDR, ®); | 116 | ret = regmap_read(priv->tm_map, CNTL_ADDR, ®); |
| 121 | if (ret) | 117 | if (ret) |
| 122 | return ret; | 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 | ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST); | 136 | ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST); |
| 126 | if (ret) | 137 | if (ret) |
| 127 | return ret; | 138 | return ret; |
| 128 | 139 | ||
| 140 | reg |= MEASURE_PERIOD; | ||
| 141 | |||
| 129 | if (priv->num_sensors > 1) | 142 | if (priv->num_sensors > 1) |
| 130 | reg |= mask | SLP_CLK_ENA | EN; | 143 | reg |= mask | SLP_CLK_ENA | EN; |
| 131 | else | 144 | else |
| @@ -162,63 +175,11 @@ static void disable_8960(struct tsens_priv *priv) · 30 unmodified lines | |||
| 162 | regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); | 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 | static int calibrate_8960(struct tsens_priv *priv) | 178 | static int calibrate_8960(struct tsens_priv *priv) |
| 216 | { | 179 | { |
| 217 | int i; | 180 | int i; |
| 218 | char *data; | 181 | char *data; |
| 219 | 182 | u32 p1[11]; | |
| 220 | ssize_t num_read = priv->num_sensors; | ||
| 221 | struct tsens_sensor *s = priv->sensor; | ||
| 222 | 183 | ||
| 223 | data = qfprom_read(priv->dev, "calib"); | 184 | data = qfprom_read(priv->dev, "calib"); |
| 224 | if (IS_ERR(data)) | 185 | if (IS_ERR(data)) |
| @@ -226,60 +187,96 @@ static int calibrate_8960(struct tsens_priv *priv) · 1 unmodified line | |||
| 226 | if (IS_ERR(data)) | 187 | if (IS_ERR(data)) |
| 227 | return PTR_ERR(data); | 188 | return PTR_ERR(data); |
| 228 | 189 | ||
| 229 | for (i = 0; i < num_read; i++, s++) | 190 | for (i = 0; i < priv->num_sensors; i++) { |
| 230 | s->offset = data[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 | kfree(data); | 197 | kfree(data); |
| 233 | 198 | ||
| 234 | return 0; | 199 | return 0; |
| 235 | } | 200 | } |
| 236 | 201 | ||
| 237 | /* Temperature on y axis and ADC-code on x-axis */ | 202 | static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = { |
| 238 | static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s) | 203 | /* ----- SROT ------ */ |
| 239 | { | 204 | /* No VERSION information */ |
| 240 | int slope, offset; | 205 | |
| 241 | 206 | /* CNTL */ | |
| 242 | slope = thermal_zone_get_slope(s->tzd); | 207 | [TSENS_EN] = REG_FIELD(CNTL_ADDR, 0, 0), |
| 243 | offset = CAL_MDEGC - slope * s->offset; | 208 | [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR, 1, 1), |
| 244 | 209 | /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */ | |
| 245 | return adc_code * slope + offset; | 210 | [SENSOR_EN] = REG_FIELD(CNTL_ADDR, 3, 7), |
| 246 | } | 211 | |
| 247 | 212 | /* ----- TM ------ */ | |
| 248 | static int get_temp_8960(const struct tsens_sensor *s, int *temp) | 213 | /* INTERRUPT ENABLE */ |
| 249 | { | 214 | /* NO INTERRUPT ENABLE */ |
| 250 | int ret; | 215 | |
| 251 | u32 code, trdy; | 216 | /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */ |
| 252 | struct tsens_priv *priv = s->priv; | 217 | [LOW_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 0, 7), |
| 253 | unsigned long timeout; | 218 | [UP_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 8, 15), |
| 254 | 219 | /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield | |
| 255 | timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); | 220 | * Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded temp |
| 256 | do { | 221 | * MIN_THRESH_0 -> CRIT_THRESH_1 |
| 257 | ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy); | 222 | * MAX_THRESH_0 -> CRIT_THRESH_0 |
| 258 | if (ret) | 223 | */ |
| 259 | return ret; | 224 | [CRIT_THRESH_1] = REG_FIELD(THRESHOLD_ADDR, 16, 23), |
| 260 | if (!(trdy & TRDY_MASK)) | 225 | [CRIT_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 24, 31), |
| 261 | continue; | 226 | |
| 262 | ret = regmap_read(priv->tm_map, s->status, &code); | 227 | /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */ |
| 263 | if (ret) | 228 | /* 1 == clear, 0 == normal operation */ |
| 264 | return ret; | 229 | [LOW_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 9, 9), |
| 265 | *temp = code_to_mdegC(code, s); | 230 | [UP_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 10, 10), |
| 266 | return 0; | 231 | |
| 267 | } while (time_before(jiffies, timeout)); | 232 | /* NO CRITICAL INTERRUPT SUPPORT on 8960 */ |
| 268 | 233 | ||
| 269 | return -ETIMEDOUT; | 234 | /* Sn_STATUS */ |
| 270 | } | 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 | static const struct tsens_ops ops_8960 = { | 259 | static const struct tsens_ops ops_8960 = { |
| 273 | .init = init_8960, | 260 | .init = init_common, |
| 274 | .calibrate = calibrate_8960, | 261 | .calibrate = calibrate_8960, |
| 275 | .get_temp = get_temp_8960, | 262 | .get_temp = get_temp_common, |
| 276 | .enable = enable_8960, | 263 | .enable = enable_8960, |
| 277 | .disable = disable_8960, | 264 | .disable = disable_8960, |
| 278 | .suspend = suspend_8960, | 265 | .suspend = suspend_8960, |
| 279 | .resume = resume_8960, | 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 | struct tsens_plat_data data_8960 = { | 277 | struct tsens_plat_data data_8960 = { |
| 283 | .num_sensors = 11, | 278 | .num_sensors = 11, |
| 284 | .ops = &ops_8960, | 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 | #define BIT_APPEND 0x3 | 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 | static int calibrate_8916(struct tsens_priv *priv) | 226 | static int calibrate_8916(struct tsens_priv *priv) |
| 194 | { | 227 | { |
| 195 | int base0 = 0, base1 = 0, i; | 228 | int base0 = 0, base1 = 0, i; |
| @@ -452,7 +485,56 @@ static int calibrate_8974(struct tsens_priv *priv) · 256 unmodified lines | |||
| 452 | return 0; | 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 | static struct tsens_features tsens_v0_1_feat = { | 539 | static struct tsens_features tsens_v0_1_feat = { |
| 458 | .ver_major = VER_0_1, | 540 | .ver_major = VER_0_1, |
| @@ -540,3 +622,17 @@ struct tsens_plat_data data_8974 = { · 81 unmodified lines | |||
| 540 | .feat = &tsens_v0_1_feat, | 622 | .feat = &tsens_v0_1_feat, |
| 541 | .fields = tsens_v0_1_regfields, | 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 | .get_temp = get_temp_tsens_valid, | 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 | struct tsens_plat_data data_8976 = { | 384 | struct tsens_plat_data data_8976 = { |
| 385 | .num_sensors = 11, | 385 | .num_sensors = 11, |
| 386 | .ops = &ops_8976, | 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 | .feat = &tsens_v1_feat, | 388 | .feat = &tsens_v1_feat, |
| 389 | .fields = tsens_v1_regfields, | 389 | .fields = tsens_v1_regfields, |
| 390 | }; | 390 | }; |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include <linux/of.h> | 12 | #include <linux/of.h> |
| 13 | #include <linux/of_address.h> | 13 | #include <linux/of_address.h> |
| 14 | #include <linux/of_platform.h> | 14 | #include <linux/of_platform.h> |
| 15 | #include <linux/mfd/syscon.h> | ||
| 15 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
| 16 | #include <linux/pm.h> | 17 | #include <linux/pm.h> |
| 17 | #include <linux/regmap.h> | 18 | #include <linux/regmap.h> |
| @@ -85,7 +86,8 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1, · 67 unmodified lines | |||
| 85 | "%s: sensor%d - data_point1:%#x data_point2:%#x\n", | 86 | "%s: sensor%d - data_point1:%#x data_point2:%#x\n", |
| 86 | __func__, i, p1[i], p2[i]); | 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 | if (mode == TWO_PT_CALIB) { | 91 | if (mode == TWO_PT_CALIB) { |
| 90 | /* | 92 | /* |
| 91 | * slope (m) = adc_code2 - adc_code1 (y2 - y1)/ | 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 | dev_dbg(priv->dev, "[%u] %s: no violation: %d\n", | 517 | dev_dbg(priv->dev, "[%u] %s: no violation: %d\n", |
| 516 | hw_id, __func__, temp); | 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 | return IRQ_HANDLED; | 531 | return IRQ_HANDLED; |
| @@ -530,6 +541,13 @@ static int tsens_set_trips(void *_sensor, int low, int high) · 9 unmodified lines | |||
| 530 | int high_val, low_val, cl_high, cl_low; | 541 | int high_val, low_val, cl_high, cl_low; |
| 531 | u32 hw_id = s->hw_id; | 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 | dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n", | 551 | dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n", |
| 534 | hw_id, __func__, low, high); | 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 | u32 valid; | 602 | u32 valid; |
| 585 | int ret; | 603 | int ret; |
| 586 | 604 | ||
| 587 | ret = regmap_field_read(priv->rf[valid_idx], &valid); | 605 | /* VER_0 doesn't have VALID bit */ |
| 588 | if (ret) | 606 | if (tsens_version(priv) >= VER_0_1) { |
| 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); | ||
| 596 | ret = regmap_field_read(priv->rf[valid_idx], &valid); | 607 | ret = regmap_field_read(priv->rf[valid_idx], &valid); |
| 597 | if (ret) | 608 | if (ret) |
| 598 | return ret; | 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 | /* Valid bit is set, OK to read the temperature */ | 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 | struct tsens_priv *priv = s->priv; | 630 | struct tsens_priv *priv = s->priv; |
| 610 | int hw_id = s->hw_id; | 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); | 635 | timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); |
| 614 | if (ret) | 636 | do { |
| 615 | return ret; | 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 | #ifdef CONFIG_DEBUG_FS | 657 | #ifdef CONFIG_DEBUG_FS |
| @@ -738,25 +773,42 @@ int __init init_common(struct tsens_priv *priv) · 115 unmodified lines | |||
| 738 | priv->tm_offset = 0x1000; | 773 | priv->tm_offset = 0x1000; |
| 739 | } | 774 | } |
| 740 | 775 | ||
| 741 | res = platform_get_resource(op, IORESOURCE_MEM, 0); | 776 | if (tsens_version(priv) >= VER_0_1) { |
| 742 | tm_base = devm_ioremap_resource(dev, res); | 777 | res = platform_get_resource(op, IORESOURCE_MEM, 0); |
| 743 | if (IS_ERR(tm_base)) { | 778 | tm_base = devm_ioremap_resource(dev, res); |
| 744 | ret = PTR_ERR(tm_base); | 779 | if (IS_ERR(tm_base)) { |
| 745 | goto err_put_device; | 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); | 792 | if (IS_ERR_OR_NULL(priv->tm_map)) { |
| 749 | if (IS_ERR(priv->tm_map)) { | 793 | if (!priv->tm_map) |
| 750 | ret = PTR_ERR(priv->tm_map); | 794 | ret = -ENODEV; |
| 795 | else | ||
| 796 | ret = PTR_ERR(priv->tm_map); | ||
| 751 | goto err_put_device; | 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 | if (tsens_version(priv) > VER_0_1) { | 804 | if (tsens_version(priv) > VER_0_1) { |
| 755 | for (i = VER_MAJOR; i <= VER_STEP; i++) { | 805 | for (i = VER_MAJOR; i <= VER_STEP; i++) { |
| 756 | priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map, | 806 | priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map, |
| 757 | priv->fields[i]); | 807 | priv->fields[i]); |
| 758 | if (IS_ERR(priv->rf[i])) | 808 | if (IS_ERR(priv->rf[i])) { |
| 759 | return PTR_ERR(priv->rf[i]); | 809 | ret = PTR_ERR(priv->rf[i]); |
| 810 | goto err_put_device; | ||
| 811 | } | ||
| 760 | } | 812 | } |
| 761 | ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor); | 813 | ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor); |
| 762 | if (ret) | 814 | if (ret) |
| @@ -769,6 +821,10 @@ int __init init_common(struct tsens_priv *priv) · 6 unmodified lines | |||
| 769 | ret = PTR_ERR(priv->rf[TSENS_EN]); | 821 | ret = PTR_ERR(priv->rf[TSENS_EN]); |
| 770 | goto err_put_device; | 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 | ret = regmap_field_read(priv->rf[TSENS_EN], &enabled); | 828 | ret = regmap_field_read(priv->rf[TSENS_EN], &enabled); |
| 773 | if (ret) | 829 | if (ret) |
| 774 | goto err_put_device; | 830 | goto err_put_device; |
| @@ -791,6 +847,19 @@ int __init init_common(struct tsens_priv *priv) · 16 unmodified lines | |||
| 791 | goto err_put_device; | 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 | /* This loop might need changes if enum regfield_ids is reordered */ | 863 | /* This loop might need changes if enum regfield_ids is reordered */ |
| 795 | for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) { | 864 | for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) { |
| 796 | for (i = 0; i < priv->feat->max_sensors; i++) { | 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 | /* Loop might need changes if enum regfield_ids is reordered */ | 879 | /* Loop might need changes if enum regfield_ids is reordered */ |
| 811 | for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) { | 880 | for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) { |
| 812 | for (i = 0; i < priv->feat->max_sensors; i++) { | 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 | spin_lock_init(&priv->ul_lock); | 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 | tsens_debug_init(op); | 921 | tsens_debug_init(op); |
| 849 | 922 | ||
| 850 | err_put_device: | 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 | static const struct of_device_id tsens_table[] = { | 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 | .compatible = "qcom,msm8916-tsens", | 977 | .compatible = "qcom,msm8916-tsens", |
| 899 | .data = &data_8916, | 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 | if (irq == -ENXIO) | 1022 | if (irq == -ENXIO) |
| 944 | ret = 0; | 1023 | ret = 0; |
| 945 | } else { | 1024 | } else { |
| 946 | ret = devm_request_threaded_irq(&pdev->dev, irq, | 1025 | /* VER_0 interrupt is TRIGGER_RISING, VER_0_1 and up is ONESHOT */ |
| 947 | NULL, thread_fn, | 1026 | if (tsens_version(priv) == VER_0) |
| 948 | IRQF_ONESHOT, | 1027 | ret = devm_request_threaded_irq(&pdev->dev, irq, |
| 949 | dev_name(&pdev->dev), priv); | 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 | if (ret) | 1038 | if (ret) |
| 951 | dev_err(&pdev->dev, "%s: failed to get irq\n", | 1039 | dev_err(&pdev->dev, "%s: failed to get irq\n", |
| 952 | __func__); | 1040 | __func__); |
| @@ -975,6 +1063,19 @@ static int tsens_register(struct tsens_priv *priv) · 22 unmodified lines | |||
| 975 | priv->ops->enable(priv, i); | 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 | ret = tsens_register_irq(priv, "uplow", tsens_irq_thread); | 1079 | ret = tsens_register_irq(priv, "uplow", tsens_irq_thread); |
| 979 | if (ret < 0) | 1080 | if (ret < 0) |
| 980 | return ret; | 1081 | return ret; |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | |||
| 13 | #define CAL_DEGC_PT2 120 | 13 | #define CAL_DEGC_PT2 120 |
| 14 | #define SLOPE_FACTOR 1000 | 14 | #define SLOPE_FACTOR 1000 |
| 15 | #define SLOPE_DEFAULT 3200 | 15 | #define SLOPE_DEFAULT 3200 |
| 16 | #define TIMEOUT_US 100 | ||
| 16 | #define THRESHOLD_MAX_ADC_CODE 0x3ff | 17 | #define THRESHOLD_MAX_ADC_CODE 0x3ff |
| 17 | #define THRESHOLD_MIN_ADC_CODE 0x0 | 18 | #define THRESHOLD_MIN_ADC_CODE 0x0 |
| 18 | 19 | ||
| @@ -25,7 +26,8 @@ struct tsens_priv; · 6 unmodified lines | |||
| 25 | 26 | ||
| 26 | /* IP version numbers in ascending order */ | 27 | /* IP version numbers in ascending order */ |
| 27 | enum tsens_ver { | 28 | enum tsens_ver { |
| 28 | VER_0_1 = 0, | 29 | VER_0 = 0, |
| 30 | VER_0_1, | ||
| 29 | VER_1_X, | 31 | VER_1_X, |
| 30 | VER_2_X, | 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 | extern struct tsens_plat_data data_8960; | 587 | extern struct tsens_plat_data data_8960; |
| 586 | 588 | ||
| 587 | /* TSENS v0.1 targets */ | 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 | /* TSENS v1 targets */ | 592 | /* TSENS v1 targets */ |
| 591 | extern struct tsens_plat_data data_tsens_v1, data_8976; | 593 | extern struct tsens_plat_data data_tsens_v1, data_8976; |
| @@ -60,7 +60,7 @@ · 59 unmodified lines | |||
| 60 | #define MCELSIUS(temp) ((temp) * 1000) | 60 | #define MCELSIUS(temp) ((temp) * 1000) |
| 61 | #define GEN3_FUSE_MASK 0xFFF | 61 | #define GEN3_FUSE_MASK 0xFFF |
| 62 | 62 | ||
| 63 | #define TSC_MAX_NUM 4 | 63 | #define TSC_MAX_NUM 5 |
| 64 | 64 | ||
| 65 | /* default THCODE values if FUSEs are missing */ | 65 | /* default THCODE values if FUSEs are missing */ |
| 66 | static const int thcodes[TSC_MAX_NUM][3] = { | 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 | { 3393, 2795, 2216 }, | 68 | { 3393, 2795, 2216 }, |
| 69 | { 3389, 2805, 2237 }, | 69 | { 3389, 2805, 2237 }, |
| 70 | { 3415, 2694, 2195 }, | 70 | { 3415, 2694, 2195 }, |
| 71 | { 3356, 2724, 2244 }, | ||
| 71 | }; | 72 | }; |
| 72 | 73 | ||
| 73 | /* Structure for thermal temperature calculation */ | 74 | /* Structure for thermal temperature calculation */ |
| @@ -300,7 +300,7 @@ static int sun8i_ths_calibrate(struct ths_device *tmdev) · 299 unmodified lines | |||
| 300 | * or 0x8xx, so they won't be away from the default value | 300 | * or 0x8xx, so they won't be away from the default value |
| 301 | * for a lot. | 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 | * not available, except the probe needs deferring. | 304 | * not available, except the probe needs deferring. |
| 305 | */ | 305 | */ |
| 306 | goto out; | 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 | * be higher than real ones by about 20C. | 422 | * be higher than real ones by about 20C. |
| 423 | */ | 423 | */ |
| 424 | #define SUN50I_H6_CTRL0_UNK 0x0000002f | 424 | #define SUN50I_H6_CTRL0_UNK 0x0000002f |
| @@ -2118,7 +2118,6 @@ static int tegra_soctherm_probe(struct platform_device *pdev) · 2117 unmodified lines | |||
| 2118 | struct tegra_soctherm *tegra; | 2118 | struct tegra_soctherm *tegra; |
| 2119 | struct thermal_zone_device *z; | 2119 | struct thermal_zone_device *z; |
| 2120 | struct tsensor_shared_calib shared_calib; | 2120 | struct tsensor_shared_calib shared_calib; |
| 2121 | struct resource *res; | ||
| 2122 | struct tegra_soctherm_soc *soc; | 2121 | struct tegra_soctherm_soc *soc; |
| 2123 | unsigned int i; | 2122 | unsigned int i; |
| 2124 | int err; | 2123 | int err; |
| @@ -2140,26 +2139,20 @@ static int tegra_soctherm_probe(struct platform_device *pdev) · 15 unmodified lines | |||
| 2140 | 2139 | ||
| 2141 | tegra->soc = soc; | 2140 | tegra->soc = soc; |
| 2142 | 2141 | ||
| 2143 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | 2142 | tegra->regs = devm_platform_ioremap_resource_byname(pdev, "soctherm-reg"); |
| 2144 | "soctherm-reg"); | ||
| 2145 | tegra->regs = devm_ioremap_resource(&pdev->dev, res); | ||
| 2146 | if (IS_ERR(tegra->regs)) { | 2143 | if (IS_ERR(tegra->regs)) { |
| 2147 | dev_err(&pdev->dev, "can't get soctherm registers"); | 2144 | dev_err(&pdev->dev, "can't get soctherm registers"); |
| 2148 | return PTR_ERR(tegra->regs); | 2145 | return PTR_ERR(tegra->regs); |
| 2149 | } | 2146 | } |
| 2150 | 2147 | ||
| 2151 | if (!tegra->soc->use_ccroc) { | 2148 | if (!tegra->soc->use_ccroc) { |
| 2152 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | 2149 | tegra->clk_regs = devm_platform_ioremap_resource_byname(pdev, "car-reg"); |
| 2153 | "car-reg"); | ||
| 2154 | tegra->clk_regs = devm_ioremap_resource(&pdev->dev, res); | ||
| 2155 | if (IS_ERR(tegra->clk_regs)) { | 2150 | if (IS_ERR(tegra->clk_regs)) { |
| 2156 | dev_err(&pdev->dev, "can't get car clk registers"); | 2151 | dev_err(&pdev->dev, "can't get car clk registers"); |
| 2157 | return PTR_ERR(tegra->clk_regs); | 2152 | return PTR_ERR(tegra->clk_regs); |
| 2158 | } | 2153 | } |
| 2159 | } else { | 2154 | } else { |
| 2160 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | 2155 | tegra->ccroc_regs = devm_platform_ioremap_resource_byname(pdev, "ccroc-reg"); |
| 2161 | "ccroc-reg"); | ||
| 2162 | tegra->ccroc_regs = devm_ioremap_resource(&pdev->dev, res); | ||
| 2163 | if (IS_ERR(tegra->ccroc_regs)) { | 2156 | if (IS_ERR(tegra->ccroc_regs)) { |
| 2164 | dev_err(&pdev->dev, "can't get ccroc registers"); | 2157 | dev_err(&pdev->dev, "can't get ccroc registers"); |
| 2165 | return PTR_ERR(tegra->ccroc_regs); | 2158 | return PTR_ERR(tegra->ccroc_regs); |
| @@ -2195,7 +2188,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev) · 29 unmodified lines | |||
| 2195 | if (err) | 2188 | if (err) |
| 2196 | return err; | 2189 | return err; |
| 2197 | 2190 | ||
| 2198 | /* calculate tsensor calibaration data */ | 2191 | /* calculate tsensor calibration data */ |
| 2199 | for (i = 0; i < soc->num_tsensors; ++i) { | 2192 | for (i = 0; i < soc->num_tsensors; ++i) { |
| 2200 | err = tegra_calc_tsensor_calib(&soc->tsensors[i], | 2193 | err = tegra_calc_tsensor_calib(&soc->tsensors[i], |
| 2201 | &shared_calib, | 2194 | &shared_calib, |
| @@ -561,24 +561,6 @@ void thermal_zone_device_update(struct thermal_zone_device *tz, · 560 unmodified lines | |||
| 561 | } | 561 | } |
| 562 | EXPORT_SYMBOL_GPL(thermal_zone_device_update); | 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 | static void thermal_zone_device_check(struct work_struct *work) | 564 | static void thermal_zone_device_check(struct work_struct *work) |
| 583 | { | 565 | { |
| 584 | struct thermal_zone_device *tz = container_of(work, struct | 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 | struct thermal_cooling_device *cdev; | 943 | struct thermal_cooling_device *cdev; |
| 962 | struct thermal_zone_device *pos = NULL; | 944 | struct thermal_zone_device *pos = NULL; |
| 963 | int result; | 945 | int ret; |
| 964 | |||
| 965 | if (type && strlen(type) >= THERMAL_NAME_LENGTH) | ||
| 966 | return ERR_PTR(-EINVAL); | ||
| 967 | 946 | ||
| 968 | if (!ops || !ops->get_max_state || !ops->get_cur_state || | 947 | if (!ops || !ops->get_max_state || !ops->get_cur_state || |
| 969 | !ops->set_cur_state) | 948 | !ops->set_cur_state) |
| @@ -973,14 +952,17 @@ __thermal_cooling_device_register(struct device_node *np, · 3 unmodified lines | |||
| 973 | if (!cdev) | 952 | if (!cdev) |
| 974 | return ERR_PTR(-ENOMEM); | 953 | return ERR_PTR(-ENOMEM); |
| 975 | 954 | ||
| 976 | result = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL); | 955 | ret = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL); |
| 977 | if (result < 0) { | 956 | if (ret < 0) |
| 978 | kfree(cdev); | 957 | goto out_kfree_cdev; |
| 979 | return ERR_PTR(result); | 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 | mutex_init(&cdev->lock); | 966 | mutex_init(&cdev->lock); |
| 985 | INIT_LIST_HEAD(&cdev->thermal_instances); | 967 | INIT_LIST_HEAD(&cdev->thermal_instances); |
| 986 | cdev->np = np; | 968 | cdev->np = np; |
| @@ -990,12 +972,9 @@ __thermal_cooling_device_register(struct device_node *np, · 3 unmodified lines | |||
| 990 | cdev->devdata = devdata; | 972 | cdev->devdata = devdata; |
| 991 | thermal_cooling_device_setup_sysfs(cdev); | 973 | thermal_cooling_device_setup_sysfs(cdev); |
| 992 | dev_set_name(&cdev->device, "cooling_device%d", cdev->id); | 974 | dev_set_name(&cdev->device, "cooling_device%d", cdev->id); |
| 993 | result = device_register(&cdev->device); | 975 | ret = device_register(&cdev->device); |
| 994 | if (result) { | 976 | if (ret) |
| 995 | ida_simple_remove(&thermal_cdev_ida, cdev->id); | 977 | goto out_kfree_type; |
| 996 | put_device(&cdev->device); | ||
| 997 | return ERR_PTR(result); | ||
| 998 | } | ||
| 999 | 978 | ||
| 1000 | /* Add 'this' new cdev to the global cdev list */ | 979 | /* Add 'this' new cdev to the global cdev list */ |
| 1001 | mutex_lock(&thermal_list_lock); | 980 | mutex_lock(&thermal_list_lock); |
| @@ -1013,6 +992,15 @@ __thermal_cooling_device_register(struct device_node *np, · 11 unmodified lines | |||
| 1013 | mutex_unlock(&thermal_list_lock); | 992 | mutex_unlock(&thermal_list_lock); |
| 1014 | 993 | ||
| 1015 | return cdev; | 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 | ida_simple_remove(&thermal_cdev_ida, cdev->id); | 1159 | ida_simple_remove(&thermal_cdev_ida, cdev->id); |
| 1172 | device_del(&cdev->device); | 1160 | device_del(&cdev->device); |
| 1173 | thermal_cooling_device_destroy_sysfs(cdev); | 1161 | thermal_cooling_device_destroy_sysfs(cdev); |
| 1162 | kfree(cdev->type); | ||
| 1174 | put_device(&cdev->device); | 1163 | put_device(&cdev->device); |
| 1175 | } | 1164 | } |
| 1176 | EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister); | 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 | void thermal_cdev_update(struct thermal_cooling_device *); | 68 | void thermal_cdev_update(struct thermal_cooling_device *); |
| 69 | void __thermal_cdev_update(struct thermal_cooling_device *cdev); | ||
| 69 | 70 | ||
| 70 | /** | 71 | /** |
| 71 | * struct thermal_trip - representation of a point in temperature domain | 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 | thermal_cooling_device_stats_update(cdev, target); | 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 | struct thermal_instance *instance; | 197 | struct thermal_instance *instance; |
| 198 | unsigned long target = 0; | 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 | /* Make sure cdev enters the deepest cooling state */ | 200 | /* Make sure cdev enters the deepest cooling state */ |
| 208 | list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) { | 201 | list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) { |
| 209 | dev_dbg(&cdev->device, "zone%d->target=%lu\n", | 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 | thermal_cdev_set_cur_state(cdev, target); | 210 | thermal_cdev_set_cur_state(cdev, target); |
| 218 | 211 | ||
| 219 | cdev->updated = true; | ||
| 220 | mutex_unlock(&cdev->lock); | ||
| 221 | trace_cdev_update(cdev, target); | 212 | trace_cdev_update(cdev, target); |
| 222 | dev_dbg(&cdev->device, "set to state %lu\n", target); | 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 | EXPORT_SYMBOL(thermal_cdev_update); | 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 | resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 55 | resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 56 | sensor->mmio_base = devm_ioremap_resource(&pdev->dev, resource); | 56 | sensor->mmio_base = devm_ioremap_resource(&pdev->dev, resource); |
| 57 | if (IS_ERR(sensor->mmio_base)) { | 57 | if (IS_ERR(sensor->mmio_base)) |
| 58 | dev_err(&pdev->dev, "failed to ioremap memory (%ld)\n", | ||
| 59 | PTR_ERR(sensor->mmio_base)); | ||
| 60 | return PTR_ERR(sensor->mmio_base); | 58 | return PTR_ERR(sensor->mmio_base); |
| 61 | } | ||
| 62 | 59 | ||
| 63 | sensor_init_func = device_get_match_data(&pdev->dev); | 60 | sensor_init_func = device_get_match_data(&pdev->dev); |
| 64 | if (sensor_init_func) { | 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 | count = of_count_phandle_with_args(np, "cooling-device", | 705 | count = of_count_phandle_with_args(np, "cooling-device", |
| 706 | "#cooling-cells"); | 706 | "#cooling-cells"); |
| 707 | if (!count) { | 707 | if (count <= 0) { |
| 708 | pr_err("Add a cooling_device property with at least one device\n"); | 708 | pr_err("Add a cooling_device property with at least one device\n"); |
| 709 | ret = -ENOENT; | ||
| 709 | goto end; | 710 | goto end; |
| 710 | } | 711 | } |
| 711 | 712 | ||
| 712 | __tcbp = kcalloc(count, sizeof(*__tcbp), GFP_KERNEL); | 713 | __tcbp = kcalloc(count, sizeof(*__tcbp), GFP_KERNEL); |
| 713 | if (!__tcbp) | 714 | if (!__tcbp) { |
| 715 | ret = -ENOMEM; | ||
| 714 | goto end; | 716 | goto end; |
| 717 | } | ||
| 715 | 718 | ||
| 716 | for (i = 0; i < count; i++) { | 719 | for (i = 0; i < count; i++) { |
| 717 | ret = of_parse_phandle_with_args(np, "cooling-device", | 720 | ret = of_parse_phandle_with_args(np, "cooling-device", |
| @@ -9,30 +9,29 @@ · 8 unmodified lines | |||
| 9 | * Eduardo Valentin <eduardo.valentin@ti.com> | 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 | #include <linux/export.h> | 16 | #include <linux/export.h> |
| 17 | #include <linux/gpio/consumer.h> | ||
| 14 | #include <linux/init.h> | 18 | #include <linux/init.h> |
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/interrupt.h> | 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 | #include <linux/io.h> | 20 | #include <linux/io.h> |
| 29 | #include <linux/iopoll.h> | 21 | #include <linux/iopoll.h> |
| 30 | #include <linux/cpu_pm.h> | 22 | #include <linux/kernel.h> |
| 31 | #include <linux/device.h> | 23 | #include <linux/module.h> |
| 32 | #include <linux/pm_runtime.h> | ||
| 33 | #include <linux/pm.h> | ||
| 34 | #include <linux/of.h> | 24 | #include <linux/of.h> |
| 35 | #include <linux/of_device.h> | 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 | #include "ti-bandgap.h" | 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 | for (i = 0; i < bgp->conf->sensor_count; i++) { | 1142 | for (i = 0; i < bgp->conf->sensor_count; i++) { |
| 1144 | struct temp_sensor_registers *tsr; | 1143 | struct temp_sensor_registers *tsr; |
| 1145 | struct temp_sensor_regval *rval; | 1144 | struct temp_sensor_regval *rval; |
| 1146 | u32 val = 0; | ||
| 1147 | 1145 | ||
| 1148 | rval = &bgp->regval[i]; | 1146 | rval = &bgp->regval[i]; |
| 1149 | tsr = bgp->conf->sensors[i].registers; | 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 | if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) | 1149 | if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) |
| 1155 | ti_bandgap_writel(bgp, rval->tshut_threshold, | 1150 | ti_bandgap_writel(bgp, rval->tshut_threshold, |
| 1156 | tsr->tshut_threshold); | 1151 | tsr->tshut_threshold); |
| @@ -91,7 +91,7 @@ struct thermal_cooling_device_ops { · 90 unmodified lines | |||
| 91 | 91 | ||
| 92 | struct thermal_cooling_device { | 92 | struct thermal_cooling_device { |
| 93 | int id; | 93 | int id; |
| 94 | char type[THERMAL_NAME_LENGTH]; | 94 | char *type; |
| 95 | struct device device; | 95 | struct device device; |
| 96 | struct device_node *np; | 96 | struct device_node *np; |
| 97 | void *devdata; | 97 | void *devdata; |
| @@ -390,7 +390,6 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp); · 292 unmodified lines | |||
| 390 | int thermal_zone_get_slope(struct thermal_zone_device *tz); | 390 | int thermal_zone_get_slope(struct thermal_zone_device *tz); |
| 391 | int thermal_zone_get_offset(struct thermal_zone_device *tz); | 391 | int thermal_zone_get_offset(struct thermal_zone_device *tz); |
| 392 | 392 | ||
| 393 | void thermal_notify_framework(struct thermal_zone_device *, int); | ||
| 394 | int thermal_zone_device_enable(struct thermal_zone_device *tz); | 393 | int thermal_zone_device_enable(struct thermal_zone_device *tz); |
| 395 | int thermal_zone_device_disable(struct thermal_zone_device *tz); | 394 | int thermal_zone_device_disable(struct thermal_zone_device *tz); |
| 396 | void thermal_zone_device_critical(struct thermal_zone_device *tz); | 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 | struct thermal_zone_device *tz) | 435 | struct thermal_zone_device *tz) |
| 437 | { return -ENODEV; } | 436 | { return -ENODEV; } |
| 438 | 437 | ||
| 439 | static inline void thermal_notify_framework(struct thermal_zone_device *tz, | ||
| 440 | int trip) | ||
| 441 | { } | ||
| 442 | |||
| 443 | static inline int thermal_zone_device_enable(struct thermal_zone_device *tz) | 438 | static inline int thermal_zone_device_enable(struct thermal_zone_device *tz) |
| 444 | { return -ENODEV; } | 439 | { return -ENODEV; } |
| 445 | 440 | ||
| @@ -60,7 +60,7 @@ enum thermal_genl_event { · 59 unmodified lines | |||
| 60 | THERMAL_GENL_EVENT_UNSPEC, | 60 | THERMAL_GENL_EVENT_UNSPEC, |
| 61 | THERMAL_GENL_EVENT_TZ_CREATE, /* Thermal zone creation */ | 61 | THERMAL_GENL_EVENT_TZ_CREATE, /* Thermal zone creation */ |
| 62 | THERMAL_GENL_EVENT_TZ_DELETE, /* Thermal zone deletion */ | 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 | THERMAL_GENL_EVENT_TZ_ENABLE, /* Thermal zone enabled */ | 64 | THERMAL_GENL_EVENT_TZ_ENABLE, /* Thermal zone enabled */ |
| 65 | THERMAL_GENL_EVENT_TZ_TRIP_UP, /* Trip point crossed the way up */ | 65 | THERMAL_GENL_EVENT_TZ_TRIP_UP, /* Trip point crossed the way up */ |
| 66 | THERMAL_GENL_EVENT_TZ_TRIP_DOWN, /* Trip point crossed the way down */ | 66 | THERMAL_GENL_EVENT_TZ_TRIP_DOWN, /* Trip point crossed the way down */ |