Merge tag 'thermal-v5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/therma...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 5 May 2021 19:46:48 +0000 (12:46 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 5 May 2021 19:46:48 +0000 (12:46 -0700)
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
  ...

38 files changed:
Documentation/devicetree/bindings/thermal/brcm,ns-thermal.txt [deleted file]
Documentation/devicetree/bindings/thermal/brcm,ns-thermal.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.yaml
Documentation/devicetree/bindings/thermal/thermal-sensor.yaml
Documentation/driver-api/thermal/sysfs-api.rst
MAINTAINERS
drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
drivers/net/wireless/intel/iwlwifi/mvm/tt.c
drivers/thermal/amlogic_thermal.c
drivers/thermal/broadcom/bcm2835_thermal.c
drivers/thermal/cpufreq_cooling.c
drivers/thermal/cpuidle_cooling.c
drivers/thermal/devfreq_cooling.c
drivers/thermal/gov_fair_share.c
drivers/thermal/gov_power_allocator.c
drivers/thermal/hisi_thermal.c
drivers/thermal/intel/Kconfig
drivers/thermal/intel/Makefile
drivers/thermal/intel/intel_tcc_cooling.c [new file with mode: 0644]
drivers/thermal/mtk_thermal.c
drivers/thermal/qcom/qcom-spmi-temp-alarm.c
drivers/thermal/qcom/tsens-8960.c
drivers/thermal/qcom/tsens-v0_1.c
drivers/thermal/qcom/tsens-v1.c
drivers/thermal/qcom/tsens.c
drivers/thermal/qcom/tsens.h
drivers/thermal/rcar_gen3_thermal.c
drivers/thermal/sun8i_thermal.c
drivers/thermal/tegra/soctherm.c
drivers/thermal/thermal_core.c
drivers/thermal/thermal_core.h
drivers/thermal/thermal_helpers.c
drivers/thermal/thermal_mmio.c
drivers/thermal/thermal_of.c
drivers/thermal/ti-soc-thermal/ti-bandgap.c
include/linux/thermal.h
include/uapi/linux/thermal.h

diff --git a/Documentation/devicetree/bindings/thermal/brcm,ns-thermal.txt b/Documentation/devicetree/bindings/thermal/brcm,ns-thermal.txt
deleted file mode 100644 (file)
index 68e0471..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-* Broadcom Northstar Thermal
-
-This binding describes thermal sensor that is part of Northstar's DMU (Device
-Management Unit).
-
-Required properties:
-- compatible : Must be "brcm,ns-thermal"
-- reg : iomem address range of PVTMON registers
-- #thermal-sensor-cells : Should be <0>
-
-Example:
-
-thermal: thermal@1800c2c0 {
-       compatible = "brcm,ns-thermal";
-       reg = <0x1800c2c0 0x10>;
-       #thermal-sensor-cells = <0>;
-};
-
-thermal-zones {
-       cpu_thermal: cpu-thermal {
-               polling-delay-passive = <0>;
-               polling-delay = <1000>;
-               coefficients = <(-556) 418000>;
-               thermal-sensors = <&thermal>;
-
-               trips {
-                       cpu-crit {
-                               temperature     = <125000>;
-                               hysteresis      = <0>;
-                               type            = "critical";
-                       };
-               };
-
-               cooling-maps {
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/thermal/brcm,ns-thermal.yaml b/Documentation/devicetree/bindings/thermal/brcm,ns-thermal.yaml
new file mode 100644 (file)
index 0000000..fdeb333
--- /dev/null
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/thermal/brcm,ns-thermal.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Broadcom Northstar Thermal
+
+maintainers:
+  - Rafał Miłecki <rafal@milecki.pl>
+
+description:
+  Thermal sensor that is part of Northstar's DMU (Device Management Unit).
+
+allOf:
+  - $ref: thermal-sensor.yaml#
+
+properties:
+  compatible:
+    const: brcm,ns-thermal
+
+  reg:
+    description: PVTMON registers range
+    maxItems: 1
+
+  "#thermal-sensor-cells":
+    const: 0
+
+unevaluatedProperties: false
+
+required:
+  - reg
+
+examples:
+  - |
+    thermal: thermal@1800c2c0 {
+        compatible = "brcm,ns-thermal";
+        reg = <0x1800c2c0 0x10>;
+        #thermal-sensor-cells = <0>;
+    };
+
+    thermal-zones {
+        cpu-thermal {
+            polling-delay-passive = <0>;
+            polling-delay = <1000>;
+            coefficients = <(-556) 418000>;
+            thermal-sensors = <&thermal>;
+
+            trips {
+                cpu-crit {
+                    temperature = <125000>;
+                    hysteresis = <0>;
+                    type = "critical";
+                };
+            };
+
+            cooling-maps {
+            };
+        };
+    };
index 95462e0..0242fd9 100644 (file)
@@ -19,9 +19,15 @@ description: |
 properties:
   compatible:
     oneOf:
+      - description: msm9860 TSENS based
+        items:
+          - enum:
+              - qcom,ipq8064-tsens
+
       - description: v0.1 of TSENS
         items:
           - enum:
+              - qcom,mdm9607-tsens
               - qcom,msm8916-tsens
               - qcom,msm8939-tsens
               - qcom,msm8974-tsens
@@ -43,6 +49,7 @@ properties:
               - qcom,sdm845-tsens
               - qcom,sm8150-tsens
               - qcom,sm8250-tsens
+              - qcom,sm8350-tsens
           - const: qcom,tsens-v2
 
   reg:
@@ -73,7 +80,9 @@ properties:
     maxItems: 2
     items:
       - const: calib
-      - const: calib_sel
+      - enum:
+          - calib_backup
+          - calib_sel
 
   "#qcom,sensors":
     description:
@@ -88,12 +97,21 @@ properties:
       Number of cells required to uniquely identify the thermal sensors. Since
       we have multiple sensors this is set to 1
 
+required:
+  - compatible
+  - interrupts
+  - interrupt-names
+  - "#thermal-sensor-cells"
+  - "#qcom,sensors"
+
 allOf:
   - if:
       properties:
         compatible:
           contains:
             enum:
+              - qcom,ipq8064-tsens
+              - qcom,mdm9607-tsens
               - qcom,msm8916-tsens
               - qcom,msm8974-tsens
               - qcom,msm8976-tsens
@@ -114,19 +132,44 @@ allOf:
         interrupt-names:
           minItems: 2
 
-required:
-  - compatible
-  - reg
-  - "#qcom,sensors"
-  - interrupts
-  - interrupt-names
-  - "#thermal-sensor-cells"
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,tsens-v0_1
+              - qcom,tsens-v1
+              - qcom,tsens-v2
+
+    then:
+      required:
+        - reg
 
 additionalProperties: false
 
 examples:
   - |
     #include <dt-bindings/interrupt-controller/arm-gic.h>
+    // Example msm9860 based SoC (ipq8064):
+    gcc: clock-controller {
+
+           /* ... */
+
+           tsens: thermal-sensor {
+                compatible = "qcom,ipq8064-tsens";
+
+                 nvmem-cells = <&tsens_calib>, <&tsens_calib_backup>;
+                 nvmem-cell-names = "calib", "calib_backup";
+                 interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
+                 interrupt-names = "uplow";
+
+                 #qcom,sensors = <11>;
+                 #thermal-sensor-cells = <1>;
+          };
+    };
+
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
     // Example 1 (legacy: for pre v1 IP):
     tsens1: thermal-sensor@900000 {
            compatible = "qcom,msm8916-tsens", "qcom,tsens-v0_1";
index b33a76e..f963204 100644 (file)
@@ -28,14 +28,7 @@ properties:
       - renesas,r8a77980-thermal # R-Car V3H
       - renesas,r8a779a0-thermal # R-Car V3U
 
-  reg:
-    minItems: 2
-    maxItems: 4
-    items:
-      - description: TSC1 registers
-      - description: TSC2 registers
-      - description: TSC3 registers
-      - description: TSC4 registers
+  reg: true
 
   interrupts:
     items:
@@ -71,8 +64,25 @@ if:
           enum:
             - renesas,r8a779a0-thermal
 then:
+  properties:
+    reg:
+      minItems: 2
+      maxItems: 3
+      items:
+        - description: TSC1 registers
+        - description: TSC2 registers
+        - description: TSC3 registers
   required:
     - interrupts
+else:
+  properties:
+    reg:
+      items:
+        - description: TSC0 registers
+        - description: TSC1 registers
+        - description: TSC2 registers
+        - description: TSC3 registers
+        - description: TSC4 registers
 
 additionalProperties: false
 
@@ -111,3 +121,20 @@ examples:
                     };
             };
     };
+  - |
+    #include <dt-bindings/clock/r8a779a0-cpg-mssr.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/power/r8a779a0-sysc.h>
+
+    tsc_r8a779a0: thermal@e6190000 {
+            compatible = "renesas,r8a779a0-thermal";
+            reg = <0xe6190000 0x200>,
+                  <0xe6198000 0x200>,
+                  <0xe61a0000 0x200>,
+                  <0xe61a8000 0x200>,
+                  <0xe61b0000 0x200>;
+            clocks = <&cpg CPG_MOD 919>;
+            power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>;
+            resets = <&cpg 919>;
+            #thermal-sensor-cells = <1>;
+    };
index 9f74792..4bd345c 100644 (file)
@@ -36,6 +36,9 @@ properties:
       containing several internal sensors.
     enum: [0, 1]
 
+required:
+  - "#thermal-sensor-cells"
+
 additionalProperties: true
 
 examples:
index 29fdd81..4b638c1 100644 (file)
@@ -730,17 +730,7 @@ This function returns the thermal_instance corresponding to a given
 {thermal_zone, cooling_device, trip_point} combination. Returns NULL
 if such an instance does not exist.
 
-4.3. thermal_notify_framework
------------------------------
-
-This function handles the trip events from sensor drivers. It starts
-throttling the cooling devices according to the policy configured.
-For CRITICAL and HOT trip points, this notifies the respective drivers,
-and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
-The throttling policy is based on the configured platform data; if no
-platform data is provided, this uses the step_wise throttling policy.
-
-4.4. thermal_cdev_update
+4.3. thermal_cdev_update
 ------------------------
 
 This function serves as an arbitrator to set the state of a cooling
index 303340f..203a569 100644 (file)
@@ -15197,6 +15197,7 @@ F:      include/linux/if_rmnet.h
 
 QUALCOMM TSENS THERMAL DRIVER
 M:     Amit Kucheria <amitk@kernel.org>
+M:     Thara Gopinath <thara.gopinath@linaro.org>
 L:     linux-pm@vger.kernel.org
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
@@ -18101,7 +18102,7 @@ THERMAL/CPU_COOLING
 M:     Amit Daniel Kachhap <amit.kachhap@gmail.com>
 M:     Daniel Lezcano <daniel.lezcano@linaro.org>
 M:     Viresh Kumar <viresh.kumar@linaro.org>
-M:     Javi Merino <javi.merino@kernel.org>
+R:     Lukasz Luba <lukasz.luba@arm.com>
 L:     linux-pm@vger.kernel.org
 S:     Supported
 F:     Documentation/driver-api/thermal/cpu-cooling-api.rst
index 37fb2e1..dfea143 100644 (file)
@@ -132,7 +132,7 @@ static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal,
        /* Allow mlxsw thermal zone binding to an external cooling device */
        for (i = 0; i < ARRAY_SIZE(mlxsw_thermal_external_allowed_cdev); i++) {
                if (strnstr(cdev->type, mlxsw_thermal_external_allowed_cdev[i],
-                           sizeof(cdev->type)))
+                           strlen(cdev->type)))
                        return 0;
        }
 
index 2a7339b..398390c 100644 (file)
@@ -146,8 +146,8 @@ void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
        if (mvm->tz_device.tzone) {
                struct iwl_mvm_thermal_device *tz_dev = &mvm->tz_device;
 
-               thermal_notify_framework(tz_dev->tzone,
-                                        tz_dev->fw_trips_index[ths_crossed]);
+               thermal_zone_device_update(tz_dev->tzone,
+                                          THERMAL_TRIP_VIOLATED);
        }
 #endif /* CONFIG_THERMAL */
 }
index dffe3ba..e61b91d 100644 (file)
@@ -254,10 +254,8 @@ static int amlogic_thermal_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, pdata);
 
        base = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(base)) {
-               dev_err(dev, "failed to get io address\n");
+       if (IS_ERR(base))
                return PTR_ERR(base);
-       }
 
        pdata->regmap = devm_regmap_init_mmio(dev, base,
                                              pdata->data->regmap_config);
index 3199977..c8e4344 100644 (file)
@@ -184,7 +184,6 @@ static int bcm2835_thermal_probe(struct platform_device *pdev)
        data->regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(data->regs)) {
                err = PTR_ERR(data->regs);
-               dev_err(&pdev->dev, "Could not get registers: %d\n", err);
                return err;
        }
 
index 10af334..eeb4e4b 100644 (file)
 #include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/cpu_cooling.h>
+#include <linux/device.h>
 #include <linux/energy_model.h>
 #include <linux/err.h>
 #include <linux/export.h>
-#include <linux/idr.h>
 #include <linux/pm_opp.h>
 #include <linux/pm_qos.h>
 #include <linux/slab.h>
@@ -50,8 +50,6 @@ struct time_in_idle {
 
 /**
  * struct cpufreq_cooling_device - data for cooling device with cpufreq
- * @id: unique integer value corresponding to each cpufreq_cooling_device
- *     registered.
  * @last_load: load measured by the latest call to cpufreq_get_requested_power()
  * @cpufreq_state: integer value representing the current state of cpufreq
  *     cooling devices.
@@ -61,7 +59,6 @@ struct time_in_idle {
  * @cdev: thermal_cooling_device pointer to keep track of the
  *     registered cooling device.
  * @policy: cpufreq policy.
- * @node: list_head to link all cpufreq_cooling_device together.
  * @idle_time: idle time stats
  * @qos_req: PM QoS contraint to apply
  *
@@ -69,23 +66,17 @@ struct time_in_idle {
  * cpufreq_cooling_device.
  */
 struct cpufreq_cooling_device {
-       int id;
        u32 last_load;
        unsigned int cpufreq_state;
        unsigned int max_level;
        struct em_perf_domain *em;
        struct cpufreq_policy *policy;
-       struct list_head node;
 #ifndef CONFIG_SMP
        struct time_in_idle *idle_time;
 #endif
        struct freq_qos_request qos_req;
 };
 
-static DEFINE_IDA(cpufreq_ida);
-static DEFINE_MUTEX(cooling_list_lock);
-static LIST_HEAD(cpufreq_cdev_list);
-
 #ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR
 /**
  * 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,
 {
        int i;
 
-       for (i = cpufreq_cdev->max_level; i >= 0; i--) {
+       for (i = cpufreq_cdev->max_level; i > 0; i--) {
                if (power >= cpufreq_cdev->em->table[i].power)
                        break;
        }
@@ -528,11 +519,11 @@ __cpufreq_cooling_register(struct device_node *np,
 {
        struct thermal_cooling_device *cdev;
        struct cpufreq_cooling_device *cpufreq_cdev;
-       char dev_name[THERMAL_NAME_LENGTH];
        unsigned int i;
        struct device *dev;
        int ret;
        struct thermal_cooling_device_ops *cooling_ops;
+       char *name;
 
        dev = get_cpu_device(policy->cpu);
        if (unlikely(!dev)) {
@@ -567,16 +558,6 @@ __cpufreq_cooling_register(struct device_node *np,
        /* max_level is an index, not a counter */
        cpufreq_cdev->max_level = i - 1;
 
-       ret = ida_simple_get(&cpufreq_ida, 0, 0, GFP_KERNEL);
-       if (ret < 0) {
-               cdev = ERR_PTR(ret);
-               goto free_idle_time;
-       }
-       cpufreq_cdev->id = ret;
-
-       snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d",
-                cpufreq_cdev->id);
-
        cooling_ops = &cpufreq_cooling_ops;
 
 #ifdef CONFIG_THERMAL_GOV_POWER_ALLOCATOR
@@ -591,7 +572,7 @@ __cpufreq_cooling_register(struct device_node *np,
                pr_err("%s: unsorted frequency tables are not supported\n",
                       __func__);
                cdev = ERR_PTR(-EINVAL);
-               goto remove_ida;
+               goto free_idle_time;
        }
 
        ret = freq_qos_add_request(&policy->constraints,
@@ -601,24 +582,25 @@ __cpufreq_cooling_register(struct device_node *np,
                pr_err("%s: Failed to add freq constraint (%d)\n", __func__,
                       ret);
                cdev = ERR_PTR(ret);
-               goto remove_ida;
+               goto free_idle_time;
        }
 
-       cdev = thermal_of_cooling_device_register(np, dev_name, cpufreq_cdev,
+       cdev = ERR_PTR(-ENOMEM);
+       name = kasprintf(GFP_KERNEL, "cpufreq-%s", dev_name(dev));
+       if (!name)
+               goto remove_qos_req;
+
+       cdev = thermal_of_cooling_device_register(np, name, cpufreq_cdev,
                                                  cooling_ops);
+       kfree(name);
+
        if (IS_ERR(cdev))
                goto remove_qos_req;
 
-       mutex_lock(&cooling_list_lock);
-       list_add(&cpufreq_cdev->node, &cpufreq_cdev_list);
-       mutex_unlock(&cooling_list_lock);
-
        return cdev;
 
 remove_qos_req:
        freq_qos_remove_request(&cpufreq_cdev->qos_req);
-remove_ida:
-       ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
 free_idle_time:
        free_idle_time(cpufreq_cdev);
 free_cdev:
@@ -706,13 +688,8 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
 
        cpufreq_cdev = cdev->devdata;
 
-       mutex_lock(&cooling_list_lock);
-       list_del(&cpufreq_cdev->node);
-       mutex_unlock(&cooling_list_lock);
-
        thermal_cooling_device_unregister(cdev);
        freq_qos_remove_request(&cpufreq_cdev->qos_req);
-       ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
        free_idle_time(cpufreq_cdev);
        kfree(cpufreq_cdev);
 }
index 7ecab4b..4f41102 100644 (file)
@@ -9,9 +9,9 @@
 
 #include <linux/cpu_cooling.h>
 #include <linux/cpuidle.h>
+#include <linux/device.h>
 #include <linux/err.h>
 #include <linux/idle_inject.h>
-#include <linux/idr.h>
 #include <linux/of_device.h>
 #include <linux/slab.h>
 #include <linux/thermal.h>
@@ -26,8 +26,6 @@ struct cpuidle_cooling_device {
        unsigned long state;
 };
 
-static DEFINE_IDA(cpuidle_ida);
-
 /**
  * cpuidle_cooling_runtime - Running time computation
  * @idle_duration_us: CPU idle time to inject in microseconds
@@ -174,10 +172,11 @@ static int __cpuidle_cooling_register(struct device_node *np,
        struct idle_inject_device *ii_dev;
        struct cpuidle_cooling_device *idle_cdev;
        struct thermal_cooling_device *cdev;
+       struct device *dev;
        unsigned int idle_duration_us = TICK_USEC;
        unsigned int latency_us = UINT_MAX;
-       char dev_name[THERMAL_NAME_LENGTH];
-       int id, ret;
+       char *name;
+       int ret;
 
        idle_cdev = kzalloc(sizeof(*idle_cdev), GFP_KERNEL);
        if (!idle_cdev) {
@@ -185,16 +184,10 @@ static int __cpuidle_cooling_register(struct device_node *np,
                goto out;
        }
 
-       id = ida_simple_get(&cpuidle_ida, 0, 0, GFP_KERNEL);
-       if (id < 0) {
-               ret = id;
-               goto out_kfree;
-       }
-
        ii_dev = idle_inject_register(drv->cpumask);
        if (!ii_dev) {
                ret = -EINVAL;
-               goto out_id;
+               goto out_kfree;
        }
 
        of_property_read_u32(np, "duration-us", &idle_duration_us);
@@ -205,24 +198,32 @@ static int __cpuidle_cooling_register(struct device_node *np,
 
        idle_cdev->ii_dev = ii_dev;
 
-       snprintf(dev_name, sizeof(dev_name), "thermal-idle-%d", id);
+       dev = get_cpu_device(cpumask_first(drv->cpumask));
 
-       cdev = thermal_of_cooling_device_register(np, dev_name, idle_cdev,
+       name = kasprintf(GFP_KERNEL, "idle-%s", dev_name(dev));
+       if (!name) {
+               ret = -ENOMEM;
+               goto out_unregister;
+       }
+
+       cdev = thermal_of_cooling_device_register(np, name, idle_cdev,
                                                  &cpuidle_cooling_ops);
        if (IS_ERR(cdev)) {
                ret = PTR_ERR(cdev);
-               goto out_unregister;
+               goto out_kfree_name;
        }
 
        pr_debug("%s: Idle injection set with idle duration=%u, latency=%u\n",
-                dev_name, idle_duration_us, latency_us);
+                name, idle_duration_us, latency_us);
+
+       kfree(name);
 
        return 0;
 
+out_kfree_name:
+       kfree(name);
 out_unregister:
        idle_inject_unregister(ii_dev);
-out_id:
-       ida_simple_remove(&cpuidle_ida, id);
 out_kfree:
        kfree(idle_cdev);
 out:
index fed3121..3a788ac 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/devfreq_cooling.h>
 #include <linux/energy_model.h>
 #include <linux/export.h>
-#include <linux/idr.h>
 #include <linux/slab.h>
 #include <linux/pm_opp.h>
 #include <linux/pm_qos.h>
 #define HZ_PER_KHZ             1000
 #define SCALE_ERROR_MITIGATION 100
 
-static DEFINE_IDA(devfreq_ida);
-
 /**
  * struct devfreq_cooling_device - Devfreq cooling device
- * @id:                unique integer value corresponding to each
  *             devfreq_cooling_device registered.
  * @cdev:      Pointer to associated thermal cooling device.
  * @devfreq:   Pointer to associated devfreq device.
@@ -51,7 +47,6 @@ static DEFINE_IDA(devfreq_ida);
  * @em_pd:             Energy Model for the associated Devfreq device
  */
 struct devfreq_cooling_device {
-       int id;
        struct thermal_cooling_device *cdev;
        struct devfreq *devfreq;
        unsigned long cooling_state;
@@ -363,7 +358,7 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
        struct thermal_cooling_device *cdev;
        struct device *dev = df->dev.parent;
        struct devfreq_cooling_device *dfc;
-       char dev_name[THERMAL_NAME_LENGTH];
+       char *name;
        int err, num_opps;
 
        dfc = kzalloc(sizeof(*dfc), GFP_KERNEL);
@@ -407,30 +402,27 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
        if (err < 0)
                goto free_table;
 
-       err = ida_simple_get(&devfreq_ida, 0, 0, GFP_KERNEL);
-       if (err < 0)
+       err = -ENOMEM;
+       name = kasprintf(GFP_KERNEL, "devfreq-%s", dev_name(dev));
+       if (!name)
                goto remove_qos_req;
 
-       dfc->id = err;
-
-       snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id);
-
-       cdev = thermal_of_cooling_device_register(np, dev_name, dfc,
+       cdev = thermal_of_cooling_device_register(np, name, dfc,
                                                  &devfreq_cooling_ops);
+       kfree(name);
+
        if (IS_ERR(cdev)) {
                err = PTR_ERR(cdev);
                dev_err(dev,
                        "Failed to register devfreq cooling device (%d)\n",
                        err);
-               goto release_ida;
+               goto remove_qos_req;
        }
 
        dfc->cdev = cdev;
 
        return cdev;
 
-release_ida:
-       ida_simple_remove(&devfreq_ida, dfc->id);
 remove_qos_req:
        dev_pm_qos_remove_request(&dfc->req_max_freq);
 free_table:
@@ -527,7 +519,6 @@ void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
        dev = dfc->devfreq->dev.parent;
 
        thermal_cooling_device_unregister(dfc->cdev);
-       ida_simple_remove(&devfreq_ida, dfc->id);
        dev_pm_qos_remove_request(&dfc->req_max_freq);
 
        em_dev_unregister_perf_domain(dev);
index aaa0718..1e5abf4 100644 (file)
@@ -82,6 +82,8 @@ static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
        int total_instance = 0;
        int cur_trip_level = get_trip_level(tz);
 
+       mutex_lock(&tz->lock);
+
        list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
                if (instance->trip != trip)
                        continue;
@@ -105,11 +107,12 @@ static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
                instance->target = get_target_state(tz, cdev, percentage,
                                                    cur_trip_level);
 
-               mutex_lock(&instance->cdev->lock);
-               instance->cdev->updated = false;
-               mutex_unlock(&instance->cdev->lock);
-               thermal_cdev_update(cdev);
+               mutex_lock(&cdev->lock);
+               __thermal_cdev_update(cdev);
+               mutex_unlock(&cdev->lock);
        }
+
+       mutex_unlock(&tz->lock);
        return 0;
 }
 
index 92acae5..13e3757 100644 (file)
@@ -301,9 +301,8 @@ power_actor_set_power(struct thermal_cooling_device *cdev,
 
        instance->target = clamp_val(state, instance->lower, instance->upper);
        mutex_lock(&cdev->lock);
-       cdev->updated = false;
+       __thermal_cdev_update(cdev);
        mutex_unlock(&cdev->lock);
-       thermal_cdev_update(cdev);
 
        return 0;
 }
@@ -374,9 +373,11 @@ static void divvy_up_power(u32 *req_power, u32 *max_power, int num_actors,
         */
        extra_power = min(extra_power, capped_extra_power);
        if (capped_extra_power > 0)
-               for (i = 0; i < num_actors; i++)
-                       granted_power[i] += (extra_actor_power[i] *
-                                       extra_power) / capped_extra_power;
+               for (i = 0; i < num_actors; i++) {
+                       u64 extra_range = (u64)extra_actor_power[i] * extra_power;
+                       granted_power[i] += DIV_ROUND_CLOSEST_ULL(extra_range,
+                                                        capped_extra_power);
+               }
 }
 
 static int allocate_power(struct thermal_zone_device *tz,
@@ -569,22 +570,33 @@ static void reset_pid_controller(struct power_allocator_params *params)
        params->prev_err = 0;
 }
 
-static void allow_maximum_power(struct thermal_zone_device *tz)
+static void allow_maximum_power(struct thermal_zone_device *tz, bool update)
 {
        struct thermal_instance *instance;
        struct power_allocator_params *params = tz->governor_data;
+       u32 req_power;
 
        mutex_lock(&tz->lock);
        list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
+               struct thermal_cooling_device *cdev = instance->cdev;
+
                if ((instance->trip != params->trip_max_desired_temperature) ||
                    (!cdev_is_power_actor(instance->cdev)))
                        continue;
 
                instance->target = 0;
                mutex_lock(&instance->cdev->lock);
-               instance->cdev->updated = false;
+               /*
+                * Call for updating the cooling devices local stats and avoid
+                * periods of dozen of seconds when those have not been
+                * maintained.
+                */
+               cdev->ops->get_requested_power(cdev, &req_power);
+
+               if (update)
+                       __thermal_cdev_update(instance->cdev);
+
                mutex_unlock(&instance->cdev->lock);
-               thermal_cdev_update(instance->cdev);
        }
        mutex_unlock(&tz->lock);
 }
@@ -698,6 +710,7 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
        int ret;
        int switch_on_temp, control_temp;
        struct power_allocator_params *params = tz->governor_data;
+       bool update;
 
        /*
         * 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)
        ret = tz->ops->get_trip_temp(tz, params->trip_switch_on,
                                     &switch_on_temp);
        if (!ret && (tz->temperature < switch_on_temp)) {
+               update = (tz->last_temperature >= switch_on_temp);
                tz->passive = 0;
                reset_pid_controller(params);
-               allow_maximum_power(tz);
+               allow_maximum_power(tz, update);
                return 0;
        }
 
index ee05950..9a21ac0 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Hisilicon thermal sensor driver
+ * HiSilicon thermal sensor driver
  *
- * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Copyright (c) 2014-2015 HiSilicon Limited.
  * Copyright (c) 2014-2015 Linaro Limited.
  *
  * Xinwei Kong <kong.kongxinwei@hisilicon.com>
@@ -572,10 +572,8 @@ static int hisi_thermal_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        data->regs = devm_ioremap_resource(dev, res);
-       if (IS_ERR(data->regs)) {
-               dev_err(dev, "failed to get io address\n");
+       if (IS_ERR(data->regs))
                return PTR_ERR(data->regs);
-       }
 
        ret = data->ops->probe(data);
        if (ret)
@@ -672,5 +670,5 @@ module_platform_driver(hisi_thermal_driver);
 
 MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
 MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
-MODULE_DESCRIPTION("Hisilicon thermal driver");
+MODULE_DESCRIPTION("HiSilicon thermal driver");
 MODULE_LICENSE("GPL v2");
index ce4f592..e4299ca 100644 (file)
@@ -79,3 +79,14 @@ config INTEL_PCH_THERMAL
          Enable this to support thermal reporting on certain intel PCHs.
          Thermal reporting device will provide temperature reading,
          programmable trip points and other information.
+
+config INTEL_TCC_COOLING
+       tristate "Intel TCC offset cooling Driver"
+       depends on X86
+       help
+         Enable this to support system cooling by adjusting the effective TCC
+         activation temperature via the TCC Offset register, which is widely
+         supported on modern Intel platforms.
+         Note that, on different platforms, the behavior might be different
+         on how fast the setting takes effect, and how much the CPU frequency
+         is reduced.
index ff2ad30..5ff2afa 100644 (file)
@@ -10,4 +10,5 @@ obj-$(CONFIG_INTEL_QUARK_DTS_THERMAL) += intel_quark_dts_thermal.o
 obj-$(CONFIG_INT340X_THERMAL)  += int340x_thermal/
 obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o
 obj-$(CONFIG_INTEL_PCH_THERMAL)        += intel_pch_thermal.o
+obj-$(CONFIG_INTEL_TCC_COOLING)        += intel_tcc_cooling.o
 obj-$(CONFIG_X86_THERMAL_VECTOR) += therm_throt.o
diff --git a/drivers/thermal/intel/intel_tcc_cooling.c b/drivers/thermal/intel/intel_tcc_cooling.c
new file mode 100644 (file)
index 0000000..8ec10d5
--- /dev/null
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * cooling device driver that activates the processor throttling by
+ * programming the TCC Offset register.
+ * Copyright (c) 2021, Intel Corporation.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/thermal.h>
+#include <asm/cpu_device_id.h>
+
+#define TCC_SHIFT 24
+#define TCC_MASK       (0x3fULL<<24)
+#define TCC_PROGRAMMABLE       BIT(30)
+
+static struct thermal_cooling_device *tcc_cdev;
+
+static int tcc_get_max_state(struct thermal_cooling_device *cdev, unsigned long
+                            *state)
+{
+       *state = TCC_MASK >> TCC_SHIFT;
+       return 0;
+}
+
+static int tcc_offset_update(int tcc)
+{
+       u64 val;
+       int err;
+
+       err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
+       if (err)
+               return err;
+
+       val &= ~TCC_MASK;
+       val |= tcc << TCC_SHIFT;
+
+       err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int tcc_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
+                            *state)
+{
+       u64 val;
+       int err;
+
+       err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
+       if (err)
+               return err;
+
+       *state = (val & TCC_MASK) >> TCC_SHIFT;
+       return 0;
+}
+
+static int tcc_set_cur_state(struct thermal_cooling_device *cdev, unsigned long
+                            state)
+{
+       return tcc_offset_update(state);
+}
+
+static const struct thermal_cooling_device_ops tcc_cooling_ops = {
+       .get_max_state = tcc_get_max_state,
+       .get_cur_state = tcc_get_cur_state,
+       .set_cur_state = tcc_set_cur_state,
+};
+
+static const struct x86_cpu_id tcc_ids[] __initconst = {
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL),
+       {}
+};
+
+MODULE_DEVICE_TABLE(x86cpu, tcc_ids);
+
+static int __init tcc_cooling_init(void)
+{
+       int ret;
+       u64 val;
+       const struct x86_cpu_id *id;
+
+       int err;
+
+       id = x86_match_cpu(tcc_ids);
+       if (!id)
+               return -ENODEV;
+
+       err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
+       if (err)
+               return err;
+
+       if (!(val & TCC_PROGRAMMABLE))
+               return -ENODEV;
+
+       pr_info("Programmable TCC Offset detected\n");
+
+       tcc_cdev =
+           thermal_cooling_device_register("TCC Offset", NULL,
+                                           &tcc_cooling_ops);
+       if (IS_ERR(tcc_cdev)) {
+               ret = PTR_ERR(tcc_cdev);
+               return ret;
+       }
+       return 0;
+}
+
+module_init(tcc_cooling_init)
+
+static void __exit tcc_cooling_exit(void)
+{
+       thermal_cooling_device_unregister(tcc_cdev);
+}
+
+module_exit(tcc_cooling_exit)
+
+MODULE_DESCRIPTION("TCC offset cooling device Driver");
+MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
+MODULE_LICENSE("GPL v2");
index 149c6d7..97e8678 100644 (file)
@@ -573,12 +573,12 @@ static int raw_to_mcelsius_v1(struct mtk_thermal *mt, int sensno, s32 raw)
 
 static int raw_to_mcelsius_v2(struct mtk_thermal *mt, int sensno, s32 raw)
 {
-       s32 format_1 = 0;
-       s32 format_2 = 0;
-       s32 g_oe = 1;
-       s32 g_gain = 1;
-       s32 g_x_roomt = 0;
-       s32 tmp = 0;
+       s32 format_1;
+       s32 format_2;
+       s32 g_oe;
+       s32 g_gain;
+       s32 g_x_roomt;
+       s32 tmp;
 
        if (raw == 0)
                return 0;
index 6dc879f..7419e19 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "../thermal_core.h"
 
+#define QPNP_TM_REG_DIG_MAJOR          0x01
 #define QPNP_TM_REG_TYPE               0x04
 #define QPNP_TM_REG_SUBTYPE            0x05
 #define QPNP_TM_REG_STATUS             0x08
 
 #define ALARM_CTRL_FORCE_ENABLE                BIT(7)
 
-/*
- * Trip point values based on threshold control
- * 0 = {105 C, 125 C, 145 C}
- * 1 = {110 C, 130 C, 150 C}
- * 2 = {115 C, 135 C, 155 C}
- * 3 = {120 C, 140 C, 160 C}
-*/
-#define TEMP_STAGE_STEP                        20000   /* Stage step: 20.000 C */
-#define TEMP_STAGE_HYSTERESIS          2000
+#define THRESH_COUNT                   4
+#define STAGE_COUNT                    3
+
+/* Over-temperature trip point values in mC */
+static const long temp_map_gen1[THRESH_COUNT][STAGE_COUNT] = {
+       { 105000, 125000, 145000 },
+       { 110000, 130000, 150000 },
+       { 115000, 135000, 155000 },
+       { 120000, 140000, 160000 },
+};
+
+static const long temp_map_gen2_v1[THRESH_COUNT][STAGE_COUNT] = {
+       {  90000, 110000, 140000 },
+       {  95000, 115000, 145000 },
+       { 100000, 120000, 150000 },
+       { 105000, 125000, 155000 },
+};
 
-#define TEMP_THRESH_MIN                        105000  /* Threshold Min: 105 C */
-#define TEMP_THRESH_STEP               5000    /* Threshold step: 5 C */
+#define TEMP_THRESH_STEP               5000 /* Threshold step: 5 C */
 
 #define THRESH_MIN                     0
 #define THRESH_MAX                     3
 
-/* Stage 2 Threshold Min: 125 C */
-#define STAGE2_THRESHOLD_MIN           125000
-/* Stage 2 Threshold Max: 140 C */
-#define STAGE2_THRESHOLD_MAX           140000
+#define TEMP_STAGE_HYSTERESIS          2000
 
 /* Temperature in Milli Celsius reported during stage 0 if no ADC is present */
 #define DEFAULT_TEMP                   37000
@@ -77,6 +82,7 @@ struct qpnp_tm_chip {
        bool                            initialized;
 
        struct iio_channel              *adc;
+       const long                      (*temp_map)[THRESH_COUNT][STAGE_COUNT];
 };
 
 /* This array maps from GEN2 alarm state to GEN1 alarm stage */
@@ -101,6 +107,23 @@ static int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 data)
 }
 
 /**
+ * qpnp_tm_decode_temp() - return temperature in mC corresponding to the
+ *             specified over-temperature stage
+ * @chip:              Pointer to the qpnp_tm chip
+ * @stage:             Over-temperature stage
+ *
+ * Return: temperature in mC
+ */
+static long qpnp_tm_decode_temp(struct qpnp_tm_chip *chip, unsigned int stage)
+{
+       if (!chip->temp_map || chip->thresh >= THRESH_COUNT || stage == 0 ||
+           stage > STAGE_COUNT)
+               return 0;
+
+       return (*chip->temp_map)[chip->thresh][stage - 1];
+}
+
+/**
  * qpnp_tm_get_temp_stage() - return over-temperature stage
  * @chip:              Pointer to the qpnp_tm chip
  *
@@ -149,14 +172,12 @@ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)
 
        if (stage_new > stage_old) {
                /* increasing stage, use lower bound */
-               chip->temp = (stage_new - 1) * TEMP_STAGE_STEP +
-                            chip->thresh * TEMP_THRESH_STEP +
-                            TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
+               chip->temp = qpnp_tm_decode_temp(chip, stage_new)
+                               + TEMP_STAGE_HYSTERESIS;
        } else if (stage_new < stage_old) {
                /* decreasing stage, use upper bound */
-               chip->temp = stage_new * TEMP_STAGE_STEP +
-                            chip->thresh * TEMP_THRESH_STEP -
-                            TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
+               chip->temp = qpnp_tm_decode_temp(chip, stage_new + 1)
+                               - TEMP_STAGE_HYSTERESIS;
        }
 
        chip->stage = stage;
@@ -199,26 +220,28 @@ static int qpnp_tm_get_temp(void *data, int *temp)
 static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip,
                                             int temp)
 {
-       u8 reg;
+       long stage2_threshold_min = (*chip->temp_map)[THRESH_MIN][1];
+       long stage2_threshold_max = (*chip->temp_map)[THRESH_MAX][1];
        bool disable_s2_shutdown = false;
+       u8 reg;
 
        WARN_ON(!mutex_is_locked(&chip->lock));
 
        /*
         * Default: S2 and S3 shutdown enabled, thresholds at
-        * 105C/125C/145C, monitoring at 25Hz
+        * lowest threshold set, monitoring at 25Hz
         */
        reg = SHUTDOWN_CTRL1_RATE_25HZ;
 
        if (temp == THERMAL_TEMP_INVALID ||
-           temp < STAGE2_THRESHOLD_MIN) {
+           temp < stage2_threshold_min) {
                chip->thresh = THRESH_MIN;
                goto skip;
        }
 
-       if (temp <= STAGE2_THRESHOLD_MAX) {
+       if (temp <= stage2_threshold_max) {
                chip->thresh = THRESH_MAX -
-                       ((STAGE2_THRESHOLD_MAX - temp) /
+                       ((stage2_threshold_max - temp) /
                         TEMP_THRESH_STEP);
                disable_s2_shutdown = true;
        } else {
@@ -326,9 +349,7 @@ static int qpnp_tm_init(struct qpnp_tm_chip *chip)
                ? chip->stage : alarm_state_map[chip->stage];
 
        if (stage)
-               chip->temp = chip->thresh * TEMP_THRESH_STEP +
-                            (stage - 1) * TEMP_STAGE_STEP +
-                            TEMP_THRESH_MIN;
+               chip->temp = qpnp_tm_decode_temp(chip, stage);
 
        crit_temp = qpnp_tm_get_critical_trip_temp(chip);
        ret = qpnp_tm_update_critical_trip_temp(chip, crit_temp);
@@ -350,7 +371,7 @@ static int qpnp_tm_probe(struct platform_device *pdev)
 {
        struct qpnp_tm_chip *chip;
        struct device_node *node;
-       u8 type, subtype;
+       u8 type, subtype, dig_major;
        u32 res;
        int ret, irq;
 
@@ -400,6 +421,12 @@ static int qpnp_tm_probe(struct platform_device *pdev)
                return ret;
        }
 
+       ret = qpnp_tm_read(chip, QPNP_TM_REG_DIG_MAJOR, &dig_major);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "could not read dig_major\n");
+               return ret;
+       }
+
        if (type != QPNP_TM_TYPE || (subtype != QPNP_TM_SUBTYPE_GEN1
                                     && subtype != QPNP_TM_SUBTYPE_GEN2)) {
                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)
        }
 
        chip->subtype = subtype;
+       if (subtype == QPNP_TM_SUBTYPE_GEN2 && dig_major >= 1)
+               chip->temp_map = &temp_map_gen2_v1;
+       else
+               chip->temp_map = &temp_map_gen1;
 
        /*
         * Register the sensor before initializing the hardware to be able to
index 2a28a5a..67c1748 100644 (file)
@@ -10,8 +10,6 @@
 #include <linux/thermal.h>
 #include "tsens.h"
 
-#define CAL_MDEGC              30000
-
 #define CONFIG_ADDR            0x3640
 #define CONFIG_ADDR_8660       0x3620
 /* CONFIG_ADDR bitmasks */
 #define CONFIG_SHIFT_8660      28
 #define CONFIG_MASK_8660       (3 << CONFIG_SHIFT_8660)
 
-#define STATUS_CNTL_ADDR_8064  0x3660
 #define CNTL_ADDR              0x3620
 /* CNTL_ADDR bitmasks */
 #define EN                     BIT(0)
 #define SW_RST                 BIT(1)
-#define SENSOR0_EN             BIT(3)
+
+#define MEASURE_PERIOD         BIT(18)
 #define SLP_CLK_ENA            BIT(26)
 #define SLP_CLK_ENA_8660       BIT(24)
-#define MEASURE_PERIOD         1
 #define SENSOR0_SHIFT          3
 
-/* INT_STATUS_ADDR bitmasks */
-#define MIN_STATUS_MASK                BIT(0)
-#define LOWER_STATUS_CLR       BIT(1)
-#define UPPER_STATUS_CLR       BIT(2)
-#define MAX_STATUS_MASK                BIT(3)
-
 #define THRESHOLD_ADDR         0x3624
-/* THRESHOLD_ADDR bitmasks */
-#define THRESHOLD_MAX_LIMIT_SHIFT      24
-#define THRESHOLD_MIN_LIMIT_SHIFT      16
-#define THRESHOLD_UPPER_LIMIT_SHIFT    8
-#define THRESHOLD_LOWER_LIMIT_SHIFT    0
-
-/* Initial temperature threshold values */
-#define LOWER_LIMIT_TH         0x50
-#define UPPER_LIMIT_TH         0xdf
-#define MIN_LIMIT_TH           0x0
-#define MAX_LIMIT_TH           0xff
-
-#define S0_STATUS_ADDR         0x3628
+
 #define INT_STATUS_ADDR                0x363c
-#define TRDY_MASK              BIT(7)
-#define TIMEOUT_US             100
+
+#define S0_STATUS_OFF          0x3628
+#define S1_STATUS_OFF          0x362c
+#define S2_STATUS_OFF          0x3630
+#define S3_STATUS_OFF          0x3634
+#define S4_STATUS_OFF          0x3638
+#define S5_STATUS_OFF          0x3664  /* Sensors 5-10 found on apq8064/msm8960 */
+#define S6_STATUS_OFF          0x3668
+#define S7_STATUS_OFF          0x366c
+#define S8_STATUS_OFF          0x3670
+#define S9_STATUS_OFF          0x3674
+#define S10_STATUS_OFF         0x3678
+
+/* Original slope - 350 to compensate mC to C inaccuracy */
+static u32 tsens_msm8960_slope[] = {
+                       826, 826, 804, 826,
+                       761, 782, 782, 849,
+                       782, 849, 782
+                       };
 
 static int suspend_8960(struct tsens_priv *priv)
 {
@@ -115,17 +111,34 @@ static int resume_8960(struct tsens_priv *priv)
 static int enable_8960(struct tsens_priv *priv, int id)
 {
        int ret;
-       u32 reg, mask;
+       u32 reg, mask = BIT(id);
 
        ret = regmap_read(priv->tm_map, CNTL_ADDR, &reg);
        if (ret)
                return ret;
 
-       mask = BIT(id + SENSOR0_SHIFT);
+       /* HARDWARE BUG:
+        * On platforms with more than 6 sensors, all remaining sensors
+        * must be enabled together, otherwise undefined results are expected.
+        * (Sensor 6-7 disabled, Sensor 3 disabled...) In the original driver,
+        * all the sensors are enabled in one step hence this bug is not
+        * triggered.
+        */
+       if (id > 5)
+               mask = GENMASK(10, 6);
+
+       mask <<= SENSOR0_SHIFT;
+
+       /* Sensors already enabled. Skip. */
+       if ((reg & mask) == mask)
+               return 0;
+
        ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST);
        if (ret)
                return ret;
 
+       reg |= MEASURE_PERIOD;
+
        if (priv->num_sensors > 1)
                reg |= mask | SLP_CLK_ENA | EN;
        else
@@ -162,63 +175,11 @@ static void disable_8960(struct tsens_priv *priv)
        regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
 }
 
-static int init_8960(struct tsens_priv *priv)
-{
-       int ret, i;
-       u32 reg_cntl;
-
-       priv->tm_map = dev_get_regmap(priv->dev, NULL);
-       if (!priv->tm_map)
-               return -ENODEV;
-
-       /*
-        * The status registers for each sensor are discontiguous
-        * because some SoCs have 5 sensors while others have more
-        * but the control registers stay in the same place, i.e
-        * directly after the first 5 status registers.
-        */
-       for (i = 0; i < priv->num_sensors; i++) {
-               if (i >= 5)
-                       priv->sensor[i].status = S0_STATUS_ADDR + 40;
-               priv->sensor[i].status += i * 4;
-       }
-
-       reg_cntl = SW_RST;
-       ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
-       if (ret)
-               return ret;
-
-       if (priv->num_sensors > 1) {
-               reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
-               reg_cntl &= ~SW_RST;
-               ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR,
-                                        CONFIG_MASK, CONFIG);
-       } else {
-               reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
-               reg_cntl &= ~CONFIG_MASK_8660;
-               reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
-       }
-
-       reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
-       ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
-       if (ret)
-               return ret;
-
-       reg_cntl |= EN;
-       ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
 static int calibrate_8960(struct tsens_priv *priv)
 {
        int i;
        char *data;
-
-       ssize_t num_read = priv->num_sensors;
-       struct tsens_sensor *s = priv->sensor;
+       u32 p1[11];
 
        data = qfprom_read(priv->dev, "calib");
        if (IS_ERR(data))
@@ -226,60 +187,96 @@ static int calibrate_8960(struct tsens_priv *priv)
        if (IS_ERR(data))
                return PTR_ERR(data);
 
-       for (i = 0; i < num_read; i++, s++)
-               s->offset = data[i];
+       for (i = 0; i < priv->num_sensors; i++) {
+               p1[i] = data[i];
+               priv->sensor[i].slope = tsens_msm8960_slope[i];
+       }
+
+       compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB);
 
        kfree(data);
 
        return 0;
 }
 
-/* Temperature on y axis and ADC-code on x-axis */
-static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
-{
-       int slope, offset;
-
-       slope = thermal_zone_get_slope(s->tzd);
-       offset = CAL_MDEGC - slope * s->offset;
-
-       return adc_code * slope + offset;
-}
-
-static int get_temp_8960(const struct tsens_sensor *s, int *temp)
-{
-       int ret;
-       u32 code, trdy;
-       struct tsens_priv *priv = s->priv;
-       unsigned long timeout;
-
-       timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
-       do {
-               ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy);
-               if (ret)
-                       return ret;
-               if (!(trdy & TRDY_MASK))
-                       continue;
-               ret = regmap_read(priv->tm_map, s->status, &code);
-               if (ret)
-                       return ret;
-               *temp = code_to_mdegC(code, s);
-               return 0;
-       } while (time_before(jiffies, timeout));
-
-       return -ETIMEDOUT;
-}
+static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = {
+       /* ----- SROT ------ */
+       /* No VERSION information */
+
+       /* CNTL */
+       [TSENS_EN]     = REG_FIELD(CNTL_ADDR,  0, 0),
+       [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR,  1, 1),
+       /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */
+       [SENSOR_EN]    = REG_FIELD(CNTL_ADDR,  3, 7),
+
+       /* ----- TM ------ */
+       /* INTERRUPT ENABLE */
+       /* NO INTERRUPT ENABLE */
+
+       /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */
+       [LOW_THRESH_0]   = REG_FIELD(THRESHOLD_ADDR,  0,  7),
+       [UP_THRESH_0]    = REG_FIELD(THRESHOLD_ADDR,  8, 15),
+       /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield
+        * Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded temp
+        * MIN_THRESH_0 -> CRIT_THRESH_1
+        * MAX_THRESH_0 -> CRIT_THRESH_0
+        */
+       [CRIT_THRESH_1]   = REG_FIELD(THRESHOLD_ADDR, 16, 23),
+       [CRIT_THRESH_0]   = REG_FIELD(THRESHOLD_ADDR, 24, 31),
+
+       /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */
+       /* 1 == clear, 0 == normal operation */
+       [LOW_INT_CLEAR_0]   = REG_FIELD(CNTL_ADDR,  9,  9),
+       [UP_INT_CLEAR_0]    = REG_FIELD(CNTL_ADDR, 10, 10),
+
+       /* NO CRITICAL INTERRUPT SUPPORT on 8960 */
+
+       /* Sn_STATUS */
+       [LAST_TEMP_0]  = REG_FIELD(S0_STATUS_OFF,  0,  7),
+       [LAST_TEMP_1]  = REG_FIELD(S1_STATUS_OFF,  0,  7),
+       [LAST_TEMP_2]  = REG_FIELD(S2_STATUS_OFF,  0,  7),
+       [LAST_TEMP_3]  = REG_FIELD(S3_STATUS_OFF,  0,  7),
+       [LAST_TEMP_4]  = REG_FIELD(S4_STATUS_OFF,  0,  7),
+       [LAST_TEMP_5]  = REG_FIELD(S5_STATUS_OFF,  0,  7),
+       [LAST_TEMP_6]  = REG_FIELD(S6_STATUS_OFF,  0,  7),
+       [LAST_TEMP_7]  = REG_FIELD(S7_STATUS_OFF,  0,  7),
+       [LAST_TEMP_8]  = REG_FIELD(S8_STATUS_OFF,  0,  7),
+       [LAST_TEMP_9]  = REG_FIELD(S9_STATUS_OFF,  0,  7),
+       [LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0,  7),
+
+       /* No VALID field on 8960 */
+       /* TSENS_INT_STATUS bits: 1 == threshold violated */
+       [MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0),
+       [LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1),
+       [UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2),
+       /* No CRITICAL field on 8960 */
+       [MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3),
+
+       /* TRDY: 1=ready, 0=in progress */
+       [TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7),
+};
 
 static const struct tsens_ops ops_8960 = {
-       .init           = init_8960,
+       .init           = init_common,
        .calibrate      = calibrate_8960,
-       .get_temp       = get_temp_8960,
+       .get_temp       = get_temp_common,
        .enable         = enable_8960,
        .disable        = disable_8960,
        .suspend        = suspend_8960,
        .resume         = resume_8960,
 };
 
+static struct tsens_features tsens_8960_feat = {
+       .ver_major      = VER_0,
+       .crit_int       = 0,
+       .adc            = 1,
+       .srot_split     = 0,
+       .max_sensors    = 11,
+};
+
 struct tsens_plat_data data_8960 = {
        .num_sensors    = 11,
        .ops            = &ops_8960,
+       .feat           = &tsens_8960_feat,
+       .fields         = tsens_8960_regfields,
 };
index 4ffa2e2..f136cb3 100644 (file)
 
 #define BIT_APPEND             0x3
 
+/* eeprom layout data for mdm9607 */
+#define MDM9607_BASE0_MASK     0x000000ff
+#define MDM9607_BASE1_MASK     0x000ff000
+#define MDM9607_BASE0_SHIFT    0
+#define MDM9607_BASE1_SHIFT    12
+
+#define MDM9607_S0_P1_MASK     0x00003f00
+#define MDM9607_S1_P1_MASK     0x03f00000
+#define MDM9607_S2_P1_MASK     0x0000003f
+#define MDM9607_S3_P1_MASK     0x0003f000
+#define MDM9607_S4_P1_MASK     0x0000003f
+
+#define MDM9607_S0_P2_MASK     0x000fc000
+#define MDM9607_S1_P2_MASK     0xfc000000
+#define MDM9607_S2_P2_MASK     0x00000fc0
+#define MDM9607_S3_P2_MASK     0x00fc0000
+#define MDM9607_S4_P2_MASK     0x00000fc0
+
+#define MDM9607_S0_P1_SHIFT    8
+#define MDM9607_S1_P1_SHIFT    20
+#define MDM9607_S2_P1_SHIFT    0
+#define MDM9607_S3_P1_SHIFT    12
+#define MDM9607_S4_P1_SHIFT    0
+
+#define MDM9607_S0_P2_SHIFT    14
+#define MDM9607_S1_P2_SHIFT    26
+#define MDM9607_S2_P2_SHIFT    6
+#define MDM9607_S3_P2_SHIFT    18
+#define MDM9607_S4_P2_SHIFT    6
+
+#define MDM9607_CAL_SEL_MASK   0x00700000
+#define MDM9607_CAL_SEL_SHIFT  20
+
 static int calibrate_8916(struct tsens_priv *priv)
 {
        int base0 = 0, base1 = 0, i;
@@ -452,7 +485,56 @@ static int calibrate_8974(struct tsens_priv *priv)
        return 0;
 }
 
-/* v0.1: 8916, 8939, 8974 */
+static int calibrate_9607(struct tsens_priv *priv)
+{
+       int base, i;
+       u32 p1[5], p2[5];
+       int mode = 0;
+       u32 *qfprom_cdata;
+
+       qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib");
+       if (IS_ERR(qfprom_cdata))
+               return PTR_ERR(qfprom_cdata);
+
+       mode = (qfprom_cdata[2] & MDM9607_CAL_SEL_MASK) >> MDM9607_CAL_SEL_SHIFT;
+       dev_dbg(priv->dev, "calibration mode is %d\n", mode);
+
+       switch (mode) {
+       case TWO_PT_CALIB:
+               base = (qfprom_cdata[2] & MDM9607_BASE1_MASK) >> MDM9607_BASE1_SHIFT;
+               p2[0] = (qfprom_cdata[0] & MDM9607_S0_P2_MASK) >> MDM9607_S0_P2_SHIFT;
+               p2[1] = (qfprom_cdata[0] & MDM9607_S1_P2_MASK) >> MDM9607_S1_P2_SHIFT;
+               p2[2] = (qfprom_cdata[1] & MDM9607_S2_P2_MASK) >> MDM9607_S2_P2_SHIFT;
+               p2[3] = (qfprom_cdata[1] & MDM9607_S3_P2_MASK) >> MDM9607_S3_P2_SHIFT;
+               p2[4] = (qfprom_cdata[2] & MDM9607_S4_P2_MASK) >> MDM9607_S4_P2_SHIFT;
+               for (i = 0; i < priv->num_sensors; i++)
+                       p2[i] = ((base + p2[i]) << 2);
+               fallthrough;
+       case ONE_PT_CALIB2:
+               base = (qfprom_cdata[0] & MDM9607_BASE0_MASK);
+               p1[0] = (qfprom_cdata[0] & MDM9607_S0_P1_MASK) >> MDM9607_S0_P1_SHIFT;
+               p1[1] = (qfprom_cdata[0] & MDM9607_S1_P1_MASK) >> MDM9607_S1_P1_SHIFT;
+               p1[2] = (qfprom_cdata[1] & MDM9607_S2_P1_MASK) >> MDM9607_S2_P1_SHIFT;
+               p1[3] = (qfprom_cdata[1] & MDM9607_S3_P1_MASK) >> MDM9607_S3_P1_SHIFT;
+               p1[4] = (qfprom_cdata[2] & MDM9607_S4_P1_MASK) >> MDM9607_S4_P1_SHIFT;
+               for (i = 0; i < priv->num_sensors; i++)
+                       p1[i] = ((base + p1[i]) << 2);
+               break;
+       default:
+               for (i = 0; i < priv->num_sensors; i++) {
+                       p1[i] = 500;
+                       p2[i] = 780;
+               }
+               break;
+       }
+
+       compute_intercept_slope(priv, p1, p2, mode);
+       kfree(qfprom_cdata);
+
+       return 0;
+}
+
+/* v0.1: 8916, 8939, 8974, 9607 */
 
 static struct tsens_features tsens_v0_1_feat = {
        .ver_major      = VER_0_1,
@@ -540,3 +622,17 @@ struct tsens_plat_data data_8974 = {
        .feat           = &tsens_v0_1_feat,
        .fields = tsens_v0_1_regfields,
 };
+
+static const struct tsens_ops ops_9607 = {
+       .init           = init_common,
+       .calibrate      = calibrate_9607,
+       .get_temp       = get_temp_common,
+};
+
+struct tsens_plat_data data_9607 = {
+       .num_sensors    = 5,
+       .ops            = &ops_9607,
+       .hw_ids         = (unsigned int []){ 0, 1, 2, 3, 4 },
+       .feat           = &tsens_v0_1_feat,
+       .fields = tsens_v0_1_regfields,
+};
index 3c19a38..573e261 100644 (file)
@@ -380,11 +380,11 @@ static const struct tsens_ops ops_8976 = {
        .get_temp       = get_temp_tsens_valid,
 };
 
-/* Valid for both MSM8956 and MSM8976. Sensor ID 3 is unused. */
+/* Valid for both MSM8956 and MSM8976. */
 struct tsens_plat_data data_8976 = {
        .num_sensors    = 11,
        .ops            = &ops_8976,
-       .hw_ids         = (unsigned int[]){0, 1, 2, 4, 5, 6, 7, 8, 9, 10},
+       .hw_ids         = (unsigned int[]){0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
        .feat           = &tsens_v1_feat,
        .fields         = tsens_v1_regfields,
 };
index d8ce3a6..4c7ebd1 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
+#include <linux/mfd/syscon.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/regmap.h>
@@ -85,7 +86,8 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1,
                        "%s: sensor%d - data_point1:%#x data_point2:%#x\n",
                        __func__, i, p1[i], p2[i]);
 
-               priv->sensor[i].slope = SLOPE_DEFAULT;
+               if (!priv->sensor[i].slope)
+                       priv->sensor[i].slope = SLOPE_DEFAULT;
                if (mode == TWO_PT_CALIB) {
                        /*
                         * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
@@ -515,6 +517,15 @@ static irqreturn_t tsens_irq_thread(int irq, void *data)
                        dev_dbg(priv->dev, "[%u] %s: no violation:  %d\n",
                                hw_id, __func__, temp);
                }
+
+               if (tsens_version(priv) < VER_0_1) {
+                       /* Constraint: There is only 1 interrupt control register for all
+                        * 11 temperature sensor. So monitoring more than 1 sensor based
+                        * on interrupts will yield inconsistent result. To overcome this
+                        * issue we will monitor only sensor 0 which is the master sensor.
+                        */
+                       break;
+               }
        }
 
        return IRQ_HANDLED;
@@ -530,6 +541,13 @@ static int tsens_set_trips(void *_sensor, int low, int high)
        int high_val, low_val, cl_high, cl_low;
        u32 hw_id = s->hw_id;
 
+       if (tsens_version(priv) < VER_0_1) {
+               /* Pre v0.1 IP had a single register for each type of interrupt
+                * and thresholds
+                */
+               hw_id = 0;
+       }
+
        dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
                hw_id, __func__, low, high);
 
@@ -584,18 +602,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
        u32 valid;
        int ret;
 
-       ret = regmap_field_read(priv->rf[valid_idx], &valid);
-       if (ret)
-               return ret;
-       while (!valid) {
-               /* Valid bit is 0 for 6 AHB clock cycles.
-                * At 19.2MHz, 1 AHB clock is ~60ns.
-                * We should enter this loop very, very rarely.
-                */
-               ndelay(400);
+       /* VER_0 doesn't have VALID bit */
+       if (tsens_version(priv) >= VER_0_1) {
                ret = regmap_field_read(priv->rf[valid_idx], &valid);
                if (ret)
                        return ret;
+               while (!valid) {
+                       /* Valid bit is 0 for 6 AHB clock cycles.
+                        * At 19.2MHz, 1 AHB clock is ~60ns.
+                        * We should enter this loop very, very rarely.
+                        */
+                       ndelay(400);
+                       ret = regmap_field_read(priv->rf[valid_idx], &valid);
+                       if (ret)
+                               return ret;
+               }
        }
 
        /* Valid bit is set, OK to read the temperature */
@@ -608,15 +629,29 @@ int get_temp_common(const struct tsens_sensor *s, int *temp)
 {
        struct tsens_priv *priv = s->priv;
        int hw_id = s->hw_id;
-       int last_temp = 0, ret;
+       int last_temp = 0, ret, trdy;
+       unsigned long timeout;
 
-       ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp);
-       if (ret)
-               return ret;
+       timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
+       do {
+               if (tsens_version(priv) == VER_0) {
+                       ret = regmap_field_read(priv->rf[TRDY], &trdy);
+                       if (ret)
+                               return ret;
+                       if (!trdy)
+                               continue;
+               }
 
-       *temp = code_to_degc(last_temp, s) * 1000;
+               ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp);
+               if (ret)
+                       return ret;
 
-       return 0;
+               *temp = code_to_degc(last_temp, s) * 1000;
+
+               return 0;
+       } while (time_before(jiffies, timeout));
+
+       return -ETIMEDOUT;
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -738,25 +773,42 @@ int __init init_common(struct tsens_priv *priv)
                priv->tm_offset = 0x1000;
        }
 
-       res = platform_get_resource(op, IORESOURCE_MEM, 0);
-       tm_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(tm_base)) {
-               ret = PTR_ERR(tm_base);
-               goto err_put_device;
+       if (tsens_version(priv) >= VER_0_1) {
+               res = platform_get_resource(op, IORESOURCE_MEM, 0);
+               tm_base = devm_ioremap_resource(dev, res);
+               if (IS_ERR(tm_base)) {
+                       ret = PTR_ERR(tm_base);
+                       goto err_put_device;
+               }
+
+               priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config);
+       } else { /* VER_0 share the same gcc regs using a syscon */
+               struct device *parent = priv->dev->parent;
+
+               if (parent)
+                       priv->tm_map = syscon_node_to_regmap(parent->of_node);
        }
 
-       priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config);
-       if (IS_ERR(priv->tm_map)) {
-               ret = PTR_ERR(priv->tm_map);
+       if (IS_ERR_OR_NULL(priv->tm_map)) {
+               if (!priv->tm_map)
+                       ret = -ENODEV;
+               else
+                       ret = PTR_ERR(priv->tm_map);
                goto err_put_device;
        }
 
+       /* VER_0 have only tm_map */
+       if (!priv->srot_map)
+               priv->srot_map = priv->tm_map;
+
        if (tsens_version(priv) > VER_0_1) {
                for (i = VER_MAJOR; i <= VER_STEP; i++) {
                        priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map,
                                                              priv->fields[i]);
-                       if (IS_ERR(priv->rf[i]))
-                               return PTR_ERR(priv->rf[i]);
+                       if (IS_ERR(priv->rf[i])) {
+                               ret = PTR_ERR(priv->rf[i]);
+                               goto err_put_device;
+                       }
                }
                ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor);
                if (ret)
@@ -769,6 +821,10 @@ int __init init_common(struct tsens_priv *priv)
                ret = PTR_ERR(priv->rf[TSENS_EN]);
                goto err_put_device;
        }
+       /* in VER_0 TSENS need to be explicitly enabled */
+       if (tsens_version(priv) == VER_0)
+               regmap_field_write(priv->rf[TSENS_EN], 1);
+
        ret = regmap_field_read(priv->rf[TSENS_EN], &enabled);
        if (ret)
                goto err_put_device;
@@ -791,6 +847,19 @@ int __init init_common(struct tsens_priv *priv)
                goto err_put_device;
        }
 
+       priv->rf[TSENS_SW_RST] =
+               devm_regmap_field_alloc(dev, priv->srot_map, priv->fields[TSENS_SW_RST]);
+       if (IS_ERR(priv->rf[TSENS_SW_RST])) {
+               ret = PTR_ERR(priv->rf[TSENS_SW_RST]);
+               goto err_put_device;
+       }
+
+       priv->rf[TRDY] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[TRDY]);
+       if (IS_ERR(priv->rf[TRDY])) {
+               ret = PTR_ERR(priv->rf[TRDY]);
+               goto err_put_device;
+       }
+
        /* This loop might need changes if enum regfield_ids is reordered */
        for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) {
                for (i = 0; i < priv->feat->max_sensors; i++) {
@@ -806,7 +875,7 @@ int __init init_common(struct tsens_priv *priv)
                }
        }
 
-       if (priv->feat->crit_int) {
+       if (priv->feat->crit_int || tsens_version(priv) < VER_0_1) {
                /* Loop might need changes if enum regfield_ids is reordered */
                for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) {
                        for (i = 0; i < priv->feat->max_sensors; i++) {
@@ -844,7 +913,11 @@ int __init init_common(struct tsens_priv *priv)
        }
 
        spin_lock_init(&priv->ul_lock);
-       tsens_enable_irq(priv);
+
+       /* VER_0 interrupt doesn't need to be enabled */
+       if (tsens_version(priv) >= VER_0_1)
+               tsens_enable_irq(priv);
+
        tsens_debug_init(op);
 
 err_put_device:
@@ -895,6 +968,12 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
 
 static const struct of_device_id tsens_table[] = {
        {
+               .compatible = "qcom,ipq8064-tsens",
+               .data = &data_8960,
+       }, {
+               .compatible = "qcom,mdm9607-tsens",
+               .data = &data_9607,
+       }, {
                .compatible = "qcom,msm8916-tsens",
                .data = &data_8916,
        }, {
@@ -943,10 +1022,19 @@ static int tsens_register_irq(struct tsens_priv *priv, char *irqname,
                if (irq == -ENXIO)
                        ret = 0;
        } else {
-               ret = devm_request_threaded_irq(&pdev->dev, irq,
-                                               NULL, thread_fn,
-                                               IRQF_ONESHOT,
-                                               dev_name(&pdev->dev), priv);
+               /* VER_0 interrupt is TRIGGER_RISING, VER_0_1 and up is ONESHOT */
+               if (tsens_version(priv) == VER_0)
+                       ret = devm_request_threaded_irq(&pdev->dev, irq,
+                                                       thread_fn, NULL,
+                                                       IRQF_TRIGGER_RISING,
+                                                       dev_name(&pdev->dev),
+                                                       priv);
+               else
+                       ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+                                                       thread_fn, IRQF_ONESHOT,
+                                                       dev_name(&pdev->dev),
+                                                       priv);
+
                if (ret)
                        dev_err(&pdev->dev, "%s: failed to get irq\n",
                                __func__);
@@ -975,6 +1063,19 @@ static int tsens_register(struct tsens_priv *priv)
                        priv->ops->enable(priv, i);
        }
 
+       /* VER_0 require to set MIN and MAX THRESH
+        * These 2 regs are set using the:
+        * - CRIT_THRESH_0 for MAX THRESH hardcoded to 120°C
+        * - CRIT_THRESH_1 for MIN THRESH hardcoded to   0°C
+        */
+       if (tsens_version(priv) < VER_0_1) {
+               regmap_field_write(priv->rf[CRIT_THRESH_0],
+                                  tsens_mC_to_hw(priv->sensor, 120000));
+
+               regmap_field_write(priv->rf[CRIT_THRESH_1],
+                                  tsens_mC_to_hw(priv->sensor, 0));
+       }
+
        ret = tsens_register_irq(priv, "uplow", tsens_irq_thread);
        if (ret < 0)
                return ret;
index f40b625..1471a2c 100644 (file)
@@ -13,6 +13,7 @@
 #define CAL_DEGC_PT2           120
 #define SLOPE_FACTOR           1000
 #define SLOPE_DEFAULT          3200
+#define TIMEOUT_US             100
 #define THRESHOLD_MAX_ADC_CODE 0x3ff
 #define THRESHOLD_MIN_ADC_CODE 0x0
 
@@ -25,7 +26,8 @@ struct tsens_priv;
 
 /* IP version numbers in ascending order */
 enum tsens_ver {
-       VER_0_1 = 0,
+       VER_0 = 0,
+       VER_0_1,
        VER_1_X,
        VER_2_X,
 };
@@ -585,7 +587,7 @@ int get_temp_common(const struct tsens_sensor *s, int *temp);
 extern struct tsens_plat_data data_8960;
 
 /* TSENS v0.1 targets */
-extern struct tsens_plat_data data_8916, data_8939, data_8974;
+extern struct tsens_plat_data data_8916, data_8939, data_8974, data_9607;
 
 /* TSENS v1 targets */
 extern struct tsens_plat_data data_tsens_v1, data_8976;
index 75c69fe..e1e4123 100644 (file)
@@ -60,7 +60,7 @@
 #define MCELSIUS(temp) ((temp) * 1000)
 #define GEN3_FUSE_MASK 0xFFF
 
-#define TSC_MAX_NUM    4
+#define TSC_MAX_NUM    5
 
 /* default THCODE values if FUSEs are missing */
 static const int thcodes[TSC_MAX_NUM][3] = {
@@ -68,6 +68,7 @@ static const int thcodes[TSC_MAX_NUM][3] = {
        { 3393, 2795, 2216 },
        { 3389, 2805, 2237 },
        { 3415, 2694, 2195 },
+       { 3356, 2724, 2244 },
 };
 
 /* Structure for thermal temperature calculation */
index 8c80bd0..d9cd23c 100644 (file)
@@ -300,7 +300,7 @@ static int sun8i_ths_calibrate(struct ths_device *tmdev)
                 * or 0x8xx, so they won't be away from the default value
                 * for a lot.
                 *
-                * So here we do not return error if the calibartion data is
+                * So here we do not return error if the calibration data is
                 * not available, except the probe needs deferring.
                 */
                goto out;
@@ -418,7 +418,7 @@ static int sun8i_h3_thermal_init(struct ths_device *tmdev)
 }
 
 /*
- * Without this undocummented value, the returned temperatures would
+ * Without this undocumented value, the returned temperatures would
  * be higher than real ones by about 20C.
  */
 #define SUN50I_H6_CTRL0_UNK 0x0000002f
index 66e0639..8e303e9 100644 (file)
@@ -2118,7 +2118,6 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
        struct tegra_soctherm *tegra;
        struct thermal_zone_device *z;
        struct tsensor_shared_calib shared_calib;
-       struct resource *res;
        struct tegra_soctherm_soc *soc;
        unsigned int i;
        int err;
@@ -2140,26 +2139,20 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
 
        tegra->soc = soc;
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-                                          "soctherm-reg");
-       tegra->regs = devm_ioremap_resource(&pdev->dev, res);
+       tegra->regs = devm_platform_ioremap_resource_byname(pdev, "soctherm-reg");
        if (IS_ERR(tegra->regs)) {
                dev_err(&pdev->dev, "can't get soctherm registers");
                return PTR_ERR(tegra->regs);
        }
 
        if (!tegra->soc->use_ccroc) {
-               res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-                                                  "car-reg");
-               tegra->clk_regs = devm_ioremap_resource(&pdev->dev, res);
+               tegra->clk_regs = devm_platform_ioremap_resource_byname(pdev, "car-reg");
                if (IS_ERR(tegra->clk_regs)) {
                        dev_err(&pdev->dev, "can't get car clk registers");
                        return PTR_ERR(tegra->clk_regs);
                }
        } else {
-               res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-                                                  "ccroc-reg");
-               tegra->ccroc_regs = devm_ioremap_resource(&pdev->dev, res);
+               tegra->ccroc_regs = devm_platform_ioremap_resource_byname(pdev, "ccroc-reg");
                if (IS_ERR(tegra->ccroc_regs)) {
                        dev_err(&pdev->dev, "can't get ccroc registers");
                        return PTR_ERR(tegra->ccroc_regs);
@@ -2195,7 +2188,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev)
        if (err)
                return err;
 
-       /* calculate tsensor calibaration data */
+       /* calculate tsensor calibration data */
        for (i = 0; i < soc->num_tsensors; ++i) {
                err = tegra_calc_tsensor_calib(&soc->tsensors[i],
                                               &shared_calib,
index 996c038..d20b25f 100644 (file)
@@ -561,24 +561,6 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
 }
 EXPORT_SYMBOL_GPL(thermal_zone_device_update);
 
-/**
- * thermal_notify_framework - Sensor drivers use this API to notify framework
- * @tz:                thermal zone device
- * @trip:      indicates which trip point has been crossed
- *
- * This function handles the trip events from sensor drivers. It starts
- * throttling the cooling devices according to the policy configured.
- * For CRITICAL and HOT trip points, this notifies the respective drivers,
- * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
- * The throttling policy is based on the configured platform data; if no
- * platform data is provided, this uses the step_wise throttling policy.
- */
-void thermal_notify_framework(struct thermal_zone_device *tz, int trip)
-{
-       handle_thermal_trip(tz, trip);
-}
-EXPORT_SYMBOL_GPL(thermal_notify_framework);
-
 static void thermal_zone_device_check(struct work_struct *work)
 {
        struct thermal_zone_device *tz = container_of(work, struct
@@ -960,10 +942,7 @@ __thermal_cooling_device_register(struct device_node *np,
 {
        struct thermal_cooling_device *cdev;
        struct thermal_zone_device *pos = NULL;
-       int result;
-
-       if (type && strlen(type) >= THERMAL_NAME_LENGTH)
-               return ERR_PTR(-EINVAL);
+       int ret;
 
        if (!ops || !ops->get_max_state || !ops->get_cur_state ||
            !ops->set_cur_state)
@@ -973,14 +952,17 @@ __thermal_cooling_device_register(struct device_node *np,
        if (!cdev)
                return ERR_PTR(-ENOMEM);
 
-       result = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL);
-       if (result < 0) {
-               kfree(cdev);
-               return ERR_PTR(result);
+       ret = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL);
+       if (ret < 0)
+               goto out_kfree_cdev;
+       cdev->id = ret;
+
+       cdev->type = kstrdup(type ? type : "", GFP_KERNEL);
+       if (!cdev->type) {
+               ret = -ENOMEM;
+               goto out_ida_remove;
        }
 
-       cdev->id = result;
-       strlcpy(cdev->type, type ? : "", sizeof(cdev->type));
        mutex_init(&cdev->lock);
        INIT_LIST_HEAD(&cdev->thermal_instances);
        cdev->np = np;
@@ -990,12 +972,9 @@ __thermal_cooling_device_register(struct device_node *np,
        cdev->devdata = devdata;
        thermal_cooling_device_setup_sysfs(cdev);
        dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
-       result = device_register(&cdev->device);
-       if (result) {
-               ida_simple_remove(&thermal_cdev_ida, cdev->id);
-               put_device(&cdev->device);
-               return ERR_PTR(result);
-       }
+       ret = device_register(&cdev->device);
+       if (ret)
+               goto out_kfree_type;
 
        /* Add 'this' new cdev to the global cdev list */
        mutex_lock(&thermal_list_lock);
@@ -1013,6 +992,15 @@ __thermal_cooling_device_register(struct device_node *np,
        mutex_unlock(&thermal_list_lock);
 
        return cdev;
+
+out_kfree_type:
+       kfree(cdev->type);
+       put_device(&cdev->device);
+out_ida_remove:
+       ida_simple_remove(&thermal_cdev_ida, cdev->id);
+out_kfree_cdev:
+       kfree(cdev);
+       return ERR_PTR(ret);
 }
 
 /**
@@ -1171,6 +1159,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
        ida_simple_remove(&thermal_cdev_ida, cdev->id);
        device_del(&cdev->device);
        thermal_cooling_device_destroy_sysfs(cdev);
+       kfree(cdev->type);
        put_device(&cdev->device);
 }
 EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);
index 86b8cef..726e327 100644 (file)
@@ -66,6 +66,7 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)
 }
 
 void thermal_cdev_update(struct thermal_cooling_device *);
+void __thermal_cdev_update(struct thermal_cooling_device *cdev);
 
 /**
  * struct thermal_trip - representation of a point in temperature domain
index 7f50f41..3edd047 100644 (file)
@@ -192,18 +192,11 @@ static void thermal_cdev_set_cur_state(struct thermal_cooling_device *cdev,
        thermal_cooling_device_stats_update(cdev, target);
 }
 
-void thermal_cdev_update(struct thermal_cooling_device *cdev)
+void __thermal_cdev_update(struct thermal_cooling_device *cdev)
 {
        struct thermal_instance *instance;
        unsigned long target = 0;
 
-       mutex_lock(&cdev->lock);
-       /* cooling device is updated*/
-       if (cdev->updated) {
-               mutex_unlock(&cdev->lock);
-               return;
-       }
-
        /* Make sure cdev enters the deepest cooling state */
        list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
                dev_dbg(&cdev->device, "zone%d->target=%lu\n",
@@ -216,11 +209,25 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev)
 
        thermal_cdev_set_cur_state(cdev, target);
 
-       cdev->updated = true;
-       mutex_unlock(&cdev->lock);
        trace_cdev_update(cdev, target);
        dev_dbg(&cdev->device, "set to state %lu\n", target);
 }
+
+/**
+ * thermal_cdev_update - update cooling device state if needed
+ * @cdev:      pointer to struct thermal_cooling_device
+ *
+ * Update the cooling device state if there is a need.
+ */
+void thermal_cdev_update(struct thermal_cooling_device *cdev)
+{
+       mutex_lock(&cdev->lock);
+       if (!cdev->updated) {
+               __thermal_cdev_update(cdev);
+               cdev->updated = true;
+       }
+       mutex_unlock(&cdev->lock);
+}
 EXPORT_SYMBOL(thermal_cdev_update);
 
 /**
index d0bdf1e..ded1dd0 100644 (file)
@@ -54,11 +54,8 @@ static int thermal_mmio_probe(struct platform_device *pdev)
 
        resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        sensor->mmio_base = devm_ioremap_resource(&pdev->dev, resource);
-       if (IS_ERR(sensor->mmio_base)) {
-               dev_err(&pdev->dev, "failed to ioremap memory (%ld)\n",
-                       PTR_ERR(sensor->mmio_base));
+       if (IS_ERR(sensor->mmio_base))
                return PTR_ERR(sensor->mmio_base);
-       }
 
        sensor_init_func = device_get_match_data(&pdev->dev);
        if (sensor_init_func) {
index 69ef12f..5b76f9a 100644 (file)
@@ -704,14 +704,17 @@ static int thermal_of_populate_bind_params(struct device_node *np,
 
        count = of_count_phandle_with_args(np, "cooling-device",
                                           "#cooling-cells");
-       if (!count) {
+       if (count <= 0) {
                pr_err("Add a cooling_device property with at least one device\n");
+               ret = -ENOENT;
                goto end;
        }
 
        __tcbp = kcalloc(count, sizeof(*__tcbp), GFP_KERNEL);
-       if (!__tcbp)
+       if (!__tcbp) {
+               ret = -ENOMEM;
                goto end;
+       }
 
        for (i = 0; i < count; i++) {
                ret = of_parse_phandle_with_args(np, "cooling-device",
index 8a3646e..ebe7cb7 100644 (file)
@@ -9,30 +9,29 @@
  *   Eduardo Valentin <eduardo.valentin@ti.com>
  */
 
-#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/cpu_pm.h>
+#include <linux/device.h>
+#include <linux/err.h>
 #include <linux/export.h>
+#include <linux/gpio/consumer.h>
 #include <linux/init.h>
-#include <linux/kernel.h>
 #include <linux/interrupt.h>
-#include <linux/clk.h>
-#include <linux/gpio/consumer.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <linux/sys_soc.h>
-#include <linux/reboot.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-#include <linux/of_irq.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
-#include <linux/cpu_pm.h>
-#include <linux/device.h>
-#include <linux/pm_runtime.h>
-#include <linux/pm.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/reboot.h>
+#include <linux/spinlock.h>
+#include <linux/sys_soc.h>
+#include <linux/types.h>
 
 #include "ti-bandgap.h"
 
@@ -1143,14 +1142,10 @@ static int ti_bandgap_restore_ctxt(struct ti_bandgap *bgp)
        for (i = 0; i < bgp->conf->sensor_count; i++) {
                struct temp_sensor_registers *tsr;
                struct temp_sensor_regval *rval;
-               u32 val = 0;
 
                rval = &bgp->regval[i];
                tsr = bgp->conf->sensors[i].registers;
 
-               if (TI_BANDGAP_HAS(bgp, COUNTER))
-                       val = ti_bandgap_readl(bgp, tsr->bgap_counter);
-
                if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG))
                        ti_bandgap_writel(bgp, rval->tshut_threshold,
                                          tsr->tshut_threshold);
index 6ac7bb1..d296f3b 100644 (file)
@@ -91,7 +91,7 @@ struct thermal_cooling_device_ops {
 
 struct thermal_cooling_device {
        int id;
-       char type[THERMAL_NAME_LENGTH];
+       char *type;
        struct device device;
        struct device_node *np;
        void *devdata;
@@ -390,7 +390,6 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
 int thermal_zone_get_slope(struct thermal_zone_device *tz);
 int thermal_zone_get_offset(struct thermal_zone_device *tz);
 
-void thermal_notify_framework(struct thermal_zone_device *, int);
 int thermal_zone_device_enable(struct thermal_zone_device *tz);
 int thermal_zone_device_disable(struct thermal_zone_device *tz);
 void thermal_zone_device_critical(struct thermal_zone_device *tz);
@@ -436,10 +435,6 @@ static inline int thermal_zone_get_offset(
                struct thermal_zone_device *tz)
 { return -ENODEV; }
 
-static inline void thermal_notify_framework(struct thermal_zone_device *tz,
-       int trip)
-{ }
-
 static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
 { return -ENODEV; }
 
index c105054..9aa2fed 100644 (file)
@@ -60,7 +60,7 @@ enum thermal_genl_event {
        THERMAL_GENL_EVENT_UNSPEC,
        THERMAL_GENL_EVENT_TZ_CREATE,           /* Thermal zone creation */
        THERMAL_GENL_EVENT_TZ_DELETE,           /* Thermal zone deletion */
-       THERMAL_GENL_EVENT_TZ_DISABLE,          /* Thermal zone disabed */
+       THERMAL_GENL_EVENT_TZ_DISABLE,          /* Thermal zone disabled */
        THERMAL_GENL_EVENT_TZ_ENABLE,           /* Thermal zone enabled */
        THERMAL_GENL_EVENT_TZ_TRIP_UP,          /* Trip point crossed the way up */
        THERMAL_GENL_EVENT_TZ_TRIP_DOWN,        /* Trip point crossed the way down */