mirror of
https://github.com/torvalds/linux.git
synced 2026-05-24 23:22:31 +02:00
- Converted Mediatek Thermal to the json-schema (Rafał Miłecki)
- Fixed DT bindings issue on Loongson (Binbin Zhou) - Fixed returning NULL instead of -ENODEV on Loogsoo (Binbin Zhou) - Added the DT binding for the tsens on SM8650 platform (Neil Armstrong) - Added a reboot on critical option feature (Fabio Estevam) - Made usage of DEFINE_SIMPLE_DEV_PM_OPS on AmLogic (Uwe Kleine-König) - Added the D1/T113s THS controller support on Sun8i (Maxim Kiselev) - Fixed example in the DT binding for QCom SPMI (Johan Hovold) - Fixed compilation warning for the tmon utility (Florian Eckert) - Added interrupt based configuration on Exynos along with a set of related cleanups (Mateusz Majewski) -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEGn3N4YVz0WNVyHskqDIjiipP6E8FAmWT0yUACgkQqDIjiipP 6E+YjggAsrsQNrsUgiW0/M0i75kfcEBgLfXscyPFsUYwpByb+haWzAJSLrvCBko8 zPFvNE0or6KTQJCtseWWQDNQKWilAKARurEg7vuahfWo5LmfauPGMxsw+iHM9TgW 8Ptkc1biy3TNr1zVCpQrCZK9GdLGsG7JRgxHi4Hfr/Hb/FZN9Mm0Yk1pRpFU+pn8 Ff5UScMcU7NWhhxlQavLOoMmyAmh2k/jvfCSlmXGj7kxRrX8YIC02dTDjFm5cpyP Toy2POWkcZr4Xr+kWOh8pxojZVwKU2pN7cYyLJn8+OO+rpUAf0ol4PW0mly7uMgH 1HCZ0x0hiNJQ8N6SwN+Eptq9TpgCBw== =W2kc -----END PGP SIGNATURE----- Merge tag 'thermal-v6.8-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/thermal/linux into thermal Merge thermal control material for 6.8-rc1 from Daniel Lezcano: "- Converted Mediatek Thermal to the json-schema (Rafał Miłecki) - Fixed DT bindings issue on Loongson (Binbin Zhou) - Fixed returning NULL instead of -ENODEV on Loogsoo (Binbin Zhou) - Added the DT binding for the tsens on SM8650 platform (Neil Armstrong) - Added a reboot on critical option feature (Fabio Estevam) - Made usage of DEFINE_SIMPLE_DEV_PM_OPS on AmLogic (Uwe Kleine-König) - Added the D1/T113s THS controller support on Sun8i (Maxim Kiselev) - Fixed example in the DT binding for QCom SPMI (Johan Hovold) - Fixed compilation warning for the tmon utility (Florian Eckert) - Added interrupt based configuration on Exynos along with a set of related cleanups (Mateusz Majewski)" * tag 'thermal-v6.8-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/thermal/linux: (24 commits) thermal/drivers/exynos: Use set_trips ops thermal/drivers/exynos: Use BIT wherever possible thermal/drivers/exynos: Split initialization of TMU and the thermal zone thermal/drivers/exynos: Stop using the threshold mechanism on Exynos 4210 thermal/drivers/exynos: Simplify regulator (de)initialization thermal/drivers/exynos: Handle devm_regulator_get_optional return value correctly thermal/drivers/exynos: Wwitch from workqueue-driven interrupt handling to threaded interrupts thermal/drivers/exynos: Drop id field thermal/drivers/exynos: Remove an unnecessary field description tools/thermal/tmon: Fix compilation warning for wrong format dt-bindings: thermal: qcom-spmi-adc-tm5/hc: Clean up examples dt-bindings: thermal: qcom-spmi-adc-tm5/hc: Fix example node names thermal/drivers/sun8i: Add D1/T113s THS controller support dt-bindings: thermal: sun8i: Add binding for D1/T113s THS controller thermal: amlogic: Use DEFINE_SIMPLE_DEV_PM_OPS for PM functions thermal: amlogic: Make amlogic_thermal_disable() return void thermal/thermal_of: Allow rebooting after critical temp reboot: Introduce thermal_zone_device_critical_reboot() thermal/core: Prepare for introduction of thermal reboot dt-bindings: thermal-zones: Document critical-action ...
This commit is contained in:
commit
d654362d53
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ maintainers:
|
|||
- zhanghongchen <zhanghongchen@loongson.cn>
|
||||
- Yinbo Zhu <zhuyinbo@loongson.cn>
|
||||
|
||||
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>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 <s.hauer@pengutronix.de>
|
||||
|
||||
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 <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/clock/mt8173-clk.h>
|
||||
#include <dt-bindings/reset/mt8173-resets.h>
|
||||
|
||||
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>;
|
||||
};
|
||||
|
|
@ -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";
|
||||
};
|
||||
|
|
@ -114,12 +114,14 @@ examples:
|
|||
- |
|
||||
#include <dt-bindings/iio/qcom,spmi-vadc.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spmi_bus {
|
||||
|
||||
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>;
|
||||
|
|
@ -130,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>;
|
||||
|
|
|
|||
|
|
@ -167,12 +167,14 @@ examples:
|
|||
- |
|
||||
#include <dt-bindings/iio/qcom,spmi-vadc.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spmi_bus {
|
||||
|
||||
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>;
|
||||
|
|
@ -186,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>;
|
||||
|
|
@ -207,12 +209,14 @@ examples:
|
|||
#include <dt-bindings/iio/qcom,spmi-adc7-pmk8350.h>
|
||||
#include <dt-bindings/iio/qcom,spmi-adc7-pm8350.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spmi_bus {
|
||||
|
||||
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>;
|
||||
|
|
@ -233,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>;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -298,27 +296,30 @@ 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);
|
||||
|
||||
return amlogic_thermal_disable(data);
|
||||
amlogic_thermal_disable(data);
|
||||
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -138,12 +138,10 @@ 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.
|
||||
* @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.
|
||||
|
|
@ -159,13 +157,13 @@ 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.
|
||||
* @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
|
||||
* @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
|
||||
|
|
@ -173,12 +171,10 @@ 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;
|
||||
enum soc_type soc;
|
||||
struct work_struct irq_work;
|
||||
struct mutex lock;
|
||||
struct clk *clk, *clk_sec, *sclk;
|
||||
u32 cal_type;
|
||||
|
|
@ -188,15 +184,14 @@ 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;
|
||||
|
||||
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);
|
||||
|
|
@ -258,25 +253,8 @@ 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, 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
clk_enable(data->clk);
|
||||
|
|
@ -287,36 +265,46 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
|
|||
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++) {
|
||||
|
||||
struct thermal_trip trip;
|
||||
|
||||
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);
|
||||
}
|
||||
err:
|
||||
clk_disable(data->clk);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
if (!IS_ERR(data->clk_sec))
|
||||
clk_disable(data->clk_sec);
|
||||
out:
|
||||
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 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;
|
||||
|
||||
dev_err(&pdev->dev,
|
||||
"No CRITICAL trip point defined in device tree!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
clk_enable(data->clk);
|
||||
|
||||
data->tmu_set_crit_temp(data, temp / MCELSIUS);
|
||||
|
||||
clk_disable(data->clk);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 get_con_reg(struct exynos_tmu_data *data, u32 con)
|
||||
{
|
||||
if (data->soc == SOC_ARCH_EXYNOS4412 ||
|
||||
|
|
@ -347,30 +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)
|
||||
{
|
||||
struct thermal_trip trip;
|
||||
u8 ref, th_code;
|
||||
u32 interrupt_en;
|
||||
|
||||
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;
|
||||
writeb(temp, data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + trip_id * 4);
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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 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 + 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. */
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
@ -378,35 +410,35 @@ 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,
|
||||
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);
|
||||
|
||||
if (trip == 3) {
|
||||
con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
|
||||
con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
|
||||
writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
static void exynos4412_tmu_set_trip_hyst(struct exynos_tmu_data *data,
|
||||
int trip, u8 temp, u8 hyst)
|
||||
static void exynos4412_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp)
|
||||
{
|
||||
u32 th;
|
||||
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);
|
||||
}
|
||||
|
||||
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_disable_low(struct exynos_tmu_data *data)
|
||||
{
|
||||
exynos_tmu_update_bit(data, EXYNOS_TMU_REG_INTEN,
|
||||
EXYNOS_TMU_INTEN_FALL0_SHIFT, false);
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
@ -436,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;
|
||||
}
|
||||
|
||||
th = readl(data->base + reg_off);
|
||||
th &= ~(0xff << j * 8);
|
||||
th |= (temp_to_code(data, temp) << j * 8);
|
||||
writel(th, data->base + reg_off);
|
||||
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);
|
||||
}
|
||||
|
||||
static void exynos5433_tmu_set_trip_hyst(struct exynos_tmu_data *data,
|
||||
int trip, u8 temp, u8 hyst)
|
||||
static void exynos5433_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp)
|
||||
{
|
||||
unsigned int reg_off, j;
|
||||
u32 th;
|
||||
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);
|
||||
}
|
||||
|
||||
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_low(struct exynos_tmu_data *data)
|
||||
{
|
||||
exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN,
|
||||
EXYNOS_TMU_INTEN_FALL0_SHIFT, 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_disable_high(struct exynos_tmu_data *data)
|
||||
{
|
||||
exynos_tmu_update_bit(data, EXYNOS5433_TMU_REG_INTEN,
|
||||
EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, false);
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
@ -509,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);
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
static void exynos7_tmu_set_trip_hyst(struct exynos_tmu_data *data,
|
||||
int trip, u8 temp, u8 hyst)
|
||||
static void exynos7_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp)
|
||||
{
|
||||
unsigned int reg_off, bit_off;
|
||||
u32 th;
|
||||
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);
|
||||
}
|
||||
|
||||
reg_off = ((7 - trip) / 2) * 4;
|
||||
bit_off = ((8 - trip) % 2);
|
||||
static void exynos7_tmu_disable_low(struct exynos_tmu_data *data)
|
||||
{
|
||||
exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN,
|
||||
EXYNOS_TMU_INTEN_FALL0_SHIFT + 0, 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_disable_high(struct exynos_tmu_data *data)
|
||||
{
|
||||
exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN,
|
||||
EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, false);
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
@ -551,95 +585,51 @@ 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;
|
||||
if (on)
|
||||
con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT);
|
||||
else
|
||||
con &= ~BIT(EXYNOS_TMU_CORE_EN_SHIFT);
|
||||
|
||||
interrupt_en |=
|
||||
(1 << (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);
|
||||
} else {
|
||||
con &= ~(1 << 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 |=
|
||||
(1 << (EXYNOS7_TMU_INTEN_RISE0_SHIFT + i));
|
||||
}
|
||||
|
||||
interrupt_en |=
|
||||
interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
|
||||
|
||||
con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
|
||||
} else
|
||||
con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
|
||||
if (on)
|
||||
con |= BIT(EXYNOS_TMU_CORE_EN_SHIFT);
|
||||
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 |=
|
||||
(1 << (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);
|
||||
writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
|
||||
}
|
||||
|
||||
|
|
@ -766,10 +756,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);
|
||||
|
||||
|
|
@ -781,7 +770,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)
|
||||
|
|
@ -815,16 +805,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",
|
||||
|
|
@ -866,10 +846,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");
|
||||
|
|
@ -891,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;
|
||||
|
|
@ -910,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;
|
||||
|
|
@ -929,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;
|
||||
|
|
@ -947,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;
|
||||
|
|
@ -990,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)
|
||||
|
|
@ -1013,44 +1020,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 {
|
||||
if (PTR_ERR(data->regulator) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
dev_info(&pdev->dev, "Regulator node (vtmu) not found\n");
|
||||
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;
|
||||
|
||||
INIT_WORK(&data->irq_work, exynos_tmu_work);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1080,10 +1083,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)) {
|
||||
|
|
@ -1094,14 +1099,17 @@ 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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -1117,10 +1125,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
@ -1134,9 +1138,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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -318,21 +318,34 @@ void thermal_governor_update_tz(struct thermal_zone_device *tz,
|
|||
tz->governor->update_tz(tz, reason);
|
||||
}
|
||||
|
||||
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, "
|
||||
"shutting down\n", tz->type);
|
||||
dev_emerg(&tz->device, "%s: critical temperature reached\n", tz->type);
|
||||
|
||||
hw_protection_shutdown("Temperature too high", poweroff_delay_ms);
|
||||
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)
|
||||
{
|
||||
thermal_zone_device_halt(tz, true);
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
void thermal_governor_update_tz(struct thermal_zone_device *tz,
|
||||
enum thermal_notify_event reason);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -177,7 +177,17 @@ 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_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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Emergency restart, callable from an interrupt handler.
|
||||
|
|
|
|||
|
|
@ -957,21 +957,24 @@ 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)
|
||||
void __hw_protection_shutdown(const char *reason, int ms_until_forced, bool shutdown)
|
||||
{
|
||||
static atomic_t allow_proceed = ATOMIC_INIT(1);
|
||||
|
||||
|
|
@ -986,9 +989,12 @@ 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);
|
||||
else
|
||||
orderly_reboot();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hw_protection_shutdown);
|
||||
EXPORT_SYMBOL_GPL(__hw_protection_shutdown);
|
||||
|
||||
static int __init reboot_setup(char *str)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user