Merge tag 'thermal-v6.2-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/therm...
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 14 Dec 2022 16:05:45 +0000 (17:05 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 14 Dec 2022 16:05:45 +0000 (17:05 +0100)
Pull thermal driver changes for 6.2-rc1 from Daniel Lezcano:

"- Add the sm8450 QCom compatible string in the DT bindings (Luca
   Weiss)

 - Use devm_platform_get_and_ioremap_resource on the ST platform to
   group two calls into a single one (Minghao Chi)

 - Add the sm8550 QCom compatible string in the DT bindings (Neil
   Armstrong)

 - Use GENMASK instead of bitmaps and validate the temperature after
   reading it (Marcus Folkesson)

 - Convert generic-adc-thermal to DT schema (Rob Herring)

 - Fix the debug print message where the logic is inverted (Keerthy)

 - Fix memory leak on thermal_of_zone_register() failure (Ido Schimmel)

 - Add support for IPQ8074 in the tsens driver along with the DT
   bindings (Robert Marko)

 - Fix and rework the debugfs code in the tsens driver (Christian
   Marangi)

 - Add calibration and DT documentation for the imx8mm driver (Marek
   Vasut)

 - Add DT bindings and compatible for the Mediatek SoCs mt7981 and
   mt7983 (Daniel Golle)

 - Don't show an error message if it happens at probe time while it
   will be deferred on the QCom SPMI ADC driver (Johan Hovold)

 - Add the HWMon support on the imx8mm board (Alexander Stein)

 - Remove a pointless include in the power allocator governor
   (Christophe JAILLET)

 - Add interrupt DT bindings for QCom SoCs SC8280XP, SM6350 and SM8450
   (Krzysztof Kozlowski)

 - Fix inaccurate warning message for the QCom tsens gen2 (Luca Weiss)

 - Demote error log of thermal zone register to debug on the tsens QCom
   driver (Manivannan Sadhasivam)

 - Consolidate the TI Bandgap driver regarding how is handled the efuse
   values and the errata handling (Bryan Brattlof)

 - Document the Renesas RZ/Five as compatible with RZ/G2UL in the DT
   bindings (Lad Prabhakar)

 - Fix the irq handler return value in the LMh driver (Bjorn Andersson)

 - Delete platform remove callback as it is empty (Uwe Kleine-König)"

* tag 'thermal-v6.2-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux: (34 commits)
  thermal/drivers/imx_sc_thermal: Drop empty platform remove function
  thermal/drivers/qcom/lmh: Fix irq handler return value
  dt-bindings: thermal: qcom-tsens: Add compatible for sm8550
  thermal/drivers/st: Use devm_platform_get_and_ioremap_resource()
  dt-bindings: thermal: rzg2l-thermal: Document RZ/Five SoC
  dt-bindings: thermal: k3-j72xx: conditionally require efuse reg range
  dt-bindings: thermal: k3-j72xx: elaborate on binding description
  thermal/drivers/k3_j72xx_bandgap: Map fuse_base only for erratum workaround
  thermal/drivers/k3_j72xx_bandgap: Remove fuse_base from structure
  thermal/drivers/k3_j72xx_bandgap: Use bool for i2128 erratum flag
  thermal/drivers/k3_j72xx_bandgap: Simplify k3_thermal_get_temp() function
  thermal/drivers/qcom: Demote error log of thermal zone register to debug
  thermal/drivers/qcom/temp-alarm: Fix inaccurate warning for gen2
  dt-bindings: thermal: qcom-tsens: narrow interrupts for SC8280XP, SM6350 and SM8450
  thermal/core/power allocator: Remove a useless include
  thermal/drivers/imx8mm: Add hwmon support
  thermal: qcom-spmi-adc-tm5: suppress probe-deferral error message
  dt-bindings: thermal: mediatek: add compatible string for MT7986 and MT7981 SoC
  thermal: ti-soc-thermal: Drop comma after SoC match table sentinel
  thermal/drivers/imx: Add support for loading calibration data from OCOTP
  ...

23 files changed:
Documentation/devicetree/bindings/thermal/generic-adc-thermal.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/thermal/imx8mm-thermal.yaml
Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
Documentation/devicetree/bindings/thermal/rzg2l-thermal.yaml
Documentation/devicetree/bindings/thermal/thermal-generic-adc.txt [deleted file]
Documentation/devicetree/bindings/thermal/ti,j72xx-thermal.yaml
drivers/thermal/gov_power_allocator.c
drivers/thermal/imx8mm_thermal.c
drivers/thermal/imx_sc_thermal.c
drivers/thermal/k3_j72xx_bandgap.c
drivers/thermal/qcom/lmh.c
drivers/thermal/qcom/qcom-spmi-adc-tm5.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-v2.c
drivers/thermal/qcom/tsens.c
drivers/thermal/qcom/tsens.h
drivers/thermal/st/stm_thermal.c
drivers/thermal/thermal_of.c
drivers/thermal/ti-soc-thermal/ti-bandgap.c

diff --git a/Documentation/devicetree/bindings/thermal/generic-adc-thermal.yaml b/Documentation/devicetree/bindings/thermal/generic-adc-thermal.yaml
new file mode 100644 (file)
index 0000000..f1fc3b0
--- /dev/null
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/thermal/generic-adc-thermal.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: General Purpose Analog To Digital Converter (ADC) based thermal sensor
+
+maintainers:
+  - Laxman Dewangan <ldewangan@nvidia.com>
+
+description:
+  On some of platforms, thermal sensor like thermistors are connected to
+  one of ADC channel and sensor resistance is read via voltage across the
+  sensor resistor. The voltage read across the sensor is mapped to
+  temperature using voltage-temperature lookup table.
+
+properties:
+  compatible:
+    const: generic-adc-thermal
+
+  '#thermal-sensor-cells':
+    const: 0
+
+  io-channels:
+    maxItems: 1
+
+  io-channel-names:
+    const: sensor-channel
+
+  temperature-lookup-table:
+    description: |
+      Lookup table to map the relation between ADC value and temperature.
+      When ADC is read, the value is looked up on the table to get the
+      equivalent temperature.
+
+      If not specified, driver assumes the ADC channel gives milliCelsius
+      directly.
+    $ref: /schemas/types.yaml#/definitions/int32-matrix
+    items:
+      items:
+        - description: Temperature in milliCelsius
+        - description: ADC read value
+
+required:
+  - compatible
+  - '#thermal-sensor-cells'
+  - io-channels
+  - io-channel-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/thermal/thermal.h>
+
+    thermal-sensor {
+        compatible = "generic-adc-thermal";
+        #thermal-sensor-cells = <0>;
+        io-channels = <&ads1015 1>;
+        io-channel-names = "sensor-channel";
+        temperature-lookup-table = <
+              (-40000) 2578
+              (-39000) 2577
+              (-38000) 2576
+              (-37000) 2575
+              (-36000) 2574
+              (-35000) 2573
+              (-34000) 2572
+              (-33000) 2571
+              (-32000) 2569
+              (-31000) 2568
+              (-30000) 2567
+              /* skip */
+              118000 254
+              119000 247
+              120000 240
+              121000 233
+              122000 226
+              123000 220
+              124000 214
+              125000 208>;
+    };
+...
index 89c54e0..b907262 100644 (file)
@@ -32,6 +32,13 @@ properties:
   clocks:
     maxItems: 1
 
+  nvmem-cells:
+    maxItems: 1
+    description: Phandle to the calibration data provided by ocotp
+
+  nvmem-cell-names:
+    const: calib
+
   "#thermal-sensor-cells":
     description: |
       Number of cells required to uniquely identify the thermal
index 5c7e7bd..38b32bb 100644 (file)
@@ -13,6 +13,8 @@ Required properties:
   - "mediatek,mt2701-thermal" : For MT2701 family of SoCs
   - "mediatek,mt2712-thermal" : For MT2712 family of SoCs
   - "mediatek,mt7622-thermal" : For MT7622 SoC
+  - "mediatek,mt7981-thermal", "mediatek,mt7986-thermal" : For MT7981 SoC
+  - "mediatek,mt7986-thermal" : For MT7986 SoC
   - "mediatek,mt8183-thermal" : For MT8183 family of SoCs
   - "mediatek,mt8516-thermal", "mediatek,mt2701-thermal : For MT8516 family of SoCs
 - reg: Address range of the thermal controller
index 038d813..7e04804 100644 (file)
@@ -57,8 +57,14 @@ properties:
               - qcom,sm8150-tsens
               - qcom,sm8250-tsens
               - qcom,sm8350-tsens
+              - qcom,sm8450-tsens
+              - qcom,sm8550-tsens
           - const: qcom,tsens-v2
 
+      - description: v2 of TSENS with combined interrupt
+        enum:
+          - qcom,ipq8074-tsens
+
   reg:
     items:
       - description: TM registers
@@ -66,15 +72,11 @@ properties:
 
   interrupts:
     minItems: 1
-    items:
-      - description: Combined interrupt if upper or lower threshold crossed
-      - description: Interrupt if critical threshold crossed
+    maxItems: 2
 
   interrupt-names:
     minItems: 1
-    items:
-      - const: uplow
-      - const: critical
+    maxItems: 2
 
   nvmem-cells:
     minItems: 1
@@ -128,22 +130,64 @@ allOf:
     then:
       properties:
         interrupts:
-          maxItems: 1
+          items:
+            - description: Combined interrupt if upper or lower threshold crossed
         interrupt-names:
-          maxItems: 1
+          items:
+            - const: uplow
 
-    else:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,msm8953-tsens
+              - qcom,msm8996-tsens
+              - qcom,msm8998-tsens
+              - qcom,sc7180-tsens
+              - qcom,sc7280-tsens
+              - qcom,sc8180x-tsens
+              - qcom,sc8280xp-tsens
+              - qcom,sdm630-tsens
+              - qcom,sdm845-tsens
+              - qcom,sm6350-tsens
+              - qcom,sm8150-tsens
+              - qcom,sm8250-tsens
+              - qcom,sm8350-tsens
+              - qcom,sm8450-tsens
+              - qcom,tsens-v2
+    then:
       properties:
         interrupts:
-          minItems: 2
+          items:
+            - description: Combined interrupt if upper or lower threshold crossed
+            - description: Interrupt if critical threshold crossed
         interrupt-names:
-          minItems: 2
+          items:
+            - const: uplow
+            - const: critical
 
   - if:
       properties:
         compatible:
           contains:
             enum:
+              - qcom,ipq8074-tsens
+    then:
+      properties:
+        interrupts:
+          items:
+            - description: Combined interrupt if upper, lower or critical thresholds crossed
+        interrupt-names:
+          items:
+            - const: combined
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,ipq8074-tsens
               - qcom,tsens-v0_1
               - qcom,tsens-v1
               - qcom,tsens-v2
@@ -226,4 +270,19 @@ examples:
            #qcom,sensors = <13>;
            #thermal-sensor-cells = <1>;
     };
+
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    // Example 4 (for any IPQ8074 based SoC-s):
+    tsens4: thermal-sensor@4a9000 {
+           compatible = "qcom,ipq8074-tsens";
+           reg = <0x4a9000 0x1000>,
+                 <0x4a8000 0x1000>;
+
+           interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+           interrupt-names = "combined";
+
+           #qcom,sensors = <16>;
+           #thermal-sensor-cells = <1>;
+    };
 ...
index 1d83733..03f4b92 100644 (file)
@@ -17,7 +17,7 @@ properties:
   compatible:
     items:
       - enum:
-          - renesas,r9a07g043-tsu # RZ/G2UL
+          - renesas,r9a07g043-tsu # RZ/G2UL and RZ/Five
           - renesas,r9a07g044-tsu # RZ/G2{L,LC}
           - renesas,r9a07g054-tsu # RZ/V2L
       - const: renesas,rzg2l-tsu
diff --git a/Documentation/devicetree/bindings/thermal/thermal-generic-adc.txt b/Documentation/devicetree/bindings/thermal/thermal-generic-adc.txt
deleted file mode 100644 (file)
index e136946..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-General Purpose Analog To Digital Converter (ADC) based thermal sensor.
-
-On some of platforms, thermal sensor like thermistors are connected to
-one of ADC channel and sensor resistance is read via voltage across the
-sensor resistor. The voltage read across the sensor is mapped to
-temperature using voltage-temperature lookup table.
-
-Required properties:
-===================
-- compatible:               Must be "generic-adc-thermal".
-- #thermal-sensor-cells:     Should be 1. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description
-                            of this property.
-Optional properties:
-===================
-- temperature-lookup-table:  Two dimensional array of Integer; lookup table
-                            to map the relation between ADC value and
-                            temperature. When ADC is read, the value is
-                            looked up on the table to get the equivalent
-                            temperature.
-
-                            The first value of the each row of array is the
-                            temperature in milliCelsius and second value of
-                            the each row of array is the ADC read value.
-
-                            If not specified, driver assumes the ADC channel
-                            gives milliCelsius directly.
-
-Example :
-#include <dt-bindings/thermal/thermal.h>
-
-i2c@7000c400 {
-       ads1015: ads1015@4a {
-               reg = <0x4a>;
-               compatible = "ads1015";
-               sampling-frequency = <3300>;
-               #io-channel-cells = <1>;
-       };
-};
-
-tboard_thermistor: thermal-sensor {
-       compatible = "generic-adc-thermal";
-       #thermal-sensor-cells = <0>;
-       io-channels = <&ads1015 1>;
-       io-channel-names = "sensor-channel";
-       temperature-lookup-table = <    (-40000) 2578
-                                       (-39000) 2577
-                                       (-38000) 2576
-                                       (-37000) 2575
-                                       (-36000) 2574
-                                       (-35000) 2573
-                                       (-34000) 2572
-                                       (-33000) 2571
-                                       (-32000) 2569
-                                       (-31000) 2568
-                                       (-30000) 2567
-                                       ::::::::::
-                                       118000 254
-                                       119000 247
-                                       120000 240
-                                       121000 233
-                                       122000 226
-                                       123000 220
-                                       124000 214
-                                       125000 208>;
-};
-
-dummy_cool_dev: dummy-cool-dev {
-       compatible = "dummy-cooling-dev";
-       #cooling-cells = <2>; /* min followed by max */
-};
-
-thermal-zones {
-       Tboard {
-               polling-delay = <15000>; /* milliseconds */
-               polling-delay-passive = <0>; /* milliseconds */
-               thermal-sensors = <&tboard_thermistor>;
-
-               trips {
-                       therm_est_trip: therm_est_trip {
-                               temperature = <40000>;
-                               type = "active";
-                               hysteresis = <1000>;
-                       };
-               };
-
-               cooling-maps {
-                       map0 {
-                               trip = <&therm_est_trip>;
-                               cooling-device = <&dummy_cool_dev THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
-                               contribution = <100>;
-                       };
-
-               };
-       };
-};
index c74f124..0509c9c 100644 (file)
@@ -9,6 +9,19 @@ title: Texas Instruments J72XX VTM (DTS) binding
 maintainers:
   - Keerthy <j-keerthy@ti.com>
 
+description: |
+  The TI K3 family of SoCs typically have a Voltage & Thermal
+  Management (VTM) device to control up to 8 temperature diode
+  sensors to measure silicon junction temperatures from different
+  hotspots of the chip as well as provide temperature, interrupt
+  and alerting information.
+
+  The following polynomial equation can then be used to convert
+  value returned by this device into a temperature in Celsius
+
+  Temp(C) = (-9.2627e-12) * x^4 + (6.0373e-08) * x^3 + \
+            (-1.7058e-04) * x^2 + (3.2512e-01) * x   + (-4.9003e+01)
+
 properties:
   compatible:
     enum:
@@ -19,7 +32,12 @@ properties:
     items:
       - description: VTM cfg1 register space
       - description: VTM cfg2 register space
-      - description: VTM efuse register space
+      - description: |
+          A software trimming method must be applied to some Jacinto
+          devices to function properly. This eFuse region provides
+          the information needed for these SoCs to report
+          temperatures accurately.
+    minItems: 2
 
   power-domains:
     maxItems: 1
@@ -27,6 +45,21 @@ properties:
   "#thermal-sensor-cells":
     const: 1
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: ti,j721e-vtm
+    then:
+      properties:
+        reg:
+          minItems: 3
+    else:
+      properties:
+        reg:
+          maxItems: 2
+
 required:
   - compatible
   - reg
index 2d1aeab..d5d4eae 100644 (file)
@@ -8,7 +8,6 @@
 
 #define pr_fmt(fmt) "Power allocator: " fmt
 
-#include <linux/rculist.h>
 #include <linux/slab.h>
 #include <linux/thermal.h>
 
index e2c2673..d247b48 100644 (file)
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/nvmem-consumer.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 #include <linux/thermal.h>
 
 #include "thermal_core.h"
+#include "thermal_hwmon.h"
 
 #define TER                    0x0     /* TMU enable */
 #define TPS                    0x4
 #define TRITSR                 0x20    /* TMU immediate temp */
+/* TMU calibration data registers */
+#define TASR                   0x28
+#define TASR_BUF_SLOPE_MASK    GENMASK(19, 16)
+#define TASR_BUF_VREF_MASK     GENMASK(4, 0)   /* TMU_V1 */
+#define TASR_BUF_VERF_SEL_MASK GENMASK(1, 0)   /* TMU_V2 */
+#define TCALIV(n)              (0x30 + ((n) * 4))
+#define TCALIV_EN              BIT(31)
+#define TCALIV_HR_MASK         GENMASK(23, 16) /* TMU_V1 */
+#define TCALIV_RT_MASK         GENMASK(7, 0)   /* TMU_V1 */
+#define TCALIV_SNSR105C_MASK   GENMASK(27, 16) /* TMU_V2 */
+#define TCALIV_SNSR25C_MASK    GENMASK(11, 0)  /* TMU_V2 */
+#define TRIM                   0x3c
+#define TRIM_BJT_CUR_MASK      GENMASK(23, 20)
+#define TRIM_BGR_MASK          GENMASK(31, 28)
+#define TRIM_VLSB_MASK         GENMASK(15, 12)
+#define TRIM_EN_CH             BIT(7)
 
 #define TER_ADC_PD             BIT(30)
 #define TER_EN                 BIT(31)
-#define TRITSR_TEMP0_VAL_MASK  0xff
-#define TRITSR_TEMP1_VAL_MASK  0xff0000
+#define TRITSR_TEMP0_VAL_MASK  GENMASK(7, 0)
+#define TRITSR_TEMP1_VAL_MASK  GENMASK(23, 16)
 
 #define PROBE_SEL_ALL          GENMASK(31, 30)
 
 #define SIGN_BIT               BIT(7)
 #define TEMP_VAL_MASK          GENMASK(6, 0)
 
+/* TMU OCOTP calibration data bitfields */
+#define ANA0_EN                        BIT(25)
+#define ANA0_BUF_VREF_MASK     GENMASK(24, 20)
+#define ANA0_BUF_SLOPE_MASK    GENMASK(19, 16)
+#define ANA0_HR_MASK           GENMASK(15, 8)
+#define ANA0_RT_MASK           GENMASK(7, 0)
+#define TRIM2_VLSB_MASK                GENMASK(23, 20)
+#define TRIM2_BGR_MASK         GENMASK(19, 16)
+#define TRIM2_BJT_CUR_MASK     GENMASK(15, 12)
+#define TRIM2_BUF_SLOP_SEL_MASK        GENMASK(11, 8)
+#define TRIM2_BUF_VERF_SEL_MASK        GENMASK(7, 6)
+#define TRIM3_TCA25_0_LSB_MASK GENMASK(31, 28)
+#define TRIM3_TCA40_0_MASK     GENMASK(27, 16)
+#define TRIM4_TCA40_1_MASK     GENMASK(31, 20)
+#define TRIM4_TCA105_0_MASK    GENMASK(19, 8)
+#define TRIM4_TCA25_0_MSB_MASK GENMASK(7, 0)
+#define TRIM5_TCA105_1_MASK    GENMASK(23, 12)
+#define TRIM5_TCA25_1_MASK     GENMASK(11, 0)
+
 #define VER1_TEMP_LOW_LIMIT    10000
 #define VER2_TEMP_LOW_LIMIT    -40000
 #define VER2_TEMP_HIGH_LIMIT   125000
@@ -65,8 +103,14 @@ static int imx8mm_tmu_get_temp(void *data, int *temp)
        u32 val;
 
        val = readl_relaxed(tmu->base + TRITSR) & TRITSR_TEMP0_VAL_MASK;
+
+       /*
+        * Do not validate against the V bit (bit 31) due to errata
+        * ERR051272: TMU: Bit 31 of registers TMU_TSCR/TMU_TRITSR/TMU_TRATSR invalid
+        */
+
        *temp = val * 1000;
-       if (*temp < VER1_TEMP_LOW_LIMIT)
+       if (*temp < VER1_TEMP_LOW_LIMIT || *temp > VER2_TEMP_HIGH_LIMIT)
                return -EAGAIN;
 
        return 0;
@@ -128,6 +172,129 @@ static void imx8mm_tmu_probe_sel_all(struct imx8mm_tmu *tmu)
        writel_relaxed(val, tmu->base + TPS);
 }
 
+static int imx8mm_tmu_probe_set_calib_v1(struct platform_device *pdev,
+                                        struct imx8mm_tmu *tmu)
+{
+       struct device *dev = &pdev->dev;
+       u32 ana0;
+       int ret;
+
+       ret = nvmem_cell_read_u32(&pdev->dev, "calib", &ana0);
+       if (ret) {
+               dev_warn(dev, "Failed to read OCOTP nvmem cell (%d).\n", ret);
+               return ret;
+       }
+
+       writel(FIELD_PREP(TASR_BUF_VREF_MASK,
+                         FIELD_GET(ANA0_BUF_VREF_MASK, ana0)) |
+              FIELD_PREP(TASR_BUF_SLOPE_MASK,
+                         FIELD_GET(ANA0_BUF_SLOPE_MASK, ana0)),
+              tmu->base + TASR);
+
+       writel(FIELD_PREP(TCALIV_RT_MASK, FIELD_GET(ANA0_RT_MASK, ana0)) |
+              FIELD_PREP(TCALIV_HR_MASK, FIELD_GET(ANA0_HR_MASK, ana0)) |
+              ((ana0 & ANA0_EN) ? TCALIV_EN : 0),
+              tmu->base + TCALIV(0));
+
+       return 0;
+}
+
+static int imx8mm_tmu_probe_set_calib_v2(struct platform_device *pdev,
+                                        struct imx8mm_tmu *tmu)
+{
+       struct device *dev = &pdev->dev;
+       struct nvmem_cell *cell;
+       u32 trim[4] = { 0 };
+       size_t len;
+       void *buf;
+
+       cell = nvmem_cell_get(dev, "calib");
+       if (IS_ERR(cell))
+               return PTR_ERR(cell);
+
+       buf = nvmem_cell_read(cell, &len);
+       nvmem_cell_put(cell);
+
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+
+       memcpy(trim, buf, min(len, sizeof(trim)));
+       kfree(buf);
+
+       if (len != 16) {
+               dev_err(dev,
+                       "OCOTP nvmem cell length is %zu, must be 16.\n", len);
+               return -EINVAL;
+       }
+
+       /* Blank sample hardware */
+       if (!trim[0] && !trim[1] && !trim[2] && !trim[3]) {
+               /* Use a default 25C binary codes */
+               writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 0x63c),
+                      tmu->base + TCALIV(0));
+               writel(FIELD_PREP(TCALIV_SNSR25C_MASK, 0x63c),
+                      tmu->base + TCALIV(1));
+               return 0;
+       }
+
+       writel(FIELD_PREP(TASR_BUF_VERF_SEL_MASK,
+                         FIELD_GET(TRIM2_BUF_VERF_SEL_MASK, trim[0])) |
+              FIELD_PREP(TASR_BUF_SLOPE_MASK,
+                         FIELD_GET(TRIM2_BUF_SLOP_SEL_MASK, trim[0])),
+              tmu->base + TASR);
+
+       writel(FIELD_PREP(TRIM_BJT_CUR_MASK,
+                         FIELD_GET(TRIM2_BJT_CUR_MASK, trim[0])) |
+              FIELD_PREP(TRIM_BGR_MASK, FIELD_GET(TRIM2_BGR_MASK, trim[0])) |
+              FIELD_PREP(TRIM_VLSB_MASK, FIELD_GET(TRIM2_VLSB_MASK, trim[0])) |
+              TRIM_EN_CH,
+              tmu->base + TRIM);
+
+       writel(FIELD_PREP(TCALIV_SNSR25C_MASK,
+                         FIELD_GET(TRIM3_TCA25_0_LSB_MASK, trim[1]) |
+                         (FIELD_GET(TRIM4_TCA25_0_MSB_MASK, trim[2]) << 4)) |
+              FIELD_PREP(TCALIV_SNSR105C_MASK,
+                         FIELD_GET(TRIM4_TCA105_0_MASK, trim[2])),
+              tmu->base + TCALIV(0));
+
+       writel(FIELD_PREP(TCALIV_SNSR25C_MASK,
+                         FIELD_GET(TRIM5_TCA25_1_MASK, trim[3])) |
+              FIELD_PREP(TCALIV_SNSR105C_MASK,
+                         FIELD_GET(TRIM5_TCA105_1_MASK, trim[3])),
+              tmu->base + TCALIV(1));
+
+       writel(FIELD_PREP(TCALIV_SNSR25C_MASK,
+                         FIELD_GET(TRIM3_TCA40_0_MASK, trim[1])) |
+              FIELD_PREP(TCALIV_SNSR105C_MASK,
+                         FIELD_GET(TRIM4_TCA40_1_MASK, trim[2])),
+              tmu->base + TCALIV(2));
+
+       return 0;
+}
+
+static int imx8mm_tmu_probe_set_calib(struct platform_device *pdev,
+                                     struct imx8mm_tmu *tmu)
+{
+       struct device *dev = &pdev->dev;
+
+       /*
+        * Lack of calibration data OCOTP reference is not considered
+        * fatal to retain compatibility with old DTs. It is however
+        * strongly recommended to update such old DTs to get correct
+        * temperature compensation values for each SoC.
+        */
+       if (!of_find_property(pdev->dev.of_node, "nvmem-cells", NULL)) {
+               dev_warn(dev,
+                        "No OCOTP nvmem reference found, SoC-specific calibration not loaded. Please update your DT.\n");
+               return 0;
+       }
+
+       if (tmu->socdata->version == TMU_VER1)
+               return imx8mm_tmu_probe_set_calib_v1(pdev, tmu);
+
+       return imx8mm_tmu_probe_set_calib_v2(pdev, tmu);
+}
+
 static int imx8mm_tmu_probe(struct platform_device *pdev)
 {
        const struct thermal_soc_data *data;
@@ -176,10 +343,17 @@ static int imx8mm_tmu_probe(struct platform_device *pdev)
                        goto disable_clk;
                }
                tmu->sensors[i].hw_id = i;
+
+               if (devm_thermal_add_hwmon_sysfs(tmu->sensors[i].tzd))
+                       dev_warn(&pdev->dev, "failed to add hwmon sysfs attributes\n");
        }
 
        platform_set_drvdata(pdev, tmu);
 
+       ret = imx8mm_tmu_probe_set_calib(pdev, tmu);
+       if (ret)
+               goto disable_clk;
+
        /* enable all the probes for V2 TMU */
        if (tmu->socdata->version == TMU_VER2)
                imx8mm_tmu_probe_sel_all(tmu);
index 5d92b70..4df925e 100644 (file)
@@ -127,11 +127,6 @@ static int imx_sc_thermal_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int imx_sc_thermal_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 static int imx_sc_sensors[] = { IMX_SC_R_SYSTEM, IMX_SC_R_PMIC_0, -1 };
 
 static const struct of_device_id imx_sc_thermal_table[] = {
@@ -142,7 +137,6 @@ MODULE_DEVICE_TABLE(of, imx_sc_thermal_table);
 
 static struct platform_driver imx_sc_thermal_driver = {
                .probe = imx_sc_thermal_probe,
-               .remove = imx_sc_thermal_remove,
                .driver = {
                        .name = "imx-sc-thermal",
                        .of_match_table = imx_sc_thermal_table,
index 16b6bcf..031ea10 100644 (file)
@@ -177,7 +177,6 @@ struct k3_j72xx_bandgap {
        struct device *dev;
        void __iomem *base;
        void __iomem *cfg2_base;
-       void __iomem *fuse_base;
        struct k3_thermal_data *ts_data[K3_VTM_MAX_NUM_TS];
 };
 
@@ -249,14 +248,7 @@ static inline int k3_bgp_read_temp(struct k3_thermal_data *devdata,
 /* Get temperature callback function for thermal zone */
 static int k3_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
 {
-       struct k3_thermal_data *data = tz->devdata;
-       int ret = 0;
-
-       ret = k3_bgp_read_temp(data, temp);
-       if (ret)
-               return ret;
-
-       return ret;
+       return k3_bgp_read_temp(tz->devdata, temp);
 }
 
 static const struct thermal_zone_device_ops k3_of_thermal_ops = {
@@ -283,7 +275,7 @@ static int k3_j72xx_bandgap_temp_to_adc_code(int temp)
 }
 
 static void get_efuse_values(int id, struct k3_thermal_data *data, int *err,
-                            struct k3_j72xx_bandgap *bgp)
+                            void __iomem *fuse_base)
 {
        int i, tmp, pow;
        int ct_offsets[5][K3_VTM_CORRECTION_TEMP_CNT] = {
@@ -305,16 +297,16 @@ static void get_efuse_values(int id, struct k3_thermal_data *data, int *err,
                /* Extract the offset value using bit-mask */
                if (ct_offsets[id][i] == -1 && i == 1) {
                        /* 25C offset Case of Sensor 2 split between 2 regs */
-                       tmp = (readl(bgp->fuse_base + 0x8) & 0xE0000000) >> (29);
-                       tmp |= ((readl(bgp->fuse_base + 0xC) & 0x1F) << 3);
+                       tmp = (readl(fuse_base + 0x8) & 0xE0000000) >> (29);
+                       tmp |= ((readl(fuse_base + 0xC) & 0x1F) << 3);
                        pow = tmp & 0x80;
                } else if (ct_offsets[id][i] == -1 && i == 2) {
                        /* 125C Case of Sensor 3 split between 2 regs */
-                       tmp = (readl(bgp->fuse_base + 0x4) & 0xF8000000) >> (27);
-                       tmp |= ((readl(bgp->fuse_base + 0x8) & 0xF) << 5);
+                       tmp = (readl(fuse_base + 0x4) & 0xF8000000) >> (27);
+                       tmp |= ((readl(fuse_base + 0x8) & 0xF) << 5);
                        pow = tmp & 0x100;
                } else {
-                       tmp = readl(bgp->fuse_base + ct_offsets[id][i]);
+                       tmp = readl(fuse_base + ct_offsets[id][i]);
                        tmp &= ct_bm[id][i];
                        tmp = tmp >> __ffs(ct_bm[id][i]);
 
@@ -347,7 +339,7 @@ static void print_look_up_table(struct device *dev, int *ref_table)
 }
 
 struct k3_j72xx_bandgap_data {
-       unsigned int has_errata_i2128;
+       const bool has_errata_i2128;
 };
 
 static int k3_j72xx_bandgap_probe(struct platform_device *pdev)
@@ -358,11 +350,12 @@ static int k3_j72xx_bandgap_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct k3_j72xx_bandgap *bgp;
        struct k3_thermal_data *data;
-       int workaround_needed = 0;
+       bool workaround_needed = false;
        const struct k3_j72xx_bandgap_data *driver_data;
        struct thermal_zone_device *ti_thermal;
        int *ref_table;
        struct err_values err_vals;
+       void __iomem *fuse_base;
 
        const s64 golden_factors[] = {
                -490019999999999936,
@@ -393,15 +386,32 @@ static int k3_j72xx_bandgap_probe(struct platform_device *pdev)
        if (IS_ERR(bgp->cfg2_base))
                return PTR_ERR(bgp->cfg2_base);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-       bgp->fuse_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(bgp->fuse_base))
-               return PTR_ERR(bgp->fuse_base);
-
        driver_data = of_device_get_match_data(dev);
        if (driver_data)
                workaround_needed = driver_data->has_errata_i2128;
 
+       /*
+        * Some of TI's J721E SoCs require a software trimming procedure
+        * for the temperature monitors to function properly. To determine
+        * if this particular SoC is NOT affected, both bits in the
+        * WKUP_SPARE_FUSE0[31:30] will be set (0xC0000000) indicating
+        * when software trimming should NOT be applied.
+        *
+        * https://www.ti.com/lit/er/sprz455c/sprz455c.pdf
+        */
+       if (workaround_needed) {
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+               fuse_base = devm_ioremap_resource(dev, res);
+               if (IS_ERR(fuse_base))
+                       return PTR_ERR(fuse_base);
+
+               if ((readl(fuse_base) & 0xc0000000) == 0xc0000000)
+                       workaround_needed = false;
+       }
+
+       dev_dbg(bgp->dev, "Work around %sneeded\n",
+               workaround_needed ? "" : "not ");
+
        pm_runtime_enable(dev);
        ret = pm_runtime_get_sync(dev);
        if (ret < 0) {
@@ -434,13 +444,6 @@ static int k3_j72xx_bandgap_probe(struct platform_device *pdev)
                goto err_free_ref_table;
        }
 
-       /* Workaround not needed if bit30/bit31 is set even for J721e */
-       if (workaround_needed && (readl(bgp->fuse_base + 0x0) & 0xc0000000) == 0xc0000000)
-               workaround_needed = false;
-
-       dev_dbg(bgp->dev, "Work around %sneeded\n",
-               workaround_needed ? "not " : "");
-
        if (!workaround_needed)
                init_table(5, ref_table, golden_factors);
        else
@@ -459,7 +462,7 @@ static int k3_j72xx_bandgap_probe(struct platform_device *pdev)
                        err_vals.refs[1] = PLUS30CREF;
                        err_vals.refs[2] = PLUS125CREF;
                        err_vals.refs[3] = PLUS150CREF;
-                       get_efuse_values(id, &data[id], err_vals.errs, bgp);
+                       get_efuse_values(id, &data[id], err_vals.errs, fuse_base);
                }
 
                if (id == 0 && workaround_needed)
@@ -529,11 +532,11 @@ static int k3_j72xx_bandgap_remove(struct platform_device *pdev)
 }
 
 static const struct k3_j72xx_bandgap_data k3_j72xx_bandgap_j721e_data = {
-       .has_errata_i2128 = 1,
+       .has_errata_i2128 = true,
 };
 
 static const struct k3_j72xx_bandgap_data k3_j72xx_bandgap_j7200_data = {
-       .has_errata_i2128 = 0,
+       .has_errata_i2128 = false,
 };
 
 static const struct of_device_id of_k3_j72xx_bandgap_match[] = {
index d3d9b9f..4122a51 100644 (file)
@@ -45,7 +45,7 @@ static irqreturn_t lmh_handle_irq(int hw_irq, void *data)
        if (irq)
                generic_handle_irq(irq);
 
-       return 0;
+       return IRQ_HANDLED;
 }
 
 static void lmh_enable_interrupt(struct irq_data *d)
index 1b2c43e..ff47fc9 100644 (file)
@@ -678,7 +678,7 @@ static int adc_tm5_register_tzd(struct adc_tm5_chip *adc_tm)
                                                    &adc_tm5_thermal_ops);
                if (IS_ERR(tzd)) {
                        if (PTR_ERR(tzd) == -ENODEV) {
-                               dev_warn(adc_tm->dev, "thermal sensor on channel %d is not used\n",
+                               dev_dbg(adc_tm->dev, "thermal sensor on channel %d is not used\n",
                                         adc_tm->channels[i].channel);
                                continue;
                        }
@@ -1030,10 +1030,8 @@ static int adc_tm5_probe(struct platform_device *pdev)
                return irq;
 
        ret = adc_tm5_get_dt_data(adc_tm, node);
-       if (ret) {
-               dev_err(dev, "get dt data failed: %d\n", ret);
-               return ret;
-       }
+       if (ret)
+               return dev_err_probe(dev, ret, "get dt data failed\n");
 
        ret = adc_tm->data->init(adc_tm);
        if (ret) {
index be785ab..ad84978 100644 (file)
@@ -252,7 +252,8 @@ static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip,
                        disable_s2_shutdown = true;
                else
                        dev_warn(chip->dev,
-                                "No ADC is configured and critical temperature is above the maximum stage 2 threshold of 140 C! Configuring stage 2 shutdown at 140 C.\n");
+                                "No ADC is configured and critical temperature %d mC is above the maximum stage 2 threshold of %ld mC! Configuring stage 2 shutdown at %ld mC.\n",
+                                temp, stage2_threshold_max, stage2_threshold_max);
        }
 
 skip:
index 67c1748..4585904 100644 (file)
@@ -269,9 +269,12 @@ static const struct tsens_ops ops_8960 = {
 static struct tsens_features tsens_8960_feat = {
        .ver_major      = VER_0,
        .crit_int       = 0,
+       .combo_int      = 0,
        .adc            = 1,
        .srot_split     = 0,
        .max_sensors    = 11,
+       .trip_min_temp  = -40000,
+       .trip_max_temp  = 120000,
 };
 
 struct tsens_plat_data data_8960 = {
index 327f372..04d012e 100644 (file)
@@ -539,9 +539,12 @@ static int calibrate_9607(struct tsens_priv *priv)
 static struct tsens_features tsens_v0_1_feat = {
        .ver_major      = VER_0_1,
        .crit_int       = 0,
+       .combo_int      = 0,
        .adc            = 1,
        .srot_split     = 1,
        .max_sensors    = 11,
+       .trip_min_temp  = -40000,
+       .trip_max_temp  = 120000,
 };
 
 static const struct reg_field tsens_v0_1_regfields[MAX_REGFIELDS] = {
index 573e261..1d7f8a8 100644 (file)
@@ -302,9 +302,12 @@ static int calibrate_8976(struct tsens_priv *priv)
 static struct tsens_features tsens_v1_feat = {
        .ver_major      = VER_1_X,
        .crit_int       = 0,
+       .combo_int      = 0,
        .adc            = 1,
        .srot_split     = 1,
        .max_sensors    = 11,
+       .trip_min_temp  = -40000,
+       .trip_max_temp  = 120000,
 };
 
 static const struct reg_field tsens_v1_regfields[MAX_REGFIELDS] = {
index b293ed3..29a61d2 100644 (file)
 static struct tsens_features tsens_v2_feat = {
        .ver_major      = VER_2_X,
        .crit_int       = 1,
+       .combo_int      = 0,
        .adc            = 0,
        .srot_split     = 1,
        .max_sensors    = 16,
+       .trip_min_temp  = -40000,
+       .trip_max_temp  = 120000,
+};
+
+static struct tsens_features ipq8074_feat = {
+       .ver_major      = VER_2_X,
+       .crit_int       = 1,
+       .combo_int      = 1,
+       .adc            = 0,
+       .srot_split     = 1,
+       .max_sensors    = 16,
+       .trip_min_temp  = 0,
+       .trip_max_temp  = 204000,
 };
 
 static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
@@ -101,6 +115,12 @@ struct tsens_plat_data data_tsens_v2 = {
        .fields = tsens_v2_regfields,
 };
 
+struct tsens_plat_data data_ipq8074 = {
+       .ops            = &ops_generic_v2,
+       .feat           = &ipq8074_feat,
+       .fields = tsens_v2_regfields,
+};
+
 /* Kept around for backward compatibility with old msm8996.dtsi */
 struct tsens_plat_data data_8996 = {
        .num_sensors    = 13,
index b1b1000..b5b136f 100644 (file)
@@ -532,6 +532,27 @@ static irqreturn_t tsens_irq_thread(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+/**
+ * tsens_combined_irq_thread() - Threaded interrupt handler for combined interrupts
+ * @irq: irq number
+ * @data: tsens controller private data
+ *
+ * Handle the combined interrupt as if it were 2 separate interrupts, so call the
+ * critical handler first and then the up/low one.
+ *
+ * Return: IRQ_HANDLED
+ */
+static irqreturn_t tsens_combined_irq_thread(int irq, void *data)
+{
+       irqreturn_t ret;
+
+       ret = tsens_critical_irq_thread(irq, data);
+       if (ret != IRQ_HANDLED)
+               return ret;
+
+       return tsens_irq_thread(irq, data);
+}
+
 static int tsens_set_trips(struct thermal_zone_device *tz, int low, int high)
 {
        struct tsens_sensor *s = tz->devdata;
@@ -552,8 +573,8 @@ static int tsens_set_trips(struct thermal_zone_device *tz, int low, int high)
        dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
                hw_id, __func__, low, high);
 
-       cl_high = clamp_val(high, -40000, 120000);
-       cl_low  = clamp_val(low, -40000, 120000);
+       cl_high = clamp_val(high, priv->feat->trip_min_temp, priv->feat->trip_max_temp);
+       cl_low  = clamp_val(low, priv->feat->trip_min_temp, priv->feat->trip_max_temp);
 
        high_val = tsens_mC_to_hw(s, cl_high);
        low_val  = tsens_mC_to_hw(s, cl_low);
@@ -692,7 +713,7 @@ static int dbg_version_show(struct seq_file *s, void *data)
                        return ret;
                seq_printf(s, "%d.%d.%d\n", maj_ver, min_ver, step_ver);
        } else {
-               seq_puts(s, "0.1.0\n");
+               seq_printf(s, "0.%d.0\n", priv->feat->ver_major);
        }
 
        return 0;
@@ -704,21 +725,14 @@ DEFINE_SHOW_ATTRIBUTE(dbg_sensors);
 static void tsens_debug_init(struct platform_device *pdev)
 {
        struct tsens_priv *priv = platform_get_drvdata(pdev);
-       struct dentry *root, *file;
 
-       root = debugfs_lookup("tsens", NULL);
-       if (!root)
+       priv->debug_root = debugfs_lookup("tsens", NULL);
+       if (!priv->debug_root)
                priv->debug_root = debugfs_create_dir("tsens", NULL);
-       else
-               priv->debug_root = root;
-
-       file = debugfs_lookup("version", priv->debug_root);
-       if (!file)
-               debugfs_create_file("version", 0444, priv->debug_root,
-                                   pdev, &dbg_version_fops);
 
        /* A directory for each instance of the TSENS IP */
        priv->debug = debugfs_create_dir(dev_name(&pdev->dev), priv->debug_root);
+       debugfs_create_file("version", 0444, priv->debug, pdev, &dbg_version_fops);
        debugfs_create_file("sensors", 0444, priv->debug, pdev, &dbg_sensors_fops);
 }
 #else
@@ -918,8 +932,6 @@ int __init init_common(struct tsens_priv *priv)
        if (tsens_version(priv) >= VER_0_1)
                tsens_enable_irq(priv);
 
-       tsens_debug_init(op);
-
 err_put_device:
        put_device(&op->dev);
        return ret;
@@ -960,6 +972,9 @@ static const struct of_device_id tsens_table[] = {
                .compatible = "qcom,ipq8064-tsens",
                .data = &data_8960,
        }, {
+               .compatible = "qcom,ipq8074-tsens",
+               .data = &data_ipq8074,
+       }, {
                .compatible = "qcom,mdm9607-tsens",
                .data = &data_9607,
        }, {
@@ -1071,13 +1086,18 @@ static int tsens_register(struct tsens_priv *priv)
                                   tsens_mC_to_hw(priv->sensor, 0));
        }
 
-       ret = tsens_register_irq(priv, "uplow", tsens_irq_thread);
-       if (ret < 0)
-               return ret;
+       if (priv->feat->combo_int) {
+               ret = tsens_register_irq(priv, "combined",
+                                        tsens_combined_irq_thread);
+       } else {
+               ret = tsens_register_irq(priv, "uplow", tsens_irq_thread);
+               if (ret < 0)
+                       return ret;
 
-       if (priv->feat->crit_int)
-               ret = tsens_register_irq(priv, "critical",
-                                        tsens_critical_irq_thread);
+               if (priv->feat->crit_int)
+                       ret = tsens_register_irq(priv, "critical",
+                                                tsens_critical_irq_thread);
+       }
 
        return ret;
 }
@@ -1153,7 +1173,11 @@ static int tsens_probe(struct platform_device *pdev)
                }
        }
 
-       return tsens_register(priv);
+       ret = tsens_register(priv);
+       if (!ret)
+               tsens_debug_init(pdev);
+
+       return ret;
 }
 
 static int tsens_remove(struct platform_device *pdev)
index ba05c82..899af12 100644 (file)
@@ -493,19 +493,25 @@ enum regfield_ids {
  * struct tsens_features - Features supported by the IP
  * @ver_major: Major number of IP version
  * @crit_int: does the IP support critical interrupts?
+ * @combo_int: does the IP use one IRQ for up, low and critical thresholds?
  * @adc:      do the sensors only output adc code (instead of temperature)?
  * @srot_split: does the IP neatly splits the register space into SROT and TM,
  *              with SROT only being available to secure boot firmware?
  * @has_watchdog: does this IP support watchdog functionality?
  * @max_sensors: maximum sensors supported by this version of the IP
+ * @trip_min_temp: minimum trip temperature supported by this version of the IP
+ * @trip_max_temp: maximum trip temperature supported by this version of the IP
  */
 struct tsens_features {
        unsigned int ver_major;
        unsigned int crit_int:1;
+       unsigned int combo_int:1;
        unsigned int adc:1;
        unsigned int srot_split:1;
        unsigned int has_watchdog:1;
        unsigned int max_sensors;
+       int trip_min_temp;
+       int trip_max_temp;
 };
 
 /**
@@ -591,6 +597,6 @@ extern struct tsens_plat_data data_8916, data_8939, data_8974, data_9607;
 extern struct tsens_plat_data data_tsens_v1, data_8976;
 
 /* TSENS v2 targets */
-extern struct tsens_plat_data data_8996, data_tsens_v2;
+extern struct tsens_plat_data data_8996, data_ipq8074, data_tsens_v2;
 
 #endif /* __QCOM_TSENS_H__ */
index 78feb80..e7834cc 100644 (file)
@@ -488,7 +488,6 @@ MODULE_DEVICE_TABLE(of, stm_thermal_of_match);
 static int stm_thermal_probe(struct platform_device *pdev)
 {
        struct stm_thermal_sensor *sensor;
-       struct resource *res;
        void __iomem *base;
        int ret;
 
@@ -506,8 +505,7 @@ static int stm_thermal_probe(struct platform_device *pdev)
 
        sensor->dev = &pdev->dev;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(&pdev->dev, res);
+       base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
index d4b6335..aacba30 100644 (file)
@@ -604,13 +604,15 @@ struct thermal_zone_device *thermal_of_zone_register(struct device_node *sensor,
        if (IS_ERR(np)) {
                if (PTR_ERR(np) != -ENODEV)
                        pr_err("Failed to find thermal zone for %pOFn id=%d\n", sensor, id);
-               return ERR_CAST(np);
+               ret = PTR_ERR(np);
+               goto out_kfree_of_ops;
        }
 
        trips = thermal_of_trips_init(np, &ntrips);
        if (IS_ERR(trips)) {
                pr_err("Failed to find trip points for %pOFn id=%d\n", sensor, id);
-               return ERR_CAST(trips);
+               ret = PTR_ERR(trips);
+               goto out_kfree_of_ops;
        }
 
        ret = thermal_of_monitor_init(np, &delay, &pdelay);
@@ -659,6 +661,8 @@ out_kfree_tzp:
        kfree(tzp);
 out_kfree_trips:
        kfree(trips);
+out_kfree_of_ops:
+       kfree(of_ops);
 
        return ERR_PTR(ret);
 }
index 67050a1..a1c9a15 100644 (file)
@@ -878,7 +878,7 @@ static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev)
  */
 static const struct soc_device_attribute soc_no_cpu_notifier[] = {
        { .machine = "OMAP4430" },
-       { /* sentinel */ },
+       { /* sentinel */ }
 };
 
 /***   Device driver call backs   ***/