From 788494ba09992f6bc1c50327afdd1c861113fbe4 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Fri, 17 Nov 2023 06:22:14 +0100 Subject: dt-bindings: thermal: convert Mediatek Thermal to the json-schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helps validating DTS files. Introduced changes: 1. Improved title 2. Simplified description (dropped "This describes the device tree...") 3. Dropped undocumented "reset-names" from example Signed-off-by: Rafał Miłecki Reviewed-by: Rob Herring Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231117052214.24554-1-zajec5@gmail.com --- .../bindings/thermal/mediatek,thermal.yaml | 99 ++++++++++++++++++++++ .../bindings/thermal/mediatek-thermal.txt | 52 ------------ 2 files changed, 99 insertions(+), 52 deletions(-) create mode 100644 Documentation/devicetree/bindings/thermal/mediatek,thermal.yaml delete mode 100644 Documentation/devicetree/bindings/thermal/mediatek-thermal.txt diff --git a/Documentation/devicetree/bindings/thermal/mediatek,thermal.yaml b/Documentation/devicetree/bindings/thermal/mediatek,thermal.yaml new file mode 100644 index 000000000000..d96a2e32bd8f --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/mediatek,thermal.yaml @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/thermal/mediatek,thermal.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek thermal controller for on-SoC temperatures + +maintainers: + - Sascha Hauer + +description: + This device does not have its own ADC, instead it directly controls the AUXADC + via AHB bus accesses. For this reason it needs phandles to the AUXADC. Also it + controls a mux in the apmixedsys register space via AHB bus accesses, so a + phandle to the APMIXEDSYS is also needed. + +allOf: + - $ref: thermal-sensor.yaml# + +properties: + compatible: + enum: + - mediatek,mt2701-thermal + - mediatek,mt2712-thermal + - mediatek,mt7622-thermal + - mediatek,mt7981-thermal + - mediatek,mt7986-thermal + - mediatek,mt8173-thermal + - mediatek,mt8183-thermal + - mediatek,mt8365-thermal + - mediatek,mt8516-thermal + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Main clock needed for register access + - description: The AUXADC clock + + clock-names: + items: + - const: therm + - const: auxadc + + mediatek,auxadc: + $ref: /schemas/types.yaml#/definitions/phandle + description: A phandle to the AUXADC which the thermal controller uses + + mediatek,apmixedsys: + $ref: /schemas/types.yaml#/definitions/phandle + description: A phandle to the APMIXEDSYS controller + + resets: + description: Reset controller controlling the thermal controller + + nvmem-cells: + items: + - description: + NVMEM cell with EEPROMA phandle to the calibration data provided by an + NVMEM device. If unspecified default values shall be used. + + nvmem-cell-names: + items: + - const: calibration-data + +required: + - reg + - interrupts + - clocks + - clock-names + - mediatek,auxadc + - mediatek,apmixedsys + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + thermal@1100b000 { + compatible = "mediatek,mt8173-thermal"; + reg = <0x1100b000 0x1000>; + interrupts = <0 70 IRQ_TYPE_LEVEL_LOW>; + clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>; + clock-names = "therm", "auxadc"; + resets = <&pericfg MT8173_PERI_THERM_SW_RST>; + mediatek,auxadc = <&auxadc>; + mediatek,apmixedsys = <&apmixedsys>; + nvmem-cells = <&thermal_calibration_data>; + nvmem-cell-names = "calibration-data"; + #thermal-sensor-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt b/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt deleted file mode 100644 index ac39c7156fde..000000000000 --- a/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt +++ /dev/null @@ -1,52 +0,0 @@ -* Mediatek Thermal - -This describes the device tree binding for the Mediatek thermal controller -which measures the on-SoC temperatures. This device does not have its own ADC, -instead it directly controls the AUXADC via AHB bus accesses. For this reason -this device needs phandles to the AUXADC. Also it controls a mux in the -apmixedsys register space via AHB bus accesses, so a phandle to the APMIXEDSYS -is also needed. - -Required properties: -- compatible: - - "mediatek,mt8173-thermal" : For MT8173 family of SoCs - - "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,mt8365-thermal" : For MT8365 family of SoCs - - "mediatek,mt8516-thermal", "mediatek,mt2701-thermal : For MT8516 family of SoCs -- reg: Address range of the thermal controller -- interrupts: IRQ for the thermal controller -- clocks, clock-names: Clocks needed for the thermal controller. required - clocks are: - "therm": Main clock needed for register access - "auxadc": The AUXADC clock -- mediatek,auxadc: A phandle to the AUXADC which the thermal controller uses -- mediatek,apmixedsys: A phandle to the APMIXEDSYS controller. -- #thermal-sensor-cells : Should be 0. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description. - -Optional properties: -- resets: Reference to the reset controller controlling the thermal controller. -- nvmem-cells: A phandle to the calibration data provided by a nvmem device. If - unspecified default values shall be used. -- nvmem-cell-names: Should be "calibration-data" - -Example: - - thermal: thermal@1100b000 { - #thermal-sensor-cells = <1>; - compatible = "mediatek,mt8173-thermal"; - reg = <0 0x1100b000 0 0x1000>; - interrupts = <0 70 IRQ_TYPE_LEVEL_LOW>; - clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>; - clock-names = "therm", "auxadc"; - resets = <&pericfg MT8173_PERI_THERM_SW_RST>; - reset-names = "therm"; - mediatek,auxadc = <&auxadc>; - mediatek,apmixedsys = <&apmixedsys>; - nvmem-cells = <&thermal_calibration_data>; - nvmem-cell-names = "calibration-data"; - }; -- cgit From 88071e31e994ee23356674e0c5461b25e2a95cdc Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Fri, 24 Nov 2023 17:57:44 +0800 Subject: dt-bindings: thermal: loongson,ls2k-thermal: Fix binding check issues Add the missing 'thermal-sensor-cells' property which is required for every thermal sensor as it's used when using phandles. And add the thermal-sensor.yaml reference. In fact, it was a careless mistake when submitting the driver that caused it to not work properly. So the fix is necessary, although it will result in the ABI break. Fixes: 72684d99a854 ("thermal: dt-bindings: add loongson-2 thermal") Cc: Yinbo Zhu Signed-off-by: Binbin Zhou Reviewed-by: Conor Dooley Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/6d69362632271ab0af9a5fbfa3bc46a0894f1d54.1700817227.git.zhoubinbin@loongson.cn --- .../devicetree/bindings/thermal/loongson,ls2k-thermal.yaml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml index 7538469997f9..b634f57cd011 100644 --- a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml +++ b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml @@ -10,6 +10,9 @@ maintainers: - zhanghongchen - Yinbo Zhu +allOf: + - $ref: /schemas/thermal/thermal-sensor.yaml# + properties: compatible: oneOf: @@ -26,12 +29,16 @@ properties: interrupts: maxItems: 1 + '#thermal-sensor-cells': + const: 1 + required: - compatible - reg - interrupts + - '#thermal-sensor-cells' -additionalProperties: false +unevaluatedProperties: false examples: - | @@ -41,4 +48,5 @@ examples: reg = <0x1fe01500 0x30>; interrupt-parent = <&liointc0>; interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + #thermal-sensor-cells = <1>; }; -- cgit From 15ef92e9c41124ee9d88b01208364f3fe1f45f84 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Fri, 24 Nov 2023 17:57:45 +0800 Subject: drivers/thermal/loongson2_thermal: Fix incorrect PTR_ERR() judgment PTR_ERR() returns -ENODEV when thermal-zones are undefined, and we need -ENODEV as the right value for comparison. Otherwise, tz->type is NULL when thermal-zones is undefined, resulting in the following error: [ 12.290030] CPU 1 Unable to handle kernel paging request at virtual address fffffffffffffff1, era == 900000000355f410, ra == 90000000031579b8 [ 12.302877] Oops[#1]: [ 12.305190] CPU: 1 PID: 181 Comm: systemd-udevd Not tainted 6.6.0-rc7+ #5385 [ 12.312304] pc 900000000355f410 ra 90000000031579b8 tp 90000001069e8000 sp 90000001069eba10 [ 12.320739] a0 0000000000000000 a1 fffffffffffffff1 a2 0000000000000014 a3 0000000000000001 [ 12.329173] a4 90000001069eb990 a5 0000000000000001 a6 0000000000001001 a7 900000010003431c [ 12.337606] t0 fffffffffffffff1 t1 54567fd5da9b4fd4 t2 900000010614ec40 t3 00000000000dc901 [ 12.346041] t4 0000000000000000 t5 0000000000000004 t6 900000010614ee20 t7 900000000d00b790 [ 12.354472] t8 00000000000dc901 u0 54567fd5da9b4fd4 s9 900000000402ae10 s0 900000010614ec40 [ 12.362916] s1 90000000039fced0 s2 ffffffffffffffed s3 ffffffffffffffed s4 9000000003acc000 [ 12.362931] s5 0000000000000004 s6 fffffffffffff000 s7 0000000000000490 s8 90000001028b2ec8 [ 12.362938] ra: 90000000031579b8 thermal_add_hwmon_sysfs+0x258/0x300 [ 12.386411] ERA: 900000000355f410 strscpy+0xf0/0x160 [ 12.391626] CRMD: 000000b0 (PLV0 -IE -DA +PG DACF=CC DACM=CC -WE) [ 12.397898] PRMD: 00000004 (PPLV0 +PIE -PWE) [ 12.403678] EUEN: 00000000 (-FPE -SXE -ASXE -BTE) [ 12.409859] ECFG: 00071c1c (LIE=2-4,10-12 VS=7) [ 12.415882] ESTAT: 00010000 [PIL] (IS= ECode=1 EsubCode=0) [ 12.415907] BADV: fffffffffffffff1 [ 12.415911] PRID: 0014a000 (Loongson-64bit, Loongson-2K1000) [ 12.415917] Modules linked in: loongson2_thermal(+) vfat fat uio_pdrv_genirq uio fuse zram zsmalloc [ 12.415950] Process systemd-udevd (pid: 181, threadinfo=00000000358b9718, task=00000000ace72fe3) [ 12.415961] Stack : 0000000000000dc0 54567fd5da9b4fd4 900000000402ae10 9000000002df9358 [ 12.415982] ffffffffffffffed 0000000000000004 9000000107a10aa8 90000001002a3410 [ 12.415999] ffffffffffffffed ffffffffffffffed 9000000107a11268 9000000003157ab0 [ 12.416016] 9000000107a10aa8 ffffff80020fc0c8 90000001002a3410 ffffffffffffffed [ 12.416032] 0000000000000024 ffffff80020cc1e8 900000000402b2a0 9000000003acc000 [ 12.416048] 90000001002a3410 0000000000000000 ffffff80020f4030 90000001002a3410 [ 12.416065] 0000000000000000 9000000002df6808 90000001002a3410 0000000000000000 [ 12.416081] ffffff80020f4030 0000000000000000 90000001002a3410 9000000002df2ba8 [ 12.416097] 00000000000000b4 90000001002a34f4 90000001002a3410 0000000000000002 [ 12.416114] ffffff80020f4030 fffffffffffffff0 90000001002a3410 9000000002df2f30 [ 12.416131] ... [ 12.416138] Call Trace: [ 12.416142] [<900000000355f410>] strscpy+0xf0/0x160 [ 12.416167] [<90000000031579b8>] thermal_add_hwmon_sysfs+0x258/0x300 [ 12.416183] [<9000000003157ab0>] devm_thermal_add_hwmon_sysfs+0x50/0xe0 [ 12.416200] [] loongson2_thermal_probe+0x128/0x200 [loongson2_thermal] [ 12.416232] [<9000000002df6808>] platform_probe+0x68/0x140 [ 12.416249] [<9000000002df2ba8>] really_probe+0xc8/0x3c0 [ 12.416269] [<9000000002df2f30>] __driver_probe_device+0x90/0x180 [ 12.416286] [<9000000002df3058>] driver_probe_device+0x38/0x160 [ 12.416302] [<9000000002df33a8>] __driver_attach+0xa8/0x200 [ 12.416314] [<9000000002deffec>] bus_for_each_dev+0x8c/0x120 [ 12.416330] [<9000000002df198c>] bus_add_driver+0x10c/0x2a0 [ 12.416346] [<9000000002df46b4>] driver_register+0x74/0x160 [ 12.416358] [<90000000022201a4>] do_one_initcall+0x84/0x220 [ 12.416372] [<90000000022f3ab8>] do_init_module+0x58/0x2c0 [ 12.416386] [<90000000022f6538>] init_module_from_file+0x98/0x100 [ 12.416399] [<90000000022f67f0>] sys_finit_module+0x230/0x3c0 [ 12.416412] [<900000000358f7c8>] do_syscall+0x88/0xc0 [ 12.416431] [<900000000222137c>] handle_syscall+0xbc/0x158 Fixes: e7e3a7c35791 ("thermal/drivers/loongson-2: Add thermal management support") Cc: Yinbo Zhu Signed-off-by: Binbin Zhou Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/343c14de98216636a47b43e8bfd47b70d0a8e068.1700817227.git.zhoubinbin@loongson.cn --- drivers/thermal/loongson2_thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c index 133098dc0854..99ca0c7bc41c 100644 --- a/drivers/thermal/loongson2_thermal.c +++ b/drivers/thermal/loongson2_thermal.c @@ -127,7 +127,7 @@ static int loongson2_thermal_probe(struct platform_device *pdev) if (!IS_ERR(tzd)) break; - if (PTR_ERR(tzd) != ENODEV) + if (PTR_ERR(tzd) != -ENODEV) continue; return dev_err_probe(dev, PTR_ERR(tzd), "failed to register"); -- cgit From 748b49c7dfe59d026c2e44cfb63cf66659aceb50 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 28 Nov 2023 09:44:48 +0100 Subject: dt-bindings: thermal: qcom-tsens: document the SM8650 Temperature Sensor Document the Temperature Sensor (TSENS) on the SM8650 Platform. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Neil Armstrong Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231128-topic-sm8650-upstream-bindings-tsens-v3-1-54179e6646d3@linaro.org --- Documentation/devicetree/bindings/thermal/qcom-tsens.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml index 437b74732886..99d9c526c0b6 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml @@ -66,6 +66,7 @@ properties: - qcom,sm8350-tsens - qcom,sm8450-tsens - qcom,sm8550-tsens + - qcom,sm8650-tsens - const: qcom,tsens-v2 - description: v2 of TSENS with combined interrupt -- cgit From 87f67d1747bc3ce8ace14be99b47d7731041ff03 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 29 Nov 2023 09:43:27 -0300 Subject: dt-bindings: thermal-zones: Document critical-action Document the critical-action property to describe the thermal action the OS should perform after the critical temperature is reached. The possible values are "shutdown" and "reboot". The motivation for introducing the critical-action property is that different systems may need different thermal actions when the critical temperature is reached. For example, in a desktop PC, it is desired that a shutdown happens after the critical temperature is reached. However, in some embedded cases, such behavior does not suit well, as the board may be unattended in the field and rebooting may be a better approach. The bootloader may also benefit from this new property as it can check the SoC temperature and in case the temperature is above the critical point, it can trigger a shutdown or reboot accordingly. Signed-off-by: Fabio Estevam Reviewed-by: Krzysztof Kozlowski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231129124330.519423-1-festevam@gmail.com --- .../devicetree/bindings/thermal/thermal-zones.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/thermal/thermal-zones.yaml b/Documentation/devicetree/bindings/thermal/thermal-zones.yaml index 4a8dabc48170..dbd52620d293 100644 --- a/Documentation/devicetree/bindings/thermal/thermal-zones.yaml +++ b/Documentation/devicetree/bindings/thermal/thermal-zones.yaml @@ -75,6 +75,22 @@ patternProperties: framework and assumes that the thermal sensors in this zone support interrupts. + critical-action: + $ref: /schemas/types.yaml#/definitions/string + description: | + The action the OS should perform after the critical temperature is reached. + By default the system will shutdown as a safe action to prevent damage + to the hardware, if the property is not set. + The shutdown action should be always the default and preferred one. + Choose 'reboot' with care, as the hardware may be in thermal stress, + thus leading to infinite reboots that may cause damage to the hardware. + Make sure the firmware/bootloader will act as the last resort and take + over the thermal control. + + enum: + - shutdown + - reboot + thermal-sensors: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 -- cgit From 5a0e241003b80247de59727c945bc94c848f893d Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 29 Nov 2023 09:43:28 -0300 Subject: thermal/core: Prepare for introduction of thermal reboot Add some helper functions to make it easier introducing the support for thermal reboot. No functional change. Signed-off-by: Fabio Estevam Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231129124330.519423-2-festevam@gmail.com --- drivers/thermal/thermal_core.c | 14 ++++++++++---- include/linux/reboot.h | 7 ++++++- kernel/reboot.c | 8 ++++---- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 5e5fcbd81dda..859f62e9d779 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -311,18 +311,24 @@ static void handle_non_critical_trips(struct thermal_zone_device *tz, def_governor->throttle(tz, trip); } -void thermal_zone_device_critical(struct thermal_zone_device *tz) +static void thermal_zone_device_halt(struct thermal_zone_device *tz, bool shutdown) { /* * poweroff_delay_ms must be a carefully profiled positive value. * Its a must for forced_emergency_poweroff_work to be scheduled. */ int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS; + const char *msg = "Temperature too high"; + + dev_emerg(&tz->device, "%s: critical temperature reached\n", tz->type); - dev_emerg(&tz->device, "%s: critical temperature reached, " - "shutting down\n", tz->type); + if (shutdown) + hw_protection_shutdown(msg, poweroff_delay_ms); +} - hw_protection_shutdown("Temperature too high", poweroff_delay_ms); +void thermal_zone_device_critical(struct thermal_zone_device *tz) +{ + thermal_zone_device_halt(tz, true); } EXPORT_SYMBOL(thermal_zone_device_critical); diff --git a/include/linux/reboot.h b/include/linux/reboot.h index c4cc3b89ced1..4586c663884e 100644 --- a/include/linux/reboot.h +++ b/include/linux/reboot.h @@ -177,7 +177,12 @@ void ctrl_alt_del(void); extern void orderly_poweroff(bool force); extern void orderly_reboot(void); -void hw_protection_shutdown(const char *reason, int ms_until_forced); +void __hw_protection_shutdown(const char *reason, int ms_until_forced, bool shutdown); + +static inline void hw_protection_shutdown(const char *reason, int ms_until_forced) +{ + __hw_protection_shutdown(reason, ms_until_forced, true); +} /* * Emergency restart, callable from an interrupt handler. diff --git a/kernel/reboot.c b/kernel/reboot.c index 395a0ea3c7a8..b236c4c06bb3 100644 --- a/kernel/reboot.c +++ b/kernel/reboot.c @@ -957,7 +957,7 @@ static void hw_failure_emergency_poweroff(int poweroff_delay_ms) } /** - * hw_protection_shutdown - Trigger an emergency system poweroff + * __hw_protection_shutdown - Trigger an emergency system poweroff * * @reason: Reason of emergency shutdown to be printed. * @ms_until_forced: Time to wait for orderly shutdown before tiggering a @@ -971,7 +971,7 @@ static void hw_failure_emergency_poweroff(int poweroff_delay_ms) * if the previous request has given a large timeout for forced shutdown. * Can be called from any context. */ -void hw_protection_shutdown(const char *reason, int ms_until_forced) +void __hw_protection_shutdown(const char *reason, int ms_until_forced, bool shutdown) { static atomic_t allow_proceed = ATOMIC_INIT(1); @@ -986,9 +986,9 @@ void hw_protection_shutdown(const char *reason, int ms_until_forced) * orderly_poweroff failure */ hw_failure_emergency_poweroff(ms_until_forced); - orderly_poweroff(true); + if (shutdown) + orderly_poweroff(true); } -EXPORT_SYMBOL_GPL(hw_protection_shutdown); static int __init reboot_setup(char *str) { -- cgit From 79fa723ba84c2b1b3124c72df8a3b07b851a5477 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 29 Nov 2023 09:43:29 -0300 Subject: reboot: Introduce thermal_zone_device_critical_reboot() Introduce thermal_zone_device_critical_reboot() to trigger an emergency reboot. It is a counterpart of thermal_zone_device_critical() with the difference that it will force a reboot instead of shutdown. The motivation for doing this is to allow the thermal subystem to trigger a reboot when the temperature reaches the critical temperature. Signed-off-by: Fabio Estevam Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231129124330.519423-3-festevam@gmail.com --- drivers/thermal/thermal_core.c | 7 +++++++ drivers/thermal/thermal_core.h | 1 + include/linux/reboot.h | 5 +++++ kernel/reboot.c | 28 +++++++++++++++++----------- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 859f62e9d779..0d761afb7cbc 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -324,6 +324,8 @@ static void thermal_zone_device_halt(struct thermal_zone_device *tz, bool shutdo if (shutdown) hw_protection_shutdown(msg, poweroff_delay_ms); + else + hw_protection_reboot(msg, poweroff_delay_ms); } void thermal_zone_device_critical(struct thermal_zone_device *tz) @@ -332,6 +334,11 @@ void thermal_zone_device_critical(struct thermal_zone_device *tz) } EXPORT_SYMBOL(thermal_zone_device_critical); +void thermal_zone_device_critical_reboot(struct thermal_zone_device *tz) +{ + thermal_zone_device_halt(tz, false); +} + static void handle_critical_trips(struct thermal_zone_device *tz, const struct thermal_trip *trip) { diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index fe2917a74054..b5e6743bd157 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -114,6 +114,7 @@ int thermal_zone_device_set_policy(struct thermal_zone_device *, char *); int thermal_build_list_of_policies(char *buf); void __thermal_zone_device_update(struct thermal_zone_device *tz, enum thermal_notify_event event); +void thermal_zone_device_critical_reboot(struct thermal_zone_device *tz); /* Helpers */ #define for_each_trip(__tz, __trip) \ diff --git a/include/linux/reboot.h b/include/linux/reboot.h index 4586c663884e..abcdde4df697 100644 --- a/include/linux/reboot.h +++ b/include/linux/reboot.h @@ -179,6 +179,11 @@ extern void orderly_poweroff(bool force); extern void orderly_reboot(void); void __hw_protection_shutdown(const char *reason, int ms_until_forced, bool shutdown); +static inline void hw_protection_reboot(const char *reason, int ms_until_forced) +{ + __hw_protection_shutdown(reason, ms_until_forced, false); +} + static inline void hw_protection_shutdown(const char *reason, int ms_until_forced) { __hw_protection_shutdown(reason, ms_until_forced, true); diff --git a/kernel/reboot.c b/kernel/reboot.c index b236c4c06bb3..35d5e0b67993 100644 --- a/kernel/reboot.c +++ b/kernel/reboot.c @@ -957,19 +957,22 @@ static void hw_failure_emergency_poweroff(int poweroff_delay_ms) } /** - * __hw_protection_shutdown - Trigger an emergency system poweroff + * __hw_protection_shutdown - Trigger an emergency system shutdown or reboot * - * @reason: Reason of emergency shutdown to be printed. - * @ms_until_forced: Time to wait for orderly shutdown before tiggering a - * forced shudown. Negative value disables the forced - * shutdown. + * @reason: Reason of emergency shutdown or reboot to be printed. + * @ms_until_forced: Time to wait for orderly shutdown or reboot before + * triggering it. Negative value disables the forced + * shutdown or reboot. + * @shutdown: If true, indicates that a shutdown will happen + * after the critical tempeature is reached. + * If false, indicates that a reboot will happen + * after the critical tempeature is reached. * - * Initiate an emergency system shutdown in order to protect hardware from - * further damage. Usage examples include a thermal protection or a voltage or - * current regulator failures. - * NOTE: The request is ignored if protection shutdown is already pending even - * if the previous request has given a large timeout for forced shutdown. - * Can be called from any context. + * Initiate an emergency system shutdown or reboot in order to protect + * hardware from further damage. Usage examples include a thermal protection. + * NOTE: The request is ignored if protection shutdown or reboot is already + * pending even if the previous request has given a large timeout for forced + * shutdown/reboot. */ void __hw_protection_shutdown(const char *reason, int ms_until_forced, bool shutdown) { @@ -988,7 +991,10 @@ void __hw_protection_shutdown(const char *reason, int ms_until_forced, bool shut hw_failure_emergency_poweroff(ms_until_forced); if (shutdown) orderly_poweroff(true); + else + orderly_reboot(); } +EXPORT_SYMBOL_GPL(__hw_protection_shutdown); static int __init reboot_setup(char *str) { -- cgit From 62e79e38b257a59f1e3d8aff801ae8590e2e45b4 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 29 Nov 2023 09:43:30 -0300 Subject: thermal/thermal_of: Allow rebooting after critical temp Currently, the default mechanism is to trigger a shutdown after the critical temperature is reached. In some embedded cases, such behavior does not suit well, as the board may be unattended in the field and rebooting may be a better approach. The bootloader may also check the temperature and only allow the boot to proceed when the temperature is below a certain threshold. Introduce support for allowing a reboot to be triggered after the critical temperature is reached. If the "critical-action" devicetree property is not found, fall back to the shutdown action to preserve the existing default behavior. If a custom ops->critical exists, then it takes preference over critical-actions. Tested on a i.MX8MM board with the following devicetree changes: thermal-zones { cpu-thermal { critical-action = "reboot"; }; }; Signed-off-by: Fabio Estevam Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231129124330.519423-4-festevam@gmail.com --- drivers/thermal/thermal_of.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c index 1e0655b63259..4d6c22e0ed85 100644 --- a/drivers/thermal/thermal_of.c +++ b/drivers/thermal/thermal_of.c @@ -475,6 +475,7 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node * struct thermal_zone_params tzp = {}; struct thermal_zone_device_ops *of_ops; struct device_node *np; + const char *action; int delay, pdelay; int ntrips, mask; int ret; @@ -511,6 +512,11 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node * mask = GENMASK_ULL((ntrips) - 1, 0); + ret = of_property_read_string(np, "critical-action", &action); + if (!ret) + if (!of_ops->critical && !strcasecmp(action, "reboot")) + of_ops->critical = thermal_zone_device_critical_reboot; + tz = thermal_zone_device_register_with_trips(np->name, trips, ntrips, mask, data, of_ops, &tzp, pdelay, delay); -- cgit From 720f8db834a31009d8d11893278ca3f8072a575e Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 16 Nov 2023 12:26:35 +0100 Subject: thermal: amlogic: Make amlogic_thermal_disable() return void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit amlogic_thermal_disable() returned zero unconditionally and amlogic_thermal_remove() already ignores the return value. Make it return no value and modify amlogic_thermal_suspend to not check the value. This patch introduces no semantic changes, but makes it more obvious for a human reader that amlogic_thermal_suspend() cannot fail. Signed-off-by: Uwe Kleine-König Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231116112633.668826-2-u.kleine-koenig@pengutronix.de --- drivers/thermal/amlogic_thermal.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/amlogic_thermal.c b/drivers/thermal/amlogic_thermal.c index 5877cde25b79..562f63b7bf27 100644 --- a/drivers/thermal/amlogic_thermal.c +++ b/drivers/thermal/amlogic_thermal.c @@ -167,13 +167,11 @@ static int amlogic_thermal_enable(struct amlogic_thermal *data) return 0; } -static int amlogic_thermal_disable(struct amlogic_thermal *data) +static void amlogic_thermal_disable(struct amlogic_thermal *data) { regmap_update_bits(data->regmap, TSENSOR_CFG_REG1, TSENSOR_CFG_REG1_ENABLE, 0); clk_disable_unprepare(data->clk); - - return 0; } static int amlogic_thermal_get_temp(struct thermal_zone_device *tz, int *temp) @@ -302,7 +300,9 @@ static int __maybe_unused amlogic_thermal_suspend(struct device *dev) { struct amlogic_thermal *data = dev_get_drvdata(dev); - return amlogic_thermal_disable(data); + amlogic_thermal_disable(data); + + return 0; } static int __maybe_unused amlogic_thermal_resume(struct device *dev) -- cgit From ac99b129630efa14efe176e968045cde9d442e55 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 16 Nov 2023 12:26:36 +0100 Subject: thermal: amlogic: Use DEFINE_SIMPLE_DEV_PM_OPS for PM functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This macro has the advantage over SIMPLE_DEV_PM_OPS that we don't have to care about when the functions are actually used, so the corresponding __maybe_unused can be dropped. Also make use of pm_ptr() to discard all PM related stuff if CONFIG_PM isn't enabled. Signed-off-by: Uwe Kleine-König Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231116112633.668826-3-u.kleine-koenig@pengutronix.de --- drivers/thermal/amlogic_thermal.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/thermal/amlogic_thermal.c b/drivers/thermal/amlogic_thermal.c index 562f63b7bf27..df7a5ed55385 100644 --- a/drivers/thermal/amlogic_thermal.c +++ b/drivers/thermal/amlogic_thermal.c @@ -296,7 +296,7 @@ static void amlogic_thermal_remove(struct platform_device *pdev) amlogic_thermal_disable(data); } -static int __maybe_unused amlogic_thermal_suspend(struct device *dev) +static int amlogic_thermal_suspend(struct device *dev) { struct amlogic_thermal *data = dev_get_drvdata(dev); @@ -305,20 +305,21 @@ static int __maybe_unused amlogic_thermal_suspend(struct device *dev) return 0; } -static int __maybe_unused amlogic_thermal_resume(struct device *dev) +static int amlogic_thermal_resume(struct device *dev) { struct amlogic_thermal *data = dev_get_drvdata(dev); return amlogic_thermal_enable(data); } -static SIMPLE_DEV_PM_OPS(amlogic_thermal_pm_ops, - amlogic_thermal_suspend, amlogic_thermal_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(amlogic_thermal_pm_ops, + amlogic_thermal_suspend, + amlogic_thermal_resume); static struct platform_driver amlogic_thermal_driver = { .driver = { .name = "amlogic_thermal", - .pm = &amlogic_thermal_pm_ops, + .pm = pm_ptr(&amlogic_thermal_pm_ops), .of_match_table = of_amlogic_thermal_match, }, .probe = amlogic_thermal_probe, -- cgit From 20bf6262d518c5d3bf38c805be1bbda36acb9506 Mon Sep 17 00:00:00 2001 From: Maxim Kiselev Date: Mon, 18 Dec 2023 00:06:22 +0300 Subject: dt-bindings: thermal: sun8i: Add binding for D1/T113s THS controller Add a binding for D1/T113s thermal sensor controller. Signed-off-by: Maxim Kiselev Reviewed-by: Conor Dooley Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231217210629.131486-2-bigunclemax@gmail.com --- .../devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml b/Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml index fbd4212285e2..9b2272a9ec15 100644 --- a/Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml +++ b/Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml @@ -16,6 +16,7 @@ properties: - allwinner,sun8i-a83t-ths - allwinner,sun8i-h3-ths - allwinner,sun8i-r40-ths + - allwinner,sun20i-d1-ths - allwinner,sun50i-a64-ths - allwinner,sun50i-a100-ths - allwinner,sun50i-h5-ths @@ -61,6 +62,7 @@ allOf: compatible: contains: enum: + - allwinner,sun20i-d1-ths - allwinner,sun50i-a100-ths - allwinner,sun50i-h6-ths @@ -84,7 +86,9 @@ allOf: properties: compatible: contains: - const: allwinner,sun8i-h3-ths + enum: + - allwinner,sun8i-h3-ths + - allwinner,sun20i-d1-ths then: properties: @@ -103,6 +107,7 @@ allOf: enum: - allwinner,sun8i-h3-ths - allwinner,sun8i-r40-ths + - allwinner,sun20i-d1-ths - allwinner,sun50i-a64-ths - allwinner,sun50i-a100-ths - allwinner,sun50i-h5-ths -- cgit From ebbf19e36d021f253425344b4d4b987f3b7d9be5 Mon Sep 17 00:00:00 2001 From: Maxim Kiselev Date: Mon, 18 Dec 2023 00:06:23 +0300 Subject: thermal/drivers/sun8i: Add D1/T113s THS controller support This patch adds a thermal sensor controller support for the D1/T113s, which is similar to the one on H6, but with only one sensor and different scale and offset values. Signed-off-by: Maxim Kiselev Acked-by: Jernej Skrabec Reviewed-by: Andre Przywara Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231217210629.131486-3-bigunclemax@gmail.com --- drivers/thermal/sun8i_thermal.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c index f989b55a8aa8..6a8e386dbc8d 100644 --- a/drivers/thermal/sun8i_thermal.c +++ b/drivers/thermal/sun8i_thermal.c @@ -606,6 +606,18 @@ static const struct ths_thermal_chip sun50i_h6_ths = { .calc_temp = sun8i_ths_calc_temp, }; +static const struct ths_thermal_chip sun20i_d1_ths = { + .sensor_num = 1, + .has_bus_clk_reset = true, + .offset = 188552, + .scale = 673, + .temp_data_base = SUN50I_H6_THS_TEMP_DATA, + .calibrate = sun50i_h6_ths_calibrate, + .init = sun50i_h6_thermal_init, + .irq_ack = sun50i_h6_irq_ack, + .calc_temp = sun8i_ths_calc_temp, +}; + static const struct of_device_id of_ths_match[] = { { .compatible = "allwinner,sun8i-a83t-ths", .data = &sun8i_a83t_ths }, { .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths }, @@ -614,6 +626,7 @@ static const struct of_device_id of_ths_match[] = { { .compatible = "allwinner,sun50i-a100-ths", .data = &sun50i_a100_ths }, { .compatible = "allwinner,sun50i-h5-ths", .data = &sun50i_h5_ths }, { .compatible = "allwinner,sun50i-h6-ths", .data = &sun50i_h6_ths }, + { .compatible = "allwinner,sun20i-d1-ths", .data = &sun20i_d1_ths }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, of_ths_match); -- cgit From 7ec597ba25a3d942e13870cc27848e301c26c561 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 30 Nov 2023 18:41:13 +0100 Subject: dt-bindings: thermal: qcom-spmi-adc-tm5/hc: Fix example node names The ADC Thermal Monitor is part of an SPMI PMIC, which in turn sits on an SPMI bus. Fixes: db03874b8543 ("dt-bindings: thermal: qcom: add HC variant of adc-thermal monitor bindings") Fixes: e8ffd6c0756b ("dt-bindings: thermal: qcom: add adc-thermal monitor bindings") Signed-off-by: Johan Hovold Acked-by: Krzysztof Kozlowski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231130174114.13122-2-johan+linaro@kernel.org --- Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml | 3 ++- Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml index 01253d58bf9f..82f8f25885c0 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml @@ -114,7 +114,8 @@ examples: - | #include #include - spmi_bus { + + pmic { #address-cells = <1>; #size-cells = <0>; pm8998_adc: adc@3100 { diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml index 3c81def03c84..02347cee6c6f 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml @@ -167,7 +167,8 @@ examples: - | #include #include - spmi_bus { + + pmic { #address-cells = <1>; #size-cells = <0>; pm8150b_adc: adc@3100 { @@ -207,7 +208,8 @@ examples: #include #include #include - spmi_bus { + + pmic { #address-cells = <1>; #size-cells = <0>; pmk8350_vadc: adc@3100 { -- cgit From 4bddb0cdfad9148a08b2bda7c3d479b1da715929 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 30 Nov 2023 18:41:14 +0100 Subject: dt-bindings: thermal: qcom-spmi-adc-tm5/hc: Clean up examples Clean up the examples by adding newline separators, moving 'reg' properties after 'compatible' and dropping unused labels. Signed-off-by: Johan Hovold Acked-by: Krzysztof Kozlowski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231130174114.13122-3-johan+linaro@kernel.org --- .../devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml | 5 +++-- .../devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml index 82f8f25885c0..7541e27704ca 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml @@ -118,9 +118,10 @@ examples: pmic { #address-cells = <1>; #size-cells = <0>; + pm8998_adc: adc@3100 { - reg = <0x3100>; compatible = "qcom,spmi-adc-rev2"; + reg = <0x3100>; #address-cells = <1>; #size-cells = <0>; #io-channel-cells = <1>; @@ -131,7 +132,7 @@ examples: }; }; - pm8998_adc_tm: adc-tm@3400 { + adc-tm@3400 { compatible = "qcom,spmi-adc-tm-hc"; reg = <0x3400>; interrupts = <0x2 0x34 0x0 IRQ_TYPE_EDGE_RISING>; diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml index 02347cee6c6f..d9d2657287cb 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml @@ -171,9 +171,10 @@ examples: pmic { #address-cells = <1>; #size-cells = <0>; + pm8150b_adc: adc@3100 { - reg = <0x3100>; compatible = "qcom,spmi-adc5"; + reg = <0x3100>; #address-cells = <1>; #size-cells = <0>; #io-channel-cells = <1>; @@ -187,7 +188,7 @@ examples: }; }; - pm8150b_adc_tm: adc-tm@3500 { + adc-tm@3500 { compatible = "qcom,spmi-adc-tm5"; reg = <0x3500>; interrupts = <0x2 0x35 0x0 IRQ_TYPE_EDGE_RISING>; @@ -212,9 +213,10 @@ examples: pmic { #address-cells = <1>; #size-cells = <0>; + pmk8350_vadc: adc@3100 { - reg = <0x3100>; compatible = "qcom,spmi-adc7"; + reg = <0x3100>; #address-cells = <1>; #size-cells = <0>; #io-channel-cells = <1>; @@ -235,7 +237,7 @@ examples: }; }; - pmk8350_adc_tm: adc-tm@3400 { + adc-tm@3400 { compatible = "qcom,spmi-adc-tm5-gen2"; reg = <0x3400>; interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>; -- cgit From 9da39ef332c417ce52732564c1c682a6e1209302 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Mon, 4 Dec 2023 15:13:35 +0100 Subject: tools/thermal/tmon: Fix compilation warning for wrong format The following warnings are shown during compilation: tui.c: In function 'show_cooling_device': tui.c:216:40: warning: format '%d' expects argument of type 'int', but argument 7 has type 'long unsigned int' [-Wformat=] 216 | "%02d %12.12s%6d %6d", | ~~^ | | | int | %6ld ...... 219 | ptdata.cdi[j].cur_state, | ~~~~~~~~~~~~~~~~~~~~~~~ | | | long unsigned int tui.c:216:44: warning: format '%d' expects argument of type 'int', but argument 8 has type 'long unsigned int' [-Wformat=] 216 | "%02d %12.12s%6d %6d", | ~~^ | | | int | %6ld ...... 220 | ptdata.cdi[j].max_state); | ~~~~~~~~~~~~~~~~~~~~~~~ | | | long unsigned int To fix this, the correct string format must be used for printing. Signed-off-by: Florian Eckert Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231204141335.2798194-1-fe@dev.tdt.de --- tools/thermal/tmon/tui.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/thermal/tmon/tui.c b/tools/thermal/tmon/tui.c index 031b258667d8..7f5dd2b87f15 100644 --- a/tools/thermal/tmon/tui.c +++ b/tools/thermal/tmon/tui.c @@ -213,7 +213,7 @@ void show_cooling_device(void) * cooling device instances. skip unused idr. */ mvwprintw(cooling_device_window, j + 2, 1, - "%02d %12.12s%6d %6d", + "%02d %12.12s%6lu %6lu", ptdata.cdi[j].instance, ptdata.cdi[j].type, ptdata.cdi[j].cur_state, -- cgit From 0cefaf6c89c016e9eae9f8881ecaf50e836869a9 Mon Sep 17 00:00:00 2001 From: Mateusz Majewski Date: Fri, 1 Dec 2023 10:56:17 +0100 Subject: thermal/drivers/exynos: Remove an unnecessary field description It seems that the field has been removed in one of the previous commits, but the description has been forgotten. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mateusz Majewski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231201095625.301884-2-m.majewski2@samsung.com --- drivers/thermal/samsung/exynos_tmu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 123ec81e1943..187086658e8f 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -160,7 +160,6 @@ enum soc_type { * in the positive-TC generator block * 0 < reference_voltage <= 31 * @regulator: pointer to the TMU regulator structure. - * @reg_conf: pointer to structure to register with core thermal. * @tzd: pointer to thermal_zone_device structure * @ntrip: number of supported trip points. * @enabled: current status of TMU device -- cgit From 0ac3e1cf37367aea1fef26569b793b5e57eb7a51 Mon Sep 17 00:00:00 2001 From: Mateusz Majewski Date: Fri, 1 Dec 2023 10:56:18 +0100 Subject: thermal/drivers/exynos: Drop id field We do not use the value, and only Exynos 7 defines this alias anyway. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mateusz Majewski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231201095625.301884-3-m.majewski2@samsung.com --- drivers/thermal/samsung/exynos_tmu.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 187086658e8f..4ff32245d2a9 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -138,7 +138,6 @@ enum soc_type { /** * struct exynos_tmu_data : A structure to hold the private data of the TMU * driver - * @id: identifier of the one instance of the TMU controller. * @base: base address of the single instance of the TMU controller. * @base_second: base address of the common registers of the TMU controller. * @irq: irq number of the TMU controller. @@ -172,7 +171,6 @@ enum soc_type { * @tmu_clear_irqs: SoC specific TMU interrupts clearing method */ struct exynos_tmu_data { - int id; void __iomem *base; void __iomem *base_second; int irq; @@ -865,10 +863,6 @@ static int exynos_map_dt_data(struct platform_device *pdev) if (!data || !pdev->dev.of_node) return -ENODEV; - data->id = of_alias_get_id(pdev->dev.of_node, "tmuctrl"); - if (data->id < 0) - data->id = 0; - data->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); if (data->irq <= 0) { dev_err(&pdev->dev, "failed to get IRQ\n"); -- cgit From 20009a8137eefbeebb86402d04cae8955795385a Mon Sep 17 00:00:00 2001 From: Mateusz Majewski Date: Fri, 1 Dec 2023 10:56:19 +0100 Subject: thermal/drivers/exynos: Wwitch from workqueue-driven interrupt handling to threaded interrupts The workqueue boilerplate is mostly one-to-one what the threaded interrupts do. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mateusz Majewski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231201095625.301884-4-m.majewski2@samsung.com --- drivers/thermal/samsung/exynos_tmu.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 4ff32245d2a9..c144592d4584 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -142,7 +142,6 @@ enum soc_type { * @base_second: base address of the common registers of the TMU controller. * @irq: irq number of the TMU controller. * @soc: id of the SOC type. - * @irq_work: pointer to the irq work structure. * @lock: lock to implement synchronization. * @clk: pointer to the clock structure. * @clk_sec: pointer to the clock structure for accessing the base_second. @@ -175,7 +174,6 @@ struct exynos_tmu_data { void __iomem *base_second; int irq; enum soc_type soc; - struct work_struct irq_work; struct mutex lock; struct clk *clk, *clk_sec, *sclk; u32 cal_type; @@ -763,10 +761,9 @@ static int exynos7_tmu_read(struct exynos_tmu_data *data) EXYNOS7_TMU_TEMP_MASK; } -static void exynos_tmu_work(struct work_struct *work) +static irqreturn_t exynos_tmu_threaded_irq(int irq, void *id) { - struct exynos_tmu_data *data = container_of(work, - struct exynos_tmu_data, irq_work); + struct exynos_tmu_data *data = id; thermal_zone_device_update(data->tzd, THERMAL_EVENT_UNSPECIFIED); @@ -778,7 +775,8 @@ static void exynos_tmu_work(struct work_struct *work) clk_disable(data->clk); mutex_unlock(&data->lock); - enable_irq(data->irq); + + return IRQ_HANDLED; } static void exynos4210_tmu_clear_irqs(struct exynos_tmu_data *data) @@ -812,16 +810,6 @@ static void exynos4210_tmu_clear_irqs(struct exynos_tmu_data *data) writel(val_irq, data->base + tmu_intclear); } -static irqreturn_t exynos_tmu_irq(int irq, void *id) -{ - struct exynos_tmu_data *data = id; - - disable_irq_nosync(irq); - schedule_work(&data->irq_work); - - return IRQ_HANDLED; -} - static const struct of_device_id exynos_tmu_match[] = { { .compatible = "samsung,exynos3250-tmu", @@ -1023,8 +1011,6 @@ static int exynos_tmu_probe(struct platform_device *pdev) if (ret) goto err_sensor; - INIT_WORK(&data->irq_work, exynos_tmu_work); - data->clk = devm_clk_get(&pdev->dev, "tmu_apbif"); if (IS_ERR(data->clk)) { dev_err(&pdev->dev, "Failed to get clock\n"); @@ -1093,8 +1079,11 @@ static int exynos_tmu_probe(struct platform_device *pdev) goto err_sclk; } - ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq, - IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data); + ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL, + exynos_tmu_threaded_irq, + IRQF_TRIGGER_RISING + | IRQF_SHARED | IRQF_ONESHOT, + dev_name(&pdev->dev), data); if (ret) { dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq); goto err_sclk; -- cgit From 52ef6f567e6b9a878a8e0e5d6367aa65a08227a5 Mon Sep 17 00:00:00 2001 From: Mateusz Majewski Date: Fri, 1 Dec 2023 10:56:20 +0100 Subject: thermal/drivers/exynos: Handle devm_regulator_get_optional return value correctly Currently, if regulator is required in the SoC, but devm_regulator_get_optional fails for whatever reason, the execution will proceed without propagating the error. Meanwhile there is no reason to output the error in case of -ENODEV. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mateusz Majewski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231201095625.301884-5-m.majewski2@samsung.com --- drivers/thermal/samsung/exynos_tmu.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index c144592d4584..8bcad8a70dc5 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -1002,9 +1002,17 @@ static int exynos_tmu_probe(struct platform_device *pdev) return ret; } } else { - if (PTR_ERR(data->regulator) == -EPROBE_DEFER) + ret = PTR_ERR(data->regulator); + switch (ret) { + case -ENODEV: + break; + case -EPROBE_DEFER: return -EPROBE_DEFER; - dev_info(&pdev->dev, "Regulator node (vtmu) not found\n"); + default: + dev_err(&pdev->dev, "Failed to get regulator: %d\n", + ret); + return ret; + } } ret = exynos_map_dt_data(pdev); -- cgit From 5d6976d01414f23af4b81d7f91cfd59839c8b1fe Mon Sep 17 00:00:00 2001 From: Mateusz Majewski Date: Fri, 1 Dec 2023 10:56:21 +0100 Subject: thermal/drivers/exynos: Simplify regulator (de)initialization We rewrite the initialization to enable the regulator as part of devm, which allows us to not handle the struct instance manually. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mateusz Majewski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231201095625.301884-6-m.majewski2@samsung.com --- drivers/thermal/samsung/exynos_tmu.c | 49 +++++++++++------------------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 8bcad8a70dc5..3bdcbab7466f 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -157,7 +157,6 @@ enum soc_type { * @reference_voltage: reference voltage of amplifier * in the positive-TC generator block * 0 < reference_voltage <= 31 - * @regulator: pointer to the TMU regulator structure. * @tzd: pointer to thermal_zone_device structure * @ntrip: number of supported trip points. * @enabled: current status of TMU device @@ -183,7 +182,6 @@ struct exynos_tmu_data { u16 temp_error1, temp_error2; u8 gain; u8 reference_voltage; - struct regulator *regulator; struct thermal_zone_device *tzd; unsigned int ntrip; bool enabled; @@ -994,50 +992,40 @@ static int exynos_tmu_probe(struct platform_device *pdev) * TODO: Add regulator as an SOC feature, so that regulator enable * is a compulsory call. */ - data->regulator = devm_regulator_get_optional(&pdev->dev, "vtmu"); - if (!IS_ERR(data->regulator)) { - ret = regulator_enable(data->regulator); - if (ret) { - dev_err(&pdev->dev, "failed to enable vtmu\n"); - return ret; - } - } else { - ret = PTR_ERR(data->regulator); - switch (ret) { - case -ENODEV: - break; - case -EPROBE_DEFER: - return -EPROBE_DEFER; - default: - dev_err(&pdev->dev, "Failed to get regulator: %d\n", - ret); - return ret; - } + ret = devm_regulator_get_enable_optional(&pdev->dev, "vtmu"); + switch (ret) { + case 0: + case -ENODEV: + break; + case -EPROBE_DEFER: + return -EPROBE_DEFER; + default: + dev_err(&pdev->dev, "Failed to get enabled regulator: %d\n", + ret); + return ret; } ret = exynos_map_dt_data(pdev); if (ret) - goto err_sensor; + return ret; data->clk = devm_clk_get(&pdev->dev, "tmu_apbif"); if (IS_ERR(data->clk)) { dev_err(&pdev->dev, "Failed to get clock\n"); - ret = PTR_ERR(data->clk); - goto err_sensor; + return PTR_ERR(data->clk); } data->clk_sec = devm_clk_get(&pdev->dev, "tmu_triminfo_apbif"); if (IS_ERR(data->clk_sec)) { if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) { dev_err(&pdev->dev, "Failed to get triminfo clock\n"); - ret = PTR_ERR(data->clk_sec); - goto err_sensor; + return PTR_ERR(data->clk_sec); } } else { ret = clk_prepare(data->clk_sec); if (ret) { dev_err(&pdev->dev, "Failed to get clock\n"); - goto err_sensor; + return ret; } } @@ -1107,10 +1095,6 @@ err_clk: err_clk_sec: if (!IS_ERR(data->clk_sec)) clk_unprepare(data->clk_sec); -err_sensor: - if (!IS_ERR(data->regulator)) - regulator_disable(data->regulator); - return ret; } @@ -1124,9 +1108,6 @@ static void exynos_tmu_remove(struct platform_device *pdev) clk_unprepare(data->clk); if (!IS_ERR(data->clk_sec)) clk_unprepare(data->clk_sec); - - if (!IS_ERR(data->regulator)) - regulator_disable(data->regulator); } #ifdef CONFIG_PM_SLEEP -- cgit From d7a5b431911c5d9da7fbff852433e6f99a4c6616 Mon Sep 17 00:00:00 2001 From: Mateusz Majewski Date: Fri, 1 Dec 2023 10:56:22 +0100 Subject: thermal/drivers/exynos: Stop using the threshold mechanism on Exynos 4210 Exynos 4210 supports setting a base threshold value, which is added to all trip points. This might be useful, but is not really necessary in our usecase, so we always set it to 0 to simplify the code a bit. Additionally, this change makes it so that we convert the value to the calibrated one in a slightly different place. This is more correct morally, though it does not make any change when single-point calibration is being used (which is the case currently). Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mateusz Majewski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231201095625.301884-7-m.majewski2@samsung.com --- drivers/thermal/samsung/exynos_tmu.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 3bdcbab7466f..d918bf6d5359 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -343,20 +343,7 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on) static void exynos4210_tmu_set_trip_temp(struct exynos_tmu_data *data, int trip_id, u8 temp) { - struct thermal_trip trip; - u8 ref, th_code; - - if (thermal_zone_get_trip(data->tzd, 0, &trip)) - return; - - ref = trip.temperature / MCELSIUS; - - if (trip_id == 0) { - th_code = temp_to_code(data, ref); - writeb(th_code, data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP); - } - - temp -= ref; + temp = temp_to_code(data, temp); writeb(temp, data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + trip_id * 4); } @@ -371,6 +358,8 @@ static void exynos4210_tmu_initialize(struct platform_device *pdev) struct exynos_tmu_data *data = platform_get_drvdata(pdev); sanitize_temp_error(data, readl(data->base + EXYNOS_TMU_REG_TRIMINFO)); + + writeb(0, data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP); } static void exynos4412_tmu_set_trip_temp(struct exynos_tmu_data *data, -- cgit From b72ba67baec1d8ff67edc6e70c371ab6b2f7d31c Mon Sep 17 00:00:00 2001 From: Mateusz Majewski Date: Fri, 1 Dec 2023 10:56:23 +0100 Subject: thermal/drivers/exynos: Split initialization of TMU and the thermal zone This will be needed in the future, as the thermal zone subsystem might call our callbacks right after devm_thermal_of_zone_register. Currently we just make get_temp return EAGAIN in such case, but this will not be possible with state-modifying callbacks, for instance set_trips. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mateusz Majewski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231201095625.301884-8-m.majewski2@samsung.com --- drivers/thermal/samsung/exynos_tmu.c | 84 +++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index d918bf6d5359..970bada90f2f 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -251,18 +251,47 @@ static void sanitize_temp_error(struct exynos_tmu_data *data, u32 trim_info) static int exynos_tmu_initialize(struct platform_device *pdev) { struct exynos_tmu_data *data = platform_get_drvdata(pdev); - struct thermal_zone_device *tzd = data->tzd; - int num_trips = thermal_zone_get_num_trips(tzd); unsigned int status; + int ret = 0; + + mutex_lock(&data->lock); + clk_enable(data->clk); + if (!IS_ERR(data->clk_sec)) + clk_enable(data->clk_sec); + + status = readb(data->base + EXYNOS_TMU_REG_STATUS); + if (!status) { + ret = -EBUSY; + } else { + data->tmu_initialize(pdev); + data->tmu_clear_irqs(data); + } + + if (!IS_ERR(data->clk_sec)) + clk_disable(data->clk_sec); + clk_disable(data->clk); + mutex_unlock(&data->lock); + + return ret; +} + +static int exynos_thermal_zone_configure(struct platform_device *pdev) +{ + struct exynos_tmu_data *data = platform_get_drvdata(pdev); + struct thermal_zone_device *tzd = data->tzd; + int i, num_trips = thermal_zone_get_num_trips(tzd); int ret = 0, temp; ret = thermal_zone_get_crit_temp(tzd, &temp); + if (ret && data->soc != SOC_ARCH_EXYNOS5433) { /* FIXME */ dev_err(&pdev->dev, "No CRITICAL trip point defined in device tree!\n"); goto out; } + mutex_lock(&data->lock); + if (num_trips > data->ntrip) { dev_info(&pdev->dev, "More trip points than supported by this TMU.\n"); @@ -271,41 +300,26 @@ static int exynos_tmu_initialize(struct platform_device *pdev) num_trips - data->ntrip); } - mutex_lock(&data->lock); clk_enable(data->clk); - if (!IS_ERR(data->clk_sec)) - clk_enable(data->clk_sec); - - status = readb(data->base + EXYNOS_TMU_REG_STATUS); - if (!status) { - ret = -EBUSY; - } else { - int i, ntrips = - min_t(int, num_trips, data->ntrip); - - data->tmu_initialize(pdev); - /* Write temperature code for rising and falling threshold */ - for (i = 0; i < ntrips; i++) { + num_trips = min_t(int, num_trips, data->ntrip); - struct thermal_trip trip; + /* Write temperature code for rising and falling threshold */ + for (i = 0; i < num_trips; i++) { + struct thermal_trip trip; - ret = thermal_zone_get_trip(tzd, i, &trip); - if (ret) - goto err; + ret = thermal_zone_get_trip(tzd, i, &trip); + if (ret) + goto err; - data->tmu_set_trip_temp(data, i, trip.temperature / MCELSIUS); - data->tmu_set_trip_hyst(data, i, trip.temperature / MCELSIUS, - trip.hysteresis / MCELSIUS); - } - - data->tmu_clear_irqs(data); + data->tmu_set_trip_temp(data, i, trip.temperature / MCELSIUS); + data->tmu_set_trip_hyst(data, i, trip.temperature / MCELSIUS, + trip.hysteresis / MCELSIUS); } + err: clk_disable(data->clk); mutex_unlock(&data->lock); - if (!IS_ERR(data->clk_sec)) - clk_disable(data->clk_sec); out: return ret; } @@ -1044,10 +1058,12 @@ static int exynos_tmu_probe(struct platform_device *pdev) break; } - /* - * data->tzd must be registered before calling exynos_tmu_initialize(), - * requesting irq and calling exynos_tmu_control(). - */ + ret = exynos_tmu_initialize(pdev); + if (ret) { + dev_err(&pdev->dev, "Failed to initialize TMU\n"); + goto err_sclk; + } + data->tzd = devm_thermal_of_zone_register(&pdev->dev, 0, data, &exynos_sensor_ops); if (IS_ERR(data->tzd)) { @@ -1058,9 +1074,9 @@ static int exynos_tmu_probe(struct platform_device *pdev) goto err_sclk; } - ret = exynos_tmu_initialize(pdev); + ret = exynos_thermal_zone_configure(pdev); if (ret) { - dev_err(&pdev->dev, "Failed to initialize TMU\n"); + dev_err(&pdev->dev, "Failed to configure the thermal zone\n"); goto err_sclk; } -- cgit From af00d488339aee7bf42b07057053ef919bedee6f Mon Sep 17 00:00:00 2001 From: Mateusz Majewski Date: Fri, 1 Dec 2023 10:56:24 +0100 Subject: thermal/drivers/exynos: Use BIT wherever possible The original driver did not use that macro and it allows us to make our intentions slightly clearer. Reviewed-by: Lukasz Luba Signed-off-by: Mateusz Majewski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231201095625.301884-9-m.majewski2@samsung.com --- drivers/thermal/samsung/exynos_tmu.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 970bada90f2f..ca1b1cec0300 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -388,7 +388,7 @@ static void exynos4412_tmu_set_trip_temp(struct exynos_tmu_data *data, if (trip == 3) { con = readl(data->base + EXYNOS_TMU_REG_CONTROL); - con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT); + con |= BIT(EXYNOS_TMU_THERM_TRIP_EN_SHIFT); writel(con, data->base + EXYNOS_TMU_REG_CONTROL); } } @@ -559,16 +559,16 @@ static void exynos4210_tmu_control(struct platform_device *pdev, bool on) continue; interrupt_en |= - (1 << (EXYNOS_TMU_INTEN_RISE0_SHIFT + i * 4)); + BIT(EXYNOS_TMU_INTEN_RISE0_SHIFT + i * 4); } if (data->soc != SOC_ARCH_EXYNOS4210) interrupt_en |= interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT; - con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); + con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT); } else { - con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT); + con &= ~BIT(EXYNOS_TMU_CORE_EN_SHIFT); } writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN); @@ -590,15 +590,15 @@ static void exynos5433_tmu_control(struct platform_device *pdev, bool on) continue; interrupt_en |= - (1 << (EXYNOS7_TMU_INTEN_RISE0_SHIFT + i)); + BIT(EXYNOS7_TMU_INTEN_RISE0_SHIFT + i); } interrupt_en |= interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT; - con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); + con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT); } else - con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT); + con &= ~BIT(EXYNOS_TMU_CORE_EN_SHIFT); pd_det_en = on ? EXYNOS5433_PD_DET_EN : 0; @@ -622,17 +622,17 @@ static void exynos7_tmu_control(struct platform_device *pdev, bool on) continue; interrupt_en |= - (1 << (EXYNOS7_TMU_INTEN_RISE0_SHIFT + i)); + BIT(EXYNOS7_TMU_INTEN_RISE0_SHIFT + i); } interrupt_en |= interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT; - con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); - con |= (1 << EXYNOS7_PD_DET_EN_SHIFT); + con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT); + con |= BIT(EXYNOS7_PD_DET_EN_SHIFT); } else { - con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT); - con &= ~(1 << EXYNOS7_PD_DET_EN_SHIFT); + con &= ~BIT(EXYNOS_TMU_CORE_EN_SHIFT); + con &= ~BIT(EXYNOS7_PD_DET_EN_SHIFT); } writel(interrupt_en, data->base + EXYNOS7_TMU_REG_INTEN); -- cgit From 5314b1543787e6cd5d248186fcfd5c5fc4ca2146 Mon Sep 17 00:00:00 2001 From: Mateusz Majewski Date: Fri, 1 Dec 2023 10:56:25 +0100 Subject: thermal/drivers/exynos: Use set_trips ops Currently, each trip point defined in the device tree corresponds to a single hardware interrupt. This commit instead switches to using two hardware interrupts, whose values are set dynamically using the set_trips callback. Additionally, the critical temperature threshold is handled specifically. Setting interrupts in this way also fixes a long-standing lockdep warning, which was caused by calling thermal_zone_get_trips with our lock being held. Do note that this requires TMU initialization to be split into two parts, as done by the parent commit: parts of the initialization call into the thermal_zone_device structure and so must be done after its registration, but the initialization is also responsible for setting up calibration, which must be done before thermal_zone_device registration, which will call set_trips for the first time; if the calibration is not done in time, the interrupt values will be silently wrong! Reviewed-by: Lukasz Luba Signed-off-by: Mateusz Majewski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20231201095625.301884-10-m.majewski2@samsung.com --- drivers/thermal/samsung/exynos_tmu.c | 385 +++++++++++++++++++---------------- 1 file changed, 205 insertions(+), 180 deletions(-) diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index ca1b1cec0300..6482513bfe66 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -158,10 +158,12 @@ enum soc_type { * in the positive-TC generator block * 0 < reference_voltage <= 31 * @tzd: pointer to thermal_zone_device structure - * @ntrip: number of supported trip points. * @enabled: current status of TMU device - * @tmu_set_trip_temp: SoC specific method to set trip (rising threshold) - * @tmu_set_trip_hyst: SoC specific to set hysteresis (falling threshold) + * @tmu_set_low_temp: SoC specific method to set trip (falling threshold) + * @tmu_set_high_temp: SoC specific method to set trip (rising threshold) + * @tmu_set_crit_temp: SoC specific method to set critical temperature + * @tmu_disable_low: SoC specific method to disable an interrupt (falling threshold) + * @tmu_disable_high: SoC specific method to disable an interrupt (rising threshold) * @tmu_initialize: SoC specific TMU initialization method * @tmu_control: SoC specific TMU control method * @tmu_read: SoC specific TMU temperature read method @@ -183,13 +185,13 @@ struct exynos_tmu_data { u8 gain; u8 reference_voltage; struct thermal_zone_device *tzd; - unsigned int ntrip; bool enabled; - void (*tmu_set_trip_temp)(struct exynos_tmu_data *data, int trip, - u8 temp); - void (*tmu_set_trip_hyst)(struct exynos_tmu_data *data, int trip, - u8 temp, u8 hyst); + void (*tmu_set_low_temp)(struct exynos_tmu_data *data, u8 temp); + void (*tmu_set_high_temp)(struct exynos_tmu_data *data, u8 temp); + void (*tmu_set_crit_temp)(struct exynos_tmu_data *data, u8 temp); + void (*tmu_disable_low)(struct exynos_tmu_data *data); + void (*tmu_disable_high)(struct exynos_tmu_data *data); void (*tmu_initialize)(struct platform_device *pdev); void (*tmu_control)(struct platform_device *pdev, bool on); int (*tmu_read)(struct exynos_tmu_data *data); @@ -279,49 +281,28 @@ static int exynos_thermal_zone_configure(struct platform_device *pdev) { struct exynos_tmu_data *data = platform_get_drvdata(pdev); struct thermal_zone_device *tzd = data->tzd; - int i, num_trips = thermal_zone_get_num_trips(tzd); - int ret = 0, temp; + int ret, temp; ret = thermal_zone_get_crit_temp(tzd, &temp); + if (ret) { + /* FIXME: Remove this special case */ + if (data->soc == SOC_ARCH_EXYNOS5433) + return 0; - if (ret && data->soc != SOC_ARCH_EXYNOS5433) { /* FIXME */ dev_err(&pdev->dev, "No CRITICAL trip point defined in device tree!\n"); - goto out; + return ret; } mutex_lock(&data->lock); - - if (num_trips > data->ntrip) { - dev_info(&pdev->dev, - "More trip points than supported by this TMU.\n"); - dev_info(&pdev->dev, - "%d trip points should be configured in polling mode.\n", - num_trips - data->ntrip); - } - clk_enable(data->clk); - num_trips = min_t(int, num_trips, data->ntrip); - - /* Write temperature code for rising and falling threshold */ - for (i = 0; i < num_trips; i++) { - struct thermal_trip trip; + data->tmu_set_crit_temp(data, temp / MCELSIUS); - ret = thermal_zone_get_trip(tzd, i, &trip); - if (ret) - goto err; - - data->tmu_set_trip_temp(data, i, trip.temperature / MCELSIUS); - data->tmu_set_trip_hyst(data, i, trip.temperature / MCELSIUS, - trip.hysteresis / MCELSIUS); - } - -err: clk_disable(data->clk); mutex_unlock(&data->lock); -out: - return ret; + + return 0; } static u32 get_con_reg(struct exynos_tmu_data *data, u32 con) @@ -354,17 +335,74 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on) mutex_unlock(&data->lock); } -static void exynos4210_tmu_set_trip_temp(struct exynos_tmu_data *data, - int trip_id, u8 temp) +static void exynos_tmu_update_bit(struct exynos_tmu_data *data, int reg_off, + int bit_off, bool enable) +{ + u32 interrupt_en; + + interrupt_en = readl(data->base + reg_off); + if (enable) + interrupt_en |= BIT(bit_off); + else + interrupt_en &= ~BIT(bit_off); + writel(interrupt_en, data->base + reg_off); +} + +static void exynos_tmu_update_temp(struct exynos_tmu_data *data, int reg_off, + int bit_off, u8 temp) +{ + u16 tmu_temp_mask; + u32 th; + + tmu_temp_mask = + (data->soc == SOC_ARCH_EXYNOS7) ? EXYNOS7_TMU_TEMP_MASK + : EXYNOS_TMU_TEMP_MASK; + + th = readl(data->base + reg_off); + th &= ~(tmu_temp_mask << bit_off); + th |= temp_to_code(data, temp) << bit_off; + writel(th, data->base + reg_off); +} + +static void exynos4210_tmu_set_low_temp(struct exynos_tmu_data *data, u8 temp) +{ + /* + * Failing thresholds are not supported on Exynos 4210. + * We use polling instead. + */ +} + +static void exynos4210_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp) { temp = temp_to_code(data, temp); - writeb(temp, data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + trip_id * 4); + writeb(temp, data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + 4); + exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN, + EXYNOS_TMU_INTEN_RISE0_SHIFT + 4, true); +} + +static void exynos4210_tmu_disable_low(struct exynos_tmu_data *data) +{ + /* Again, this is handled by polling. */ } -/* failing thresholds are not supported on Exynos4210 */ -static void exynos4210_tmu_set_trip_hyst(struct exynos_tmu_data *data, - int trip, u8 temp, u8 hyst) +static void exynos4210_tmu_disable_high(struct exynos_tmu_data *data) { + exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN, + EXYNOS_TMU_INTEN_RISE0_SHIFT + 4, false); +} + +static void exynos4210_tmu_set_crit_temp(struct exynos_tmu_data *data, u8 temp) +{ + /* + * Hardware critical temperature handling is not supported on Exynos 4210. + * We still set the critical temperature threshold, but this is only to + * make sure it is handled as soon as possible. It is just a normal interrupt. + */ + + temp = temp_to_code(data, temp); + writeb(temp, data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + 12); + exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN, + EXYNOS_TMU_INTEN_RISE0_SHIFT + 12, true); } static void exynos4210_tmu_initialize(struct platform_device *pdev) @@ -376,33 +414,31 @@ static void exynos4210_tmu_initialize(struct platform_device *pdev) writeb(0, data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP); } -static void exynos4412_tmu_set_trip_temp(struct exynos_tmu_data *data, - int trip, u8 temp) +static void exynos4412_tmu_set_low_temp(struct exynos_tmu_data *data, u8 temp) { - u32 th, con; - - th = readl(data->base + EXYNOS_THD_TEMP_RISE); - th &= ~(0xff << 8 * trip); - th |= temp_to_code(data, temp) << 8 * trip; - writel(th, data->base + EXYNOS_THD_TEMP_RISE); + exynos_tmu_update_temp(data, EXYNOS_THD_TEMP_FALL, 0, temp); + exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN, + EXYNOS_TMU_INTEN_FALL0_SHIFT, true); +} - if (trip == 3) { - con = readl(data->base + EXYNOS_TMU_REG_CONTROL); - con |= BIT(EXYNOS_TMU_THERM_TRIP_EN_SHIFT); - writel(con, data->base + EXYNOS_TMU_REG_CONTROL); - } +static void exynos4412_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp) +{ + exynos_tmu_update_temp(data, EXYNOS_THD_TEMP_RISE, 8, temp); + exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN, + EXYNOS_TMU_INTEN_RISE0_SHIFT + 4, true); } -static void exynos4412_tmu_set_trip_hyst(struct exynos_tmu_data *data, - int trip, u8 temp, u8 hyst) +static void exynos4412_tmu_disable_low(struct exynos_tmu_data *data) { - u32 th; + exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN, + EXYNOS_TMU_INTEN_FALL0_SHIFT, false); +} - th = readl(data->base + EXYNOS_THD_TEMP_FALL); - th &= ~(0xff << 8 * trip); - if (hyst) - th |= temp_to_code(data, temp - hyst) << 8 * trip; - writel(th, data->base + EXYNOS_THD_TEMP_FALL); +static void exynos4412_tmu_set_crit_temp(struct exynos_tmu_data *data, u8 temp) +{ + exynos_tmu_update_temp(data, EXYNOS_THD_TEMP_RISE, 24, temp); + exynos_tmu_update_bit(data, EXYNOS_TMU_REG_CONTROL, + EXYNOS_TMU_THERM_TRIP_EN_SHIFT, true); } static void exynos4412_tmu_initialize(struct platform_device *pdev) @@ -432,44 +468,39 @@ static void exynos4412_tmu_initialize(struct platform_device *pdev) sanitize_temp_error(data, trim_info); } -static void exynos5433_tmu_set_trip_temp(struct exynos_tmu_data *data, - int trip, u8 temp) +static void exynos5433_tmu_set_low_temp(struct exynos_tmu_data *data, u8 temp) { - unsigned int reg_off, j; - u32 th; - - if (trip > 3) { - reg_off = EXYNOS5433_THD_TEMP_RISE7_4; - j = trip - 4; - } else { - reg_off = EXYNOS5433_THD_TEMP_RISE3_0; - j = trip; - } + exynos_tmu_update_temp(data, EXYNOS5433_THD_TEMP_FALL3_0, 0, temp); + exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN, + EXYNOS_TMU_INTEN_FALL0_SHIFT, true); +} - th = readl(data->base + reg_off); - th &= ~(0xff << j * 8); - th |= (temp_to_code(data, temp) << j * 8); - writel(th, data->base + reg_off); +static void exynos5433_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp) +{ + exynos_tmu_update_temp(data, EXYNOS5433_THD_TEMP_RISE3_0, 8, temp); + exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN, + EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, true); } -static void exynos5433_tmu_set_trip_hyst(struct exynos_tmu_data *data, - int trip, u8 temp, u8 hyst) +static void exynos5433_tmu_disable_low(struct exynos_tmu_data *data) { - unsigned int reg_off, j; - u32 th; + exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN, + EXYNOS_TMU_INTEN_FALL0_SHIFT, false); +} - if (trip > 3) { - reg_off = EXYNOS5433_THD_TEMP_FALL7_4; - j = trip - 4; - } else { - reg_off = EXYNOS5433_THD_TEMP_FALL3_0; - j = trip; - } +static void exynos5433_tmu_disable_high(struct exynos_tmu_data *data) +{ + exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN, + EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, false); +} - th = readl(data->base + reg_off); - th &= ~(0xff << j * 8); - th |= (temp_to_code(data, temp - hyst) << j * 8); - writel(th, data->base + reg_off); +static void exynos5433_tmu_set_crit_temp(struct exynos_tmu_data *data, u8 temp) +{ + exynos_tmu_update_temp(data, EXYNOS5433_THD_TEMP_RISE7_4, 24, temp); + exynos_tmu_update_bit(data, EXYNOS_TMU_REG_CONTROL, + EXYNOS_TMU_THERM_TRIP_EN_SHIFT, true); + exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN, + EXYNOS7_TMU_INTEN_RISE0_SHIFT + 7, true); } static void exynos5433_tmu_initialize(struct platform_device *pdev) @@ -505,34 +536,41 @@ static void exynos5433_tmu_initialize(struct platform_device *pdev) cal_type ? 2 : 1); } -static void exynos7_tmu_set_trip_temp(struct exynos_tmu_data *data, - int trip, u8 temp) +static void exynos7_tmu_set_low_temp(struct exynos_tmu_data *data, u8 temp) { - unsigned int reg_off, bit_off; - u32 th; - - reg_off = ((7 - trip) / 2) * 4; - bit_off = ((8 - trip) % 2); + exynos_tmu_update_temp(data, EXYNOS7_THD_TEMP_FALL7_6 + 12, 0, temp); + exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN, + EXYNOS_TMU_INTEN_FALL0_SHIFT + 0, true); +} - th = readl(data->base + EXYNOS7_THD_TEMP_RISE7_6 + reg_off); - th &= ~(EXYNOS7_TMU_TEMP_MASK << (16 * bit_off)); - th |= temp_to_code(data, temp) << (16 * bit_off); - writel(th, data->base + EXYNOS7_THD_TEMP_RISE7_6 + reg_off); +static void exynos7_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp) +{ + exynos_tmu_update_temp(data, EXYNOS7_THD_TEMP_RISE7_6 + 12, 16, temp); + exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN, + EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, true); } -static void exynos7_tmu_set_trip_hyst(struct exynos_tmu_data *data, - int trip, u8 temp, u8 hyst) +static void exynos7_tmu_disable_low(struct exynos_tmu_data *data) { - unsigned int reg_off, bit_off; - u32 th; + exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN, + EXYNOS_TMU_INTEN_FALL0_SHIFT + 0, false); +} - reg_off = ((7 - trip) / 2) * 4; - bit_off = ((8 - trip) % 2); +static void exynos7_tmu_disable_high(struct exynos_tmu_data *data) +{ + exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN, + EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, false); +} - th = readl(data->base + EXYNOS7_THD_TEMP_FALL7_6 + reg_off); - th &= ~(EXYNOS7_TMU_TEMP_MASK << (16 * bit_off)); - th |= temp_to_code(data, temp - hyst) << (16 * bit_off); - writel(th, data->base + EXYNOS7_THD_TEMP_FALL7_6 + reg_off); +static void exynos7_tmu_set_crit_temp(struct exynos_tmu_data *data, u8 temp) +{ + /* + * Like Exynos 4210, Exynos 7 does not seem to support critical temperature + * handling in hardware. Again, we still set a separate interrupt for it. + */ + exynos_tmu_update_temp(data, EXYNOS7_THD_TEMP_RISE7_6 + 0, 16, temp); + exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN, + EXYNOS7_TMU_INTEN_RISE0_SHIFT + 7, true); } static void exynos7_tmu_initialize(struct platform_device *pdev) @@ -547,87 +585,44 @@ static void exynos7_tmu_initialize(struct platform_device *pdev) static void exynos4210_tmu_control(struct platform_device *pdev, bool on) { struct exynos_tmu_data *data = platform_get_drvdata(pdev); - struct thermal_zone_device *tz = data->tzd; - struct thermal_trip trip; - unsigned int con, interrupt_en = 0, i; + unsigned int con; con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL)); - if (on) { - for (i = 0; i < data->ntrip; i++) { - if (thermal_zone_get_trip(tz, i, &trip)) - continue; - - interrupt_en |= - BIT(EXYNOS_TMU_INTEN_RISE0_SHIFT + i * 4); - } - - if (data->soc != SOC_ARCH_EXYNOS4210) - interrupt_en |= - interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT; - + if (on) con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT); - } else { + else con &= ~BIT(EXYNOS_TMU_CORE_EN_SHIFT); - } - writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN); writel(con, data->base + EXYNOS_TMU_REG_CONTROL); } static void exynos5433_tmu_control(struct platform_device *pdev, bool on) { struct exynos_tmu_data *data = platform_get_drvdata(pdev); - struct thermal_zone_device *tz = data->tzd; - struct thermal_trip trip; - unsigned int con, interrupt_en = 0, pd_det_en, i; + unsigned int con, pd_det_en; con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL)); - if (on) { - for (i = 0; i < data->ntrip; i++) { - if (thermal_zone_get_trip(tz, i, &trip)) - continue; - - interrupt_en |= - BIT(EXYNOS7_TMU_INTEN_RISE0_SHIFT + i); - } - - interrupt_en |= - interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT; - + if (on) con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT); - } else + else con &= ~BIT(EXYNOS_TMU_CORE_EN_SHIFT); pd_det_en = on ? EXYNOS5433_PD_DET_EN : 0; writel(pd_det_en, data->base + EXYNOS5433_TMU_PD_DET_EN); - writel(interrupt_en, data->base + EXYNOS5433_TMU_REG_INTEN); writel(con, data->base + EXYNOS_TMU_REG_CONTROL); } static void exynos7_tmu_control(struct platform_device *pdev, bool on) { struct exynos_tmu_data *data = platform_get_drvdata(pdev); - struct thermal_zone_device *tz = data->tzd; - struct thermal_trip trip; - unsigned int con, interrupt_en = 0, i; + unsigned int con; con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL)); if (on) { - for (i = 0; i < data->ntrip; i++) { - if (thermal_zone_get_trip(tz, i, &trip)) - continue; - - interrupt_en |= - BIT(EXYNOS7_TMU_INTEN_RISE0_SHIFT + i); - } - - interrupt_en |= - interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT; - con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT); con |= BIT(EXYNOS7_PD_DET_EN_SHIFT); } else { @@ -635,7 +630,6 @@ static void exynos7_tmu_control(struct platform_device *pdev, bool on) con &= ~BIT(EXYNOS7_PD_DET_EN_SHIFT); } - writel(interrupt_en, data->base + EXYNOS7_TMU_REG_INTEN); writel(con, data->base + EXYNOS_TMU_REG_CONTROL); } @@ -873,13 +867,15 @@ static int exynos_map_dt_data(struct platform_device *pdev) switch (data->soc) { case SOC_ARCH_EXYNOS4210: - data->tmu_set_trip_temp = exynos4210_tmu_set_trip_temp; - data->tmu_set_trip_hyst = exynos4210_tmu_set_trip_hyst; + data->tmu_set_low_temp = exynos4210_tmu_set_low_temp; + data->tmu_set_high_temp = exynos4210_tmu_set_high_temp; + data->tmu_disable_low = exynos4210_tmu_disable_low; + data->tmu_disable_high = exynos4210_tmu_disable_high; + data->tmu_set_crit_temp = exynos4210_tmu_set_crit_temp; data->tmu_initialize = exynos4210_tmu_initialize; data->tmu_control = exynos4210_tmu_control; data->tmu_read = exynos4210_tmu_read; data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; - data->ntrip = 4; data->gain = 15; data->reference_voltage = 7; data->efuse_value = 55; @@ -892,14 +888,16 @@ static int exynos_map_dt_data(struct platform_device *pdev) case SOC_ARCH_EXYNOS5260: case SOC_ARCH_EXYNOS5420: case SOC_ARCH_EXYNOS5420_TRIMINFO: - data->tmu_set_trip_temp = exynos4412_tmu_set_trip_temp; - data->tmu_set_trip_hyst = exynos4412_tmu_set_trip_hyst; + data->tmu_set_low_temp = exynos4412_tmu_set_low_temp; + data->tmu_set_high_temp = exynos4412_tmu_set_high_temp; + data->tmu_disable_low = exynos4412_tmu_disable_low; + data->tmu_disable_high = exynos4210_tmu_disable_high; + data->tmu_set_crit_temp = exynos4412_tmu_set_crit_temp; data->tmu_initialize = exynos4412_tmu_initialize; data->tmu_control = exynos4210_tmu_control; data->tmu_read = exynos4412_tmu_read; data->tmu_set_emulation = exynos4412_tmu_set_emulation; data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; - data->ntrip = 4; data->gain = 8; data->reference_voltage = 16; data->efuse_value = 55; @@ -911,14 +909,16 @@ static int exynos_map_dt_data(struct platform_device *pdev) data->max_efuse_value = 100; break; case SOC_ARCH_EXYNOS5433: - data->tmu_set_trip_temp = exynos5433_tmu_set_trip_temp; - data->tmu_set_trip_hyst = exynos5433_tmu_set_trip_hyst; + data->tmu_set_low_temp = exynos5433_tmu_set_low_temp; + data->tmu_set_high_temp = exynos5433_tmu_set_high_temp; + data->tmu_disable_low = exynos5433_tmu_disable_low; + data->tmu_disable_high = exynos5433_tmu_disable_high; + data->tmu_set_crit_temp = exynos5433_tmu_set_crit_temp; data->tmu_initialize = exynos5433_tmu_initialize; data->tmu_control = exynos5433_tmu_control; data->tmu_read = exynos4412_tmu_read; data->tmu_set_emulation = exynos4412_tmu_set_emulation; data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; - data->ntrip = 8; data->gain = 8; if (res.start == EXYNOS5433_G3D_BASE) data->reference_voltage = 23; @@ -929,14 +929,16 @@ static int exynos_map_dt_data(struct platform_device *pdev) data->max_efuse_value = 150; break; case SOC_ARCH_EXYNOS7: - data->tmu_set_trip_temp = exynos7_tmu_set_trip_temp; - data->tmu_set_trip_hyst = exynos7_tmu_set_trip_hyst; + data->tmu_set_low_temp = exynos7_tmu_set_low_temp; + data->tmu_set_high_temp = exynos7_tmu_set_high_temp; + data->tmu_disable_low = exynos7_tmu_disable_low; + data->tmu_disable_high = exynos7_tmu_disable_high; + data->tmu_set_crit_temp = exynos7_tmu_set_crit_temp; data->tmu_initialize = exynos7_tmu_initialize; data->tmu_control = exynos7_tmu_control; data->tmu_read = exynos7_tmu_read; data->tmu_set_emulation = exynos4412_tmu_set_emulation; data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; - data->ntrip = 8; data->gain = 9; data->reference_voltage = 17; data->efuse_value = 75; @@ -972,9 +974,32 @@ static int exynos_map_dt_data(struct platform_device *pdev) return 0; } +static int exynos_set_trips(struct thermal_zone_device *tz, int low, int high) +{ + struct exynos_tmu_data *data = thermal_zone_device_priv(tz); + + mutex_lock(&data->lock); + clk_enable(data->clk); + + if (low > INT_MIN) + data->tmu_set_low_temp(data, low / MCELSIUS); + else + data->tmu_disable_low(data); + if (high < INT_MAX) + data->tmu_set_high_temp(data, high / MCELSIUS); + else + data->tmu_disable_high(data); + + clk_disable(data->clk); + mutex_unlock(&data->lock); + + return 0; +} + static const struct thermal_zone_device_ops exynos_sensor_ops = { .get_temp = exynos_get_temp, .set_emul_temp = exynos_tmu_set_emulation, + .set_trips = exynos_set_trips, }; static int exynos_tmu_probe(struct platform_device *pdev) -- cgit