diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-07-10 11:43:25 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-07-10 11:43:25 -0700 |
commit | f7ea4be434fe7ea38699d14c1192481899e6ac94 (patch) | |
tree | c3fae752d7fde95d4d776a51cc11da849e266137 | |
parent | 81361b837a3450f0a44255fddfd7a4c72502b667 (diff) | |
parent | fe6a6de6692e7f7159c1ff42b07ecd737df712b4 (diff) |
Merge tag 'thermal-v5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux
Pull thermal updates from Daniel Lezcano:
- Add rk3568 sensor support (Finley Xiao)
- Add missing MODULE_DEVICE_TABLE for the Spreadtrum sensor (Chunyan
Zhang)
- Export additionnal attributes for the int340x thermal processor
(Srinivas Pandruvada)
- Add SC7280 compatible for the tsens driver (Rajeshwari Ravindra
Kamble)
- Fix kernel documentation for thermal_zone_device_unregister() and use
devm_platform_get_and_ioremap_resource() (Yang Yingliang)
- Fix coefficient calculations for the rcar_gen3 sensor driver (Niklas
Söderlund)
- Fix shadowing variable rcar_gen3_ths_tj_1 (Geert Uytterhoeven)
- Add missing of_node_put() for the iMX and Spreadtrum sensors
(Krzysztof Kozlowski)
- Add tegra3 thermal sensor DT bindings (Dmitry Osipenko)
- Stop the thermal zone monitoring when unregistering it to prevent a
temperature update without the 'get_temp' callback (Dmitry Osipenko)
- Add rk3568 DT bindings, convert bindings to yaml schemas and add the
corresponding compatible in the Rockchip sensor (Ezequiel Garcia)
- Add the sc8180x compatible for the Qualcomm tsensor (Bjorn Andersson)
- Use the find_first_zero_bit() function instead of custom code (Andy
Shevchenko)
- Fix the kernel doc for the device cooling device (Yang Li)
- Reorg the processor thermal int340x to set the scene for the PCI mmio
driver (Srinivas Pandruvada)
- Add PCI MMIO driver for the int340x processor thermal driver
(Srinivas Pandruvada)
- Add hwmon sensors for the mediatek sensor (Frank Wunderlich)
- Fix warning for return value reported by Smatch for the int340x
thermal processor (Srinivas Pandruvada)
- Fix wrong register access and decoding for the int340x thermal
processor (Srinivas Pandruvada)
* tag 'thermal-v5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux: (23 commits)
thermal/drivers/int340x/processor_thermal: Fix tcc setting
thermal/drivers/int340x/processor_thermal: Fix warning for return value
thermal/drivers/mediatek: Add sensors-support
thermal/drivers/int340x/processor_thermal: Add PCI MMIO based thermal driver
thermal/drivers/int340x/processor_thermal: Split enumeration and processing part
thermal: devfreq_cooling: Fix kernel-doc
thermal/drivers/intel/intel_soc_dts_iosf: Switch to use find_first_zero_bit()
dt-bindings: thermal: tsens: Add sc8180x compatible
dt-bindings: rockchip-thermal: Support the RK3568 SoC compatible
dt-bindings: thermal: convert rockchip-thermal to json-schema
thermal/core/thermal_of: Stop zone device before unregistering it
dt-bindings: thermal: Add binding for Tegra30 thermal sensor
thermal/drivers/sprd: Add missing of_node_put for loop iteration
thermal/drivers/imx_sc: Add missing of_node_put for loop iteration
thermal/drivers/rcar_gen3_thermal: Do not shadow rcar_gen3_ths_tj_1
thermal/drivers/rcar_gen3_thermal: Fix coefficient calculations
thermal/drivers/st: Use devm_platform_get_and_ioremap_resource()
thermal/core: Correct function name thermal_zone_device_unregister()
dt-bindings: thermal: tsens: Add compatible string to TSENS binding for SC7280
thermal/drivers/int340x: processor_thermal: Export additional attributes
...
22 files changed, 1066 insertions, 384 deletions
diff --git a/Documentation/devicetree/bindings/thermal/nvidia,tegra30-tsensor.yaml b/Documentation/devicetree/bindings/thermal/nvidia,tegra30-tsensor.yaml new file mode 100644 index 000000000000..a35da257b070 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/nvidia,tegra30-tsensor.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/thermal/nvidia,tegra30-tsensor.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra30 Thermal Sensor + +maintainers: + - Dmitry Osipenko <digetx@gmail.com> + - Jon Hunter <jonathanh@nvidia.com> + - Thierry Reding <thierry.reding@gmail.com> + +description: | + TSENSOR provides thermal and voltage sensors which monitor temperature + and voltage of the chip. Sensors are placed across the die to gauge the + temperature of the whole chip. The TSENSOR module: + + Generates an interrupt to SW to lower temperature via DVFS on reaching + a certain thermal/voltage threshold. + + Generates a signal to the CAR to reduce CPU frequency by half on reaching + a certain thermal/voltage threshold. + + Generates a signal to the PMC when the temperature reaches dangerously high + levels to reset the chip and sets a flag in the PMC. + + TSENSOR has two channels which monitor two different spots of the SoC. + +properties: + compatible: + const: nvidia,tegra30-tsensor + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + + interrupts: + maxItems: 1 + + "#thermal-sensor-cells": + const: 1 + + assigned-clock-parents: true + assigned-clock-rates: true + assigned-clocks: true + +required: + - compatible + - reg + - clocks + - resets + - interrupts + - "#thermal-sensor-cells" + +additionalProperties: false + +examples: + - | + thermal-sensor@70014000 { + compatible = "nvidia,tegra30-tsensor"; + reg = <0x70014000 0x500>; + interrupts = <0 102 4>; + clocks = <&clk 100>; + resets = <&rst 100>; + + #thermal-sensor-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml index 0b3b6af7bd5b..4a2eaf28e3fd 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml @@ -46,6 +46,8 @@ properties: - qcom,msm8996-tsens - qcom,msm8998-tsens - qcom,sc7180-tsens + - qcom,sc7280-tsens + - qcom,sc8180x-tsens - qcom,sdm845-tsens - qcom,sm8150-tsens - qcom,sm8250-tsens diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt deleted file mode 100644 index 7f94669e9ebe..000000000000 --- a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt +++ /dev/null @@ -1,85 +0,0 @@ -* Temperature Sensor ADC (TSADC) on rockchip SoCs - -Required properties: -- compatible : should be "rockchip,<name>-tsadc" - "rockchip,px30-tsadc": found on PX30 SoCs - "rockchip,rv1108-tsadc": found on RV1108 SoCs - "rockchip,rk3228-tsadc": found on RK3228 SoCs - "rockchip,rk3288-tsadc": found on RK3288 SoCs - "rockchip,rk3328-tsadc": found on RK3328 SoCs - "rockchip,rk3368-tsadc": found on RK3368 SoCs - "rockchip,rk3399-tsadc": found on RK3399 SoCs -- reg : physical base address of the controller and length of memory mapped - region. -- interrupts : The interrupt number to the cpu. The interrupt specifier format - depends on the interrupt controller. -- clocks : Must contain an entry for each entry in clock-names. -- clock-names : Shall be "tsadc" for the converter-clock, and "apb_pclk" for - the peripheral clock. -- resets : Must contain an entry for each entry in reset-names. - See ../reset/reset.txt for details. -- reset-names : Must include the name "tsadc-apb". -- pinctrl-names : The pin control state names; -- pinctrl-0 : The "init" pinctrl state, it will be set before device probe. -- pinctrl-1 : The "default" pinctrl state, it will be set after reset the - TSADC controller. -- pinctrl-2 : The "sleep" pinctrl state, it will be in for suspend. -- #thermal-sensor-cells : Should be 1. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description. - -Optional properties: -- rockchip,hw-tshut-temp : The hardware-controlled shutdown temperature value. -- rockchip,hw-tshut-mode : The hardware-controlled shutdown mode 0:CRU 1:GPIO. -- rockchip,hw-tshut-polarity : The hardware-controlled active polarity 0:LOW - 1:HIGH. -- rockchip,grf : The phandle of the syscon node for the general register file. - -Exiample: -tsadc: tsadc@ff280000 { - compatible = "rockchip,rk3288-tsadc"; - reg = <0xff280000 0x100>; - interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>; - clock-names = "tsadc", "apb_pclk"; - resets = <&cru SRST_TSADC>; - reset-names = "tsadc-apb"; - pinctrl-names = "init", "default", "sleep"; - pinctrl-0 = <&otp_gpio>; - pinctrl-1 = <&otp_out>; - pinctrl-2 = <&otp_gpio>; - #thermal-sensor-cells = <1>; - rockchip,hw-tshut-temp = <95000>; - rockchip,hw-tshut-mode = <0>; - rockchip,hw-tshut-polarity = <0>; -}; - -Example: referring to thermal sensors: -thermal-zones { - cpu_thermal: cpu_thermal { - polling-delay-passive = <1000>; /* milliseconds */ - polling-delay = <5000>; /* milliseconds */ - - /* sensor ID */ - thermal-sensors = <&tsadc 1>; - - trips { - cpu_alert0: cpu_alert { - temperature = <70000>; /* millicelsius */ - hysteresis = <2000>; /* millicelsius */ - type = "passive"; - }; - cpu_crit: cpu_crit { - temperature = <90000>; /* millicelsius */ - hysteresis = <2000>; /* millicelsius */ - type = "critical"; - }; - }; - - cooling-maps { - map0 { - trip = <&cpu_alert0>; - cooling-device = - <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; - }; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.yaml b/Documentation/devicetree/bindings/thermal/rockchip-thermal.yaml new file mode 100644 index 000000000000..b96ea277b558 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.yaml @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: GPL-2.0-only +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/thermal/rockchip-thermal.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Temperature Sensor ADC (TSADC) on Rockchip SoCs + +maintainers: + - Heiko Stuebner <heiko@sntech.de> + +properties: + compatible: + enum: + - rockchip,px30-tsadc # PX30 SoCs + - rockchip,rv1108-tsadc # RV1108 SoCs + - rockchip,rk3228-tsadc # RK3228 SoCs + - rockchip,rk3288-tsadc # RK3288 SoCs + - rockchip,rk3328-tsadc # RK3328 SoCs + - rockchip,rk3368-tsadc # RK3368 SoCs + - rockchip,rk3399-tsadc # RK3399 SoCs + - rockchip,rk3568-tsadc # RK3568 SoCs + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 2 + maxItems: 2 + + clock-names: + items: + - const: tsadc + - const: apb_pclk + + resets: + maxItems: 1 + + reset-names: + items: + - const: tsadc-apb + + "#thermal-sensor-cells": + const: 1 + + rockchip,grf: + description: The phandle of the syscon node for the general register file. + $ref: /schemas/types.yaml#/definitions/phandle + + rockchip,hw-tshut-temp: + description: The hardware-controlled shutdown temperature value. + $ref: /schemas/types.yaml#/definitions/uint32 + + rockchip,hw-tshut-mode: + description: The hardware-controlled shutdown mode 0:CRU 1:GPIO. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + + rockchip,hw-tshut-polarity: + description: The hardware-controlled active polarity 0:LOW 1:HIGH. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - resets + - reset-names + - "#thermal-sensor-cells" + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/clock/rk3288-cru.h> + + tsadc: tsadc@ff280000 { + compatible = "rockchip,rk3288-tsadc"; + reg = <0xff280000 0x100>; + interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>; + clock-names = "tsadc", "apb_pclk"; + resets = <&cru SRST_TSADC>; + reset-names = "tsadc-apb"; + #thermal-sensor-cells = <1>; + rockchip,hw-tshut-temp = <95000>; + rockchip,hw-tshut-mode = <0>; + rockchip,hw-tshut-polarity = <0>; + }; diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c index 3a788ac4f525..5a86cffd78f6 100644 --- a/drivers/thermal/devfreq_cooling.c +++ b/drivers/thermal/devfreq_cooling.c @@ -458,7 +458,7 @@ struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df) EXPORT_SYMBOL_GPL(devfreq_cooling_register); /** - * devfreq_cooling_em_register_power() - Register devfreq cooling device with + * devfreq_cooling_em_register() - Register devfreq cooling device with * power information and automatically register Energy Model (EM) * @df: Pointer to devfreq device. * @dfc_power: Pointer to devfreq_cooling_power. diff --git a/drivers/thermal/imx_sc_thermal.c b/drivers/thermal/imx_sc_thermal.c index b01d28eca7ee..8d76dbfde6a9 100644 --- a/drivers/thermal/imx_sc_thermal.c +++ b/drivers/thermal/imx_sc_thermal.c @@ -93,6 +93,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev) for_each_available_child_of_node(np, child) { sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL); if (!sensor) { + of_node_put(child); of_node_put(sensor_np); return -ENOMEM; } @@ -104,6 +105,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to get valid sensor resource id: %d\n", ret); + of_node_put(child); break; } @@ -114,6 +116,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev) if (IS_ERR(sensor->tzd)) { dev_err(&pdev->dev, "failed to register thermal zone\n"); ret = PTR_ERR(sensor->tzd); + of_node_put(child); break; } diff --git a/drivers/thermal/intel/int340x_thermal/Makefile b/drivers/thermal/intel/int340x_thermal/Makefile index 38a2731e503c..4e852ce4a5d5 100644 --- a/drivers/thermal/intel/int340x_thermal/Makefile +++ b/drivers/thermal/intel/int340x_thermal/Makefile @@ -4,6 +4,9 @@ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o +obj-$(CONFIG_INT340X_THERMAL) += int3401_thermal.o +obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device_pci_legacy.o +obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device_pci.o obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_rfim.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_mbox.o diff --git a/drivers/thermal/intel/int340x_thermal/int3401_thermal.c b/drivers/thermal/intel/int340x_thermal/int3401_thermal.c new file mode 100644 index 000000000000..acebc8ba94e2 --- /dev/null +++ b/drivers/thermal/intel/int340x_thermal/int3401_thermal.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * INT3401 processor thermal device + * Copyright (c) 2020, Intel Corporation. + */ +#include <linux/acpi.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/thermal.h> + +#include "int340x_thermal_zone.h" +#include "processor_thermal_device.h" + +static const struct acpi_device_id int3401_device_ids[] = { + {"INT3401", 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, int3401_device_ids); + +static int int3401_add(struct platform_device *pdev) +{ + struct proc_thermal_device *proc_priv; + int ret; + + proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL); + if (!proc_priv) + return -ENOMEM; + + ret = proc_thermal_add(&pdev->dev, proc_priv); + if (ret) + return ret; + + platform_set_drvdata(pdev, proc_priv); + + return ret; +} + +static int int3401_remove(struct platform_device *pdev) +{ + proc_thermal_remove(platform_get_drvdata(pdev)); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int int3401_thermal_resume(struct device *dev) +{ + return proc_thermal_resume(dev); +} +#else +#define int3401_thermal_resume NULL +#endif + +static SIMPLE_DEV_PM_OPS(int3401_proc_thermal_pm, NULL, int3401_thermal_resume); + +static struct platform_driver int3401_driver = { + .probe = int3401_add, + .remove = int3401_remove, + .driver = { + .name = "int3401 thermal", + .acpi_match_table = int3401_device_ids, + .pm = &int3401_proc_thermal_pm, + }, +}; + +static int __init proc_thermal_init(void) +{ + return platform_driver_register(&int3401_driver); +} + +static void __exit proc_thermal_exit(void) +{ + platform_driver_unregister(&int3401_driver); +} + +module_init(proc_thermal_init); +module_exit(proc_thermal_exit); + +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); +MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index 9e6f2a895a23..0f0038af2ad4 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c @@ -3,34 +3,17 @@ * processor_thermal_device.c * Copyright (c) 2014, Intel Corporation. */ +#include <linux/acpi.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/pci.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/acpi.h> #include <linux/thermal.h> -#include <linux/cpuhotplug.h> #include "int340x_thermal_zone.h" #include "processor_thermal_device.h" #include "../intel_soc_dts_iosf.h" #define DRV_NAME "proc_thermal" -enum proc_thermal_emum_mode_type { - PROC_THERMAL_NONE, - PROC_THERMAL_PCI, - PROC_THERMAL_PLATFORM_DEV -}; - -/* - * We can have only one type of enumeration, PCI or Platform, - * not both. So we don't need instance specific data. - */ -static enum proc_thermal_emum_mode_type proc_thermal_emum_mode = - PROC_THERMAL_NONE; - #define POWER_LIMIT_SHOW(index, suffix) \ static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \ struct device_attribute *attr, \ @@ -38,11 +21,6 @@ static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \ { \ struct proc_thermal_device *proc_dev = dev_get_drvdata(dev); \ \ - if (proc_thermal_emum_mode == PROC_THERMAL_NONE) { \ - dev_warn(dev, "Attempted to get power limit before device was initialized!\n"); \ - return 0; \ - } \ - \ return sprintf(buf, "%lu\n",\ (unsigned long)proc_dev->power_limits[index].suffix * 1000); \ } @@ -100,24 +78,27 @@ static ssize_t tcc_offset_degree_celsius_show(struct device *dev, if (err) return err; - val = (val >> 24) & 0xff; + val = (val >> 24) & 0x3f; return sprintf(buf, "%d\n", (int)val); } -static int tcc_offset_update(int tcc) +static int tcc_offset_update(unsigned int tcc) { u64 val; int err; - if (!tcc) + if (tcc > 63) return -EINVAL; err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val); if (err) return err; - val &= ~GENMASK_ULL(31, 24); - val |= (tcc & 0xff) << 24; + if (val & BIT(31)) + return -EPERM; + + val &= ~GENMASK_ULL(29, 24); + val |= (tcc & 0x3f) << 24; err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val); if (err) @@ -126,14 +107,15 @@ static int tcc_offset_update(int tcc) return 0; } -static int tcc_offset_save; +static unsigned int tcc_offset_save; static ssize_t tcc_offset_degree_celsius_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + unsigned int tcc; u64 val; - int tcc, err; + int err; err = rdmsrl_safe(MSR_PLATFORM_INFO, &val); if (err) @@ -142,7 +124,7 @@ static ssize_t tcc_offset_degree_celsius_store(struct device *dev, if (!(val & BIT(30))) return -EACCES; - if (kstrtoint(buf, 0, &tcc)) + if (kstrtouint(buf, 0, &tcc)) return -EINVAL; err = tcc_offset_update(tcc); @@ -291,11 +273,8 @@ static void proc_thermal_notify(acpi_handle handle, u32 event, void *data) } } - -static int proc_thermal_add(struct device *dev, - struct proc_thermal_device **priv) +int proc_thermal_add(struct device *dev, struct proc_thermal_device *proc_priv) { - struct proc_thermal_device *proc_priv; struct acpi_device *adev; acpi_status status; unsigned long long tmp; @@ -306,13 +285,8 @@ static int proc_thermal_add(struct device *dev, if (!adev) return -ENODEV; - proc_priv = devm_kzalloc(dev, sizeof(*proc_priv), GFP_KERNEL); - if (!proc_priv) - return -ENOMEM; - proc_priv->dev = dev; proc_priv->adev = adev; - *priv = proc_priv; ret = proc_thermal_read_ppcc(proc_priv); if (ret) @@ -338,15 +312,29 @@ static int proc_thermal_add(struct device *dev, if (ret) goto remove_zone; + ret = sysfs_create_file(&dev->kobj, &dev_attr_tcc_offset_degree_celsius.attr); + if (ret) + goto remove_notify; + + ret = sysfs_create_group(&dev->kobj, &power_limit_attribute_group); + if (ret) { + sysfs_remove_file(&dev->kobj, &dev_attr_tcc_offset_degree_celsius.attr); + goto remove_notify; + } + return 0; +remove_notify: + acpi_remove_notify_handler(adev->handle, + ACPI_DEVICE_NOTIFY, proc_thermal_notify); remove_zone: int340x_thermal_zone_remove(proc_priv->int340x_zone); return ret; } +EXPORT_SYMBOL_GPL(proc_thermal_add); -static void proc_thermal_remove(struct proc_thermal_device *proc_priv) +void proc_thermal_remove(struct proc_thermal_device *proc_priv) { acpi_remove_notify_handler(proc_priv->adev->handle, ACPI_DEVICE_NOTIFY, proc_thermal_notify); @@ -355,60 +343,24 @@ static void proc_thermal_remove(struct proc_thermal_device *proc_priv) sysfs_remove_group(&proc_priv->dev->kobj, &power_limit_attribute_group); } +EXPORT_SYMBOL_GPL(proc_thermal_remove); -static int int3401_add(struct platform_device *pdev) +int proc_thermal_resume(struct device *dev) { - struct proc_thermal_device *proc_priv; - int ret; - - if (proc_thermal_emum_mode == PROC_THERMAL_PCI) { - dev_err(&pdev->dev, "error: enumerated as PCI dev\n"); - return -ENODEV; - } - - ret = proc_thermal_add(&pdev->dev, &proc_priv); - if (ret) - return ret; - - platform_set_drvdata(pdev, proc_priv); - proc_thermal_emum_mode = PROC_THERMAL_PLATFORM_DEV; - - dev_info(&pdev->dev, "Creating sysfs group for PROC_THERMAL_PLATFORM_DEV\n"); - - ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr); - if (ret) - return ret; - - ret = sysfs_create_group(&pdev->dev.kobj, &power_limit_attribute_group); - if (ret) - sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr); + struct proc_thermal_device *proc_dev; - return ret; -} + proc_dev = dev_get_drvdata(dev); + proc_thermal_read_ppcc(proc_dev); -static int int3401_remove(struct platform_device *pdev) -{ - proc_thermal_remove(platform_get_drvdata(pdev)); + tcc_offset_update(tcc_offset_save); return 0; } - -static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid) -{ - struct proc_thermal_device *proc_priv; - struct pci_dev *pdev = devid; - - proc_priv = pci_get_drvdata(pdev); - - intel_soc_dts_iosf_interrupt_handler(proc_priv->soc_dts); - - return IRQ_HANDLED; -} +EXPORT_SYMBOL_GPL(proc_thermal_resume); #define MCHBAR 0 -static int proc_thermal_set_mmio_base(struct pci_dev *pdev, - struct proc_thermal_device *proc_priv) +static int proc_thermal_set_mmio_base(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) { int ret; @@ -423,9 +375,9 @@ static int proc_thermal_set_mmio_base(struct pci_dev *pdev, return 0; } -static int proc_thermal_mmio_add(struct pci_dev *pdev, - struct proc_thermal_device *proc_priv, - kernel_ulong_t feature_mask) +int proc_thermal_mmio_add(struct pci_dev *pdev, + struct proc_thermal_device *proc_priv, + kernel_ulong_t feature_mask) { int ret; @@ -471,11 +423,10 @@ err_rem_rapl: return ret; } +EXPORT_SYMBOL_GPL(proc_thermal_mmio_add); -static void proc_thermal_mmio_remove(struct pci_dev *pdev) +void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) { - struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); - if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL) proc_thermal_rapl_remove(); @@ -486,181 +437,7 @@ static void proc_thermal_mmio_remove(struct pci_dev *pdev) if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MBOX) proc_thermal_mbox_remove(pdev); } - -static int proc_thermal_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct proc_thermal_device *proc_priv; - int ret; - - if (proc_thermal_emum_mode == PROC_THERMAL_PLATFORM_DEV) { - dev_err(&pdev->dev, "error: enumerated as platform dev\n"); - return -ENODEV; - } - - ret = pcim_enable_device(pdev); - if (ret < 0) { - dev_err(&pdev->dev, "error: could not enable device\n"); - return ret; - } - - ret = proc_thermal_add(&pdev->dev, &proc_priv); - if (ret) - return ret; - - pci_set_drvdata(pdev, proc_priv); - proc_thermal_emum_mode = PROC_THERMAL_PCI; - - if (pdev->device == PCI_DEVICE_ID_INTEL_BSW_THERMAL) { - /* - * Enumerate additional DTS sensors available via IOSF. - * But we are not treating as a failure condition, if - * there are no aux DTSs enabled or fails. This driver - * already exposes sensors, which can be accessed via - * ACPI/MSR. So we don't want to fail for auxiliary DTSs. - */ - proc_priv->soc_dts = intel_soc_dts_iosf_init( - INTEL_SOC_DTS_INTERRUPT_MSI, 2, 0); - - if (!IS_ERR(proc_priv->soc_dts) && pdev->irq) { - ret = pci_enable_msi(pdev); - if (!ret) { - ret = request_threaded_irq(pdev->irq, NULL, - proc_thermal_pci_msi_irq, - IRQF_ONESHOT, "proc_thermal", - pdev); - if (ret) { - intel_soc_dts_iosf_exit( - proc_priv->soc_dts); - pci_disable_msi(pdev); - proc_priv->soc_dts = NULL; - } - } - } else - dev_err(&pdev->dev, "No auxiliary DTSs enabled\n"); - } - - dev_info(&pdev->dev, "Creating sysfs group for PROC_THERMAL_PCI\n"); - - ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr); - if (ret) - return ret; - - ret = sysfs_create_group(&pdev->dev.kobj, &power_limit_attribute_group); - if (ret) { - sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tcc_offset_degree_celsius.attr); - return ret; - } - - ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data); - if (ret) { - proc_thermal_remove(proc_priv); - return ret; - } - - return 0; -} - -static void proc_thermal_pci_remove(struct pci_dev *pdev) -{ - struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); - - if (proc_priv->soc_dts) { - intel_soc_dts_iosf_exit(proc_priv->soc_dts); - if (pdev->irq) { - free_irq(pdev->irq, pdev); - pci_disable_msi(pdev); - } - } - - proc_thermal_mmio_remove(pdev); - proc_thermal_remove(proc_priv); -} - -#ifdef CONFIG_PM_SLEEP -static int proc_thermal_resume(struct device *dev) -{ - struct proc_thermal_device *proc_dev; - - proc_dev = dev_get_drvdata(dev); - proc_thermal_read_ppcc(proc_dev); - - tcc_offset_update(tcc_offset_save); - - return 0; -} -#else -#define proc_thermal_resume NULL -#endif - -static SIMPLE_DEV_PM_OPS(proc_thermal_pm, NULL, proc_thermal_resume); - -static const struct pci_device_id proc_thermal_pci_ids[] = { - { PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) }, - { PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, BXT1_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, BXTX_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, BXTP_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, CNL_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, CFL_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, GLK_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, HSB_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, - { PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) }, - { PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, - { PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_MBOX) }, - { }, -}; - -MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids); - -static struct pci_driver proc_thermal_pci_driver = { - .name = DRV_NAME, - .probe = proc_thermal_pci_probe, - .remove = proc_thermal_pci_remove, - .id_table = proc_thermal_pci_ids, - .driver.pm = &proc_thermal_pm, -}; - -static const struct acpi_device_id int3401_device_ids[] = { - {"INT3401", 0}, - {"", 0}, -}; -MODULE_DEVICE_TABLE(acpi, int3401_device_ids); - -static struct platform_driver int3401_driver = { - .probe = int3401_add, - .remove = int3401_remove, - .driver = { - .name = "int3401 thermal", - .acpi_match_table = int3401_device_ids, - .pm = &proc_thermal_pm, - }, -}; - -static int __init proc_thermal_init(void) -{ - int ret; - - ret = platform_driver_register(&int3401_driver); - if (ret) - return ret; - - ret = pci_register_driver(&proc_thermal_pci_driver); - - return ret; -} - -static void __exit proc_thermal_exit(void) -{ - platform_driver_unregister(&int3401_driver); - pci_unregister_driver(&proc_thermal_pci_driver); -} - -module_init(proc_thermal_init); -module_exit(proc_thermal_exit); +EXPORT_SYMBOL_GPL(proc_thermal_mmio_remove); MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver"); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h index b9ed64561aaf..5a1cfe4864f1 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.h @@ -44,6 +44,7 @@ struct proc_thermal_device { struct intel_soc_dts_sensors *soc_dts; u32 mmio_feature_mask; void __iomem *mmio_base; + void *priv_data; }; struct rapl_mmio_regs { @@ -79,4 +80,12 @@ void proc_thermal_rfim_remove(struct pci_dev *pdev); int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); void proc_thermal_mbox_remove(struct pci_dev *pdev); +int processor_thermal_send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u32 *cmd_resp); +int proc_thermal_add(struct device *dev, struct proc_thermal_device *priv); +void proc_thermal_remove(struct proc_thermal_device *proc_priv); +int proc_thermal_resume(struct device *dev); +int proc_thermal_mmio_add(struct pci_dev *pdev, + struct proc_thermal_device *proc_priv, + kernel_ulong_t feature_mask); +void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *proc_priv); #endif diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c new file mode 100644 index 000000000000..11dd2e825f4f --- /dev/null +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Processor thermal device for newer processors + * Copyright (c) 2020, Intel Corporation. + */ + +#include <linux/acpi.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/thermal.h> + +#include "int340x_thermal_zone.h" +#include "processor_thermal_device.h" + +#define DRV_NAME "proc_thermal_pci" + +struct proc_thermal_pci { + struct pci_dev *pdev; + struct proc_thermal_device *proc_priv; + struct thermal_zone_device *tzone; + struct delayed_work work; + int stored_thres; + int no_legacy; +}; + +enum proc_thermal_mmio_type { + PROC_THERMAL_MMIO_TJMAX, + PROC_THERMAL_MMIO_PP0_TEMP, + PROC_THERMAL_MMIO_PP1_TEMP, + PROC_THERMAL_MMIO_PKG_TEMP, + PROC_THERMAL_MMIO_THRES_0, + PROC_THERMAL_MMIO_THRES_1, + PROC_THERMAL_MMIO_INT_ENABLE_0, + PROC_THERMAL_MMIO_INT_ENABLE_1, + PROC_THERMAL_MMIO_INT_STATUS_0, + PROC_THERMAL_MMIO_INT_STATUS_1, + PROC_THERMAL_MMIO_MAX +}; + +struct proc_thermal_mmio_info { + enum proc_thermal_mmio_type mmio_type; + u64 mmio_addr; + u64 shift; + u64 mask; +}; + +static struct proc_thermal_mmio_info proc_thermal_mmio_info[] = { + { PROC_THERMAL_MMIO_TJMAX, 0x599c, 16, 0xff }, + { PROC_THERMAL_MMIO_PP0_TEMP, 0x597c, 0, 0xff }, + { PROC_THERMAL_MMIO_PP1_TEMP, 0x5980, 0, 0xff }, + { PROC_THERMAL_MMIO_PKG_TEMP, 0x5978, 0, 0xff }, + { PROC_THERMAL_MMIO_THRES_0, 0x5820, 8, 0x7F }, + { PROC_THERMAL_MMIO_THRES_1, 0x5820, 16, 0x7F }, + { PROC_THERMAL_MMIO_INT_ENABLE_0, 0x5820, 15, 0x01 }, + { PROC_THERMAL_MMIO_INT_ENABLE_1, 0x5820, 23, 0x01 }, + { PROC_THERMAL_MMIO_INT_STATUS_0, 0x7200, 6, 0x01 }, + { PROC_THERMAL_MMIO_INT_STATUS_1, 0x7200, 8, 0x01 }, +}; + +#define B0D4_THERMAL_NOTIFY_DELAY 1000 +static int notify_delay_ms = B0D4_THERMAL_NOTIFY_DELAY; + +static void proc_thermal_mmio_read(struct proc_thermal_pci *pci_info, + enum proc_thermal_mmio_type type, + u32 *value) +{ + *value = ioread32(((u8 __iomem *)pci_info->proc_priv->mmio_base + + proc_thermal_mmio_info[type].mmio_addr)); + *value >>= proc_thermal_mmio_info[type].shift; + *value &= proc_thermal_mmio_info[type].mask; +} + +static void proc_thermal_mmio_write(struct proc_thermal_pci *pci_info, + enum proc_thermal_mmio_type type, + u32 value) +{ + u32 current_val; + u32 mask; + + current_val = ioread32(((u8 __iomem *)pci_info->proc_priv->mmio_base + + proc_thermal_mmio_info[type].mmio_addr)); + mask = proc_thermal_mmio_info[type].mask << proc_thermal_mmio_info[type].shift; + current_val &= ~mask; + + value &= proc_thermal_mmio_info[type].mask; + value <<= proc_thermal_mmio_info[type].shift; + + current_val |= value; + iowrite32(current_val, ((u8 __iomem *)pci_info->proc_priv->mmio_base + + proc_thermal_mmio_info[type].mmio_addr)); +} + +/* + * To avoid sending two many messages to user space, we have 1 second delay. + * On interrupt we are disabling interrupt and enabling after 1 second. + * This workload function is delayed by 1 second. + */ +static void proc_thermal_threshold_work_fn(struct work_struct *work) +{ + struct delayed_work *delayed_work = to_delayed_work(work); + struct proc_thermal_pci *pci_info = container_of(delayed_work, + struct proc_thermal_pci, work); + struct thermal_zone_device *tzone = pci_info->tzone; + + if (tzone) + thermal_zone_device_update(tzone, THERMAL_TRIP_VIOLATED); + + /* Enable interrupt flag */ + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1); +} + +static void pkg_thermal_schedule_work(struct delayed_work *work) +{ + unsigned long ms = msecs_to_jiffies(notify_delay_ms); + + schedule_delayed_work(work, ms); +} + +static irqreturn_t proc_thermal_irq_handler(int irq, void *devid) +{ + struct proc_thermal_pci *pci_info = devid; + u32 status; + + proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_INT_STATUS_0, &status); + + /* Disable enable interrupt flag */ + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0); + pci_write_config_byte(pci_info->pdev, 0xdc, 0x01); + + pkg_thermal_schedule_work(&pci_info->work); + + return IRQ_HANDLED; +} + +static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp) +{ + struct proc_thermal_pci *pci_info = tzd->devdata; + u32 _temp; + + proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_PKG_TEMP, &_temp); + *temp = (unsigned long)_temp * 1000; + + return 0; +} + +static int sys_get_trip_temp(struct thermal_zone_device *tzd, + int trip, int *temp) +{ + struct proc_thermal_pci *pci_info = tzd->devdata; + u32 _temp; + + proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_THRES_0, &_temp); + if (!_temp) { + *temp = THERMAL_TEMP_INVALID; + } else { + int tjmax; + + proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_TJMAX, &tjmax); + _temp = tjmax - _temp; + *temp = (unsigned long)_temp * 1000; + } + + return 0; +} + +static int sys_get_trip_type(struct thermal_zone_device *tzd, int trip, + enum thermal_trip_type *type) +{ + *type = THERMAL_TRIP_PASSIVE; + + return 0; +} + +static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp) +{ + struct proc_thermal_pci *pci_info = tzd->devdata; + int tjmax, _temp; + + if (temp <= 0) { + cancel_delayed_work_sync(&pci_info->work); + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0); + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, 0); + thermal_zone_device_disable(tzd); + pci_info->stored_thres = 0; + return 0; + } + + proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_TJMAX, &tjmax); + _temp = tjmax - (temp / 1000); + if (_temp < 0) + return -EINVAL; + + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, _temp); + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1); + + thermal_zone_device_enable(tzd); + pci_info->stored_thres = temp; + + return 0; +} + +static struct thermal_zone_device_ops tzone_ops = { + .get_temp = sys_get_curr_temp, + .get_trip_temp = sys_get_trip_temp, + .get_trip_type = sys_get_trip_type, + .set_trip_temp = sys_set_trip_temp, +}; + +static struct thermal_zone_params tzone_params = { + .governor_name = "user_space", + .no_hwmon = true, +}; + +static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct proc_thermal_device *proc_priv; + struct proc_thermal_pci *pci_info; + int irq_flag = 0, irq, ret; + + proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL); + if (!proc_priv) + return -ENOMEM; + + pci_info = devm_kzalloc(&pdev->dev, sizeof(*pci_info), GFP_KERNEL); + if (!pci_info) + return -ENOMEM; + + pci_info->pdev = pdev; + ret = pcim_enable_device(pdev); + if (ret < 0) { + dev_err(&pdev->dev, "error: could not enable device\n"); + return ret; + } + + pci_set_master(pdev); + + INIT_DELAYED_WORK(&pci_info->work, proc_thermal_threshold_work_fn); + + ret = proc_thermal_add(&pdev->dev, proc_priv); + if (ret) { + dev_err(&pdev->dev, "error: proc_thermal_add, will continue\n"); + pci_info->no_legacy = 1; + } + + proc_priv->priv_data = pci_info; + pci_info->proc_priv = proc_priv; + pci_set_drvdata(pdev, proc_priv); + + ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data); + if (ret) + goto err_ret_thermal; + + pci_info->tzone = thermal_zone_device_register("TCPU_PCI", 1, 1, pci_info, + &tzone_ops, + &tzone_params, 0, 0); + if (IS_ERR(pci_info->tzone)) { + ret = PTR_ERR(pci_info->tzone); + goto err_ret_mmio; + } + + /* request and enable interrupt */ + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to allocate vectors!\n"); + goto err_ret_tzone; + } + if (!pdev->msi_enabled && !pdev->msix_enabled) + irq_flag = IRQF_SHARED; + + irq = pci_irq_vector(pdev, 0); + ret = devm_request_threaded_irq(&pdev->dev, irq, + proc_thermal_irq_handler, NULL, + irq_flag, KBUILD_MODNAME, pci_info); + if (ret) { + dev_err(&pdev->dev, "Request IRQ %d failed\n", pdev->irq); + goto err_free_vectors; + } + + return 0; + +err_free_vectors: + pci_free_irq_vectors(pdev); +err_ret_tzone: + thermal_zone_device_unregister(pci_info->tzone); +err_ret_mmio: + proc_thermal_mmio_remove(pdev, proc_priv); +err_ret_thermal: + if (!pci_info->no_legacy) + proc_thermal_remove(proc_priv); + pci_disable_device(pdev); + + return ret; +} + +static void proc_thermal_pci_remove(struct pci_dev *pdev) +{ + struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); + struct proc_thermal_pci *pci_info = proc_priv->priv_data; + + cancel_delayed_work_sync(&pci_info->work); + + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, 0); + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0); + + devm_free_irq(&pdev->dev, pdev->irq, pci_info); + pci_free_irq_vectors(pdev); + + thermal_zone_device_unregister(pci_info->tzone); + proc_thermal_mmio_remove(pdev, pci_info->proc_priv); + if (!pci_info->no_legacy) + proc_thermal_remove(proc_priv); + pci_disable_device(pdev); +} + +#ifdef CONFIG_PM_SLEEP +static int proc_thermal_pci_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct proc_thermal_device *proc_priv; + struct proc_thermal_pci *pci_info; + + proc_priv = pci_get_drvdata(pdev); + pci_info = proc_priv->priv_data; + + if (pci_info->stored_thres) { + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, + pci_info->stored_thres / 1000); + proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 1); + } + + if (!pci_info->no_legacy) + return proc_thermal_resume(dev); + + return 0; +} +#else +#define proc_thermal_pci_resume NULL +#endif + +static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, NULL, proc_thermal_pci_resume); + +static const struct pci_device_id proc_thermal_pci_ids[] = { + { PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) }, + { }, +}; + +MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids); + +static struct pci_driver proc_thermal_pci_driver = { + .name = DRV_NAME, + .probe = proc_thermal_pci_probe, + .remove = proc_thermal_pci_remove, + .id_table = proc_thermal_pci_ids, + .driver.pm = &proc_thermal_pci_pm, +}; + +static int __init proc_thermal_init(void) +{ + return pci_register_driver(&proc_thermal_pci_driver); +} + +static void __exit proc_thermal_exit(void) +{ + pci_unregister_driver(&proc_thermal_pci_driver); +} + +module_init(proc_thermal_init); +module_exit(proc_thermal_exit); + +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); +MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c new file mode 100644 index 000000000000..f5fc1791b11e --- /dev/null +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * B0D4 processor thermal device + * Copyright (c) 2020, Intel Corporation. + */ + +#include <linux/acpi.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/thermal.h> + +#include "int340x_thermal_zone.h" +#include "processor_thermal_device.h" +#include "../intel_soc_dts_iosf.h" + +#define DRV_NAME "proc_thermal" + +static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid) +{ + struct proc_thermal_device *proc_priv; + struct pci_dev *pdev = devid; + + proc_priv = pci_get_drvdata(pdev); + + intel_soc_dts_iosf_interrupt_handler(proc_priv->soc_dts); + + return IRQ_HANDLED; +} + +static int proc_thermal_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct proc_thermal_device *proc_priv; + int ret; + + ret = pcim_enable_device(pdev); + if (ret < 0) { + dev_err(&pdev->dev, "error: could not enable device\n"); + return ret; + } + + proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL); + if (!proc_priv) + return -ENOMEM; + + ret = proc_thermal_add(&pdev->dev, proc_priv); + if (ret) + return ret; + + pci_set_drvdata(pdev, proc_priv); + + if (pdev->device == PCI_DEVICE_ID_INTEL_BSW_THERMAL) { + /* + * Enumerate additional DTS sensors available via IOSF. + * But we are not treating as a failure condition, if + * there are no aux DTSs enabled or fails. This driver + * already exposes sensors, which can be accessed via + * ACPI/MSR. So we don't want to fail for auxiliary DTSs. + */ + proc_priv->soc_dts = intel_soc_dts_iosf_init( + INTEL_SOC_DTS_INTERRUPT_MSI, 2, 0); + + if (!IS_ERR(proc_priv->soc_dts) && pdev->irq) { + ret = pci_enable_msi(pdev); + if (!ret) { + ret = request_threaded_irq(pdev->irq, NULL, + proc_thermal_pci_msi_irq, + IRQF_ONESHOT, "proc_thermal", + pdev); + if (ret) { + intel_soc_dts_iosf_exit( + proc_priv->soc_dts); + pci_disable_msi(pdev); + proc_priv->soc_dts = NULL; + } + } + } else + dev_err(&pdev->dev, "No auxiliary DTSs enabled\n"); + } else { + + } + + ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data); + if (ret) { + proc_thermal_remove(proc_priv); + return ret; + } + + return 0; +} + +static void proc_thermal_pci_remove(struct pci_dev *pdev) +{ + struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); + + if (proc_priv->soc_dts) { + intel_soc_dts_iosf_exit(proc_priv->soc_dts); + if (pdev->irq) { + free_irq(pdev->irq, pdev); + pci_disable_msi(pdev); + } + } + + proc_thermal_mmio_remove(pdev, proc_priv); + proc_thermal_remove(proc_priv); +} + +#ifdef CONFIG_PM_SLEEP +static int proc_thermal_pci_resume(struct device *dev) +{ + return proc_thermal_resume(dev); +} +#else +#define proc_thermal_pci_resume NULL +#endif + +static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, NULL, proc_thermal_pci_resume); + +static const struct pci_device_id proc_thermal_pci_ids[] = { + { PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, BXT1_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, BXTX_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, BXTP_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, CNL_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, CFL_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, GLK_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, HSB_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, + { PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) }, + { PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) }, + { PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_MBOX) }, + { }, +}; + +MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids); + +static struct pci_driver proc_thermal_pci_driver = { + .name = DRV_NAME, + .probe = proc_thermal_pci_probe, + .remove = proc_thermal_pci_remove, + .id_table = proc_thermal_pci_ids, + .driver.pm = &proc_thermal_pci_pm, +}; + +static int __init proc_thermal_init(void) +{ + return pci_register_driver(&proc_thermal_pci_driver); +} + +static void __exit proc_thermal_exit(void) +{ + pci_unregister_driver(&proc_thermal_pci_driver); +} + +module_init(proc_thermal_init); +module_exit(proc_thermal_exit); + +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); +MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c index 990f51f22884..59e93b04f0a9 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c @@ -23,7 +23,7 @@ static DEFINE_MUTEX(mbox_lock); -static int send_mbox_cmd(struct pci_dev *pdev, u8 cmd_id, u32 cmd_data, u8 *cmd_resp) +static int send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u32 *cmd_resp) { struct proc_thermal_device *proc_priv; u32 retries, data; @@ -82,6 +82,12 @@ unlock_mbox: return ret; } +int processor_thermal_send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u32 *cmd_resp) +{ + return send_mbox_cmd(pdev, cmd_id, cmd_data, cmd_resp); +} +EXPORT_SYMBOL_GPL(processor_thermal_send_mbox_cmd); + /* List of workload types */ static const char * const workload_types[] = { "none", @@ -147,7 +153,7 @@ static ssize_t workload_type_show(struct device *dev, char *buf) { struct pci_dev *pdev = to_pci_dev(dev); - u8 cmd_resp; + u32 cmd_resp; int ret; ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp); @@ -181,7 +187,7 @@ static bool workload_req_created; int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) { - u8 cmd_resp; + u32 cmd_resp; int ret; /* Check if there is a mailbox support, if fails return success */ diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c index aef993a813e2..2b8a3235d518 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c @@ -190,6 +190,59 @@ static DEVICE_ATTR_RO(ddr_data_rate_point_2); static DEVICE_ATTR_RO(ddr_data_rate_point_3); static DEVICE_ATTR_RW(rfi_disable); +static ssize_t rfi_restriction_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u16 cmd_id = 0x0008; + u32 cmd_resp; + u32 input; + int ret; + + ret = kstrtou32(buf, 10, &input); + if (ret) + return ret; + + ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, input, &cmd_resp); + if (ret) + return ret; + + return count; +} + +static ssize_t rfi_restriction_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u16 cmd_id = 0x0007; + u32 cmd_resp; + int ret; + + ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, 0, &cmd_resp); + if (ret) + return ret; + + return sprintf(buf, "%u\n", cmd_resp); +} + +static ssize_t ddr_data_rate_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u16 cmd_id = 0x0107; + u32 cmd_resp; + int ret; + + ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, 0, &cmd_resp); + if (ret) + return ret; + + return sprintf(buf, "%u\n", cmd_resp); +} + +static DEVICE_ATTR_RW(rfi_restriction); +static DEVICE_ATTR_RO(ddr_data_rate); + static struct attribute *dvfs_attrs[] = { &dev_attr_rfi_restriction_run_busy.attr, &dev_attr_rfi_restriction_err_code.attr, @@ -199,6 +252,8 @@ static struct attribute *dvfs_attrs[] = { &dev_attr_ddr_data_rate_point_2.attr, &dev_attr_ddr_data_rate_point_3.attr, &dev_attr_rfi_disable.attr, + &dev_attr_ddr_data_rate.attr, + &dev_attr_rfi_restriction.attr, NULL }; diff --git a/drivers/thermal/intel/intel_soc_dts_iosf.c b/drivers/thermal/intel/intel_soc_dts_iosf.c index 4f1a2f7c016c..342b0bb5a56d 100644 --- a/drivers/thermal/intel/intel_soc_dts_iosf.c +++ b/drivers/thermal/intel/intel_soc_dts_iosf.c @@ -350,13 +350,14 @@ int intel_soc_dts_iosf_add_read_only_critical_trip( int i, j; for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { - for (j = 0; j < sensors->soc_dts[i].trip_count; ++j) { - if (!(sensors->soc_dts[i].trip_mask & BIT(j))) { - return update_trip_temp(&sensors->soc_dts[i], j, - sensors->tj_max - critical_offset, - THERMAL_TRIP_CRITICAL); - } - } + struct intel_soc_dts_sensor_entry *entry = &sensors->soc_dts[i]; + int temp = sensors->tj_max - critical_offset; + unsigned long count = entry->trip_count; + unsigned long mask = entry->trip_mask; + + j = find_first_zero_bit(&mask, count); + if (j < count) + return update_trip_temp(entry, j, temp, THERMAL_TRIP_CRITICAL); } return -EINVAL; diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c index 97e8678ccf0e..ede94eadddda 100644 --- a/drivers/thermal/mtk_thermal.c +++ b/drivers/thermal/mtk_thermal.c @@ -23,6 +23,8 @@ #include <linux/reset.h> #include <linux/types.h> +#include "thermal_hwmon.h" + /* AUXADC Registers */ #define AUXADC_CON1_SET_V 0x008 #define AUXADC_CON1_CLR_V 0x00c @@ -1087,6 +1089,10 @@ static int mtk_thermal_probe(struct platform_device *pdev) goto err_disable_clk_peri_therm; } + ret = devm_thermal_add_hwmon_sysfs(tzdev); + if (ret) + dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs"); + return 0; err_disable_clk_peri_therm: diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index e1e412348076..fdf16aa34eb4 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -143,7 +143,7 @@ static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_tsc *tsc, * Division is not scaled in BSP and if scaled it might overflow * the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled */ - tsc->tj_t = (FIXPT_INT((ptat[1] - ptat[2]) * 157) + tsc->tj_t = (FIXPT_INT((ptat[1] - ptat[2]) * (ths_tj_1 - TJ_3)) / (ptat[0] - ptat[2])) + FIXPT_INT(TJ_3); tsc->coef.a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]), @@ -307,7 +307,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) { struct rcar_gen3_thermal_priv *priv; struct device *dev = &pdev->dev; - const int *rcar_gen3_ths_tj_1 = of_device_get_match_data(dev); + const int *ths_tj_1 = of_device_get_match_data(dev); struct resource *res; struct thermal_zone_device *zone; int ret, i; @@ -352,8 +352,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) priv->tscs[i] = tsc; priv->thermal_init(tsc); - rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], - *rcar_gen3_ths_tj_1); + rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1); zone = devm_thermal_zone_of_sensor_register(dev, i, tsc, &rcar_gen3_tz_of_ops); diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index aa9e0e31ef98..657d84b9963e 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -211,7 +211,11 @@ struct rockchip_thermal_data { #define TSADCV3_AUTO_PERIOD_TIME 1875 /* 2.5ms */ #define TSADCV3_AUTO_PERIOD_HT_TIME 1875 /* 2.5ms */ +#define TSADCV5_AUTO_PERIOD_TIME 1622 /* 2.5ms */ +#define TSADCV5_AUTO_PERIOD_HT_TIME 1622 /* 2.5ms */ + #define TSADCV2_USER_INTER_PD_SOC 0x340 /* 13 clocks */ +#define TSADCV5_USER_INTER_PD_SOC 0xfc0 /* 97us, at least 90us */ #define GRF_SARADC_TESTBIT 0x0e644 #define GRF_TSADC_TESTBIT_L 0x0e648 @@ -219,6 +223,12 @@ struct rockchip_thermal_data { #define PX30_GRF_SOC_CON2 0x0408 +#define RK3568_GRF_TSADC_CON 0x0600 +#define RK3568_GRF_TSADC_ANA_REG0 (0x10001 << 0) +#define RK3568_GRF_TSADC_ANA_REG1 (0x10001 << 1) +#define RK3568_GRF_TSADC_ANA_REG2 (0x10001 << 2) +#define RK3568_GRF_TSADC_TSEN (0x10001 << 8) + #define GRF_SARADC_TESTBIT_ON (0x10001 << 2) #define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2) #define GRF_TSADC_VCM_EN_L (0x10001 << 7) @@ -474,6 +484,45 @@ static const struct tsadc_table rk3399_code_table[] = { {TSADCV3_DATA_MASK, 125000}, }; +static const struct tsadc_table rk3568_code_table[] = { + {0, -40000}, + {1584, -40000}, + {1620, -35000}, + {1652, -30000}, + {1688, -25000}, + {1720, -20000}, + {1756, -15000}, + {1788, -10000}, + {1824, -5000}, + {1856, 0}, + {1892, 5000}, + {1924, 10000}, + {1956, 15000}, + {1992, 20000}, + {2024, 25000}, + {2060, 30000}, + {2092, 35000}, + {2128, 40000}, + {2160, 45000}, + {2196, 50000}, + {2228, 55000}, + {2264, 60000}, + {2300, 65000}, + {2332, 70000}, + {2368, 75000}, + {2400, 80000}, + {2436, 85000}, + {2468, 90000}, + {2500, 95000}, + {2536, 100000}, + {2572, 105000}, + {2604, 110000}, + {2636, 115000}, + {2672, 120000}, + {2704, 125000}, + {TSADCV2_DATA_MASK, 125000}, +}; + static u32 rk_tsadcv2_temp_to_code(const struct chip_tsadc_table *table, int temp) { @@ -701,6 +750,49 @@ static void rk_tsadcv4_initialize(struct regmap *grf, void __iomem *regs, regmap_write(grf, PX30_GRF_SOC_CON2, GRF_CON_TSADC_CH_INV); } +static void rk_tsadcv7_initialize(struct regmap *grf, void __iomem *regs, + enum tshut_polarity tshut_polarity) +{ + writel_relaxed(TSADCV5_USER_INTER_PD_SOC, regs + TSADCV2_USER_CON); + writel_relaxed(TSADCV5_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD); + writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT, + regs + TSADCV2_HIGHT_INT_DEBOUNCE); + writel_relaxed(TSADCV5_AUTO_PERIOD_HT_TIME, + regs + TSADCV2_AUTO_PERIOD_HT); + writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, + regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); + + if (tshut_polarity == TSHUT_HIGH_ACTIVE) + writel_relaxed(0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH, + regs + TSADCV2_AUTO_CON); + else + writel_relaxed(0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH, + regs + TSADCV2_AUTO_CON); + + /* + * The general register file will is optional + * and might not be available. + */ + if (!IS_ERR(grf)) { + regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_TSEN); + /* + * RK3568 TRM, section 18.5. requires a delay no less + * than 10us between the rising edge of tsadc_tsen_en + * and the rising edge of tsadc_ana_reg_0/1/2. + */ + udelay(15); + regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_ANA_REG0); + regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_ANA_REG1); + regmap_write(grf, RK3568_GRF_TSADC_CON, RK3568_GRF_TSADC_ANA_REG2); + + /* + * RK3568 TRM, section 18.5. requires a delay no less + * than 90us after the rising edge of tsadc_ana_reg_0/1/2. + */ + usleep_range(100, 200); + } +} + static void rk_tsadcv2_irq_ack(void __iomem *regs) { u32 val; @@ -1027,6 +1119,31 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = { }, }; +static const struct rockchip_tsadc_chip rk3568_tsadc_data = { + .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ + .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */ + .chn_num = 2, /* two channels for tsadc */ + + .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ + .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv7_initialize, + .irq_ack = rk_tsadcv3_irq_ack, + .control = rk_tsadcv3_control, + .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, + .set_tshut_temp = rk_tsadcv2_tshut_temp, + .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = { + .id = rk3568_code_table, + .length = ARRAY_SIZE(rk3568_code_table), + .data_mask = TSADCV2_DATA_MASK, + .mode = ADC_INCREMENT, + }, +}; + static const struct of_device_id of_rockchip_thermal_match[] = { { .compatible = "rockchip,px30-tsadc", .data = (void *)&px30_tsadc_data, @@ -1059,6 +1176,10 @@ static const struct of_device_id of_rockchip_thermal_match[] = { .compatible = "rockchip,rk3399-tsadc", .data = (void *)&rk3399_tsadc_data, }, + { + .compatible = "rockchip,rk3568-tsadc", + .data = (void *)&rk3568_tsadc_data, + }, { /* end */ }, }; MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match); diff --git a/drivers/thermal/sprd_thermal.c b/drivers/thermal/sprd_thermal.c index 3682edb2f466..fff80fc18002 100644 --- a/drivers/thermal/sprd_thermal.c +++ b/drivers/thermal/sprd_thermal.c @@ -388,7 +388,7 @@ static int sprd_thm_probe(struct platform_device *pdev) sen = devm_kzalloc(&pdev->dev, sizeof(*sen), GFP_KERNEL); if (!sen) { ret = -ENOMEM; - goto disable_clk; + goto of_put; } sen->data = thm; @@ -397,13 +397,13 @@ static int sprd_thm_probe(struct platform_device *pdev) ret = of_property_read_u32(sen_child, "reg", &sen->id); if (ret) { dev_err(&pdev->dev, "get sensor reg failed"); - goto disable_clk; + goto of_put; } ret = sprd_thm_sensor_calibration(sen_child, thm, sen); if (ret) { dev_err(&pdev->dev, "efuse cal analysis failed"); - goto disable_clk; + goto of_put; } sprd_thm_sensor_init(thm, sen); @@ -416,19 +416,20 @@ static int sprd_thm_probe(struct platform_device *pdev) dev_err(&pdev->dev, "register thermal zone failed %d\n", sen->id); ret = PTR_ERR(sen->tzd); - goto disable_clk; + goto of_put; } thm->sensor[sen->id] = sen; } + /* sen_child set to NULL at this point */ ret = sprd_thm_set_ready(thm); if (ret) - goto disable_clk; + goto of_put; ret = sprd_thm_wait_temp_ready(thm); if (ret) - goto disable_clk; + goto of_put; for (i = 0; i < thm->nr_sensors; i++) sprd_thm_toggle_sensor(thm->sensor[i], true); @@ -436,6 +437,8 @@ static int sprd_thm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, thm); return 0; +of_put: + of_node_put(sen_child); disable_clk: clk_disable_unprepare(thm->clk); return ret; @@ -532,6 +535,7 @@ static const struct of_device_id sprd_thermal_of_match[] = { { .compatible = "sprd,ums512-thermal", .data = &ums512_data }, { }, }; +MODULE_DEVICE_TABLE(of, sprd_thermal_of_match); static const struct dev_pm_ops sprd_thermal_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(sprd_thm_suspend, sprd_thm_resume) diff --git a/drivers/thermal/st/st_thermal_memmap.c b/drivers/thermal/st/st_thermal_memmap.c index a0114452d11f..d68596c40be9 100644 --- a/drivers/thermal/st/st_thermal_memmap.c +++ b/drivers/thermal/st/st_thermal_memmap.c @@ -119,19 +119,10 @@ static int st_mmap_regmap_init(struct st_thermal_sensor *sensor) { struct device *dev = sensor->dev; struct platform_device *pdev = to_platform_device(dev); - struct resource *res; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "no memory resources defined\n"); - return -ENODEV; - } - - sensor->mmio_base = devm_ioremap_resource(dev, res); - if (IS_ERR(sensor->mmio_base)) { - dev_err(dev, "failed to remap IO\n"); + sensor->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(sensor->mmio_base)) return PTR_ERR(sensor->mmio_base); - } sensor->regmap = devm_regmap_init_mmio(dev, sensor->mmio_base, &st_416mpe_regmap_config); diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 10a2d8e1cacf..97ef9b040b84 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1315,7 +1315,7 @@ free_tz: EXPORT_SYMBOL_GPL(thermal_zone_device_register); /** - * thermal_device_unregister - removes the registered thermal zone device + * thermal_zone_device_unregister - removes the registered thermal zone device * @tz: the thermal zone device to remove */ void thermal_zone_device_unregister(struct thermal_zone_device *tz) diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c index 5b76f9a1280d..6379f26a335f 100644 --- a/drivers/thermal/thermal_of.c +++ b/drivers/thermal/thermal_of.c @@ -559,6 +559,9 @@ void thermal_zone_of_sensor_unregister(struct device *dev, if (!tz) return; + /* stop temperature polling */ + thermal_zone_device_disable(tzd); + mutex_lock(&tzd->lock); tzd->ops->get_temp = NULL; tzd->ops->get_trend = NULL; |