Commit f7ea4be4 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 81361b83 fe6a6de6
# 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>;
};
...@@ -46,6 +46,8 @@ properties: ...@@ -46,6 +46,8 @@ properties:
- qcom,msm8996-tsens - qcom,msm8996-tsens
- qcom,msm8998-tsens - qcom,msm8998-tsens
- qcom,sc7180-tsens - qcom,sc7180-tsens
- qcom,sc7280-tsens
- qcom,sc8180x-tsens
- qcom,sdm845-tsens - qcom,sdm845-tsens
- qcom,sm8150-tsens - qcom,sm8150-tsens
- qcom,sm8250-tsens - qcom,sm8250-tsens
......
* 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>;
};
};
};
};
# 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>;
};
...@@ -458,7 +458,7 @@ struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df) ...@@ -458,7 +458,7 @@ struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df)
EXPORT_SYMBOL_GPL(devfreq_cooling_register); 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) * power information and automatically register Energy Model (EM)
* @df: Pointer to devfreq device. * @df: Pointer to devfreq device.
* @dfc_power: Pointer to devfreq_cooling_power. * @dfc_power: Pointer to devfreq_cooling_power.
......
...@@ -93,6 +93,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev) ...@@ -93,6 +93,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev)
for_each_available_child_of_node(np, child) { for_each_available_child_of_node(np, child) {
sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL); sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL);
if (!sensor) { if (!sensor) {
of_node_put(child);
of_node_put(sensor_np); of_node_put(sensor_np);
return -ENOMEM; return -ENOMEM;
} }
...@@ -104,6 +105,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev) ...@@ -104,6 +105,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev)
dev_err(&pdev->dev, dev_err(&pdev->dev,
"failed to get valid sensor resource id: %d\n", "failed to get valid sensor resource id: %d\n",
ret); ret);
of_node_put(child);
break; break;
} }
...@@ -114,6 +116,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev) ...@@ -114,6 +116,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev)
if (IS_ERR(sensor->tzd)) { if (IS_ERR(sensor->tzd)) {
dev_err(&pdev->dev, "failed to register thermal zone\n"); dev_err(&pdev->dev, "failed to register thermal zone\n");
ret = PTR_ERR(sensor->tzd); ret = PTR_ERR(sensor->tzd);
of_node_put(child);
break; break;
} }
......
...@@ -4,6 +4,9 @@ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o ...@@ -4,6 +4,9 @@ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o
obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o
obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.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_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_rfim.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_rfim.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_mbox.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_mbox.o
......
// 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");
...@@ -3,34 +3,17 @@ ...@@ -3,34 +3,17 @@
* processor_thermal_device.c * processor_thermal_device.c
* Copyright (c) 2014, Intel Corporation. * Copyright (c) 2014, Intel Corporation.
*/ */
#include <linux/acpi.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/thermal.h> #include <linux/thermal.h>
#include <linux/cpuhotplug.h>
#include "int340x_thermal_zone.h" #include "int340x_thermal_zone.h"
#include "processor_thermal_device.h" #include "processor_thermal_device.h"
#include "../intel_soc_dts_iosf.h" #include "../intel_soc_dts_iosf.h"
#define DRV_NAME "proc_thermal" #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) \ #define POWER_LIMIT_SHOW(index, suffix) \
static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \ static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \
struct device_attribute *attr, \ struct device_attribute *attr, \
...@@ -38,11 +21,6 @@ static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \ ...@@ -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); \ 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",\ return sprintf(buf, "%lu\n",\
(unsigned long)proc_dev->power_limits[index].suffix * 1000); \ (unsigned long)proc_dev->power_limits[index].suffix * 1000); \
} }
...@@ -100,24 +78,27 @@ static ssize_t tcc_offset_degree_celsius_show(struct device *dev, ...@@ -100,24 +78,27 @@ static ssize_t tcc_offset_degree_celsius_show(struct device *dev,
if (err) if (err)
return err; return err;
val = (val >> 24) & 0xff; val = (val >> 24) & 0x3f;
return sprintf(buf, "%d\n", (int)val); return sprintf(buf, "%d\n", (int)val);
} }
static int tcc_offset_update(int tcc) static int tcc_offset_update(unsigned int tcc)
{ {
u64 val; u64 val;
int err; int err;
if (!tcc) if (tcc > 63)
return -EINVAL; return -EINVAL;
err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val); err = rdmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, &val);
if (err) if (err)
return err; return err;
val &= ~GENMASK_ULL(31, 24); if (val & BIT(31))
val |= (tcc & 0xff) << 24; return -EPERM;
val &= ~GENMASK_ULL(29, 24);
val |= (tcc & 0x3f) << 24;
err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val); err = wrmsrl_safe(MSR_IA32_TEMPERATURE_TARGET, val);
if (err) if (err)
...@@ -126,14 +107,15 @@ static int tcc_offset_update(int tcc) ...@@ -126,14 +107,15 @@ static int tcc_offset_update(int tcc)
return 0; return 0;
} }
static int tcc_offset_save; static unsigned int tcc_offset_save;
static ssize_t tcc_offset_degree_celsius_store(struct device *dev, static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
struct device_attribute *attr, const char *buf, struct device_attribute *attr, const char *buf,
size_t count) size_t count)
{ {
unsigned int tcc;
u64 val; u64 val;
int tcc, err; int err;
err = rdmsrl_safe(MSR_PLATFORM_INFO, &val); err = rdmsrl_safe(MSR_PLATFORM_INFO, &val);
if (err) if (err)
...@@ -142,7 +124,7 @@ static ssize_t tcc_offset_degree_celsius_store(struct device *dev, ...@@ -142,7 +124,7 @@ static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
if (!(val & BIT(30))) if (!(val & BIT(30)))
return -EACCES; return -EACCES;
if (kstrtoint(buf, 0, &tcc)) if (kstrtouint(buf, 0, &tcc))
return -EINVAL; return -EINVAL;
err = tcc_offset_update(tcc); err = tcc_offset_update(tcc);
...@@ -291,11 +273,8 @@ static void proc_thermal_notify(acpi_handle handle, u32 event, void *data) ...@@ -291,11 +273,8 @@ static void proc_thermal_notify(acpi_handle handle, u32 event, void *data)
} }
} }
int proc_thermal_add(struct device *dev, struct proc_thermal_device *proc_priv)
static int proc_thermal_add(struct device *dev,
struct proc_thermal_device **priv)
{ {
struct proc_thermal_device *proc_priv;
struct acpi_device *adev; struct acpi_device *adev;
acpi_status status; acpi_status status;
unsigned long long tmp; unsigned long long tmp;
...@@ -306,13 +285,8 @@ static int proc_thermal_add(struct device *dev, ...@@ -306,13 +285,8 @@ static int proc_thermal_add(struct device *dev,
if (!adev) if (!adev)
return -ENODEV; return -ENODEV;
proc_priv = devm_kzalloc(dev, sizeof(*proc_priv), GFP_KERNEL);
if (!proc_priv)
return -ENOMEM;
proc_priv->dev = dev; proc_priv->dev = dev;
proc_priv->adev = adev; proc_priv->adev = adev;
*priv = proc_priv;
ret = proc_thermal_read_ppcc(proc_priv); ret = proc_thermal_read_ppcc(proc_priv);
if (ret) if (ret)
...@@ -338,15 +312,29 @@ static int proc_thermal_add(struct device *dev, ...@@ -338,15 +312,29 @@ static int proc_thermal_add(struct device *dev,
if (ret) if (ret)
goto remove_zone; 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; return 0;
remove_notify:
acpi_remove_notify_handler(adev->handle,
ACPI_DEVICE_NOTIFY, proc_thermal_notify);
remove_zone: remove_zone:
int340x_thermal_zone_remove(proc_priv->int340x_zone); int340x_thermal_zone_remove(proc_priv->int340x_zone);
return ret; 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_remove_notify_handler(proc_priv->adev->handle,
ACPI_DEVICE_NOTIFY, proc_thermal_notify); ACPI_DEVICE_NOTIFY, proc_thermal_notify);
...@@ -355,60 +343,24 @@ static void proc_thermal_remove(struct proc_thermal_device *proc_priv) ...@@ -355,60 +343,24 @@ static void proc_thermal_remove(struct proc_thermal_device *proc_priv)
sysfs_remove_group(&proc_priv->dev->kobj, sysfs_remove_group(&proc_priv->dev->kobj,
&power_limit_attribute_group); &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; struct proc_thermal_device *proc_dev;
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);
return ret; proc_dev = dev_get_drvdata(dev);
} proc_thermal_read_ppcc(proc_dev);
static int int3401_remove(struct platform_device *pdev) tcc_offset_update(tcc_offset_save);
{
proc_thermal_remove(platform_get_drvdata(pdev));
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(proc_thermal_resume);
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;
}
#define MCHBAR 0 #define MCHBAR 0
static int proc_thermal_set_mmio_base(struct pci_dev *pdev, static int proc_thermal_set_mmio_base(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
struct proc_thermal_device *proc_priv)
{ {
int ret; int ret;
...@@ -423,9 +375,9 @@ static int proc_thermal_set_mmio_base(struct pci_dev *pdev, ...@@ -423,9 +375,9 @@ static int proc_thermal_set_mmio_base(struct pci_dev *pdev,
return 0; return 0;
} }
static int proc_thermal_mmio_add(struct pci_dev *pdev, int proc_thermal_mmio_add(struct pci_dev *pdev,
struct proc_thermal_device *proc_priv, struct proc_thermal_device *proc_priv,
kernel_ulong_t feature_mask) kernel_ulong_t feature_mask)
{ {
int ret; int ret;
...@@ -471,11 +423,10 @@ static int proc_thermal_mmio_add(struct pci_dev *pdev, ...@@ -471,11 +423,10 @@ static int proc_thermal_mmio_add(struct pci_dev *pdev,
return ret; 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) if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_RAPL)
proc_thermal_rapl_remove(); proc_thermal_rapl_remove();
...@@ -486,181 +437,7 @@ static void proc_thermal_mmio_remove(struct pci_dev *pdev) ...@@ -486,181 +437,7 @@ static void proc_thermal_mmio_remove(struct pci_dev *pdev)
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MBOX) if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MBOX)
proc_thermal_mbox_remove(pdev); proc_thermal_mbox_remove(pdev);
} }
EXPORT_SYMBOL_GPL(proc_thermal_mmio_remove);
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);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver"); MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
......
...@@ -44,6 +44,7 @@ struct proc_thermal_device { ...@@ -44,6 +44,7 @@ struct proc_thermal_device {
struct intel_soc_dts_sensors *soc_dts; struct intel_soc_dts_sensors *soc_dts;
u32 mmio_feature_mask; u32 mmio_feature_mask;
void __iomem *mmio_base; void __iomem *mmio_base;
void *priv_data;
}; };
struct rapl_mmio_regs { struct rapl_mmio_regs {
...@@ -79,4 +80,12 @@ void proc_thermal_rfim_remove(struct pci_dev *pdev); ...@@ -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); int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
void proc_thermal_mbox_remove(struct pci_dev *pdev); 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 #endif
// 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");
// 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");
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
static DEFINE_MUTEX(mbox_lock); 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; struct proc_thermal_device *proc_priv;
u32 retries, data; u32 retries, data;
...@@ -82,6 +82,12 @@ static int send_mbox_cmd(struct pci_dev *pdev, u8 cmd_id, u32 cmd_data, u8 *cmd_ ...@@ -82,6 +82,12 @@ static int send_mbox_cmd(struct pci_dev *pdev, u8 cmd_id, u32 cmd_data, u8 *cmd_
return ret; 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 */ /* List of workload types */
static const char * const workload_types[] = { static const char * const workload_types[] = {
"none", "none",
...@@ -147,7 +153,7 @@ static ssize_t workload_type_show(struct device *dev, ...@@ -147,7 +153,7 @@ static ssize_t workload_type_show(struct device *dev,
char *buf) char *buf)
{ {
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
u8 cmd_resp; u32 cmd_resp;
int ret; int ret;
ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp); ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp);
...@@ -181,7 +187,7 @@ static bool workload_req_created; ...@@ -181,7 +187,7 @@ static bool workload_req_created;
int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
{ {
u8 cmd_resp; u32 cmd_resp;
int ret; int ret;
/* Check if there is a mailbox support, if fails return success */ /* Check if there is a mailbox support, if fails return success */
......
...@@ -190,6 +190,59 @@ static DEVICE_ATTR_RO(ddr_data_rate_point_2); ...@@ -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_RO(ddr_data_rate_point_3);
static DEVICE_ATTR_RW(rfi_disable); 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[] = { static struct attribute *dvfs_attrs[] = {
&dev_attr_rfi_restriction_run_busy.attr, &dev_attr_rfi_restriction_run_busy.attr,
&dev_attr_rfi_restriction_err_code.attr, &dev_attr_rfi_restriction_err_code.attr,
...@@ -199,6 +252,8 @@ static struct attribute *dvfs_attrs[] = { ...@@ -199,6 +252,8 @@ static struct attribute *dvfs_attrs[] = {
&dev_attr_ddr_data_rate_point_2.attr, &dev_attr_ddr_data_rate_point_2.attr,
&dev_attr_ddr_data_rate_point_3.attr, &dev_attr_ddr_data_rate_point_3.attr,
&dev_attr_rfi_disable.attr, &dev_attr_rfi_disable.attr,
&dev_attr_ddr_data_rate.attr,
&dev_attr_rfi_restriction.attr,
NULL NULL
}; };
......
...@@ -350,13 +350,14 @@ int intel_soc_dts_iosf_add_read_only_critical_trip( ...@@ -350,13 +350,14 @@ int intel_soc_dts_iosf_add_read_only_critical_trip(
int i, j; int i, j;
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
for (j = 0; j < sensors->soc_dts[i].trip_count; ++j) { struct intel_soc_dts_sensor_entry *entry = &sensors->soc_dts[i];
if (!(sensors->soc_dts[i].trip_mask & BIT(j))) { int temp = sensors->tj_max - critical_offset;
return update_trip_temp(&sensors->soc_dts[i], j, unsigned long count = entry->trip_count;
sensors->tj_max - critical_offset, unsigned long mask = entry->trip_mask;
THERMAL_TRIP_CRITICAL);
} j = find_first_zero_bit(&mask, count);
} if (j < count)
return update_trip_temp(entry, j, temp, THERMAL_TRIP_CRITICAL);
} }
return -EINVAL; return -EINVAL;
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/types.h> #include <linux/types.h>
#include "thermal_hwmon.h"
/* AUXADC Registers */ /* AUXADC Registers */
#define AUXADC_CON1_SET_V 0x008 #define AUXADC_CON1_SET_V 0x008
#define AUXADC_CON1_CLR_V 0x00c #define AUXADC_CON1_CLR_V 0x00c
...@@ -1087,6 +1089,10 @@ static int mtk_thermal_probe(struct platform_device *pdev) ...@@ -1087,6 +1089,10 @@ static int mtk_thermal_probe(struct platform_device *pdev)
goto err_disable_clk_peri_therm; 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; return 0;
err_disable_clk_peri_therm: err_disable_clk_peri_therm:
......
...@@ -143,7 +143,7 @@ static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_tsc *tsc, ...@@ -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 * Division is not scaled in BSP and if scaled it might overflow
* the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled * 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); / (ptat[0] - ptat[2])) + FIXPT_INT(TJ_3);
tsc->coef.a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]), 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) ...@@ -307,7 +307,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
{ {
struct rcar_gen3_thermal_priv *priv; struct rcar_gen3_thermal_priv *priv;
struct device *dev = &pdev->dev; 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 resource *res;
struct thermal_zone_device *zone; struct thermal_zone_device *zone;
int ret, i; int ret, i;
...@@ -352,8 +352,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) ...@@ -352,8 +352,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
priv->tscs[i] = tsc; priv->tscs[i] = tsc;
priv->thermal_init(tsc); priv->thermal_init(tsc);
rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1);
*rcar_gen3_ths_tj_1);
zone = devm_thermal_zone_of_sensor_register(dev, i, tsc, zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
&rcar_gen3_tz_of_ops); &rcar_gen3_tz_of_ops);
......
...@@ -211,7 +211,11 @@ struct rockchip_thermal_data { ...@@ -211,7 +211,11 @@ struct rockchip_thermal_data {
#define TSADCV3_AUTO_PERIOD_TIME 1875 /* 2.5ms */ #define TSADCV3_AUTO_PERIOD_TIME 1875 /* 2.5ms */
#define TSADCV3_AUTO_PERIOD_HT_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 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_SARADC_TESTBIT 0x0e644
#define GRF_TSADC_TESTBIT_L 0x0e648 #define GRF_TSADC_TESTBIT_L 0x0e648
...@@ -219,6 +223,12 @@ struct rockchip_thermal_data { ...@@ -219,6 +223,12 @@ struct rockchip_thermal_data {
#define PX30_GRF_SOC_CON2 0x0408 #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_SARADC_TESTBIT_ON (0x10001 << 2)
#define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2) #define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2)
#define GRF_TSADC_VCM_EN_L (0x10001 << 7) #define GRF_TSADC_VCM_EN_L (0x10001 << 7)
...@@ -474,6 +484,45 @@ static const struct tsadc_table rk3399_code_table[] = { ...@@ -474,6 +484,45 @@ static const struct tsadc_table rk3399_code_table[] = {
{TSADCV3_DATA_MASK, 125000}, {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, static u32 rk_tsadcv2_temp_to_code(const struct chip_tsadc_table *table,
int temp) int temp)
{ {
...@@ -701,6 +750,49 @@ static void rk_tsadcv4_initialize(struct regmap *grf, void __iomem *regs, ...@@ -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); 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) static void rk_tsadcv2_irq_ack(void __iomem *regs)
{ {
u32 val; u32 val;
...@@ -1027,6 +1119,31 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = { ...@@ -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[] = { static const struct of_device_id of_rockchip_thermal_match[] = {
{ .compatible = "rockchip,px30-tsadc", { .compatible = "rockchip,px30-tsadc",
.data = (void *)&px30_tsadc_data, .data = (void *)&px30_tsadc_data,
...@@ -1059,6 +1176,10 @@ static const struct of_device_id of_rockchip_thermal_match[] = { ...@@ -1059,6 +1176,10 @@ static const struct of_device_id of_rockchip_thermal_match[] = {
.compatible = "rockchip,rk3399-tsadc", .compatible = "rockchip,rk3399-tsadc",
.data = (void *)&rk3399_tsadc_data, .data = (void *)&rk3399_tsadc_data,
}, },
{
.compatible = "rockchip,rk3568-tsadc",
.data = (void *)&rk3568_tsadc_data,
},
{ /* end */ }, { /* end */ },
}; };
MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match); MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
......
...@@ -388,7 +388,7 @@ static int sprd_thm_probe(struct platform_device *pdev) ...@@ -388,7 +388,7 @@ static int sprd_thm_probe(struct platform_device *pdev)
sen = devm_kzalloc(&pdev->dev, sizeof(*sen), GFP_KERNEL); sen = devm_kzalloc(&pdev->dev, sizeof(*sen), GFP_KERNEL);
if (!sen) { if (!sen) {
ret = -ENOMEM; ret = -ENOMEM;
goto disable_clk; goto of_put;
} }
sen->data = thm; sen->data = thm;
...@@ -397,13 +397,13 @@ static int sprd_thm_probe(struct platform_device *pdev) ...@@ -397,13 +397,13 @@ static int sprd_thm_probe(struct platform_device *pdev)
ret = of_property_read_u32(sen_child, "reg", &sen->id); ret = of_property_read_u32(sen_child, "reg", &sen->id);
if (ret) { if (ret) {
dev_err(&pdev->dev, "get sensor reg failed"); dev_err(&pdev->dev, "get sensor reg failed");
goto disable_clk; goto of_put;
} }
ret = sprd_thm_sensor_calibration(sen_child, thm, sen); ret = sprd_thm_sensor_calibration(sen_child, thm, sen);
if (ret) { if (ret) {
dev_err(&pdev->dev, "efuse cal analysis failed"); dev_err(&pdev->dev, "efuse cal analysis failed");
goto disable_clk; goto of_put;
} }
sprd_thm_sensor_init(thm, sen); sprd_thm_sensor_init(thm, sen);
...@@ -416,19 +416,20 @@ static int sprd_thm_probe(struct platform_device *pdev) ...@@ -416,19 +416,20 @@ static int sprd_thm_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "register thermal zone failed %d\n", dev_err(&pdev->dev, "register thermal zone failed %d\n",
sen->id); sen->id);
ret = PTR_ERR(sen->tzd); ret = PTR_ERR(sen->tzd);
goto disable_clk; goto of_put;
} }
thm->sensor[sen->id] = sen; thm->sensor[sen->id] = sen;
} }
/* sen_child set to NULL at this point */
ret = sprd_thm_set_ready(thm); ret = sprd_thm_set_ready(thm);
if (ret) if (ret)
goto disable_clk; goto of_put;
ret = sprd_thm_wait_temp_ready(thm); ret = sprd_thm_wait_temp_ready(thm);
if (ret) if (ret)
goto disable_clk; goto of_put;
for (i = 0; i < thm->nr_sensors; i++) for (i = 0; i < thm->nr_sensors; i++)
sprd_thm_toggle_sensor(thm->sensor[i], true); sprd_thm_toggle_sensor(thm->sensor[i], true);
...@@ -436,6 +437,8 @@ static int sprd_thm_probe(struct platform_device *pdev) ...@@ -436,6 +437,8 @@ static int sprd_thm_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, thm); platform_set_drvdata(pdev, thm);
return 0; return 0;
of_put:
of_node_put(sen_child);
disable_clk: disable_clk:
clk_disable_unprepare(thm->clk); clk_disable_unprepare(thm->clk);
return ret; return ret;
...@@ -532,6 +535,7 @@ static const struct of_device_id sprd_thermal_of_match[] = { ...@@ -532,6 +535,7 @@ static const struct of_device_id sprd_thermal_of_match[] = {
{ .compatible = "sprd,ums512-thermal", .data = &ums512_data }, { .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 = { static const struct dev_pm_ops sprd_thermal_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(sprd_thm_suspend, sprd_thm_resume) SET_SYSTEM_SLEEP_PM_OPS(sprd_thm_suspend, sprd_thm_resume)
......
...@@ -119,19 +119,10 @@ static int st_mmap_regmap_init(struct st_thermal_sensor *sensor) ...@@ -119,19 +119,10 @@ static int st_mmap_regmap_init(struct st_thermal_sensor *sensor)
{ {
struct device *dev = sensor->dev; struct device *dev = sensor->dev;
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); sensor->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (!res) { if (IS_ERR(sensor->mmio_base))
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");
return PTR_ERR(sensor->mmio_base); return PTR_ERR(sensor->mmio_base);
}
sensor->regmap = devm_regmap_init_mmio(dev, sensor->mmio_base, sensor->regmap = devm_regmap_init_mmio(dev, sensor->mmio_base,
&st_416mpe_regmap_config); &st_416mpe_regmap_config);
......
...@@ -1315,7 +1315,7 @@ thermal_zone_device_register(const char *type, int trips, int mask, ...@@ -1315,7 +1315,7 @@ thermal_zone_device_register(const char *type, int trips, int mask,
EXPORT_SYMBOL_GPL(thermal_zone_device_register); 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 * @tz: the thermal zone device to remove
*/ */
void thermal_zone_device_unregister(struct thermal_zone_device *tz) void thermal_zone_device_unregister(struct thermal_zone_device *tz)
......
...@@ -559,6 +559,9 @@ void thermal_zone_of_sensor_unregister(struct device *dev, ...@@ -559,6 +559,9 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
if (!tz) if (!tz)
return; return;
/* stop temperature polling */
thermal_zone_device_disable(tzd);
mutex_lock(&tzd->lock); mutex_lock(&tzd->lock);
tzd->ops->get_temp = NULL; tzd->ops->get_temp = NULL;
tzd->ops->get_trend = NULL; tzd->ops->get_trend = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment