Commit 601c1aa8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'thermal-6.2-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull more thermal control updates from Rafael Wysocki:
 "These are updates of assorted thermal drivers, mostly for ARM
  platforms, generally isolated and fairly straightforward, and the
  recent Intel HFI driver fix for systems without HFI support.

  Specifics:

   - Avoid clearing the HFI status bit on systems without HFI support
     which triggers unchecked MSR access errors (Srinivas Pandruvada)

   - Add sm8450 and sm8550 QCom compatible string to DT bindings (Luca
     Weiss, Neil Armstrong)

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

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

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

   - Fix debug print message with inverted logic in the k3_j72xx_bandgap
     driver (Keerthy)

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

   - Add support for IPQ8074 in the tsens thermal 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 HWMon support for the imx8mm board (Alexander Stein)

   - Remove pointless include from 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 in the tsens
     QCom driver (Manivannan Sadhasivam)

   - Consolidate the the efuse values and the errata handling in the TI
     Bandgap driver (Bryan Brattlof)

   - Document 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 empty platform remove callback from imx_sc_thermal (Uwe
     Kleine-König)"

* tag 'thermal-6.2-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (35 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
  ...
parents c0f234ff bd7bcc4f
# 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>;
};
...
......@@ -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
......
......@@ -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
......
......@@ -58,8 +58,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
......@@ -67,15 +73,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
......@@ -129,22 +131,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
......@@ -227,4 +271,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>;
};
...
......@@ -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
......
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>;
};
};
};
};
......@@ -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
......
......@@ -8,7 +8,6 @@
#define pr_fmt(fmt) "Power allocator: " fmt
#include <linux/rculist.h>
#include <linux/slab.h>
#include <linux/thermal.h>
......
......@@ -10,21 +10,40 @@
#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)
......@@ -32,6 +51,25 @@
#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);
......
......@@ -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,
......
......@@ -194,7 +194,7 @@ static const struct attribute_group thermal_attr_group = {
#define THERM_STATUS_PROCHOT_LOG BIT(1)
#define THERM_STATUS_CLEAR_CORE_MASK (BIT(1) | BIT(3) | BIT(5) | BIT(7) | BIT(9) | BIT(11) | BIT(13) | BIT(15))
#define THERM_STATUS_CLEAR_PKG_MASK (BIT(1) | BIT(3) | BIT(5) | BIT(7) | BIT(9) | BIT(11) | BIT(26))
#define THERM_STATUS_CLEAR_PKG_MASK (BIT(1) | BIT(3) | BIT(5) | BIT(7) | BIT(9) | BIT(11))
/*
* Clear the bits in package thermal status register for bit = 1
......@@ -211,6 +211,9 @@ void thermal_clear_package_intr_status(int level, u64 bit_mask)
} else {
msr = MSR_IA32_PACKAGE_THERM_STATUS;
msr_val = THERM_STATUS_CLEAR_PKG_MASK;
if (boot_cpu_has(X86_FEATURE_HFI))
msr_val |= BIT(26);
}
msr_val &= ~bit_mask;
......
......@@ -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[] = {
......
......@@ -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)
......
......@@ -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) {
......
......@@ -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:
......
......@@ -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 = {
......
......@@ -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] = {
......
......@@ -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] = {
......
......@@ -31,9 +31,23 @@
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,
......
......@@ -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;
......@@ -959,6 +971,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)
......
......@@ -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__ */
......@@ -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);
......
......@@ -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 @@ struct thermal_zone_device *thermal_of_zone_register(struct device_node *sensor,
kfree(tzp);
out_kfree_trips:
kfree(trips);
out_kfree_of_ops:
kfree(of_ops);
return ERR_PTR(ret);
}
......
......@@ -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 ***/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment