Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

Pull thermal control updates from Rafael Wysocki:
"These are mostly thermal driver updates, including new thermal drivers
for Renesas RZ/G3S and Renesas RZ/G3E SoCs, a new power slider
platform feature support in the Intel int340x thermal driver, a new
Tegra114- specific SOCTHERM driver and more.

There is also a Step-wise thermal governor update allowing it to start
reducing cooling somewhat earlier if the temperature of the given
thermal zone is falling down and a thermal testing code cleanup.

Specifics:

- Add new thermal driver for the Renesas RZ/G3S SoC (Claudiu Beznea)

- Add new thermal driver for the Renesas RZ/G3E SoC (John Madieu)

- Add support for new platform power slider feature to the Intel
int340x driver (Srinivas Pandruvada).

- Add new Tegra114-specific SOCTHERM driver and document Tegra114
SOCTHERM Thermal Management System in DT bindings (Svyatoslav
Ryhel)

- Add temperature sensor channel to thermal-generic-adc (Svyatoslav
Ryhel)

- Add support for per-SoC default trim values to the Renesas
rcar_gen3 thermal driver, use it for adding R-Car V4H default trim
values, fix a comment typo in that driver and document Gen4 support
in its Kconfig entry (Marek Vasut)

- Fix mapping SoCs to generic Gen4 entry in the Renesas rcar_gen3
thermal driver (Wolfram Sang)

- Document the TSU unit in the r9a08g045-tsu and r9a09g047-tsu DT
bindings (Claudiu Beznea, John Madieu)

- Make LMH select QCOM_SCM and add missing IRQ includes to the
qcom/lmh thermal driver (Dmitry Baryshkov)

- Fix incorrect error message in the qcom/lmh thermal driver (Sumeet
Pawnikar)

- Add QCS615 compatible to tsens thermal DT bindings (Gaurav Kohli)

- Document the Glymur temperature sensor in qcom-tsens thermal DT
bindings (Manaf Meethalavalappu Pallikunhi)

- Make k3_j72xx_bandgap thermal driver register the thermal sensor
with hwmon (Michael Walle)

- Tighten GRF requirements in the rockchip thermal DT bindings,
silence a GRF warning in the rockchip thermal driver and unify
struct rockchip_tsadc_chip format in it (Sebastian Reichel)

- Update the Step-wise thermal governor to allow it to reduce the
cooling level earlier if thermal zone temperature is dropping and
clean it up (Rafael Wysocki)

- Clean up the thermal testing code (Rafael Wysocki)

- Assorted cleanups of thermal drivers (Jiapeng Chong, Salah Triki,
Osama Abdelkader)"

* tag 'thermal-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (37 commits)
thermal/drivers/renesas/rzg3e: Fix add thermal driver for the Renesas RZ/G3E SoC
dt-bindings: thermal: qcom-tsens: Document the Glymur temperature Sensor
thermal/drivers/renesas/rzg3e: Add thermal driver for the Renesas RZ/G3E SoC
dt-bindings: thermal: r9a09g047-tsu: Document the TSU unit
thermal/drivers/thermal-generic-adc: Add temperature sensor channel
dt-bindings: thermal: rockchip: Tighten grf requirements
thermal/drivers/rockchip: Shut up GRF warning
thermal/drivers/rockchip: Unify struct rockchip_tsadc_chip format
thermal/drivers/renesas/rzg3s: Add thermal driver for the Renesas RZ/G3S SoC
dt-bindings: thermal: r9a08g045-tsu: Document the TSU unit
thermal/drivers/k3_j72xx_bandgap: Register sensors with hwmon
thermal/drivers/rcar_gen3: Fix mapping SoCs to generic Gen4 entry
thermal/drivers/tegra: Add Tegra114 specific SOCTHERM driver
dt-bindings: thermal: add Tegra114 soctherm header
thermal/drivers/tegra/soctherm-fuse: Prepare calibration for Tegra114 support
dt-bindings: thermal: Document Tegra114 SOCTHERM Thermal Management System
thermal/drivers/rcar_gen3: Document Gen4 support in Kconfig entry
thermal/drivers/rcar_gen3: Fix comment typo
drivers/thermal/qcom/lmh: Fix incorrect error message
thermal/drivers/qcom/lmh: Add missing IRQ includes
...

+1804 -94
+2
Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.yaml
··· 18 18 properties: 19 19 compatible: 20 20 enum: 21 + - nvidia,tegra114-soctherm 21 22 - nvidia,tegra124-soctherm 22 23 - nvidia,tegra132-soctherm 23 24 - nvidia,tegra210-soctherm ··· 207 206 compatible: 208 207 contains: 209 208 enum: 209 + - nvidia,tegra114-soctherm 210 210 - nvidia,tegra124-soctherm 211 211 - nvidia,tegra210-soctherm 212 212 - nvidia,tegra210b01-soctherm
+2
Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
··· 49 49 - description: v2 of TSENS 50 50 items: 51 51 - enum: 52 + - qcom,glymur-tsens 52 53 - qcom,milos-tsens 53 54 - qcom,msm8953-tsens 54 55 - qcom,msm8996-tsens 55 56 - qcom,msm8998-tsens 56 57 - qcom,qcm2290-tsens 58 + - qcom,qcs615-tsens 57 59 - qcom,sa8255p-tsens 58 60 - qcom,sa8775p-tsens 59 61 - qcom,sar2130p-tsens
+93
Documentation/devicetree/bindings/thermal/renesas,r9a08g045-tsu.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/thermal/renesas,r9a08g045-tsu.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Renesas RZ/G3S Thermal Sensor Unit 8 + 9 + description: 10 + The thermal sensor unit (TSU) measures the temperature(Tj) inside 11 + the LSI. 12 + 13 + maintainers: 14 + - Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> 15 + 16 + $ref: thermal-sensor.yaml# 17 + 18 + properties: 19 + compatible: 20 + const: renesas,r9a08g045-tsu 21 + 22 + reg: 23 + maxItems: 1 24 + 25 + clocks: 26 + items: 27 + - description: TSU module clock 28 + 29 + power-domains: 30 + maxItems: 1 31 + 32 + resets: 33 + items: 34 + - description: TSU module reset 35 + 36 + io-channels: 37 + items: 38 + - description: ADC channel which reports the TSU temperature 39 + 40 + io-channel-names: 41 + items: 42 + - const: tsu 43 + 44 + "#thermal-sensor-cells": 45 + const: 0 46 + 47 + required: 48 + - compatible 49 + - reg 50 + - clocks 51 + - power-domains 52 + - resets 53 + - io-channels 54 + - io-channel-names 55 + - '#thermal-sensor-cells' 56 + 57 + additionalProperties: false 58 + 59 + examples: 60 + - | 61 + #include <dt-bindings/clock/r9a08g045-cpg.h> 62 + 63 + tsu: thermal@10059000 { 64 + compatible = "renesas,r9a08g045-tsu"; 65 + reg = <0x10059000 0x1000>; 66 + clocks = <&cpg CPG_MOD R9A08G045_TSU_PCLK>; 67 + resets = <&cpg R9A08G045_TSU_PRESETN>; 68 + power-domains = <&cpg>; 69 + #thermal-sensor-cells = <0>; 70 + io-channels = <&adc 8>; 71 + io-channel-names = "tsu"; 72 + }; 73 + 74 + thermal-zones { 75 + cpu-thermal { 76 + polling-delay-passive = <250>; 77 + polling-delay = <1000>; 78 + thermal-sensors = <&tsu>; 79 + 80 + trips { 81 + sensor_crit: sensor-crit { 82 + temperature = <125000>; 83 + hysteresis = <1000>; 84 + type = "critical"; 85 + }; 86 + target: trip-point { 87 + temperature = <100000>; 88 + hysteresis = <1000>; 89 + type = "passive"; 90 + }; 91 + }; 92 + }; 93 + };
+87
Documentation/devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/thermal/renesas,r9a09g047-tsu.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Renesas RZ/G3E Temperature Sensor Unit (TSU) 8 + 9 + maintainers: 10 + - John Madieu <john.madieu.xa@bp.renesas.com> 11 + 12 + description: 13 + The Temperature Sensor Unit (TSU) is an integrated thermal sensor that 14 + monitors the chip temperature on the Renesas RZ/G3E SoC. The TSU provides 15 + real-time temperature measurements for thermal management. 16 + 17 + properties: 18 + compatible: 19 + const: renesas,r9a09g047-tsu 20 + 21 + reg: 22 + maxItems: 1 23 + 24 + clocks: 25 + maxItems: 1 26 + 27 + resets: 28 + maxItems: 1 29 + 30 + power-domains: 31 + maxItems: 1 32 + 33 + interrupts: 34 + items: 35 + - description: Conversion complete interrupt signal (pulse) 36 + - description: Comparison result interrupt signal (level) 37 + 38 + interrupt-names: 39 + items: 40 + - const: adi 41 + - const: adcmpi 42 + 43 + "#thermal-sensor-cells": 44 + const: 0 45 + 46 + renesas,tsu-trim: 47 + $ref: /schemas/types.yaml#/definitions/phandle-array 48 + items: 49 + - items: 50 + - description: phandle to system controller 51 + - description: offset of trim registers 52 + description: 53 + Phandle and offset to the system controller containing the TSU 54 + calibration trim values. The offset points to the first trim register 55 + (OTPTSU1TRMVAL0), with the second trim register (OTPTSU1TRMVAL1) located 56 + at offset + 4. 57 + 58 + required: 59 + - compatible 60 + - reg 61 + - clocks 62 + - resets 63 + - power-domains 64 + - interrupts 65 + - interrupt-names 66 + - "#thermal-sensor-cells" 67 + - renesas,tsu-trim 68 + 69 + additionalProperties: false 70 + 71 + examples: 72 + - | 73 + #include <dt-bindings/clock/renesas,r9a09g047-cpg.h> 74 + #include <dt-bindings/interrupt-controller/arm-gic.h> 75 + 76 + thermal-sensor@14002000 { 77 + compatible = "renesas,r9a09g047-tsu"; 78 + reg = <0x14002000 0x1000>; 79 + clocks = <&cpg CPG_MOD 0x10a>; 80 + resets = <&cpg 0xf8>; 81 + power-domains = <&cpg>; 82 + interrupts = <GIC_SPI 250 IRQ_TYPE_EDGE_RISING>, 83 + <GIC_SPI 251 IRQ_TYPE_LEVEL_HIGH>; 84 + interrupt-names = "adi", "adcmpi"; 85 + #thermal-sensor-cells = <0>; 86 + renesas,tsu-trim = <&sys 0x330>; 87 + };
+15
Documentation/devicetree/bindings/thermal/rockchip-thermal.yaml
··· 120 120 121 121 allOf: 122 122 - if: 123 + properties: 124 + compatible: 125 + contains: 126 + enum: 127 + - rockchip,px30-tsadc 128 + - rockchip,rk3366-tsadc 129 + - rockchip,rk3399-tsadc 130 + - rockchip,rk3568-tsadc 131 + then: 132 + required: 133 + - rockchip,grf 134 + else: 135 + properties: 136 + rockchip,grf: false 137 + - if: 123 138 not: 124 139 properties: 125 140 compatible:
+14
MAINTAINERS
··· 21701 21701 F: Documentation/devicetree/bindings/iio/potentiometer/renesas,x9250.yaml 21702 21702 F: drivers/iio/potentiometer/x9250.c 21703 21703 21704 + RENESAS RZ/G3S THERMAL SENSOR UNIT DRIVER 21705 + M: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> 21706 + L: linux-pm@vger.kernel.org 21707 + S: Maintained 21708 + F: Documentation/devicetree/bindings/thermal/renesas,r9a08g045-tsu.yaml 21709 + F: drivers/thermal/renesas/rzg3s_thermal.c 21710 + 21711 + RENESAS RZ/G3E THERMAL SENSOR UNIT DRIVER 21712 + M: John Madieu <john.madieu.xa@bp.renesas.com> 21713 + L: linux-pm@vger.kernel.org 21714 + S: Maintained 21715 + F: Documentation/devicetree/bindings/thermal/renesas,r9a09g047-tsu.yaml 21716 + F: drivers/thermal/renesas/rzg3e_thermal.c 21717 + 21704 21718 RESET CONTROLLER FRAMEWORK 21705 21719 M: Philipp Zabel <p.zabel@pengutronix.de> 21706 21720 S: Maintained
+18 -7
drivers/thermal/gov_step_wise.c
··· 20 20 * If the temperature is higher than a trip point, 21 21 * a. if the trend is THERMAL_TREND_RAISING, use higher cooling 22 22 * state for this trip point 23 - * b. if the trend is THERMAL_TREND_DROPPING, do nothing 23 + * b. if the trend is THERMAL_TREND_DROPPING, use a lower cooling state 24 + * for this trip point, but keep the cooling state above the applicable 25 + * minimum 24 26 * If the temperature is lower than a trip point, 25 27 * a. if the trend is THERMAL_TREND_RAISING, do nothing 26 - * b. if the trend is THERMAL_TREND_DROPPING, use lower cooling 27 - * state for this trip point, if the cooling state already 28 + * b. if the trend is THERMAL_TREND_DROPPING, use the minimum applicable 29 + * cooling state for this trip point, or if the cooling state already 28 30 * equals lower limit, deactivate the thermal instance 29 31 */ 30 32 static unsigned long get_target_state(struct thermal_instance *instance, ··· 53 51 if (throttle) { 54 52 if (trend == THERMAL_TREND_RAISING) 55 53 return clamp(cur_state + 1, instance->lower, instance->upper); 54 + 55 + /* 56 + * If the zone temperature is falling, the cooling level can 57 + * be reduced, but it should still be above the lower state of 58 + * the given thermal instance to pull the temperature further 59 + * down. 60 + */ 61 + if (trend == THERMAL_TREND_DROPPING) 62 + return clamp(cur_state - 1, 63 + min(instance->lower + 1, instance->upper), 64 + instance->upper); 56 65 } else if (trend == THERMAL_TREND_DROPPING) { 57 66 if (cur_state <= instance->lower) 58 67 return THERMAL_NO_TARGET; ··· 82 69 const struct thermal_trip_desc *td, 83 70 int trip_threshold) 84 71 { 72 + bool throttle = tz->temperature >= trip_threshold; 85 73 const struct thermal_trip *trip = &td->trip; 86 74 enum thermal_trend trend = get_tz_trend(tz, trip); 87 75 int trip_id = thermal_zone_trip_id(tz, trip); 88 76 struct thermal_instance *instance; 89 - bool throttle = false; 90 77 91 - if (tz->temperature >= trip_threshold) { 92 - throttle = true; 78 + if (throttle) 93 79 trace_thermal_zone_trip(tz, trip_id, trip->type); 94 - } 95 80 96 81 dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n", 97 82 trip_id, trip->type, trip_threshold, trend, throttle);
+1
drivers/thermal/intel/int340x_thermal/Kconfig
··· 12 12 select ACPI_THERMAL_LIB 13 13 select INTEL_SOC_DTS_IOSF_CORE 14 14 select INTEL_TCC 15 + select ACPI_PLATFORM_PROFILE 15 16 select PROC_THERMAL_MMIO_RAPL if POWERCAP 16 17 help 17 18 Newer laptops and tablets that use ACPI may have thermal sensors and
+1
drivers/thermal/intel/int340x_thermal/Makefile
··· 14 14 obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_wt_req.o 15 15 obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_wt_hint.o 16 16 obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_power_floor.o 17 + obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_soc_slider.o 17 18 obj-$(CONFIG_INT3406_THERMAL) += int3406_thermal.o 18 19 obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o
-3
drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c
··· 220 220 int i, result = 0; 221 221 struct psvt *psvts; 222 222 223 - if (!acpi_has_method(handle, "PSVT")) 224 - return -ENODEV; 225 - 226 223 status = acpi_evaluate_object(handle, "PSVT", NULL, &buffer); 227 224 if (ACPI_FAILURE(status)) 228 225 return -ENODEV;
+20
drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
··· 338 338 339 339 int proc_thermal_suspend(struct device *dev) 340 340 { 341 + struct proc_thermal_device *proc_dev; 342 + 341 343 tcc_offset_save = intel_tcc_get_offset(-1); 342 344 if (tcc_offset_save < 0) 343 345 dev_warn(dev, "failed to save offset (%d)\n", tcc_offset_save); 346 + 347 + proc_dev = dev_get_drvdata(dev); 348 + 349 + if (proc_dev->mmio_feature_mask & PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) 350 + proc_thermal_soc_power_slider_suspend(proc_dev); 344 351 345 352 return 0; 346 353 } ··· 363 356 /* Do not update if saving failed */ 364 357 if (tcc_offset_save >= 0) 365 358 intel_tcc_set_offset(-1, tcc_offset_save); 359 + 360 + if (proc_dev->mmio_feature_mask & PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) 361 + proc_thermal_soc_power_slider_resume(proc_dev); 366 362 367 363 return 0; 368 364 } ··· 442 432 } 443 433 } 444 434 435 + if (feature_mask & PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) { 436 + ret = proc_thermal_soc_power_slider_add(pdev, proc_priv); 437 + if (ret) { 438 + dev_info(&pdev->dev, "failed to add soc power efficiency slider\n"); 439 + goto err_rem_wlt; 440 + } 441 + } 442 + 445 443 return 0; 446 444 445 + err_rem_wlt: 446 + proc_thermal_wt_hint_remove(pdev); 447 447 err_rem_rfim: 448 448 proc_thermal_rfim_remove(pdev); 449 449 err_rem_ptc:
+6
drivers/thermal/intel/int340x_thermal/processor_thermal_device.h
··· 69 69 #define PROC_THERMAL_FEATURE_POWER_FLOOR 0x40 70 70 #define PROC_THERMAL_FEATURE_MSI_SUPPORT 0x80 71 71 #define PROC_THERMAL_FEATURE_PTC 0x100 72 + #define PROC_THERMAL_FEATURE_SOC_POWER_SLIDER 0x200 72 73 73 74 #if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL) 74 75 int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); ··· 128 127 void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); 129 128 int proc_thermal_ptc_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); 130 129 void proc_thermal_ptc_remove(struct pci_dev *pdev); 130 + 131 + int proc_thermal_soc_power_slider_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); 132 + void proc_thermal_soc_power_slider_suspend(struct proc_thermal_device *proc_priv); 133 + void proc_thermal_soc_power_slider_resume(struct proc_thermal_device *proc_priv); 134 + 131 135 #endif
+2 -1
drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
··· 498 498 { PCI_DEVICE_DATA(INTEL, PTL_THERMAL, PROC_THERMAL_FEATURE_RAPL | 499 499 PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS | 500 500 PROC_THERMAL_FEATURE_MSI_SUPPORT | PROC_THERMAL_FEATURE_WT_HINT | 501 - PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC) }, 501 + PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC | 502 + PROC_THERMAL_FEATURE_SOC_POWER_SLIDER) }, 502 503 { PCI_DEVICE_DATA(INTEL, WCL_THERMAL, PROC_THERMAL_FEATURE_MSI_SUPPORT | 503 504 PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_DLVR | 504 505 PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_HINT |
+284
drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Processor Thermal Device Interface for Reading and Writing 4 + * SoC Power Slider Values from User Space. 5 + * 6 + * Operation: 7 + * The SOC_EFFICIENCY_SLIDER_0_0_0_MCHBAR register is accessed 8 + * using the MMIO (Memory-Mapped I/O) interface with an MMIO offset of 0x5B38. 9 + * Although this register is 64 bits wide, only bits 7:0 are used, 10 + * and the other bits remain unchanged. 11 + * 12 + * Bit definitions 13 + * 14 + * Bits 2:0 (Slider value): 15 + * The SoC optimizer slider value indicates the system wide energy performance 16 + * hint. The slider has no specific units and ranges from 0 (highest 17 + * performance) to 6 (highest energy efficiency). Value of 7 is reserved. 18 + * Bits 3 : Reserved 19 + * Bits 6:4 (Offset) 20 + * Offset allows the SoC to automatically switch slider position in range 21 + * [slider value (bits 2:0) + offset] to improve power efficiency based on 22 + * internal SoC algorithms. 23 + * Bit 7 (Enable): 24 + * If this bit is set, the SoC Optimization sliders will be processed by the 25 + * SoC firmware. 26 + * 27 + * Copyright (c) 2025, Intel Corporation. 28 + */ 29 + 30 + #include <linux/bitfield.h> 31 + #include <linux/pci.h> 32 + #include <linux/platform_profile.h> 33 + #include "processor_thermal_device.h" 34 + 35 + #define SOC_POWER_SLIDER_OFFSET 0x5B38 36 + 37 + enum power_slider_preference { 38 + SOC_POWER_SLIDER_PERFORMANCE, 39 + SOC_POWER_SLIDER_BALANCE, 40 + SOC_POWER_SLIDER_POWERSAVE, 41 + }; 42 + 43 + #define SOC_SLIDER_VALUE_MINIMUM 0x00 44 + #define SOC_SLIDER_VALUE_BALANCE 0x03 45 + #define SOC_SLIDER_VALUE_MAXIMUM 0x06 46 + 47 + #define SLIDER_MASK GENMASK_ULL(2, 0) 48 + #define SLIDER_ENABLE_BIT 7 49 + 50 + static u8 slider_values[] = { 51 + [SOC_POWER_SLIDER_PERFORMANCE] = SOC_SLIDER_VALUE_MINIMUM, 52 + [SOC_POWER_SLIDER_BALANCE] = SOC_SLIDER_VALUE_BALANCE, 53 + [SOC_POWER_SLIDER_POWERSAVE] = SOC_SLIDER_VALUE_MAXIMUM, 54 + }; 55 + 56 + /* Lock to protect module param updates */ 57 + static DEFINE_MUTEX(slider_param_lock); 58 + 59 + static int slider_balanced_param = SOC_SLIDER_VALUE_BALANCE; 60 + 61 + static int slider_def_balance_set(const char *arg, const struct kernel_param *kp) 62 + { 63 + u8 slider_val; 64 + int ret; 65 + 66 + guard(mutex)(&slider_param_lock); 67 + 68 + ret = kstrtou8(arg, 16, &slider_val); 69 + if (!ret) { 70 + if (slider_val <= slider_values[SOC_POWER_SLIDER_PERFORMANCE] || 71 + slider_val >= slider_values[SOC_POWER_SLIDER_POWERSAVE]) 72 + return -EINVAL; 73 + 74 + slider_balanced_param = slider_val; 75 + } 76 + 77 + return ret; 78 + } 79 + 80 + static int slider_def_balance_get(char *buf, const struct kernel_param *kp) 81 + { 82 + guard(mutex)(&slider_param_lock); 83 + return sysfs_emit(buf, "%02x\n", slider_values[SOC_POWER_SLIDER_BALANCE]); 84 + } 85 + 86 + static const struct kernel_param_ops slider_def_balance_ops = { 87 + .set = slider_def_balance_set, 88 + .get = slider_def_balance_get, 89 + }; 90 + 91 + module_param_cb(slider_balance, &slider_def_balance_ops, NULL, 0644); 92 + MODULE_PARM_DESC(slider_balance, "Set slider default value for balance"); 93 + 94 + static u8 slider_offset; 95 + 96 + static int slider_def_offset_set(const char *arg, const struct kernel_param *kp) 97 + { 98 + u8 offset; 99 + int ret; 100 + 101 + guard(mutex)(&slider_param_lock); 102 + 103 + ret = kstrtou8(arg, 16, &offset); 104 + if (!ret) { 105 + if (offset > SOC_SLIDER_VALUE_MAXIMUM) 106 + return -EINVAL; 107 + 108 + slider_offset = offset; 109 + } 110 + 111 + return ret; 112 + } 113 + 114 + static int slider_def_offset_get(char *buf, const struct kernel_param *kp) 115 + { 116 + guard(mutex)(&slider_param_lock); 117 + return sysfs_emit(buf, "%02x\n", slider_offset); 118 + } 119 + 120 + static const struct kernel_param_ops slider_offset_ops = { 121 + .set = slider_def_offset_set, 122 + .get = slider_def_offset_get, 123 + }; 124 + 125 + /* 126 + * To enhance power efficiency dynamically, the firmware can optionally 127 + * auto-adjust the slider value based on the current workload. This 128 + * adjustment is controlled by the "slider_offset" module parameter. 129 + * This offset permits the firmware to increase the slider value 130 + * up to and including "SoC slider + slider offset,". 131 + */ 132 + module_param_cb(slider_offset, &slider_offset_ops, NULL, 0644); 133 + MODULE_PARM_DESC(slider_offset, "Set slider offset"); 134 + 135 + /* Convert from platform power profile option to SoC slider value */ 136 + static int convert_profile_to_power_slider(enum platform_profile_option profile) 137 + { 138 + switch (profile) { 139 + case PLATFORM_PROFILE_LOW_POWER: 140 + return slider_values[SOC_POWER_SLIDER_POWERSAVE]; 141 + case PLATFORM_PROFILE_BALANCED: 142 + return slider_values[SOC_POWER_SLIDER_BALANCE]; 143 + case PLATFORM_PROFILE_PERFORMANCE: 144 + return slider_values[SOC_POWER_SLIDER_PERFORMANCE]; 145 + default: 146 + break; 147 + } 148 + 149 + return -EOPNOTSUPP; 150 + } 151 + 152 + /* Convert to platform power profile option from SoC slider values */ 153 + static int convert_power_slider_to_profile(u8 slider) 154 + { 155 + if (slider == slider_values[SOC_POWER_SLIDER_PERFORMANCE]) 156 + return PLATFORM_PROFILE_PERFORMANCE; 157 + if (slider == slider_values[SOC_POWER_SLIDER_BALANCE]) 158 + return PLATFORM_PROFILE_BALANCED; 159 + if (slider == slider_values[SOC_POWER_SLIDER_POWERSAVE]) 160 + return PLATFORM_PROFILE_LOW_POWER; 161 + 162 + return -EOPNOTSUPP; 163 + } 164 + 165 + static inline u64 read_soc_slider(struct proc_thermal_device *proc_priv) 166 + { 167 + return readq(proc_priv->mmio_base + SOC_POWER_SLIDER_OFFSET); 168 + } 169 + 170 + static inline void write_soc_slider(struct proc_thermal_device *proc_priv, u64 val) 171 + { 172 + writeq(val, proc_priv->mmio_base + SOC_POWER_SLIDER_OFFSET); 173 + } 174 + 175 + #define SLIDER_OFFSET_MASK GENMASK_ULL(6, 4) 176 + 177 + static void set_soc_power_profile(struct proc_thermal_device *proc_priv, int slider) 178 + { 179 + u64 val; 180 + 181 + val = read_soc_slider(proc_priv); 182 + val &= ~SLIDER_MASK; 183 + val |= FIELD_PREP(SLIDER_MASK, slider) | BIT(SLIDER_ENABLE_BIT); 184 + 185 + /* Set the slider offset from module params */ 186 + val &= ~SLIDER_OFFSET_MASK; 187 + val |= FIELD_PREP(SLIDER_OFFSET_MASK, slider_offset); 188 + 189 + write_soc_slider(proc_priv, val); 190 + } 191 + 192 + /* profile get/set callbacks are called with a profile lock, so no need for local locks */ 193 + 194 + static int power_slider_platform_profile_set(struct device *dev, 195 + enum platform_profile_option profile) 196 + { 197 + struct proc_thermal_device *proc_priv; 198 + int slider; 199 + 200 + proc_priv = dev_get_drvdata(dev); 201 + if (!proc_priv) 202 + return -EOPNOTSUPP; 203 + 204 + guard(mutex)(&slider_param_lock); 205 + 206 + slider_values[SOC_POWER_SLIDER_BALANCE] = slider_balanced_param; 207 + 208 + slider = convert_profile_to_power_slider(profile); 209 + if (slider < 0) 210 + return slider; 211 + 212 + set_soc_power_profile(proc_priv, slider); 213 + 214 + return 0; 215 + } 216 + 217 + static int power_slider_platform_profile_get(struct device *dev, 218 + enum platform_profile_option *profile) 219 + { 220 + struct proc_thermal_device *proc_priv; 221 + int slider, ret; 222 + u64 val; 223 + 224 + proc_priv = dev_get_drvdata(dev); 225 + if (!proc_priv) 226 + return -EOPNOTSUPP; 227 + 228 + val = read_soc_slider(proc_priv); 229 + slider = FIELD_GET(SLIDER_MASK, val); 230 + 231 + ret = convert_power_slider_to_profile(slider); 232 + if (ret < 0) 233 + return ret; 234 + 235 + *profile = ret; 236 + 237 + return 0; 238 + } 239 + 240 + static int power_slider_platform_profile_probe(void *drvdata, unsigned long *choices) 241 + { 242 + set_bit(PLATFORM_PROFILE_LOW_POWER, choices); 243 + set_bit(PLATFORM_PROFILE_BALANCED, choices); 244 + set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); 245 + 246 + return 0; 247 + } 248 + 249 + static const struct platform_profile_ops power_slider_platform_profile_ops = { 250 + .probe = power_slider_platform_profile_probe, 251 + .profile_get = power_slider_platform_profile_get, 252 + .profile_set = power_slider_platform_profile_set, 253 + }; 254 + 255 + int proc_thermal_soc_power_slider_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) 256 + { 257 + struct device *ppdev; 258 + 259 + set_soc_power_profile(proc_priv, slider_values[SOC_POWER_SLIDER_BALANCE]); 260 + 261 + ppdev = devm_platform_profile_register(&pdev->dev, "SoC Power Slider", proc_priv, 262 + &power_slider_platform_profile_ops); 263 + 264 + return PTR_ERR_OR_ZERO(ppdev); 265 + } 266 + EXPORT_SYMBOL_NS_GPL(proc_thermal_soc_power_slider_add, "INT340X_THERMAL"); 267 + 268 + static u64 soc_slider_save; 269 + 270 + void proc_thermal_soc_power_slider_suspend(struct proc_thermal_device *proc_priv) 271 + { 272 + soc_slider_save = read_soc_slider(proc_priv); 273 + } 274 + EXPORT_SYMBOL_NS_GPL(proc_thermal_soc_power_slider_suspend, "INT340X_THERMAL"); 275 + 276 + void proc_thermal_soc_power_slider_resume(struct proc_thermal_device *proc_priv) 277 + { 278 + write_soc_slider(proc_priv, soc_slider_save); 279 + } 280 + EXPORT_SYMBOL_NS_GPL(proc_thermal_soc_power_slider_resume, "INT340X_THERMAL"); 281 + 282 + MODULE_IMPORT_NS("INT340X_THERMAL"); 283 + MODULE_LICENSE("GPL"); 284 + MODULE_DESCRIPTION("Processor Thermal Power Slider Interface");
+4
drivers/thermal/k3_j72xx_bandgap.c
··· 20 20 #include <linux/delay.h> 21 21 #include <linux/slab.h> 22 22 23 + #include "thermal_hwmon.h" 24 + 23 25 #define K3_VTM_DEVINFO_PWR0_OFFSET 0x4 24 26 #define K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK 0xf0 25 27 #define K3_VTM_TMPSENS0_CTRL_OFFSET 0x300 ··· 515 513 ret = PTR_ERR(ti_thermal); 516 514 goto err_free_ref_table; 517 515 } 516 + 517 + devm_thermal_add_hwmon_sysfs(bgp->dev, ti_thermal); 518 518 } 519 519 520 520 platform_set_drvdata(pdev, bgp);
+1 -1
drivers/thermal/mediatek/lvts_thermal.c
··· 639 639 640 640 lvts_sensor[i].low_thresh = INT_MIN; 641 641 lvts_sensor[i].high_thresh = INT_MIN; 642 - }; 642 + } 643 643 644 644 lvts_ctrl->valid_sensor_mask = lvts_ctrl_data->valid_sensor_mask; 645 645
+2 -1
drivers/thermal/qcom/Kconfig
··· 34 34 35 35 config QCOM_LMH 36 36 tristate "Qualcomm Limits Management Hardware" 37 - depends on ARCH_QCOM && QCOM_SCM 37 + depends on ARCH_QCOM || COMPILE_TEST 38 + select QCOM_SCM 38 39 help 39 40 This enables initialization of Qualcomm limits management 40 41 hardware(LMh). LMh allows for hardware-enforced mitigation for cpus based on
+3 -1
drivers/thermal/qcom/lmh.c
··· 5 5 */ 6 6 #include <linux/module.h> 7 7 #include <linux/interrupt.h> 8 + #include <linux/irq.h> 9 + #include <linux/irqdesc.h> 8 10 #include <linux/irqdomain.h> 9 11 #include <linux/err.h> 10 12 #include <linux/platform_device.h> ··· 206 204 ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_THERMAL, LMH_TH_LOW_THRESHOLD, temp_low, 207 205 LMH_NODE_DCVS, node_id, 0); 208 206 if (ret) { 209 - dev_err(dev, "Error setting thermal ARM threshold%d\n", ret); 207 + dev_err(dev, "Error setting thermal LOW threshold%d\n", ret); 210 208 return ret; 211 209 } 212 210
+18 -3
drivers/thermal/renesas/Kconfig
··· 10 10 thermal framework. 11 11 12 12 config RCAR_GEN3_THERMAL 13 - tristate "Renesas R-Car Gen3 and RZ/G2 thermal driver" 13 + tristate "Renesas R-Car Gen3/Gen4 and RZ/G2 thermal driver" 14 14 depends on ARCH_RENESAS || COMPILE_TEST 15 15 depends on HAS_IOMEM 16 16 depends on OF 17 17 help 18 - Enable this to plug the R-Car Gen3 or RZ/G2 thermal sensor driver into 19 - the Linux thermal framework. 18 + Enable this to plug the R-Car Gen3/Gen4 or RZ/G2 thermal sensor 19 + driver into the Linux thermal framework. 20 20 21 21 config RZG2L_THERMAL 22 22 tristate "Renesas RZ/G2L thermal driver" ··· 25 25 depends on OF 26 26 help 27 27 Enable this to plug the RZ/G2L thermal sensor driver into the Linux 28 + thermal framework. 29 + 30 + config RZG3S_THERMAL 31 + tristate "Renesas RZ/G3S thermal driver" 32 + depends on ARCH_R9A08G045 || COMPILE_TEST 33 + depends on OF && IIO && RZG2L_ADC 34 + help 35 + Enable this to plug the RZ/G3S thermal sensor driver into the Linux 36 + thermal framework. 37 + 38 + config RZG3E_THERMAL 39 + tristate "Renesas RZ/G3E thermal driver" 40 + depends on ARCH_RENESAS || COMPILE_TEST 41 + help 42 + Enable this to plug the RZ/G3E thermal sensor driver into the Linux 28 43 thermal framework.
+3
drivers/thermal/renesas/Makefile
··· 3 3 obj-$(CONFIG_RCAR_GEN3_THERMAL) += rcar_gen3_thermal.o 4 4 obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o 5 5 obj-$(CONFIG_RZG2L_THERMAL) += rzg2l_thermal.o 6 + obj-$(CONFIG_RZG3E_THERMAL) += rzg3e_thermal.o 7 + obj-$(CONFIG_RZG3S_THERMAL) += rzg3s_thermal.o 8 +
+47 -16
drivers/thermal/renesas/rcar_gen3_thermal.c
··· 73 73 u32 mask; 74 74 }; 75 75 76 + struct rcar_gen3_thermal_fuse_default { 77 + u32 ptat[3]; 78 + u32 thcodes[TSC_MAX_NUM][3]; 79 + }; 80 + 76 81 struct rcar_thermal_info { 77 82 int scale; 78 83 int adj_below; 79 84 int adj_above; 80 85 const struct rcar_gen3_thermal_fuse_info *fuses; 86 + const struct rcar_gen3_thermal_fuse_default *fuse_defaults; 81 87 }; 82 88 83 89 struct equation_set_coef { ··· 171 165 const struct equation_set_coef *coef; 172 166 int adj, decicelsius, reg, thcode; 173 167 174 - /* Read register and convert to mili Celsius */ 168 + /* Read register and convert to millidegree Celsius */ 175 169 reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK; 176 170 177 171 if (reg < tsc->thcode[1]) { ··· 295 289 296 290 static bool rcar_gen3_thermal_read_fuses(struct rcar_gen3_thermal_priv *priv) 297 291 { 292 + const struct rcar_gen3_thermal_fuse_default *fuse_defaults = priv->info->fuse_defaults; 298 293 unsigned int i; 299 294 u32 thscp; 300 295 ··· 304 297 if (!priv->info->fuses || 305 298 (thscp & THSCP_COR_PARA_VLD) != THSCP_COR_PARA_VLD) { 306 299 /* Default THCODE values in case FUSEs are not set. */ 307 - static const int thcodes[TSC_MAX_NUM][3] = { 308 - { 3397, 2800, 2221 }, 309 - { 3393, 2795, 2216 }, 310 - { 3389, 2805, 2237 }, 311 - { 3415, 2694, 2195 }, 312 - { 3356, 2724, 2244 }, 313 - }; 314 - 315 - priv->ptat[0] = 2631; 316 - priv->ptat[1] = 1509; 317 - priv->ptat[2] = 435; 300 + priv->ptat[0] = fuse_defaults->ptat[0]; 301 + priv->ptat[1] = fuse_defaults->ptat[1]; 302 + priv->ptat[2] = fuse_defaults->ptat[2]; 318 303 319 304 for (i = 0; i < priv->num_tscs; i++) { 320 305 struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i]; 321 306 322 - tsc->thcode[0] = thcodes[i][0]; 323 - tsc->thcode[1] = thcodes[i][1]; 324 - tsc->thcode[2] = thcodes[i][2]; 307 + tsc->thcode[0] = fuse_defaults->thcodes[i][0]; 308 + tsc->thcode[1] = fuse_defaults->thcodes[i][1]; 309 + tsc->thcode[2] = fuse_defaults->thcodes[i][2]; 325 310 } 326 311 327 312 return false; ··· 360 361 .mask = GEN4_FUSE_MASK, 361 362 }; 362 363 364 + static const struct rcar_gen3_thermal_fuse_default rcar_gen3_thermal_fuse_default_info_gen3 = { 365 + .ptat = { 2631, 1509, 435 }, 366 + .thcodes = { 367 + { 3397, 2800, 2221 }, 368 + { 3393, 2795, 2216 }, 369 + { 3389, 2805, 2237 }, 370 + { 3415, 2694, 2195 }, 371 + { 3356, 2724, 2244 }, 372 + }, 373 + }; 374 + 375 + static const struct rcar_gen3_thermal_fuse_default rcar_gen3_thermal_fuse_default_info_gen4 = { 376 + .ptat = { 3274, 2164, 985 }, 377 + .thcodes = { /* All four THS units share the same trimming */ 378 + { 3218, 2617, 1980 }, 379 + { 3218, 2617, 1980 }, 380 + { 3218, 2617, 1980 }, 381 + { 3218, 2617, 1980 }, 382 + } 383 + }; 384 + 363 385 static const struct rcar_thermal_info rcar_m3w_thermal_info = { 364 386 .scale = 157, 365 387 .adj_below = -41, 366 388 .adj_above = 116, 367 389 .fuses = &rcar_gen3_thermal_fuse_info_gen3, 390 + .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen3, 368 391 }; 369 392 370 393 static const struct rcar_thermal_info rcar_gen3_thermal_info = { ··· 394 373 .adj_below = -41, 395 374 .adj_above = 126, 396 375 .fuses = &rcar_gen3_thermal_fuse_info_gen3, 376 + .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen3, 377 + }; 378 + 379 + static const struct rcar_thermal_info rcar_s4_thermal_info = { 380 + .scale = 167, 381 + .adj_below = -41, 382 + .adj_above = 126, 383 + .fuses = &rcar_gen3_thermal_fuse_info_gen4, 384 + .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen3, 397 385 }; 398 386 399 387 static const struct rcar_thermal_info rcar_gen4_thermal_info = { ··· 410 380 .adj_below = -41, 411 381 .adj_above = 126, 412 382 .fuses = &rcar_gen3_thermal_fuse_info_gen4, 383 + .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen4, 413 384 }; 414 385 415 386 static const struct of_device_id rcar_gen3_thermal_dt_ids[] = { ··· 452 421 }, 453 422 { 454 423 .compatible = "renesas,r8a779f0-thermal", 455 - .data = &rcar_gen4_thermal_info, 424 + .data = &rcar_s4_thermal_info, 456 425 }, 457 426 { 458 427 .compatible = "renesas,r8a779g0-thermal",
+547
drivers/thermal/renesas/rzg3e_thermal.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Renesas RZ/G3E TSU Temperature Sensor Unit 4 + * 5 + * Copyright (C) 2025 Renesas Electronics Corporation 6 + */ 7 + #include <linux/clk.h> 8 + #include <linux/cleanup.h> 9 + #include <linux/delay.h> 10 + #include <linux/err.h> 11 + #include <linux/interrupt.h> 12 + #include <linux/io.h> 13 + #include <linux/iopoll.h> 14 + #include <linux/kernel.h> 15 + #include <linux/mfd/syscon.h> 16 + #include <linux/module.h> 17 + #include <linux/of.h> 18 + #include <linux/platform_device.h> 19 + #include <linux/pm_runtime.h> 20 + #include <linux/regmap.h> 21 + #include <linux/reset.h> 22 + #include <linux/thermal.h> 23 + #include <linux/units.h> 24 + 25 + #include "../thermal_hwmon.h" 26 + 27 + /* TSU Register offsets and bits */ 28 + #define TSU_SSUSR 0x00 29 + #define TSU_SSUSR_EN_TS BIT(0) 30 + #define TSU_SSUSR_ADC_PD_TS BIT(1) 31 + #define TSU_SSUSR_SOC_TS_EN BIT(2) 32 + 33 + #define TSU_STRGR 0x04 34 + #define TSU_STRGR_ADST BIT(0) 35 + 36 + #define TSU_SOSR1 0x08 37 + #define TSU_SOSR1_ADCT_8 0x03 38 + #define TSU_SOSR1_ADCS BIT(4) 39 + #define TSU_SOSR1_OUTSEL BIT(9) 40 + 41 + #define TSU_SCRR 0x10 42 + #define TSU_SCRR_OUT12BIT_TS GENMASK(11, 0) 43 + 44 + #define TSU_SSR 0x14 45 + #define TSU_SSR_CONV BIT(0) 46 + 47 + #define TSU_CMSR 0x18 48 + #define TSU_CMSR_CMPEN BIT(0) 49 + 50 + #define TSU_LLSR 0x1C 51 + #define TSU_ULSR 0x20 52 + 53 + #define TSU_SISR 0x30 54 + #define TSU_SISR_ADF BIT(0) 55 + #define TSU_SISR_CMPF BIT(1) 56 + 57 + #define TSU_SIER 0x34 58 + #define TSU_SIER_CMPIE BIT(1) 59 + 60 + #define TSU_SICR 0x38 61 + #define TSU_SICR_ADCLR BIT(0) 62 + #define TSU_SICR_CMPCLR BIT(1) 63 + 64 + /* Temperature calculation constants from datasheet */ 65 + #define TSU_TEMP_D (-41) 66 + #define TSU_TEMP_E 126 67 + #define TSU_CODE_MAX 0xFFF 68 + 69 + /* Timing specifications from datasheet */ 70 + #define TSU_POWERUP_TIME_US 120 /* 120T at 1MHz sensor clock per datasheet */ 71 + #define TSU_CONV_TIME_US 50 /* Per sample conversion time */ 72 + #define TSU_POLL_DELAY_US 10 /* Polling interval */ 73 + #define TSU_MIN_CLOCK_RATE 24000000 /* TSU_PCLK minimum 24MHz */ 74 + 75 + /** 76 + * struct rzg3e_thermal_priv - RZ/G3E TSU private data 77 + * @base: TSU register base 78 + * @dev: device pointer 79 + * @syscon: regmap for calibration values 80 + * @zone: thermal zone device 81 + * @rstc: reset control 82 + * @trmval0: calibration value 0 (b) 83 + * @trmval1: calibration value 1 (c) 84 + * @trim_offset: offset for trim registers in syscon 85 + * @lock: protects hardware access during conversions 86 + */ 87 + struct rzg3e_thermal_priv { 88 + void __iomem *base; 89 + struct device *dev; 90 + struct regmap *syscon; 91 + struct thermal_zone_device *zone; 92 + struct reset_control *rstc; 93 + u16 trmval0; 94 + u16 trmval1; 95 + u32 trim_offset; 96 + struct mutex lock; 97 + }; 98 + 99 + static int rzg3e_thermal_power_on(struct rzg3e_thermal_priv *priv) 100 + { 101 + u32 val; 102 + int ret; 103 + 104 + /* Clear any pending interrupts */ 105 + writel(TSU_SICR_ADCLR | TSU_SICR_CMPCLR, priv->base + TSU_SICR); 106 + 107 + /* Disable all interrupts during setup */ 108 + writel(0, priv->base + TSU_SIER); 109 + 110 + /* 111 + * Power-on sequence per datasheet 7.11.9.1: 112 + * SOC_TS_EN must be set at same time or before EN_TS and ADC_PD_TS 113 + */ 114 + val = TSU_SSUSR_SOC_TS_EN | TSU_SSUSR_EN_TS; 115 + writel(val, priv->base + TSU_SSUSR); 116 + 117 + /* Wait for sensor stabilization per datasheet 7.11.7.1 */ 118 + usleep_range(TSU_POWERUP_TIME_US, TSU_POWERUP_TIME_US + 10); 119 + 120 + /* Configure for average mode with 8 samples */ 121 + val = TSU_SOSR1_OUTSEL | TSU_SOSR1_ADCT_8; 122 + writel(val, priv->base + TSU_SOSR1); 123 + 124 + /* Ensure we're in single scan mode (default) */ 125 + val = readl(priv->base + TSU_SOSR1); 126 + if (val & TSU_SOSR1_ADCS) { 127 + dev_err(priv->dev, "Invalid scan mode setting\n"); 128 + return -EINVAL; 129 + } 130 + 131 + /* Wait for any ongoing conversion to complete */ 132 + ret = readl_poll_timeout(priv->base + TSU_SSR, val, 133 + !(val & TSU_SSR_CONV), 134 + TSU_POLL_DELAY_US, 135 + USEC_PER_MSEC); 136 + if (ret) { 137 + dev_err(priv->dev, "Timeout waiting for conversion\n"); 138 + return ret; 139 + } 140 + 141 + return 0; 142 + } 143 + 144 + static void rzg3e_thermal_power_off(struct rzg3e_thermal_priv *priv) 145 + { 146 + /* Disable all interrupts */ 147 + writel(0, priv->base + TSU_SIER); 148 + 149 + /* Clear pending interrupts */ 150 + writel(TSU_SICR_ADCLR | TSU_SICR_CMPCLR, priv->base + TSU_SICR); 151 + 152 + /* Power down sequence per datasheet */ 153 + writel(TSU_SSUSR_ADC_PD_TS, priv->base + TSU_SSUSR); 154 + } 155 + 156 + /* 157 + * Convert 12-bit sensor code to temperature in millicelsius 158 + * Formula from datasheet 7.11.7.8: 159 + * T(°C) = ((e - d) / (c - b)) * (a - b) + d 160 + * where: a = sensor code, b = trmval0, c = trmval1, d = -41, e = 126 161 + */ 162 + static int rzg3e_thermal_code_to_temp(struct rzg3e_thermal_priv *priv, u16 code) 163 + { 164 + int temp_e_mc = TSU_TEMP_E * MILLIDEGREE_PER_DEGREE; 165 + int temp_d_mc = TSU_TEMP_D * MILLIDEGREE_PER_DEGREE; 166 + s64 numerator, denominator; 167 + int temp_mc; 168 + 169 + numerator = (temp_e_mc - temp_d_mc) * (s64)(code - priv->trmval0); 170 + denominator = priv->trmval1 - priv->trmval0; 171 + 172 + temp_mc = div64_s64(numerator, denominator) + temp_d_mc; 173 + 174 + return clamp(temp_mc, temp_d_mc, temp_e_mc); 175 + } 176 + 177 + /* 178 + * Convert temperature in millicelsius to 12-bit sensor code 179 + * Formula from datasheet 7.11.7.9 (inverse of above) 180 + */ 181 + static u16 rzg3e_thermal_temp_to_code(struct rzg3e_thermal_priv *priv, int temp_mc) 182 + { 183 + int temp_e_mc = TSU_TEMP_E * MILLIDEGREE_PER_DEGREE; 184 + int temp_d_mc = TSU_TEMP_D * MILLIDEGREE_PER_DEGREE; 185 + s64 numerator, denominator; 186 + s64 code; 187 + 188 + numerator = (temp_mc - temp_d_mc) * (priv->trmval1 - priv->trmval0); 189 + denominator = temp_e_mc - temp_d_mc; 190 + 191 + code = div64_s64(numerator, denominator) + priv->trmval0; 192 + 193 + return clamp_val(code, 0, TSU_CODE_MAX); 194 + } 195 + 196 + static int rzg3e_thermal_get_temp(struct thermal_zone_device *tz, int *temp) 197 + { 198 + struct rzg3e_thermal_priv *priv = thermal_zone_device_priv(tz); 199 + u32 status, code; 200 + int ret, timeout; 201 + 202 + ret = pm_runtime_resume_and_get(priv->dev); 203 + if (ret < 0) 204 + return ret; 205 + 206 + guard(mutex)(&priv->lock); 207 + 208 + /* Clear any previous conversion status */ 209 + writel(TSU_SICR_ADCLR, priv->base + TSU_SICR); 210 + 211 + /* Start single conversion */ 212 + writel(TSU_STRGR_ADST, priv->base + TSU_STRGR); 213 + 214 + /* Wait for conversion completion - 8 samples at ~50us each */ 215 + timeout = TSU_CONV_TIME_US * 8 * 2; /* Double for margin */ 216 + ret = readl_poll_timeout(priv->base + TSU_SISR, status, 217 + status & TSU_SISR_ADF, 218 + TSU_POLL_DELAY_US, timeout); 219 + if (ret) { 220 + dev_err(priv->dev, "Conversion timeout (status=0x%08x)\n", status); 221 + goto out; 222 + } 223 + 224 + /* Read the averaged result and clear the complete flag */ 225 + code = readl(priv->base + TSU_SCRR) & TSU_SCRR_OUT12BIT_TS; 226 + writel(TSU_SICR_ADCLR, priv->base + TSU_SICR); 227 + 228 + /* Convert to temperature */ 229 + *temp = rzg3e_thermal_code_to_temp(priv, code); 230 + 231 + dev_dbg(priv->dev, "temp=%d mC (%d.%03d°C), code=0x%03x\n", 232 + *temp, *temp / 1000, abs(*temp) % 1000, code); 233 + 234 + out: 235 + pm_runtime_mark_last_busy(priv->dev); 236 + pm_runtime_put_autosuspend(priv->dev); 237 + return ret; 238 + } 239 + 240 + static int rzg3e_thermal_set_trips(struct thermal_zone_device *tz, 241 + int low, int high) 242 + { 243 + struct rzg3e_thermal_priv *priv = thermal_zone_device_priv(tz); 244 + u16 low_code, high_code; 245 + u32 val; 246 + int ret; 247 + 248 + /* Hardware requires low < high */ 249 + if (low >= high) 250 + return -EINVAL; 251 + 252 + ret = pm_runtime_resume_and_get(priv->dev); 253 + if (ret < 0) 254 + return ret; 255 + 256 + guard(mutex)(&priv->lock); 257 + 258 + /* Convert temperatures to codes */ 259 + low_code = rzg3e_thermal_temp_to_code(priv, low); 260 + high_code = rzg3e_thermal_temp_to_code(priv, high); 261 + 262 + dev_dbg(priv->dev, "set_trips: low=%d high=%d (codes: 0x%03x/0x%03x)\n", 263 + low, high, low_code, high_code); 264 + 265 + /* Disable comparison during reconfiguration */ 266 + writel(0, priv->base + TSU_SIER); 267 + writel(0, priv->base + TSU_CMSR); 268 + 269 + /* Clear any pending comparison interrupts */ 270 + writel(TSU_SICR_CMPCLR, priv->base + TSU_SICR); 271 + 272 + /* Set trip points */ 273 + writel(low_code, priv->base + TSU_LLSR); 274 + writel(high_code, priv->base + TSU_ULSR); 275 + 276 + /* 277 + * Ensure OUTSEL is set for comparison per datasheet 7.11.7.4 278 + * Comparison uses averaged data 279 + */ 280 + val = readl(priv->base + TSU_SOSR1); 281 + val |= TSU_SOSR1_OUTSEL; 282 + writel(val, priv->base + TSU_SOSR1); 283 + 284 + /* Enable comparison with "out of range" mode (CMPCOND=0) */ 285 + writel(TSU_CMSR_CMPEN, priv->base + TSU_CMSR); 286 + 287 + /* Unmask compare IRQ and start a conversion to evaluate window */ 288 + writel(TSU_SIER_CMPIE, priv->base + TSU_SIER); 289 + writel(TSU_STRGR_ADST, priv->base + TSU_STRGR); 290 + 291 + pm_runtime_mark_last_busy(priv->dev); 292 + pm_runtime_put_autosuspend(priv->dev); 293 + 294 + return 0; 295 + } 296 + 297 + static irqreturn_t rzg3e_thermal_irq_thread(int irq, void *data) 298 + { 299 + struct rzg3e_thermal_priv *priv = data; 300 + 301 + dev_dbg(priv->dev, "Temperature threshold crossed\n"); 302 + 303 + /* Notify thermal framework to re-evaluate trip points */ 304 + thermal_zone_device_update(priv->zone, THERMAL_TRIP_VIOLATED); 305 + 306 + return IRQ_HANDLED; 307 + } 308 + 309 + static irqreturn_t rzg3e_thermal_irq(int irq, void *data) 310 + { 311 + struct rzg3e_thermal_priv *priv = data; 312 + u32 status; 313 + 314 + status = readl(priv->base + TSU_SISR); 315 + 316 + /* Check if comparison interrupt occurred */ 317 + if (status & TSU_SISR_CMPF) { 318 + /* Clear irq flag and disable interrupt until reconfigured */ 319 + writel(TSU_SICR_CMPCLR, priv->base + TSU_SICR); 320 + writel(0, priv->base + TSU_SIER); 321 + 322 + return IRQ_WAKE_THREAD; 323 + } 324 + 325 + return IRQ_NONE; 326 + } 327 + 328 + static const struct thermal_zone_device_ops rzg3e_tz_ops = { 329 + .get_temp = rzg3e_thermal_get_temp, 330 + .set_trips = rzg3e_thermal_set_trips, 331 + }; 332 + 333 + static int rzg3e_thermal_get_calibration(struct rzg3e_thermal_priv *priv) 334 + { 335 + u32 val; 336 + int ret; 337 + 338 + /* Read calibration values from syscon */ 339 + ret = regmap_read(priv->syscon, priv->trim_offset, &val); 340 + if (ret) 341 + return ret; 342 + priv->trmval0 = val & GENMASK(11, 0); 343 + 344 + ret = regmap_read(priv->syscon, priv->trim_offset + 4, &val); 345 + if (ret) 346 + return ret; 347 + priv->trmval1 = val & GENMASK(11, 0); 348 + 349 + /* Validate calibration data */ 350 + if (!priv->trmval0 || !priv->trmval1 || 351 + priv->trmval0 == priv->trmval1 || 352 + priv->trmval0 == 0xFFF || priv->trmval1 == 0xFFF) { 353 + dev_err(priv->dev, "Invalid calibration: b=0x%03x, c=0x%03x\n", 354 + priv->trmval0, priv->trmval1); 355 + return -EINVAL; 356 + } 357 + 358 + dev_dbg(priv->dev, "Calibration: b=0x%03x (%u), c=0x%03x (%u)\n", 359 + priv->trmval0, priv->trmval0, priv->trmval1, priv->trmval1); 360 + 361 + return 0; 362 + } 363 + 364 + static int rzg3e_thermal_parse_dt(struct rzg3e_thermal_priv *priv) 365 + { 366 + struct device_node *np = priv->dev->of_node; 367 + u32 offset; 368 + 369 + priv->syscon = syscon_regmap_lookup_by_phandle_args(np, "renesas,tsu-trim", 1, &offset); 370 + if (IS_ERR(priv->syscon)) 371 + return dev_err_probe(priv->dev, PTR_ERR(priv->syscon), 372 + "Failed to parse renesas,tsu-trim\n"); 373 + 374 + priv->trim_offset = offset; 375 + return 0; 376 + } 377 + 378 + static int rzg3e_thermal_probe(struct platform_device *pdev) 379 + { 380 + struct device *dev = &pdev->dev; 381 + struct rzg3e_thermal_priv *priv; 382 + struct clk *clk; 383 + int irq, ret; 384 + 385 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 386 + if (!priv) 387 + return -ENOMEM; 388 + 389 + priv->dev = dev; 390 + ret = devm_mutex_init(dev, &priv->lock); 391 + if (ret) 392 + return ret; 393 + platform_set_drvdata(pdev, priv); 394 + 395 + priv->base = devm_platform_ioremap_resource(pdev, 0); 396 + if (IS_ERR(priv->base)) 397 + return PTR_ERR(priv->base); 398 + 399 + /* Parse device tree for trim register info */ 400 + ret = rzg3e_thermal_parse_dt(priv); 401 + if (ret) 402 + return ret; 403 + 404 + /* Get clock to verify frequency - clock is managed by power domain */ 405 + clk = devm_clk_get(dev, NULL); 406 + if (IS_ERR(clk)) 407 + return dev_err_probe(dev, PTR_ERR(clk), 408 + "Failed to get clock\n"); 409 + 410 + if (clk_get_rate(clk) < TSU_MIN_CLOCK_RATE) 411 + return dev_err_probe(dev, -EINVAL, 412 + "Clock rate %lu Hz too low (min %u Hz)\n", 413 + clk_get_rate(clk), TSU_MIN_CLOCK_RATE); 414 + 415 + priv->rstc = devm_reset_control_get_exclusive_deasserted(dev, NULL); 416 + if (IS_ERR(priv->rstc)) 417 + return dev_err_probe(dev, PTR_ERR(priv->rstc), 418 + "Failed to get/deassert reset control\n"); 419 + 420 + /* Get calibration data */ 421 + ret = rzg3e_thermal_get_calibration(priv); 422 + if (ret) 423 + return dev_err_probe(dev, ret, 424 + "Failed to get valid calibration data\n"); 425 + 426 + /* Get comparison interrupt */ 427 + irq = platform_get_irq_byname(pdev, "adcmpi"); 428 + if (irq < 0) 429 + return irq; 430 + 431 + /* Enable runtime PM */ 432 + pm_runtime_set_autosuspend_delay(dev, 1000); 433 + pm_runtime_use_autosuspend(dev); 434 + devm_pm_runtime_enable(dev); 435 + 436 + /* Initial hardware setup */ 437 + ret = pm_runtime_resume_and_get(dev); 438 + if (ret < 0) 439 + return dev_err_probe(dev, ret, "Runtime resume failed\n"); 440 + 441 + /* Register thermal zone - this will trigger DT parsing */ 442 + priv->zone = devm_thermal_of_zone_register(dev, 0, priv, &rzg3e_tz_ops); 443 + if (IS_ERR(priv->zone)) { 444 + ret = PTR_ERR(priv->zone); 445 + dev_err(dev, "Failed to register thermal zone: %d\n", ret); 446 + goto err_pm_put; 447 + } 448 + 449 + /* Request threaded IRQ for comparison interrupt */ 450 + ret = devm_request_threaded_irq(dev, irq, rzg3e_thermal_irq, 451 + rzg3e_thermal_irq_thread, 452 + IRQF_ONESHOT, "rzg3e_thermal", priv); 453 + if (ret) { 454 + dev_err(dev, "Failed to request IRQ: %d\n", ret); 455 + goto err_pm_put; 456 + } 457 + 458 + /* Add hwmon sysfs interface */ 459 + ret = devm_thermal_add_hwmon_sysfs(dev, priv->zone); 460 + if (ret) 461 + dev_warn(dev, "Failed to add hwmon sysfs attributes\n"); 462 + 463 + pm_runtime_mark_last_busy(dev); 464 + pm_runtime_put_autosuspend(dev); 465 + 466 + dev_info(dev, "RZ/G3E thermal sensor registered\n"); 467 + 468 + return 0; 469 + 470 + err_pm_put: 471 + pm_runtime_put_sync(dev); 472 + return ret; 473 + } 474 + 475 + static int rzg3e_thermal_runtime_suspend(struct device *dev) 476 + { 477 + struct rzg3e_thermal_priv *priv = dev_get_drvdata(dev); 478 + 479 + rzg3e_thermal_power_off(priv); 480 + return 0; 481 + } 482 + 483 + static int rzg3e_thermal_runtime_resume(struct device *dev) 484 + { 485 + struct rzg3e_thermal_priv *priv = dev_get_drvdata(dev); 486 + 487 + return rzg3e_thermal_power_on(priv); 488 + } 489 + 490 + static int rzg3e_thermal_suspend(struct device *dev) 491 + { 492 + struct rzg3e_thermal_priv *priv = dev_get_drvdata(dev); 493 + 494 + /* If device is active, power it off */ 495 + if (pm_runtime_active(dev)) 496 + rzg3e_thermal_power_off(priv); 497 + 498 + /* Assert reset to ensure clean state after resume */ 499 + reset_control_assert(priv->rstc); 500 + 501 + return 0; 502 + } 503 + 504 + static int rzg3e_thermal_resume(struct device *dev) 505 + { 506 + struct rzg3e_thermal_priv *priv = dev_get_drvdata(dev); 507 + int ret; 508 + 509 + /* Deassert reset */ 510 + ret = reset_control_deassert(priv->rstc); 511 + if (ret) { 512 + dev_err(dev, "Failed to deassert reset: %d\n", ret); 513 + return ret; 514 + } 515 + 516 + /* If device was active before suspend, power it back on */ 517 + if (pm_runtime_active(dev)) 518 + return rzg3e_thermal_power_on(priv); 519 + 520 + return 0; 521 + } 522 + 523 + static const struct dev_pm_ops rzg3e_thermal_pm_ops = { 524 + RUNTIME_PM_OPS(rzg3e_thermal_runtime_suspend, 525 + rzg3e_thermal_runtime_resume, NULL) 526 + SYSTEM_SLEEP_PM_OPS(rzg3e_thermal_suspend, rzg3e_thermal_resume) 527 + }; 528 + 529 + static const struct of_device_id rzg3e_thermal_dt_ids[] = { 530 + { .compatible = "renesas,r9a09g047-tsu" }, 531 + { /* sentinel */ } 532 + }; 533 + MODULE_DEVICE_TABLE(of, rzg3e_thermal_dt_ids); 534 + 535 + static struct platform_driver rzg3e_thermal_driver = { 536 + .driver = { 537 + .name = "rzg3e_thermal", 538 + .of_match_table = rzg3e_thermal_dt_ids, 539 + .pm = pm_ptr(&rzg3e_thermal_pm_ops), 540 + }, 541 + .probe = rzg3e_thermal_probe, 542 + }; 543 + module_platform_driver(rzg3e_thermal_driver); 544 + 545 + MODULE_DESCRIPTION("Renesas RZ/G3E TSU Thermal Sensor Driver"); 546 + MODULE_AUTHOR("John Madieu <john.madieu.xa@bp.renesas.com>"); 547 + MODULE_LICENSE("GPL");
+272
drivers/thermal/renesas/rzg3s_thermal.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Renesas RZ/G3S TSU Thermal Sensor Driver 4 + * 5 + * Copyright (C) 2024 Renesas Electronics Corporation 6 + */ 7 + 8 + #include <linux/bitfield.h> 9 + #include <linux/delay.h> 10 + #include <linux/iio/consumer.h> 11 + #include <linux/io.h> 12 + #include <linux/module.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/pm_runtime.h> 15 + #include <linux/reset.h> 16 + #include <linux/thermal.h> 17 + #include <linux/units.h> 18 + 19 + #include "../thermal_hwmon.h" 20 + 21 + #define TSU_SM 0x0 22 + #define TSU_SM_EN BIT(0) 23 + #define TSU_SM_OE BIT(1) 24 + #define OTPTSUTRIM_REG(n) (0x18 + (n) * 0x4) 25 + #define OTPTSUTRIM_EN_MASK BIT(31) 26 + #define OTPTSUTRIM_MASK GENMASK(11, 0) 27 + 28 + #define TSU_READ_STEPS 8 29 + 30 + /* Default calibration values, if FUSE values are missing. */ 31 + #define SW_CALIB0_VAL 1297 32 + #define SW_CALIB1_VAL 751 33 + 34 + #define MCELSIUS(temp) ((temp) * MILLIDEGREE_PER_DEGREE) 35 + 36 + /** 37 + * struct rzg3s_thermal_priv - RZ/G3S thermal private data structure 38 + * @base: TSU base address 39 + * @dev: device pointer 40 + * @tz: thermal zone pointer 41 + * @rstc: reset control 42 + * @channel: IIO channel to read the TSU 43 + * @mode: current device mode 44 + * @calib0: calibration value 45 + * @calib1: calibration value 46 + */ 47 + struct rzg3s_thermal_priv { 48 + void __iomem *base; 49 + struct device *dev; 50 + struct thermal_zone_device *tz; 51 + struct reset_control *rstc; 52 + struct iio_channel *channel; 53 + enum thermal_device_mode mode; 54 + u16 calib0; 55 + u16 calib1; 56 + }; 57 + 58 + static int rzg3s_thermal_get_temp(struct thermal_zone_device *tz, int *temp) 59 + { 60 + struct rzg3s_thermal_priv *priv = thermal_zone_device_priv(tz); 61 + int ts_code_ave = 0; 62 + 63 + if (priv->mode != THERMAL_DEVICE_ENABLED) 64 + return -EAGAIN; 65 + 66 + for (u8 i = 0; i < TSU_READ_STEPS; i++) { 67 + int ret, val; 68 + 69 + ret = iio_read_channel_raw(priv->channel, &val); 70 + if (ret < 0) 71 + return ret; 72 + 73 + ts_code_ave += val; 74 + /* 75 + * According to the HW manual (Rev.1.10, section 40.4.4 Procedure for Measuring 76 + * the Temperature) we need to wait here at leat 3us. 77 + */ 78 + usleep_range(5, 10); 79 + } 80 + 81 + ts_code_ave = DIV_ROUND_CLOSEST(MCELSIUS(ts_code_ave), TSU_READ_STEPS); 82 + 83 + /* 84 + * According to the HW manual (Rev.1.10, section 40.4.4 Procedure for Measuring the 85 + * Temperature) the computation formula is as follows: 86 + * 87 + * Tj = (ts_code_ave - priv->calib1) * 165 / (priv->calib0 - priv->calib1) - 40 88 + * 89 + * Convert everything to milli Celsius before applying the formula to avoid 90 + * losing precision. 91 + */ 92 + 93 + *temp = div_s64((s64)(ts_code_ave - MCELSIUS(priv->calib1)) * MCELSIUS(165), 94 + MCELSIUS(priv->calib0 - priv->calib1)) - MCELSIUS(40); 95 + 96 + /* Report it in milli degrees Celsius and round it up to 0.5 degrees Celsius. */ 97 + *temp = roundup(*temp, 500); 98 + 99 + return 0; 100 + } 101 + 102 + static void rzg3s_thermal_set_mode(struct rzg3s_thermal_priv *priv, 103 + enum thermal_device_mode mode) 104 + { 105 + struct device *dev = priv->dev; 106 + int ret; 107 + 108 + ret = pm_runtime_resume_and_get(dev); 109 + if (ret) 110 + return; 111 + 112 + if (mode == THERMAL_DEVICE_DISABLED) { 113 + writel(0, priv->base + TSU_SM); 114 + } else { 115 + writel(TSU_SM_EN, priv->base + TSU_SM); 116 + /* 117 + * According to the HW manual (Rev.1.10, section 40.4.1 Procedure for 118 + * Starting the TSU) we need to wait here 30us or more. 119 + */ 120 + usleep_range(30, 40); 121 + 122 + writel(TSU_SM_OE | TSU_SM_EN, priv->base + TSU_SM); 123 + /* 124 + * According to the HW manual (Rev.1.10, section 40.4.1 Procedure for 125 + * Starting the TSU) we need to wait here 50us or more. 126 + */ 127 + usleep_range(50, 60); 128 + } 129 + 130 + pm_runtime_put_autosuspend(dev); 131 + } 132 + 133 + static int rzg3s_thermal_change_mode(struct thermal_zone_device *tz, 134 + enum thermal_device_mode mode) 135 + { 136 + struct rzg3s_thermal_priv *priv = thermal_zone_device_priv(tz); 137 + 138 + if (priv->mode == mode) 139 + return 0; 140 + 141 + rzg3s_thermal_set_mode(priv, mode); 142 + priv->mode = mode; 143 + 144 + return 0; 145 + } 146 + 147 + static const struct thermal_zone_device_ops rzg3s_tz_of_ops = { 148 + .get_temp = rzg3s_thermal_get_temp, 149 + .change_mode = rzg3s_thermal_change_mode, 150 + }; 151 + 152 + static int rzg3s_thermal_read_calib(struct rzg3s_thermal_priv *priv) 153 + { 154 + struct device *dev = priv->dev; 155 + u32 val; 156 + int ret; 157 + 158 + ret = pm_runtime_resume_and_get(dev); 159 + if (ret) 160 + return ret; 161 + 162 + val = readl(priv->base + OTPTSUTRIM_REG(0)); 163 + if (val & OTPTSUTRIM_EN_MASK) 164 + priv->calib0 = FIELD_GET(OTPTSUTRIM_MASK, val); 165 + else 166 + priv->calib0 = SW_CALIB0_VAL; 167 + 168 + val = readl(priv->base + OTPTSUTRIM_REG(1)); 169 + if (val & OTPTSUTRIM_EN_MASK) 170 + priv->calib1 = FIELD_GET(OTPTSUTRIM_MASK, val); 171 + else 172 + priv->calib1 = SW_CALIB1_VAL; 173 + 174 + pm_runtime_put_autosuspend(dev); 175 + 176 + return 0; 177 + } 178 + 179 + static int rzg3s_thermal_probe(struct platform_device *pdev) 180 + { 181 + struct rzg3s_thermal_priv *priv; 182 + struct device *dev = &pdev->dev; 183 + int ret; 184 + 185 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 186 + if (!priv) 187 + return -ENOMEM; 188 + 189 + priv->base = devm_platform_ioremap_resource(pdev, 0); 190 + if (IS_ERR(priv->base)) 191 + return PTR_ERR(priv->base); 192 + 193 + priv->channel = devm_iio_channel_get(dev, "tsu"); 194 + if (IS_ERR(priv->channel)) 195 + return dev_err_probe(dev, PTR_ERR(priv->channel), "Failed to get IIO channel!\n"); 196 + 197 + priv->rstc = devm_reset_control_get_exclusive_deasserted(dev, NULL); 198 + if (IS_ERR(priv->rstc)) 199 + return dev_err_probe(dev, PTR_ERR(priv->rstc), "Failed to get reset!\n"); 200 + 201 + priv->dev = dev; 202 + priv->mode = THERMAL_DEVICE_DISABLED; 203 + platform_set_drvdata(pdev, priv); 204 + 205 + pm_runtime_set_autosuspend_delay(dev, 300); 206 + pm_runtime_use_autosuspend(dev); 207 + ret = devm_pm_runtime_enable(dev); 208 + if (ret) 209 + return dev_err_probe(dev, ret, "Failed to enable runtime PM!\n"); 210 + 211 + ret = rzg3s_thermal_read_calib(priv); 212 + if (ret) 213 + return dev_err_probe(dev, ret, "Failed to read calibration data!\n"); 214 + 215 + priv->tz = devm_thermal_of_zone_register(dev, 0, priv, &rzg3s_tz_of_ops); 216 + if (IS_ERR(priv->tz)) 217 + return dev_err_probe(dev, PTR_ERR(priv->tz), "Failed to register thermal zone!\n"); 218 + 219 + ret = devm_thermal_add_hwmon_sysfs(dev, priv->tz); 220 + if (ret) 221 + return dev_err_probe(dev, ret, "Failed to add hwmon sysfs!\n"); 222 + 223 + return 0; 224 + } 225 + 226 + static int rzg3s_thermal_suspend(struct device *dev) 227 + { 228 + struct rzg3s_thermal_priv *priv = dev_get_drvdata(dev); 229 + 230 + rzg3s_thermal_set_mode(priv, THERMAL_DEVICE_DISABLED); 231 + 232 + return reset_control_assert(priv->rstc); 233 + } 234 + 235 + static int rzg3s_thermal_resume(struct device *dev) 236 + { 237 + struct rzg3s_thermal_priv *priv = dev_get_drvdata(dev); 238 + int ret; 239 + 240 + ret = reset_control_deassert(priv->rstc); 241 + if (ret) 242 + return ret; 243 + 244 + if (priv->mode != THERMAL_DEVICE_DISABLED) 245 + rzg3s_thermal_set_mode(priv, priv->mode); 246 + 247 + return 0; 248 + } 249 + 250 + static const struct dev_pm_ops rzg3s_thermal_pm_ops = { 251 + SYSTEM_SLEEP_PM_OPS(rzg3s_thermal_suspend, rzg3s_thermal_resume) 252 + }; 253 + 254 + static const struct of_device_id rzg3s_thermal_dt_ids[] = { 255 + { .compatible = "renesas,r9a08g045-tsu" }, 256 + { /* sentinel */ } 257 + }; 258 + MODULE_DEVICE_TABLE(of, rzg3s_thermal_dt_ids); 259 + 260 + static struct platform_driver rzg3s_thermal_driver = { 261 + .driver = { 262 + .name = "rzg3s-thermal", 263 + .of_match_table = rzg3s_thermal_dt_ids, 264 + .pm = pm_ptr(&rzg3s_thermal_pm_ops), 265 + }, 266 + .probe = rzg3s_thermal_probe, 267 + }; 268 + module_platform_driver(rzg3s_thermal_driver); 269 + 270 + MODULE_DESCRIPTION("Renesas RZ/G3S Thermal Sensor Unit Driver"); 271 + MODULE_AUTHOR("Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>"); 272 + MODULE_LICENSE("GPL");
+18 -32
drivers/thermal/rockchip_thermal.c
··· 74 74 * @tshut_temp: the hardware-controlled shutdown temperature value, with no trim 75 75 * @tshut_mode: the hardware-controlled shutdown mode (0:CRU 1:GPIO) 76 76 * @tshut_polarity: the hardware-controlled active polarity (0:LOW 1:HIGH) 77 + * @grf_required: true, if a GRF is required for proper functionality 77 78 * @initialize: SoC special initialize tsadc controller method 78 79 * @irq_ack: clear the interrupt 79 80 * @control: enable/disable method for the tsadc controller ··· 97 96 int tshut_temp; 98 97 enum tshut_mode tshut_mode; 99 98 enum tshut_polarity tshut_polarity; 99 + 100 + /* GRF availability */ 101 + bool grf_required; 100 102 101 103 /* Chip-wide methods */ 102 104 void (*initialize)(struct regmap *grf, ··· 1102 1098 /* cpu, gpu */ 1103 1099 .chn_offset = 0, 1104 1100 .chn_num = 2, /* 2 channels for tsadc */ 1105 - 1101 + .grf_required = true, 1106 1102 .tshut_mode = TSHUT_MODE_CRU, /* default TSHUT via CRU */ 1107 1103 .tshut_temp = 95000, 1108 - 1109 1104 .initialize = rk_tsadcv4_initialize, 1110 1105 .irq_ack = rk_tsadcv3_irq_ack, 1111 1106 .control = rk_tsadcv3_control, ··· 1112 1109 .set_alarm_temp = rk_tsadcv2_alarm_temp, 1113 1110 .set_tshut_temp = rk_tsadcv2_tshut_temp, 1114 1111 .set_tshut_mode = rk_tsadcv2_tshut_mode, 1115 - 1116 1112 .table = { 1117 1113 .id = rk3328_code_table, 1118 1114 .length = ARRAY_SIZE(rk3328_code_table), ··· 1124 1122 /* cpu */ 1125 1123 .chn_offset = 0, 1126 1124 .chn_num = 1, /* one channel for tsadc */ 1127 - 1125 + .grf_required = false, 1128 1126 .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 1129 1127 .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 1130 1128 .tshut_temp = 95000, 1131 - 1132 1129 .initialize = rk_tsadcv2_initialize, 1133 1130 .irq_ack = rk_tsadcv3_irq_ack, 1134 1131 .control = rk_tsadcv3_control, ··· 1135 1134 .set_alarm_temp = rk_tsadcv2_alarm_temp, 1136 1135 .set_tshut_temp = rk_tsadcv2_tshut_temp, 1137 1136 .set_tshut_mode = rk_tsadcv2_tshut_mode, 1138 - 1139 1137 .table = { 1140 1138 .id = rv1108_table, 1141 1139 .length = ARRAY_SIZE(rv1108_table), ··· 1147 1147 /* cpu */ 1148 1148 .chn_offset = 0, 1149 1149 .chn_num = 1, /* one channel for tsadc */ 1150 - 1150 + .grf_required = false, 1151 1151 .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 1152 1152 .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 1153 1153 .tshut_temp = 95000, 1154 - 1155 1154 .initialize = rk_tsadcv2_initialize, 1156 1155 .irq_ack = rk_tsadcv3_irq_ack, 1157 1156 .control = rk_tsadcv3_control, ··· 1158 1159 .set_alarm_temp = rk_tsadcv2_alarm_temp, 1159 1160 .set_tshut_temp = rk_tsadcv2_tshut_temp, 1160 1161 .set_tshut_mode = rk_tsadcv2_tshut_mode, 1161 - 1162 1162 .table = { 1163 1163 .id = rk3228_code_table, 1164 1164 .length = ARRAY_SIZE(rk3228_code_table), ··· 1170 1172 /* cpu, gpu */ 1171 1173 .chn_offset = 1, 1172 1174 .chn_num = 2, /* two channels for tsadc */ 1173 - 1175 + .grf_required = false, 1174 1176 .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 1175 1177 .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 1176 1178 .tshut_temp = 95000, 1177 - 1178 1179 .initialize = rk_tsadcv2_initialize, 1179 1180 .irq_ack = rk_tsadcv2_irq_ack, 1180 1181 .control = rk_tsadcv2_control, ··· 1181 1184 .set_alarm_temp = rk_tsadcv2_alarm_temp, 1182 1185 .set_tshut_temp = rk_tsadcv2_tshut_temp, 1183 1186 .set_tshut_mode = rk_tsadcv2_tshut_mode, 1184 - 1185 1187 .table = { 1186 1188 .id = rk3288_code_table, 1187 1189 .length = ARRAY_SIZE(rk3288_code_table), ··· 1193 1197 /* cpu */ 1194 1198 .chn_offset = 0, 1195 1199 .chn_num = 1, /* one channels for tsadc */ 1196 - 1200 + .grf_required = false, 1197 1201 .tshut_mode = TSHUT_MODE_CRU, /* default TSHUT via CRU */ 1198 1202 .tshut_temp = 95000, 1199 - 1200 1203 .initialize = rk_tsadcv2_initialize, 1201 1204 .irq_ack = rk_tsadcv3_irq_ack, 1202 1205 .control = rk_tsadcv3_control, ··· 1203 1208 .set_alarm_temp = rk_tsadcv2_alarm_temp, 1204 1209 .set_tshut_temp = rk_tsadcv2_tshut_temp, 1205 1210 .set_tshut_mode = rk_tsadcv2_tshut_mode, 1206 - 1207 1211 .table = { 1208 1212 .id = rk3328_code_table, 1209 1213 .length = ARRAY_SIZE(rk3328_code_table), ··· 1215 1221 /* cpu, gpu */ 1216 1222 .chn_offset = 0, 1217 1223 .chn_num = 2, /* two channels for tsadc */ 1218 - 1224 + .grf_required = true, 1219 1225 .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 1220 1226 .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 1221 1227 .tshut_temp = 95000, 1222 - 1223 1228 .initialize = rk_tsadcv3_initialize, 1224 1229 .irq_ack = rk_tsadcv3_irq_ack, 1225 1230 .control = rk_tsadcv3_control, ··· 1226 1233 .set_alarm_temp = rk_tsadcv2_alarm_temp, 1227 1234 .set_tshut_temp = rk_tsadcv2_tshut_temp, 1228 1235 .set_tshut_mode = rk_tsadcv2_tshut_mode, 1229 - 1230 1236 .table = { 1231 1237 .id = rk3228_code_table, 1232 1238 .length = ARRAY_SIZE(rk3228_code_table), ··· 1238 1246 /* cpu, gpu */ 1239 1247 .chn_offset = 0, 1240 1248 .chn_num = 2, /* two channels for tsadc */ 1241 - 1249 + .grf_required = false, 1242 1250 .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 1243 1251 .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 1244 1252 .tshut_temp = 95000, 1245 - 1246 1253 .initialize = rk_tsadcv2_initialize, 1247 1254 .irq_ack = rk_tsadcv2_irq_ack, 1248 1255 .control = rk_tsadcv2_control, ··· 1249 1258 .set_alarm_temp = rk_tsadcv2_alarm_temp, 1250 1259 .set_tshut_temp = rk_tsadcv2_tshut_temp, 1251 1260 .set_tshut_mode = rk_tsadcv2_tshut_mode, 1252 - 1253 1261 .table = { 1254 1262 .id = rk3368_code_table, 1255 1263 .length = ARRAY_SIZE(rk3368_code_table), ··· 1261 1271 /* cpu, gpu */ 1262 1272 .chn_offset = 0, 1263 1273 .chn_num = 2, /* two channels for tsadc */ 1264 - 1274 + .grf_required = true, 1265 1275 .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 1266 1276 .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 1267 1277 .tshut_temp = 95000, 1268 - 1269 1278 .initialize = rk_tsadcv3_initialize, 1270 1279 .irq_ack = rk_tsadcv3_irq_ack, 1271 1280 .control = rk_tsadcv3_control, ··· 1272 1283 .set_alarm_temp = rk_tsadcv2_alarm_temp, 1273 1284 .set_tshut_temp = rk_tsadcv2_tshut_temp, 1274 1285 .set_tshut_mode = rk_tsadcv2_tshut_mode, 1275 - 1276 1286 .table = { 1277 1287 .id = rk3399_code_table, 1278 1288 .length = ARRAY_SIZE(rk3399_code_table), ··· 1284 1296 /* cpu, gpu */ 1285 1297 .chn_offset = 0, 1286 1298 .chn_num = 2, /* two channels for tsadc */ 1287 - 1299 + .grf_required = true, 1288 1300 .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 1289 1301 .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 1290 1302 .tshut_temp = 95000, 1291 - 1292 1303 .initialize = rk_tsadcv7_initialize, 1293 1304 .irq_ack = rk_tsadcv3_irq_ack, 1294 1305 .control = rk_tsadcv3_control, ··· 1295 1308 .set_alarm_temp = rk_tsadcv2_alarm_temp, 1296 1309 .set_tshut_temp = rk_tsadcv2_tshut_temp, 1297 1310 .set_tshut_mode = rk_tsadcv2_tshut_mode, 1298 - 1299 1311 .table = { 1300 1312 .id = rk3568_code_table, 1301 1313 .length = ARRAY_SIZE(rk3568_code_table), ··· 1307 1321 /* top, big_core, little_core, ddr, npu, gpu */ 1308 1322 .chn_offset = 0, 1309 1323 .chn_num = 6, /* six channels for tsadc */ 1324 + .grf_required = false, 1310 1325 .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 1311 1326 .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 1312 1327 .tshut_temp = 95000, ··· 1332 1345 /* top, big_core0, big_core1, little_core, center, gpu, npu */ 1333 1346 .chn_offset = 0, 1334 1347 .chn_num = 7, /* seven channels for tsadc */ 1348 + .grf_required = false, 1335 1349 .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 1336 1350 .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 1337 1351 .tshut_temp = 95000, ··· 1609 1621 return -EINVAL; 1610 1622 } 1611 1623 1612 - /* The tsadc wont to handle the error in here since some SoCs didn't 1613 - * need this property. 1614 - */ 1615 1624 thermal->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); 1616 - if (IS_ERR(thermal->grf)) 1617 - dev_warn(dev, "Missing rockchip,grf property\n"); 1625 + if (IS_ERR(thermal->grf) && thermal->chip->grf_required) 1626 + return dev_err_probe(dev, PTR_ERR(thermal->grf), 1627 + "Missing rockchip,grf property\n"); 1618 1628 1619 1629 rockchip_get_trim_configuration(dev, np, thermal); 1620 1630
+1
drivers/thermal/tegra/Makefile
··· 4 4 obj-$(CONFIG_TEGRA30_TSENSOR) += tegra30-tsensor.o 5 5 6 6 tegra-soctherm-y := soctherm.o soctherm-fuse.o 7 + tegra-soctherm-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114-soctherm.o 7 8 tegra-soctherm-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124-soctherm.o 8 9 tegra-soctherm-$(CONFIG_ARCH_TEGRA_132_SOC) += tegra132-soctherm.o 9 10 tegra-soctherm-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210-soctherm.o
+12 -6
drivers/thermal/tegra/soctherm-fuse.c
··· 9 9 10 10 #include "soctherm.h" 11 11 12 - #define NOMINAL_CALIB_FT 105 13 12 #define NOMINAL_CALIB_CP 25 14 13 15 14 #define FUSE_TSENSOR_CALIB_CP_TS_BASE_MASK 0x1fff 16 15 #define FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK (0x1fff << 13) 17 16 #define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT 13 18 - 19 - #define FUSE_TSENSOR_COMMON 0x180 20 17 21 18 /* 22 19 * Tegra210: Layout of bits in FUSE_TSENSOR_COMMON: ··· 23 26 * | BASE_FT | BASE_CP | SHFT_FT | SHIFT_CP | 24 27 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 25 28 * 26 - * Tegra12x, etc: 29 + * Tegra124: 27 30 * In chips prior to Tegra210, this fuse was incorrectly sized as 26 bits, 28 31 * and didn't hold SHIFT_CP in [31:26]. Therefore these missing six bits 29 32 * were obtained via the FUSE_SPARE_REALIGNMENT_REG register [5:0]. ··· 40 43 * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 41 44 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 42 45 * |---------------------------------------------------| SHIFT_CP | 46 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 47 + * 48 + * Tegra114: Layout of bits in FUSE_TSENSOR_COMMON aka FUSE_VSENSOR_CALIB: 49 + * 3 2 1 0 50 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 51 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 52 + * | SHFT_FT | BASE_FT | SHIFT_CP | BASE_CP | 43 53 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 44 54 */ 45 55 ··· 81 77 s32 shifted_cp, shifted_ft; 82 78 int err; 83 79 84 - err = tegra_fuse_readl(FUSE_TSENSOR_COMMON, &val); 80 + err = tegra_fuse_readl(tfuse->fuse_common_reg, &val); 85 81 if (err) 86 82 return err; 87 83 ··· 100 96 return err; 101 97 } 102 98 99 + shifted_cp = (val & tfuse->fuse_shift_cp_mask) >> 100 + tfuse->fuse_shift_cp_shift; 103 101 shifted_cp = sign_extend32(val, 5); 104 102 105 103 shared->actual_temp_cp = 2 * NOMINAL_CALIB_CP + shifted_cp; 106 - shared->actual_temp_ft = 2 * NOMINAL_CALIB_FT + shifted_ft; 104 + shared->actual_temp_ft = 2 * tfuse->nominal_calib_ft + shifted_ft; 107 105 108 106 return 0; 109 107 }
+13
drivers/thermal/tegra/soctherm.c
··· 31 31 #include <linux/reset.h> 32 32 #include <linux/thermal.h> 33 33 34 + #include <dt-bindings/thermal/tegra114-soctherm.h> 34 35 #include <dt-bindings/thermal/tegra124-soctherm.h> 35 36 36 37 #include "../thermal_core.h" ··· 357 356 }; 358 357 359 358 static struct soctherm_oc_irq_chip_data soc_irq_cdata; 359 + 360 + /* Ensure that TEGRA114_* and TEGRA124_* counterparts are equal */ 361 + static_assert(TEGRA114_SOCTHERM_SENSOR_CPU == TEGRA124_SOCTHERM_SENSOR_CPU); 362 + static_assert(TEGRA114_SOCTHERM_SENSOR_MEM == TEGRA124_SOCTHERM_SENSOR_MEM); 363 + static_assert(TEGRA114_SOCTHERM_SENSOR_GPU == TEGRA124_SOCTHERM_SENSOR_GPU); 364 + static_assert(TEGRA114_SOCTHERM_SENSOR_PLLX == TEGRA124_SOCTHERM_SENSOR_PLLX); 360 365 361 366 /** 362 367 * ccroc_writel() - writes a value to a CCROC register ··· 2052 2045 } 2053 2046 2054 2047 static const struct of_device_id tegra_soctherm_of_match[] = { 2048 + #ifdef CONFIG_ARCH_TEGRA_114_SOC 2049 + { 2050 + .compatible = "nvidia,tegra114-soctherm", 2051 + .data = &tegra114_soctherm, 2052 + }, 2053 + #endif 2055 2054 #ifdef CONFIG_ARCH_TEGRA_124_SOC 2056 2055 { 2057 2056 .compatible = "nvidia,tegra124-soctherm",
+10 -1
drivers/thermal/tegra/soctherm.h
··· 56 56 #define SENSOR_TEMP2_MEM_TEMP_MASK (0xffff << 16) 57 57 #define SENSOR_TEMP2_PLLX_TEMP_MASK 0xffff 58 58 59 + #define FUSE_VSENSOR_CALIB 0x08c 60 + #define FUSE_TSENSOR_COMMON 0x180 61 + 59 62 /** 60 63 * struct tegra_tsensor_group - SOC_THERM sensor group data 61 64 * @name: short name of the temperature sensor group ··· 112 109 113 110 struct tegra_soctherm_fuse { 114 111 u32 fuse_base_cp_mask, fuse_base_cp_shift; 112 + u32 fuse_shift_cp_mask, fuse_shift_cp_shift; 115 113 u32 fuse_base_ft_mask, fuse_base_ft_shift; 116 114 u32 fuse_shift_ft_mask, fuse_shift_ft_shift; 117 - u32 fuse_spare_realignment; 115 + u32 fuse_common_reg, fuse_spare_realignment; 116 + u32 nominal_calib_ft; 118 117 }; 119 118 120 119 struct tsensor_shared_calib { ··· 141 136 int tegra_calc_tsensor_calib(const struct tegra_tsensor *sensor, 142 137 const struct tsensor_shared_calib *shared, 143 138 u32 *calib); 139 + 140 + #ifdef CONFIG_ARCH_TEGRA_114_SOC 141 + extern const struct tegra_soctherm_soc tegra114_soctherm; 142 + #endif 144 143 145 144 #ifdef CONFIG_ARCH_TEGRA_124_SOC 146 145 extern const struct tegra_soctherm_soc tegra124_soctherm;
+209
drivers/thermal/tegra/tegra114-soctherm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved. 4 + * Copyright (c) 2024, Svyatoslav Ryhel <clamor95@gmail.com> 5 + */ 6 + 7 + #include <linux/module.h> 8 + #include <linux/platform_device.h> 9 + 10 + #include <dt-bindings/thermal/tegra114-soctherm.h> 11 + 12 + #include "soctherm.h" 13 + 14 + #define TEGRA114_THERMTRIP_ANY_EN_MASK (0x1 << 28) 15 + #define TEGRA114_THERMTRIP_MEM_EN_MASK (0x1 << 27) 16 + #define TEGRA114_THERMTRIP_GPU_EN_MASK (0x1 << 26) 17 + #define TEGRA114_THERMTRIP_CPU_EN_MASK (0x1 << 25) 18 + #define TEGRA114_THERMTRIP_TSENSE_EN_MASK (0x1 << 24) 19 + #define TEGRA114_THERMTRIP_GPUMEM_THRESH_MASK (0xff << 16) 20 + #define TEGRA114_THERMTRIP_CPU_THRESH_MASK (0xff << 8) 21 + #define TEGRA114_THERMTRIP_TSENSE_THRESH_MASK 0xff 22 + 23 + #define TEGRA114_THERMCTL_LVL0_UP_THRESH_MASK (0xff << 17) 24 + #define TEGRA114_THERMCTL_LVL0_DN_THRESH_MASK (0xff << 9) 25 + 26 + #define TEGRA114_THRESH_GRAIN 1000 27 + #define TEGRA114_BPTT 8 28 + 29 + static const struct tegra_tsensor_configuration tegra114_tsensor_config = { 30 + .tall = 16300, 31 + .tiddq_en = 1, 32 + .ten_count = 1, 33 + .tsample = 163, 34 + .tsample_ate = 655, 35 + }; 36 + 37 + static const struct tegra_tsensor_group tegra114_tsensor_group_cpu = { 38 + .id = TEGRA114_SOCTHERM_SENSOR_CPU, 39 + .name = "cpu", 40 + .sensor_temp_offset = SENSOR_TEMP1, 41 + .sensor_temp_mask = SENSOR_TEMP1_CPU_TEMP_MASK, 42 + .pdiv = 10, 43 + .pdiv_ate = 10, 44 + .pdiv_mask = SENSOR_PDIV_CPU_MASK, 45 + .pllx_hotspot_diff = 6, 46 + .pllx_hotspot_mask = SENSOR_HOTSPOT_CPU_MASK, 47 + .thermtrip_any_en_mask = TEGRA114_THERMTRIP_ANY_EN_MASK, 48 + .thermtrip_enable_mask = TEGRA114_THERMTRIP_CPU_EN_MASK, 49 + .thermtrip_threshold_mask = TEGRA114_THERMTRIP_CPU_THRESH_MASK, 50 + .thermctl_isr_mask = THERM_IRQ_CPU_MASK, 51 + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU, 52 + .thermctl_lvl0_up_thresh_mask = TEGRA114_THERMCTL_LVL0_UP_THRESH_MASK, 53 + .thermctl_lvl0_dn_thresh_mask = TEGRA114_THERMCTL_LVL0_DN_THRESH_MASK, 54 + }; 55 + 56 + static const struct tegra_tsensor_group tegra114_tsensor_group_gpu = { 57 + .id = TEGRA114_SOCTHERM_SENSOR_GPU, 58 + .name = "gpu", 59 + .sensor_temp_offset = SENSOR_TEMP1, 60 + .sensor_temp_mask = SENSOR_TEMP1_GPU_TEMP_MASK, 61 + .pdiv = 10, 62 + .pdiv_ate = 10, 63 + .pdiv_mask = SENSOR_PDIV_GPU_MASK, 64 + .pllx_hotspot_diff = 6, 65 + .pllx_hotspot_mask = SENSOR_HOTSPOT_GPU_MASK, 66 + .thermtrip_any_en_mask = TEGRA114_THERMTRIP_ANY_EN_MASK, 67 + .thermtrip_enable_mask = TEGRA114_THERMTRIP_GPU_EN_MASK, 68 + .thermtrip_threshold_mask = TEGRA114_THERMTRIP_GPUMEM_THRESH_MASK, 69 + .thermctl_isr_mask = THERM_IRQ_GPU_MASK, 70 + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU, 71 + .thermctl_lvl0_up_thresh_mask = TEGRA114_THERMCTL_LVL0_UP_THRESH_MASK, 72 + .thermctl_lvl0_dn_thresh_mask = TEGRA114_THERMCTL_LVL0_DN_THRESH_MASK, 73 + }; 74 + 75 + static const struct tegra_tsensor_group tegra114_tsensor_group_pll = { 76 + .id = TEGRA114_SOCTHERM_SENSOR_PLLX, 77 + .name = "pll", 78 + .sensor_temp_offset = SENSOR_TEMP2, 79 + .sensor_temp_mask = SENSOR_TEMP2_PLLX_TEMP_MASK, 80 + .pdiv = 10, 81 + .pdiv_ate = 10, 82 + .pdiv_mask = SENSOR_PDIV_PLLX_MASK, 83 + .thermtrip_any_en_mask = TEGRA114_THERMTRIP_ANY_EN_MASK, 84 + .thermtrip_enable_mask = TEGRA114_THERMTRIP_TSENSE_EN_MASK, 85 + .thermtrip_threshold_mask = TEGRA114_THERMTRIP_TSENSE_THRESH_MASK, 86 + .thermctl_isr_mask = THERM_IRQ_TSENSE_MASK, 87 + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE, 88 + .thermctl_lvl0_up_thresh_mask = TEGRA114_THERMCTL_LVL0_UP_THRESH_MASK, 89 + .thermctl_lvl0_dn_thresh_mask = TEGRA114_THERMCTL_LVL0_DN_THRESH_MASK, 90 + }; 91 + 92 + static const struct tegra_tsensor_group tegra114_tsensor_group_mem = { 93 + .id = TEGRA114_SOCTHERM_SENSOR_MEM, 94 + .name = "mem", 95 + .sensor_temp_offset = SENSOR_TEMP2, 96 + .sensor_temp_mask = SENSOR_TEMP2_MEM_TEMP_MASK, 97 + .pdiv = 10, 98 + .pdiv_ate = 10, 99 + .pdiv_mask = SENSOR_PDIV_MEM_MASK, 100 + .pllx_hotspot_diff = 0, 101 + .pllx_hotspot_mask = SENSOR_HOTSPOT_MEM_MASK, 102 + .thermtrip_any_en_mask = TEGRA114_THERMTRIP_ANY_EN_MASK, 103 + .thermtrip_enable_mask = TEGRA114_THERMTRIP_MEM_EN_MASK, 104 + .thermtrip_threshold_mask = TEGRA114_THERMTRIP_GPUMEM_THRESH_MASK, 105 + .thermctl_isr_mask = THERM_IRQ_MEM_MASK, 106 + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM, 107 + .thermctl_lvl0_up_thresh_mask = TEGRA114_THERMCTL_LVL0_UP_THRESH_MASK, 108 + .thermctl_lvl0_dn_thresh_mask = TEGRA114_THERMCTL_LVL0_DN_THRESH_MASK, 109 + }; 110 + 111 + static const struct tegra_tsensor_group *tegra114_tsensor_groups[] = { 112 + &tegra114_tsensor_group_cpu, 113 + &tegra114_tsensor_group_gpu, 114 + &tegra114_tsensor_group_pll, 115 + &tegra114_tsensor_group_mem, 116 + }; 117 + 118 + static const struct tegra_tsensor tegra114_tsensors[] = { 119 + { 120 + .name = "cpu0", 121 + .base = 0xc0, 122 + .config = &tegra114_tsensor_config, 123 + .calib_fuse_offset = 0x098, 124 + .fuse_corr_alpha = 1196400, 125 + .fuse_corr_beta = -13600000, 126 + .group = &tegra114_tsensor_group_cpu, 127 + }, { 128 + .name = "cpu1", 129 + .base = 0xe0, 130 + .config = &tegra114_tsensor_config, 131 + .calib_fuse_offset = 0x084, 132 + .fuse_corr_alpha = 1196400, 133 + .fuse_corr_beta = -13600000, 134 + .group = &tegra114_tsensor_group_cpu, 135 + }, { 136 + .name = "cpu2", 137 + .base = 0x100, 138 + .config = &tegra114_tsensor_config, 139 + .calib_fuse_offset = 0x088, 140 + .fuse_corr_alpha = 1196400, 141 + .fuse_corr_beta = -13600000, 142 + .group = &tegra114_tsensor_group_cpu, 143 + }, { 144 + .name = "cpu3", 145 + .base = 0x120, 146 + .config = &tegra114_tsensor_config, 147 + .calib_fuse_offset = 0x12c, 148 + .fuse_corr_alpha = 1196400, 149 + .fuse_corr_beta = -13600000, 150 + .group = &tegra114_tsensor_group_cpu, 151 + }, { 152 + .name = "mem0", 153 + .base = 0x140, 154 + .config = &tegra114_tsensor_config, 155 + .calib_fuse_offset = 0x158, 156 + .fuse_corr_alpha = 1000000, 157 + .fuse_corr_beta = 0, 158 + .group = &tegra114_tsensor_group_mem, 159 + }, { 160 + .name = "mem1", 161 + .base = 0x160, 162 + .config = &tegra114_tsensor_config, 163 + .calib_fuse_offset = 0x15c, 164 + .fuse_corr_alpha = 1000000, 165 + .fuse_corr_beta = 0, 166 + .group = &tegra114_tsensor_group_mem, 167 + }, { 168 + .name = "gpu", 169 + .base = 0x180, 170 + .config = &tegra114_tsensor_config, 171 + .calib_fuse_offset = 0x154, 172 + .fuse_corr_alpha = 1124500, 173 + .fuse_corr_beta = -9793100, 174 + .group = &tegra114_tsensor_group_gpu, 175 + }, { 176 + .name = "pllx", 177 + .base = 0x1a0, 178 + .config = &tegra114_tsensor_config, 179 + .calib_fuse_offset = 0x160, 180 + .fuse_corr_alpha = 1224200, 181 + .fuse_corr_beta = -14665000, 182 + .group = &tegra114_tsensor_group_pll, 183 + }, 184 + }; 185 + 186 + static const struct tegra_soctherm_fuse tegra114_soctherm_fuse = { 187 + .fuse_base_cp_mask = 0x3ff, 188 + .fuse_base_cp_shift = 0, 189 + .fuse_shift_cp_mask = 0x3f << 10, 190 + .fuse_shift_cp_shift = 10, 191 + .fuse_base_ft_mask = 0x7ff << 16, 192 + .fuse_base_ft_shift = 16, 193 + .fuse_shift_ft_mask = 0x1f << 27, 194 + .fuse_shift_ft_shift = 27, 195 + .fuse_common_reg = FUSE_VSENSOR_CALIB, 196 + .fuse_spare_realignment = 0, 197 + .nominal_calib_ft = 90, 198 + }; 199 + 200 + const struct tegra_soctherm_soc tegra114_soctherm = { 201 + .tsensors = tegra114_tsensors, 202 + .num_tsensors = ARRAY_SIZE(tegra114_tsensors), 203 + .ttgs = tegra114_tsensor_groups, 204 + .num_ttgs = ARRAY_SIZE(tegra114_tsensor_groups), 205 + .tfuse = &tegra114_soctherm_fuse, 206 + .thresh_grain = TEGRA114_THRESH_GRAIN, 207 + .bptt = TEGRA114_BPTT, 208 + .use_ccroc = false, 209 + };
+4
drivers/thermal/tegra/tegra124-soctherm.c
··· 200 200 static const struct tegra_soctherm_fuse tegra124_soctherm_fuse = { 201 201 .fuse_base_cp_mask = 0x3ff, 202 202 .fuse_base_cp_shift = 0, 203 + .fuse_shift_cp_mask = 0x3f, 204 + .fuse_shift_cp_shift = 0, 203 205 .fuse_base_ft_mask = 0x7ff << 10, 204 206 .fuse_base_ft_shift = 10, 205 207 .fuse_shift_ft_mask = 0x1f << 21, 206 208 .fuse_shift_ft_shift = 21, 209 + .fuse_common_reg = FUSE_TSENSOR_COMMON, 207 210 .fuse_spare_realignment = 0x1fc, 211 + .nominal_calib_ft = 105, 208 212 }; 209 213 210 214 const struct tegra_soctherm_soc tegra124_soctherm = {
+4
drivers/thermal/tegra/tegra132-soctherm.c
··· 200 200 static const struct tegra_soctherm_fuse tegra132_soctherm_fuse = { 201 201 .fuse_base_cp_mask = 0x3ff, 202 202 .fuse_base_cp_shift = 0, 203 + .fuse_shift_cp_mask = 0x3f, 204 + .fuse_shift_cp_shift = 0, 203 205 .fuse_base_ft_mask = 0x7ff << 10, 204 206 .fuse_base_ft_shift = 10, 205 207 .fuse_shift_ft_mask = 0x1f << 21, 206 208 .fuse_shift_ft_shift = 21, 209 + .fuse_common_reg = FUSE_TSENSOR_COMMON, 207 210 .fuse_spare_realignment = 0x1fc, 211 + .nominal_calib_ft = 105, 208 212 }; 209 213 210 214 const struct tegra_soctherm_soc tegra132_soctherm = {
+4
drivers/thermal/tegra/tegra210-soctherm.c
··· 201 201 static const struct tegra_soctherm_fuse tegra210_soctherm_fuse = { 202 202 .fuse_base_cp_mask = 0x3ff << 11, 203 203 .fuse_base_cp_shift = 11, 204 + .fuse_shift_cp_mask = 0x3f, 205 + .fuse_shift_cp_shift = 0, 204 206 .fuse_base_ft_mask = 0x7ff << 21, 205 207 .fuse_base_ft_shift = 21, 206 208 .fuse_shift_ft_mask = 0x1f << 6, 207 209 .fuse_shift_ft_shift = 6, 210 + .fuse_common_reg = FUSE_TSENSOR_COMMON, 208 211 .fuse_spare_realignment = 0, 212 + .nominal_calib_ft = 105, 209 213 }; 210 214 211 215 static struct tsensor_group_thermtrips tegra210_tsensor_thermtrips[] = {
+11 -20
drivers/thermal/testing/zone.c
··· 184 184 185 185 int tt_add_tz(void) 186 186 { 187 - struct tt_thermal_zone *tt_zone __free(kfree); 188 - struct tt_work *tt_work __free(kfree) = NULL; 189 187 int ret; 190 188 191 - tt_zone = kzalloc(sizeof(*tt_zone), GFP_KERNEL); 189 + struct tt_thermal_zone *tt_zone __free(kfree) = kzalloc(sizeof(*tt_zone), 190 + GFP_KERNEL); 192 191 if (!tt_zone) 193 192 return -ENOMEM; 194 193 195 - tt_work = kzalloc(sizeof(*tt_work), GFP_KERNEL); 194 + struct tt_work *tt_work __free(kfree) = kzalloc(sizeof(*tt_work), GFP_KERNEL); 196 195 if (!tt_work) 197 196 return -ENOMEM; 198 197 ··· 236 237 237 238 int tt_del_tz(const char *arg) 238 239 { 239 - struct tt_work *tt_work __free(kfree) = NULL; 240 240 struct tt_thermal_zone *tt_zone, *aux; 241 241 int ret; 242 242 int id; ··· 244 246 if (ret != 1) 245 247 return -EINVAL; 246 248 247 - tt_work = kzalloc(sizeof(*tt_work), GFP_KERNEL); 249 + struct tt_work *tt_work __free(kfree) = kzalloc(sizeof(*tt_work), GFP_KERNEL); 248 250 if (!tt_work) 249 251 return -ENOMEM; 250 252 ··· 328 330 329 331 int tt_zone_add_trip(const char *arg) 330 332 { 331 - struct tt_thermal_zone *tt_zone __free(put_tt_zone) = NULL; 332 - struct tt_trip *tt_trip __free(kfree) = NULL; 333 - struct tt_work *tt_work __free(kfree); 334 333 int id; 335 334 336 - tt_work = kzalloc(sizeof(*tt_work), GFP_KERNEL); 335 + struct tt_work *tt_work __free(kfree) = kzalloc(sizeof(*tt_work), GFP_KERNEL); 337 336 if (!tt_work) 338 337 return -ENOMEM; 339 338 340 - tt_trip = kzalloc(sizeof(*tt_trip), GFP_KERNEL); 339 + struct tt_trip *tt_trip __free(kfree) = kzalloc(sizeof(*tt_trip), GFP_KERNEL); 341 340 if (!tt_trip) 342 341 return -ENOMEM; 343 342 344 - tt_zone = tt_get_tt_zone(arg); 343 + struct tt_thermal_zone *tt_zone __free(put_tt_zone) = tt_get_tt_zone(arg); 345 344 if (IS_ERR(tt_zone)) 346 345 return PTR_ERR(tt_zone); 347 346 ··· 382 387 383 388 static int tt_zone_register_tz(struct tt_thermal_zone *tt_zone) 384 389 { 385 - struct thermal_trip *trips __free(kfree) = NULL; 386 390 struct thermal_zone_device *tz; 387 391 struct tt_trip *tt_trip; 388 392 int i; ··· 391 397 if (tt_zone->tz) 392 398 return -EINVAL; 393 399 394 - trips = kcalloc(tt_zone->num_trips, sizeof(*trips), GFP_KERNEL); 400 + struct thermal_trip *trips __free(kfree) = kcalloc(tt_zone->num_trips, 401 + sizeof(*trips), GFP_KERNEL); 395 402 if (!trips) 396 403 return -ENOMEM; 397 404 ··· 416 421 417 422 int tt_zone_reg(const char *arg) 418 423 { 419 - struct tt_thermal_zone *tt_zone __free(put_tt_zone); 420 - 421 - tt_zone = tt_get_tt_zone(arg); 424 + struct tt_thermal_zone *tt_zone __free(put_tt_zone) = tt_get_tt_zone(arg); 422 425 if (IS_ERR(tt_zone)) 423 426 return PTR_ERR(tt_zone); 424 427 ··· 425 432 426 433 int tt_zone_unreg(const char *arg) 427 434 { 428 - struct tt_thermal_zone *tt_zone __free(put_tt_zone); 429 - 430 - tt_zone = tt_get_tt_zone(arg); 435 + struct tt_thermal_zone *tt_zone __free(put_tt_zone) = tt_get_tt_zone(arg); 431 436 if (IS_ERR(tt_zone)) 432 437 return PTR_ERR(tt_zone); 433 438
+54 -1
drivers/thermal/thermal-generic-adc.c
··· 7 7 * Author: Laxman Dewangan <ldewangan@nvidia.com> 8 8 */ 9 9 #include <linux/iio/consumer.h> 10 + #include <linux/iio/iio.h> 10 11 #include <linux/kernel.h> 11 12 #include <linux/module.h> 12 13 #include <linux/platform_device.h> ··· 73 72 static const struct thermal_zone_device_ops gadc_thermal_ops = { 74 73 .get_temp = gadc_thermal_get_temp, 75 74 }; 75 + 76 + static const struct iio_chan_spec gadc_thermal_iio_channels[] = { 77 + { 78 + .type = IIO_TEMP, 79 + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 80 + } 81 + }; 82 + 83 + static int gadc_thermal_read_raw(struct iio_dev *indio_dev, 84 + struct iio_chan_spec const *chan, 85 + int *val, int *val2, long mask) 86 + { 87 + struct gadc_thermal_info *gtinfo = iio_priv(indio_dev); 88 + int ret; 89 + 90 + switch (mask) { 91 + case IIO_CHAN_INFO_PROCESSED: 92 + ret = gadc_thermal_get_temp(gtinfo->tz_dev, val); 93 + if (ret) 94 + return ret; 95 + 96 + return IIO_VAL_INT; 97 + 98 + default: 99 + return -EINVAL; 100 + } 101 + } 102 + 103 + static const struct iio_info gadc_thermal_iio_info = { 104 + .read_raw = gadc_thermal_read_raw, 105 + }; 106 + 107 + static int gadc_iio_register(struct device *dev, struct gadc_thermal_info *gti) 108 + { 109 + struct gadc_thermal_info *gtinfo; 110 + struct iio_dev *indio_dev; 111 + 112 + indio_dev = devm_iio_device_alloc(dev, sizeof(*gtinfo)); 113 + if (!indio_dev) 114 + return -ENOMEM; 115 + 116 + gtinfo = iio_priv(indio_dev); 117 + memcpy(gtinfo, gti, sizeof(*gtinfo)); 118 + 119 + indio_dev->name = dev_name(dev); 120 + indio_dev->info = &gadc_thermal_iio_info; 121 + indio_dev->modes = INDIO_DIRECT_MODE; 122 + indio_dev->channels = gadc_thermal_iio_channels; 123 + indio_dev->num_channels = ARRAY_SIZE(gadc_thermal_iio_channels); 124 + 125 + return devm_iio_device_register(dev, indio_dev); 126 + } 76 127 77 128 static int gadc_thermal_read_linear_lookup_table(struct device *dev, 78 129 struct gadc_thermal_info *gti) ··· 206 153 207 154 devm_thermal_add_hwmon_sysfs(dev, gti->tz_dev); 208 155 209 - return 0; 156 + return gadc_iio_register(&pdev->dev, gti); 210 157 } 211 158 212 159 static const struct of_device_id of_adc_thermal_match[] = {
+1 -1
drivers/thermal/thermal_hwmon.c
··· 96 96 97 97 mutex_lock(&thermal_hwmon_list_lock); 98 98 list_for_each_entry(hwmon, &thermal_hwmon_list, node) { 99 - strcpy(type, tz->type); 99 + strscpy(type, tz->type); 100 100 strreplace(type, '-', '_'); 101 101 if (!strcmp(hwmon->type, type)) { 102 102 mutex_unlock(&thermal_hwmon_list_lock);
+19
include/dt-bindings/thermal/tegra114-soctherm.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 + /* 3 + * This header provides constants for binding nvidia,tegra114-soctherm. 4 + */ 5 + 6 + #ifndef _DT_BINDINGS_THERMAL_TEGRA114_SOCTHERM_H 7 + #define _DT_BINDINGS_THERMAL_TEGRA114_SOCTHERM_H 8 + 9 + #define TEGRA114_SOCTHERM_SENSOR_CPU 0 10 + #define TEGRA114_SOCTHERM_SENSOR_MEM 1 11 + #define TEGRA114_SOCTHERM_SENSOR_GPU 2 12 + #define TEGRA114_SOCTHERM_SENSOR_PLLX 3 13 + 14 + #define TEGRA114_SOCTHERM_THROT_LEVEL_NONE 0 15 + #define TEGRA114_SOCTHERM_THROT_LEVEL_LOW 1 16 + #define TEGRA114_SOCTHERM_THROT_LEVEL_MED 2 17 + #define TEGRA114_SOCTHERM_THROT_LEVEL_HIGH 3 18 + 19 + #endif
+2
tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c
··· 144 144 ret = sscanf(index_str, "%d", &index); 145 145 if (ret < 0) 146 146 break; 147 + 148 + index &= 0x0f; 147 149 if (index > WORKLOAD_TYPE_MAX_INDEX) 148 150 printf("Invalid workload type index\n"); 149 151 else