diff options
18 files changed, 491 insertions, 357 deletions
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 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 <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>; }; 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 <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>; + }; 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"; - }; 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..7541e27704ca 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml @@ -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>; diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml index 3c81def03c84..d9d2657287cb 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml @@ -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>; 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 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 diff --git a/drivers/thermal/amlogic_thermal.c b/drivers/thermal/amlogic_thermal.c index 5877cde25b79..df7a5ed55385 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) @@ -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, 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"); diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 123ec81e1943..6482513bfe66 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -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,34 +265,44 @@ 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); + data->tmu_clear_irqs(data); + } - /* Write temperature code for rising and falling threshold */ - for (i = 0; i < ntrips; i++) { + if (!IS_ERR(data->clk_sec)) + clk_disable(data->clk_sec); + clk_disable(data->clk); + mutex_unlock(&data->lock); - struct thermal_trip trip; + return ret; +} - ret = thermal_zone_get_trip(tzd, i, &trip); - if (ret) - goto err; +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; - data->tmu_set_trip_temp(data, i, trip.temperature / MCELSIUS); - data->tmu_set_trip_hyst(data, i, trip.temperature / MCELSIUS, - trip.hysteresis / MCELSIUS); - } + ret = thermal_zone_get_crit_temp(tzd, &temp); + if (ret) { + /* FIXME: Remove this special case */ + if (data->soc == SOC_ARCH_EXYNOS5433) + return 0; - data->tmu_clear_irqs(data); + dev_err(&pdev->dev, + "No CRITICAL trip point defined in device tree!\n"); + return ret; } -err: + + mutex_lock(&data->lock); + clk_enable(data->clk); + + data->tmu_set_crit_temp(data, temp / MCELSIUS); + clk_disable(data->clk); mutex_unlock(&data->lock); - if (!IS_ERR(data->clk_sec)) - clk_disable(data->clk_sec); -out: - return ret; + + return 0; } static u32 get_con_reg(struct exynos_tmu_data *data, u32 con) @@ -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) +{ + 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) { - struct thermal_trip trip; - u8 ref, th_code; + u16 tmu_temp_mask; + u32 th; - if (thermal_zone_get_trip(data->tzd, 0, &trip)) - return; + tmu_temp_mask = + (data->soc == SOC_ARCH_EXYNOS7) ? EXYNOS7_TMU_TEMP_MASK + : EXYNOS_TMU_TEMP_MASK; - ref = trip.temperature / MCELSIUS; + 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); +} - if (trip_id == 0) { - th_code = temp_to_code(data, ref); - writeb(th_code, data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP); - } +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); +} - temp -= ref; - writeb(temp, data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + trip_id * 4); +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) @@ -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); + 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 |= (1 << 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) @@ -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; - } + 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) @@ -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); + 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); |
