Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
Pull thermal management updates from Zhang Rui: - add thermal driver for R-Car Gen3 thermal sensors. - add thermal driver for ZTE' zx2967 family thermal sensors. - convert thermal ID allocation from IDR to IDA. - fix a possible NULL dereference in imx thermal driver. - fix a ti-soc-thermal driver dependency issue so that critical thermal control is still available when CPU_THERMAL is not defined. - update binding information for QorIQ thermal driver. - a couple of cleanups in thermal core, intel_powerclamp, exynos, dra752-thermal, mtk-thermal driver. * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: powerpc/mpc85xx: Update TMU device tree node for T1023/T1024 powerpc/mpc85xx: Update TMU device tree node for T1040/T1042 dt-bindings: Update QorIQ TMU thermal bindings thermal: mtk_thermal: Staticise a number of data variables thermal: arm: dra752: Remove all TSHUT related definitions thermal: arm: dra752: Remove TSHUT configuration thermal: ti-soc-thermal: Remove CPU_THERMAL Dependency from TI_THERMAL thermal: imx: Fix possible NULL dereference. thermal: exynos: Remove parsing unused samsung,tmu_cal_mode property thermal: zx2967: add thermal driver for ZTE's zx2967 family thermal: use cpumask_var_t for on-stack cpu masks dt: bindings: add documentation for zx2967 family thermal sensor thermal/intel_powerclamp: Remove set-but-not-used variables thermal: rcar_gen3_thermal: Add R-Car Gen3 thermal driver thermal: rcar_gen3_thermal: Document the R-Car Gen3 thermal: convert devfreq_cooling to use an IDA thermal: convert cpu_cooling to use an IDA thermal: convert clock cooling to use an IDA thermal core: convert ID allocation to IDA
This commit is contained in:
commit
544a068f1f
|
@ -17,6 +17,12 @@ Required properties:
|
||||||
calibration data, as specified by the SoC reference manual.
|
calibration data, as specified by the SoC reference manual.
|
||||||
The first cell of each pair is the value to be written to TTCFGR,
|
The first cell of each pair is the value to be written to TTCFGR,
|
||||||
and the second is the value to be written to TSCFGR.
|
and the second is the value to be written to TSCFGR.
|
||||||
|
- #thermal-sensor-cells : Must be 1. The sensor specifier is the monitoring
|
||||||
|
site ID, and represents the "n" in TRITSRn and TRATSRn.
|
||||||
|
|
||||||
|
Optional property:
|
||||||
|
- little-endian : If present, the TMU registers are little endian. If absent,
|
||||||
|
the default is big endian.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -60,4 +66,5 @@ tmu@f0000 {
|
||||||
|
|
||||||
0x00030000 0x00000012
|
0x00030000 0x00000012
|
||||||
0x00030001 0x0000001d>;
|
0x00030001 0x0000001d>;
|
||||||
|
#thermal-sensor-cells = <1>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
* DT bindings for Renesas R-Car Gen3 Thermal Sensor driver
|
||||||
|
|
||||||
|
On R-Car Gen3 SoCs, the thermal sensor controllers (TSC) control the thermal
|
||||||
|
sensors (THS) which are the analog circuits for measuring temperature (Tj)
|
||||||
|
inside the LSI.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible : "renesas,<soctype>-thermal",
|
||||||
|
Examples with soctypes are:
|
||||||
|
- "renesas,r8a7795-thermal" (R-Car H3)
|
||||||
|
- "renesas,r8a7796-thermal" (R-Car M3-W)
|
||||||
|
- reg : Address ranges of the thermal registers. Each sensor
|
||||||
|
needs one address range. Sorting must be done in
|
||||||
|
increasing order according to datasheet, i.e.
|
||||||
|
TSC1, TSC2, ...
|
||||||
|
- clocks : Must contain a reference to the functional clock.
|
||||||
|
- #thermal-sensor-cells : must be <1>.
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
|
||||||
|
- interrupts : interrupts routed to the TSC (3 for H3 and M3-W)
|
||||||
|
- power-domain : Must contain a reference to the power domain. This
|
||||||
|
property is mandatory if the thermal sensor instance
|
||||||
|
is part of a controllable power domain.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
tsc: thermal@e6198000 {
|
||||||
|
compatible = "renesas,r8a7795-thermal";
|
||||||
|
reg = <0 0xe6198000 0 0x68>,
|
||||||
|
<0 0xe61a0000 0 0x5c>,
|
||||||
|
<0 0xe61a8000 0 0x5c>;
|
||||||
|
interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
clocks = <&cpg CPG_MOD 522>;
|
||||||
|
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
|
||||||
|
#thermal-sensor-cells = <1>;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
thermal-zones {
|
||||||
|
sensor_thermal1: sensor-thermal1 {
|
||||||
|
polling-delay-passive = <250>;
|
||||||
|
polling-delay = <1000>;
|
||||||
|
thermal-sensors = <&tsc 0>;
|
||||||
|
|
||||||
|
trips {
|
||||||
|
sensor1_crit: sensor1-crit {
|
||||||
|
temperature = <90000>;
|
||||||
|
hysteresis = <2000>;
|
||||||
|
type = "critical";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,116 @@
|
||||||
|
* ZTE zx2967 family Thermal
|
||||||
|
|
||||||
|
Required Properties:
|
||||||
|
- compatible: should be one of the following.
|
||||||
|
* zte,zx296718-thermal
|
||||||
|
- reg: physical base address of the controller and length of memory mapped
|
||||||
|
region.
|
||||||
|
- clocks : Pairs of phandle and specifier referencing the controller's clocks.
|
||||||
|
- clock-names: "topcrm" for the topcrm clock.
|
||||||
|
"apb" for the apb clock.
|
||||||
|
- #thermal-sensor-cells: must be 0.
|
||||||
|
|
||||||
|
Please note: slope coefficient defined in thermal-zones section need to be
|
||||||
|
multiplied by 1000.
|
||||||
|
|
||||||
|
Example for tempsensor:
|
||||||
|
|
||||||
|
tempsensor: tempsensor@148a000 {
|
||||||
|
compatible = "zte,zx296718-thermal";
|
||||||
|
reg = <0x0148a000 0x20>;
|
||||||
|
clocks = <&topcrm TEMPSENSOR_GATE>, <&audiocrm AUDIO_TS_PCLK>;
|
||||||
|
clock-names = "topcrm", "apb";
|
||||||
|
#thermal-sensor-cells = <0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
Example for cooling device:
|
||||||
|
|
||||||
|
cooling_dev: cooling_dev {
|
||||||
|
cluster0_cooling_dev: cluster0-cooling-dev {
|
||||||
|
#cooling-cells = <2>;
|
||||||
|
cpumask = <0xf>;
|
||||||
|
capacitance = <1500>;
|
||||||
|
};
|
||||||
|
|
||||||
|
cluster1_cooling_dev: cluster1-cooling-dev {
|
||||||
|
#cooling-cells = <2>;
|
||||||
|
cpumask = <0x30>;
|
||||||
|
capacitance = <2000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Example for thermal zones:
|
||||||
|
|
||||||
|
thermal-zones {
|
||||||
|
zx296718_thermal: zx296718_thermal {
|
||||||
|
polling-delay-passive = <500>;
|
||||||
|
polling-delay = <1000>;
|
||||||
|
sustainable-power = <6500>;
|
||||||
|
|
||||||
|
thermal-sensors = <&tempsensor 0>;
|
||||||
|
/*
|
||||||
|
* slope need to be multiplied by 1000.
|
||||||
|
*/
|
||||||
|
coefficients = <1951 (-922)>;
|
||||||
|
|
||||||
|
trips {
|
||||||
|
trip0: switch_on_temperature {
|
||||||
|
temperature = <90000>;
|
||||||
|
hysteresis = <2000>;
|
||||||
|
type = "passive";
|
||||||
|
};
|
||||||
|
|
||||||
|
trip1: desired_temperature {
|
||||||
|
temperature = <100000>;
|
||||||
|
hysteresis = <2000>;
|
||||||
|
type = "passive";
|
||||||
|
};
|
||||||
|
|
||||||
|
crit: critical_temperature {
|
||||||
|
temperature = <110000>;
|
||||||
|
hysteresis = <2000>;
|
||||||
|
type = "critical";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
cooling-maps {
|
||||||
|
map0 {
|
||||||
|
trip = <&trip0>;
|
||||||
|
cooling-device = <&gpu 2 5>;
|
||||||
|
};
|
||||||
|
|
||||||
|
map1 {
|
||||||
|
trip = <&trip0>;
|
||||||
|
cooling-device = <&cluster0_cooling_dev 1 2>;
|
||||||
|
};
|
||||||
|
|
||||||
|
map2 {
|
||||||
|
trip = <&trip1>;
|
||||||
|
cooling-device = <&cluster0_cooling_dev 1 2>;
|
||||||
|
};
|
||||||
|
|
||||||
|
map3 {
|
||||||
|
trip = <&crit>;
|
||||||
|
cooling-device = <&cluster0_cooling_dev 1 2>;
|
||||||
|
};
|
||||||
|
|
||||||
|
map4 {
|
||||||
|
trip = <&trip0>;
|
||||||
|
cooling-device = <&cluster1_cooling_dev 1 2>;
|
||||||
|
contribution = <9000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
map5 {
|
||||||
|
trip = <&trip1>;
|
||||||
|
cooling-device = <&cluster1_cooling_dev 1 2>;
|
||||||
|
contribution = <4096>;
|
||||||
|
};
|
||||||
|
|
||||||
|
map6 {
|
||||||
|
trip = <&crit>;
|
||||||
|
cooling-device = <&cluster1_cooling_dev 1 2>;
|
||||||
|
contribution = <4096>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
|
@ -422,7 +422,7 @@
|
||||||
0x00030001 0x0000000d
|
0x00030001 0x0000000d
|
||||||
0x00030002 0x00000019
|
0x00030002 0x00000019
|
||||||
0x00030003 0x00000024>;
|
0x00030003 0x00000024>;
|
||||||
#thermal-sensor-cells = <0>;
|
#thermal-sensor-cells = <1>;
|
||||||
};
|
};
|
||||||
|
|
||||||
thermal-zones {
|
thermal-zones {
|
||||||
|
@ -430,7 +430,7 @@
|
||||||
polling-delay-passive = <1000>;
|
polling-delay-passive = <1000>;
|
||||||
polling-delay = <5000>;
|
polling-delay = <5000>;
|
||||||
|
|
||||||
thermal-sensors = <&tmu>;
|
thermal-sensors = <&tmu 0>;
|
||||||
|
|
||||||
trips {
|
trips {
|
||||||
cpu_alert: cpu-alert {
|
cpu_alert: cpu-alert {
|
||||||
|
|
|
@ -526,7 +526,7 @@
|
||||||
|
|
||||||
0x00030000 0x00000012
|
0x00030000 0x00000012
|
||||||
0x00030001 0x0000001d>;
|
0x00030001 0x0000001d>;
|
||||||
#thermal-sensor-cells = <0>;
|
#thermal-sensor-cells = <1>;
|
||||||
};
|
};
|
||||||
|
|
||||||
thermal-zones {
|
thermal-zones {
|
||||||
|
@ -534,7 +534,7 @@
|
||||||
polling-delay-passive = <1000>;
|
polling-delay-passive = <1000>;
|
||||||
polling-delay = <5000>;
|
polling-delay = <5000>;
|
||||||
|
|
||||||
thermal-sensors = <&tmu>;
|
thermal-sensors = <&tmu 2>;
|
||||||
|
|
||||||
trips {
|
trips {
|
||||||
cpu_alert: cpu-alert {
|
cpu_alert: cpu-alert {
|
||||||
|
|
|
@ -245,6 +245,15 @@ config RCAR_THERMAL
|
||||||
Enable this to plug the R-Car thermal sensor driver into the Linux
|
Enable this to plug the R-Car thermal sensor driver into the Linux
|
||||||
thermal framework.
|
thermal framework.
|
||||||
|
|
||||||
|
config RCAR_GEN3_THERMAL
|
||||||
|
tristate "Renesas R-Car Gen3 thermal driver"
|
||||||
|
depends on ARCH_RENESAS || COMPILE_TEST
|
||||||
|
depends on HAS_IOMEM
|
||||||
|
depends on OF
|
||||||
|
help
|
||||||
|
Enable this to plug the R-Car Gen3 thermal sensor driver into the Linux
|
||||||
|
thermal framework.
|
||||||
|
|
||||||
config KIRKWOOD_THERMAL
|
config KIRKWOOD_THERMAL
|
||||||
tristate "Temperature sensor on Marvell Kirkwood SoCs"
|
tristate "Temperature sensor on Marvell Kirkwood SoCs"
|
||||||
depends on MACH_KIRKWOOD || COMPILE_TEST
|
depends on MACH_KIRKWOOD || COMPILE_TEST
|
||||||
|
@ -436,4 +445,12 @@ depends on (ARCH_QCOM && OF) || COMPILE_TEST
|
||||||
source "drivers/thermal/qcom/Kconfig"
|
source "drivers/thermal/qcom/Kconfig"
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
|
config ZX2967_THERMAL
|
||||||
|
tristate "Thermal sensors on zx2967 SoC"
|
||||||
|
depends on ARCH_ZX || COMPILE_TEST
|
||||||
|
help
|
||||||
|
Enable the zx2967 thermal sensors driver, which supports
|
||||||
|
the primitive temperature sensor embedded in zx2967 SoCs.
|
||||||
|
This sensor generates the real time die temperature.
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -31,6 +31,7 @@ obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o
|
||||||
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
|
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
|
||||||
obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o
|
obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o
|
||||||
obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o
|
obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o
|
||||||
|
obj-$(CONFIG_RCAR_GEN3_THERMAL) += rcar_gen3_thermal.o
|
||||||
obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o
|
obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o
|
||||||
obj-y += samsung/
|
obj-y += samsung/
|
||||||
obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o
|
obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o
|
||||||
|
@ -56,3 +57,4 @@ obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/
|
||||||
obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
|
obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
|
||||||
obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
|
obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
|
||||||
obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
|
obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
|
||||||
|
obj-$(CONFIG_ZX2967_THERMAL) += zx2967_thermal.o
|
||||||
|
|
|
@ -65,42 +65,7 @@ struct clock_cooling_device {
|
||||||
};
|
};
|
||||||
#define to_clock_cooling_device(x) \
|
#define to_clock_cooling_device(x) \
|
||||||
container_of(x, struct clock_cooling_device, clk_rate_change_nb)
|
container_of(x, struct clock_cooling_device, clk_rate_change_nb)
|
||||||
static DEFINE_IDR(clock_idr);
|
static DEFINE_IDA(clock_ida);
|
||||||
static DEFINE_MUTEX(cooling_clock_lock);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* clock_cooling_get_idr - function to get an unique id.
|
|
||||||
* @id: int * value generated by this function.
|
|
||||||
*
|
|
||||||
* This function will populate @id with an unique
|
|
||||||
* id, using the idr API.
|
|
||||||
*
|
|
||||||
* Return: 0 on success, an error code on failure.
|
|
||||||
*/
|
|
||||||
static int clock_cooling_get_idr(int *id)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
mutex_lock(&cooling_clock_lock);
|
|
||||||
ret = idr_alloc(&clock_idr, NULL, 0, 0, GFP_KERNEL);
|
|
||||||
mutex_unlock(&cooling_clock_lock);
|
|
||||||
if (unlikely(ret < 0))
|
|
||||||
return ret;
|
|
||||||
*id = ret;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* release_idr - function to free the unique id.
|
|
||||||
* @id: int value representing the unique id.
|
|
||||||
*/
|
|
||||||
static void release_idr(int id)
|
|
||||||
{
|
|
||||||
mutex_lock(&cooling_clock_lock);
|
|
||||||
idr_remove(&clock_idr, id);
|
|
||||||
mutex_unlock(&cooling_clock_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Below code defines functions to be used for clock as cooling device */
|
/* Below code defines functions to be used for clock as cooling device */
|
||||||
|
|
||||||
|
@ -432,16 +397,17 @@ clock_cooling_register(struct device *dev, const char *clock_name)
|
||||||
if (IS_ERR(ccdev->clk))
|
if (IS_ERR(ccdev->clk))
|
||||||
return ERR_CAST(ccdev->clk);
|
return ERR_CAST(ccdev->clk);
|
||||||
|
|
||||||
ret = clock_cooling_get_idr(&ccdev->id);
|
ret = ida_simple_get(&clock_ida, 0, 0, GFP_KERNEL);
|
||||||
if (ret)
|
if (ret < 0)
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(ret);
|
||||||
|
ccdev->id = ret;
|
||||||
|
|
||||||
snprintf(dev_name, sizeof(dev_name), "thermal-clock-%d", ccdev->id);
|
snprintf(dev_name, sizeof(dev_name), "thermal-clock-%d", ccdev->id);
|
||||||
|
|
||||||
cdev = thermal_cooling_device_register(dev_name, ccdev,
|
cdev = thermal_cooling_device_register(dev_name, ccdev,
|
||||||
&clock_cooling_ops);
|
&clock_cooling_ops);
|
||||||
if (IS_ERR(cdev)) {
|
if (IS_ERR(cdev)) {
|
||||||
release_idr(ccdev->id);
|
ida_simple_remove(&clock_ida, ccdev->id);
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
ccdev->cdev = cdev;
|
ccdev->cdev = cdev;
|
||||||
|
@ -450,7 +416,7 @@ clock_cooling_register(struct device *dev, const char *clock_name)
|
||||||
/* Assuming someone has already filled the opp table for this device */
|
/* Assuming someone has already filled the opp table for this device */
|
||||||
ret = dev_pm_opp_init_cpufreq_table(dev, &ccdev->freq_table);
|
ret = dev_pm_opp_init_cpufreq_table(dev, &ccdev->freq_table);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
release_idr(ccdev->id);
|
ida_simple_remove(&clock_ida, ccdev->id);
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
ccdev->clock_state = 0;
|
ccdev->clock_state = 0;
|
||||||
|
@ -481,6 +447,6 @@ void clock_cooling_unregister(struct thermal_cooling_device *cdev)
|
||||||
dev_pm_opp_free_cpufreq_table(ccdev->dev, &ccdev->freq_table);
|
dev_pm_opp_free_cpufreq_table(ccdev->dev, &ccdev->freq_table);
|
||||||
|
|
||||||
thermal_cooling_device_unregister(ccdev->cdev);
|
thermal_cooling_device_unregister(ccdev->cdev);
|
||||||
release_idr(ccdev->id);
|
ida_simple_remove(&clock_ida, ccdev->id);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(clock_cooling_unregister);
|
EXPORT_SYMBOL_GPL(clock_cooling_unregister);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <linux/thermal.h>
|
#include <linux/thermal.h>
|
||||||
#include <linux/cpufreq.h>
|
#include <linux/cpufreq.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <linux/idr.h>
|
||||||
#include <linux/pm_opp.h>
|
#include <linux/pm_opp.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/cpu.h>
|
#include <linux/cpu.h>
|
||||||
|
@ -104,50 +105,13 @@ struct cpufreq_cooling_device {
|
||||||
struct device *cpu_dev;
|
struct device *cpu_dev;
|
||||||
get_static_t plat_get_static_power;
|
get_static_t plat_get_static_power;
|
||||||
};
|
};
|
||||||
static DEFINE_IDR(cpufreq_idr);
|
static DEFINE_IDA(cpufreq_ida);
|
||||||
static DEFINE_MUTEX(cooling_cpufreq_lock);
|
|
||||||
|
|
||||||
static unsigned int cpufreq_dev_count;
|
static unsigned int cpufreq_dev_count;
|
||||||
|
|
||||||
static DEFINE_MUTEX(cooling_list_lock);
|
static DEFINE_MUTEX(cooling_list_lock);
|
||||||
static LIST_HEAD(cpufreq_dev_list);
|
static LIST_HEAD(cpufreq_dev_list);
|
||||||
|
|
||||||
/**
|
|
||||||
* get_idr - function to get a unique id.
|
|
||||||
* @idr: struct idr * handle used to create a id.
|
|
||||||
* @id: int * value generated by this function.
|
|
||||||
*
|
|
||||||
* This function will populate @id with an unique
|
|
||||||
* id, using the idr API.
|
|
||||||
*
|
|
||||||
* Return: 0 on success, an error code on failure.
|
|
||||||
*/
|
|
||||||
static int get_idr(struct idr *idr, int *id)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
mutex_lock(&cooling_cpufreq_lock);
|
|
||||||
ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
|
|
||||||
mutex_unlock(&cooling_cpufreq_lock);
|
|
||||||
if (unlikely(ret < 0))
|
|
||||||
return ret;
|
|
||||||
*id = ret;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* release_idr - function to free the unique id.
|
|
||||||
* @idr: struct idr * handle used for creating the id.
|
|
||||||
* @id: int value representing the unique id.
|
|
||||||
*/
|
|
||||||
static void release_idr(struct idr *idr, int id)
|
|
||||||
{
|
|
||||||
mutex_lock(&cooling_cpufreq_lock);
|
|
||||||
idr_remove(idr, id);
|
|
||||||
mutex_unlock(&cooling_cpufreq_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Below code defines functions to be used for cpufreq as cooling device */
|
/* Below code defines functions to be used for cpufreq as cooling device */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -645,31 +609,39 @@ static int cpufreq_state2power(struct thermal_cooling_device *cdev,
|
||||||
unsigned long state, u32 *power)
|
unsigned long state, u32 *power)
|
||||||
{
|
{
|
||||||
unsigned int freq, num_cpus;
|
unsigned int freq, num_cpus;
|
||||||
cpumask_t cpumask;
|
cpumask_var_t cpumask;
|
||||||
u32 static_power, dynamic_power;
|
u32 static_power, dynamic_power;
|
||||||
int ret;
|
int ret;
|
||||||
struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
|
struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
|
||||||
|
|
||||||
cpumask_and(&cpumask, &cpufreq_device->allowed_cpus, cpu_online_mask);
|
if (!alloc_cpumask_var(&cpumask, GFP_KERNEL))
|
||||||
num_cpus = cpumask_weight(&cpumask);
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cpumask_and(cpumask, &cpufreq_device->allowed_cpus, cpu_online_mask);
|
||||||
|
num_cpus = cpumask_weight(cpumask);
|
||||||
|
|
||||||
/* None of our cpus are online, so no power */
|
/* None of our cpus are online, so no power */
|
||||||
if (num_cpus == 0) {
|
if (num_cpus == 0) {
|
||||||
*power = 0;
|
*power = 0;
|
||||||
return 0;
|
ret = 0;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
freq = cpufreq_device->freq_table[state];
|
freq = cpufreq_device->freq_table[state];
|
||||||
if (!freq)
|
if (!freq) {
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
dynamic_power = cpu_freq_to_power(cpufreq_device, freq) * num_cpus;
|
dynamic_power = cpu_freq_to_power(cpufreq_device, freq) * num_cpus;
|
||||||
ret = get_static_power(cpufreq_device, tz, freq, &static_power);
|
ret = get_static_power(cpufreq_device, tz, freq, &static_power);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto out;
|
||||||
|
|
||||||
*power = static_power + dynamic_power;
|
*power = static_power + dynamic_power;
|
||||||
return 0;
|
out:
|
||||||
|
free_cpumask_var(cpumask);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -795,16 +767,20 @@ __cpufreq_cooling_register(struct device_node *np,
|
||||||
struct cpufreq_cooling_device *cpufreq_dev;
|
struct cpufreq_cooling_device *cpufreq_dev;
|
||||||
char dev_name[THERMAL_NAME_LENGTH];
|
char dev_name[THERMAL_NAME_LENGTH];
|
||||||
struct cpufreq_frequency_table *pos, *table;
|
struct cpufreq_frequency_table *pos, *table;
|
||||||
struct cpumask temp_mask;
|
cpumask_var_t temp_mask;
|
||||||
unsigned int freq, i, num_cpus;
|
unsigned int freq, i, num_cpus;
|
||||||
int ret;
|
int ret;
|
||||||
struct thermal_cooling_device_ops *cooling_ops;
|
struct thermal_cooling_device_ops *cooling_ops;
|
||||||
|
|
||||||
cpumask_and(&temp_mask, clip_cpus, cpu_online_mask);
|
if (!alloc_cpumask_var(&temp_mask, GFP_KERNEL))
|
||||||
policy = cpufreq_cpu_get(cpumask_first(&temp_mask));
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
cpumask_and(temp_mask, clip_cpus, cpu_online_mask);
|
||||||
|
policy = cpufreq_cpu_get(cpumask_first(temp_mask));
|
||||||
if (!policy) {
|
if (!policy) {
|
||||||
pr_debug("%s: CPUFreq policy not found\n", __func__);
|
pr_debug("%s: CPUFreq policy not found\n", __func__);
|
||||||
return ERR_PTR(-EPROBE_DEFER);
|
cool_dev = ERR_PTR(-EPROBE_DEFER);
|
||||||
|
goto free_cpumask;
|
||||||
}
|
}
|
||||||
|
|
||||||
table = policy->freq_table;
|
table = policy->freq_table;
|
||||||
|
@ -867,11 +843,12 @@ __cpufreq_cooling_register(struct device_node *np,
|
||||||
cooling_ops = &cpufreq_cooling_ops;
|
cooling_ops = &cpufreq_cooling_ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = get_idr(&cpufreq_idr, &cpufreq_dev->id);
|
ret = ida_simple_get(&cpufreq_ida, 0, 0, GFP_KERNEL);
|
||||||
if (ret) {
|
if (ret < 0) {
|
||||||
cool_dev = ERR_PTR(ret);
|
cool_dev = ERR_PTR(ret);
|
||||||
goto free_power_table;
|
goto free_power_table;
|
||||||
}
|
}
|
||||||
|
cpufreq_dev->id = ret;
|
||||||
|
|
||||||
/* Fill freq-table in descending order of frequencies */
|
/* Fill freq-table in descending order of frequencies */
|
||||||
for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) {
|
for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) {
|
||||||
|
@ -891,27 +868,24 @@ __cpufreq_cooling_register(struct device_node *np,
|
||||||
cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev,
|
cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev,
|
||||||
cooling_ops);
|
cooling_ops);
|
||||||
if (IS_ERR(cool_dev))
|
if (IS_ERR(cool_dev))
|
||||||
goto remove_idr;
|
goto remove_ida;
|
||||||
|
|
||||||
cpufreq_dev->clipped_freq = cpufreq_dev->freq_table[0];
|
cpufreq_dev->clipped_freq = cpufreq_dev->freq_table[0];
|
||||||
cpufreq_dev->cool_dev = cool_dev;
|
cpufreq_dev->cool_dev = cool_dev;
|
||||||
|
|
||||||
mutex_lock(&cooling_cpufreq_lock);
|
|
||||||
|
|
||||||
mutex_lock(&cooling_list_lock);
|
mutex_lock(&cooling_list_lock);
|
||||||
list_add(&cpufreq_dev->node, &cpufreq_dev_list);
|
list_add(&cpufreq_dev->node, &cpufreq_dev_list);
|
||||||
mutex_unlock(&cooling_list_lock);
|
|
||||||
|
|
||||||
/* Register the notifier for first cpufreq cooling device */
|
/* Register the notifier for first cpufreq cooling device */
|
||||||
if (!cpufreq_dev_count++)
|
if (!cpufreq_dev_count++)
|
||||||
cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
|
cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
|
||||||
CPUFREQ_POLICY_NOTIFIER);
|
CPUFREQ_POLICY_NOTIFIER);
|
||||||
mutex_unlock(&cooling_cpufreq_lock);
|
mutex_unlock(&cooling_list_lock);
|
||||||
|
|
||||||
goto put_policy;
|
goto put_policy;
|
||||||
|
|
||||||
remove_idr:
|
remove_ida:
|
||||||
release_idr(&cpufreq_idr, cpufreq_dev->id);
|
ida_simple_remove(&cpufreq_ida, cpufreq_dev->id);
|
||||||
free_power_table:
|
free_power_table:
|
||||||
kfree(cpufreq_dev->dyn_power_table);
|
kfree(cpufreq_dev->dyn_power_table);
|
||||||
free_table:
|
free_table:
|
||||||
|
@ -924,7 +898,8 @@ free_cdev:
|
||||||
kfree(cpufreq_dev);
|
kfree(cpufreq_dev);
|
||||||
put_policy:
|
put_policy:
|
||||||
cpufreq_cpu_put(policy);
|
cpufreq_cpu_put(policy);
|
||||||
|
free_cpumask:
|
||||||
|
free_cpumask_var(temp_mask);
|
||||||
return cool_dev;
|
return cool_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1052,20 +1027,17 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
||||||
|
|
||||||
cpufreq_dev = cdev->devdata;
|
cpufreq_dev = cdev->devdata;
|
||||||
|
|
||||||
|
mutex_lock(&cooling_list_lock);
|
||||||
/* Unregister the notifier for the last cpufreq cooling device */
|
/* Unregister the notifier for the last cpufreq cooling device */
|
||||||
mutex_lock(&cooling_cpufreq_lock);
|
|
||||||
if (!--cpufreq_dev_count)
|
if (!--cpufreq_dev_count)
|
||||||
cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
|
cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
|
||||||
CPUFREQ_POLICY_NOTIFIER);
|
CPUFREQ_POLICY_NOTIFIER);
|
||||||
|
|
||||||
mutex_lock(&cooling_list_lock);
|
|
||||||
list_del(&cpufreq_dev->node);
|
list_del(&cpufreq_dev->node);
|
||||||
mutex_unlock(&cooling_list_lock);
|
mutex_unlock(&cooling_list_lock);
|
||||||
|
|
||||||
mutex_unlock(&cooling_cpufreq_lock);
|
|
||||||
|
|
||||||
thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
|
thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
|
||||||
release_idr(&cpufreq_idr, cpufreq_dev->id);
|
ida_simple_remove(&cpufreq_ida, cpufreq_dev->id);
|
||||||
kfree(cpufreq_dev->dyn_power_table);
|
kfree(cpufreq_dev->dyn_power_table);
|
||||||
kfree(cpufreq_dev->time_in_idle_timestamp);
|
kfree(cpufreq_dev->time_in_idle_timestamp);
|
||||||
kfree(cpufreq_dev->time_in_idle);
|
kfree(cpufreq_dev->time_in_idle);
|
||||||
|
|
|
@ -21,14 +21,14 @@
|
||||||
#include <linux/devfreq.h>
|
#include <linux/devfreq.h>
|
||||||
#include <linux/devfreq_cooling.h>
|
#include <linux/devfreq_cooling.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
|
#include <linux/idr.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/pm_opp.h>
|
#include <linux/pm_opp.h>
|
||||||
#include <linux/thermal.h>
|
#include <linux/thermal.h>
|
||||||
|
|
||||||
#include <trace/events/thermal.h>
|
#include <trace/events/thermal.h>
|
||||||
|
|
||||||
static DEFINE_MUTEX(devfreq_lock);
|
static DEFINE_IDA(devfreq_ida);
|
||||||
static DEFINE_IDR(devfreq_idr);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct devfreq_cooling_device - Devfreq cooling device
|
* struct devfreq_cooling_device - Devfreq cooling device
|
||||||
|
@ -57,42 +57,6 @@ struct devfreq_cooling_device {
|
||||||
struct devfreq_cooling_power *power_ops;
|
struct devfreq_cooling_power *power_ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* get_idr - function to get a unique id.
|
|
||||||
* @idr: struct idr * handle used to create a id.
|
|
||||||
* @id: int * value generated by this function.
|
|
||||||
*
|
|
||||||
* This function will populate @id with an unique
|
|
||||||
* id, using the idr API.
|
|
||||||
*
|
|
||||||
* Return: 0 on success, an error code on failure.
|
|
||||||
*/
|
|
||||||
static int get_idr(struct idr *idr, int *id)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
mutex_lock(&devfreq_lock);
|
|
||||||
ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
|
|
||||||
mutex_unlock(&devfreq_lock);
|
|
||||||
if (unlikely(ret < 0))
|
|
||||||
return ret;
|
|
||||||
*id = ret;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* release_idr - function to free the unique id.
|
|
||||||
* @idr: struct idr * handle used for creating the id.
|
|
||||||
* @id: int value representing the unique id.
|
|
||||||
*/
|
|
||||||
static void release_idr(struct idr *idr, int id)
|
|
||||||
{
|
|
||||||
mutex_lock(&devfreq_lock);
|
|
||||||
idr_remove(idr, id);
|
|
||||||
mutex_unlock(&devfreq_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* partition_enable_opps() - disable all opps above a given state
|
* partition_enable_opps() - disable all opps above a given state
|
||||||
* @dfc: Pointer to devfreq we are operating on
|
* @dfc: Pointer to devfreq we are operating on
|
||||||
|
@ -489,9 +453,10 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
|
||||||
if (err)
|
if (err)
|
||||||
goto free_dfc;
|
goto free_dfc;
|
||||||
|
|
||||||
err = get_idr(&devfreq_idr, &dfc->id);
|
err = ida_simple_get(&devfreq_ida, 0, 0, GFP_KERNEL);
|
||||||
if (err)
|
if (err < 0)
|
||||||
goto free_tables;
|
goto free_tables;
|
||||||
|
dfc->id = err;
|
||||||
|
|
||||||
snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id);
|
snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id);
|
||||||
|
|
||||||
|
@ -502,15 +467,15 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
|
||||||
dev_err(df->dev.parent,
|
dev_err(df->dev.parent,
|
||||||
"Failed to register devfreq cooling device (%d)\n",
|
"Failed to register devfreq cooling device (%d)\n",
|
||||||
err);
|
err);
|
||||||
goto release_idr;
|
goto release_ida;
|
||||||
}
|
}
|
||||||
|
|
||||||
dfc->cdev = cdev;
|
dfc->cdev = cdev;
|
||||||
|
|
||||||
return cdev;
|
return cdev;
|
||||||
|
|
||||||
release_idr:
|
release_ida:
|
||||||
release_idr(&devfreq_idr, dfc->id);
|
ida_simple_remove(&devfreq_ida, dfc->id);
|
||||||
free_tables:
|
free_tables:
|
||||||
kfree(dfc->power_table);
|
kfree(dfc->power_table);
|
||||||
kfree(dfc->freq_table);
|
kfree(dfc->freq_table);
|
||||||
|
@ -558,7 +523,7 @@ void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
||||||
dfc = cdev->devdata;
|
dfc = cdev->devdata;
|
||||||
|
|
||||||
thermal_cooling_device_unregister(dfc->cdev);
|
thermal_cooling_device_unregister(dfc->cdev);
|
||||||
release_idr(&devfreq_idr, dfc->id);
|
ida_simple_remove(&devfreq_ida, dfc->id);
|
||||||
kfree(dfc->power_table);
|
kfree(dfc->power_table);
|
||||||
kfree(dfc->freq_table);
|
kfree(dfc->freq_table);
|
||||||
|
|
||||||
|
|
|
@ -489,6 +489,10 @@ static int imx_thermal_probe(struct platform_device *pdev)
|
||||||
data->tempmon = map;
|
data->tempmon = map;
|
||||||
|
|
||||||
data->socdata = of_device_get_match_data(&pdev->dev);
|
data->socdata = of_device_get_match_data(&pdev->dev);
|
||||||
|
if (!data->socdata) {
|
||||||
|
dev_err(&pdev->dev, "no device match found\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
/* make sure the IRQ flag is clear before enabling irq on i.MX6SX */
|
/* make sure the IRQ flag is clear before enabling irq on i.MX6SX */
|
||||||
if (data->socdata->version == TEMPMON_IMX6SX) {
|
if (data->socdata->version == TEMPMON_IMX6SX) {
|
||||||
|
|
|
@ -461,16 +461,13 @@ static void poll_pkg_cstate(struct work_struct *dummy)
|
||||||
{
|
{
|
||||||
static u64 msr_last;
|
static u64 msr_last;
|
||||||
static u64 tsc_last;
|
static u64 tsc_last;
|
||||||
static unsigned long jiffies_last;
|
|
||||||
|
|
||||||
u64 msr_now;
|
u64 msr_now;
|
||||||
unsigned long jiffies_now;
|
|
||||||
u64 tsc_now;
|
u64 tsc_now;
|
||||||
u64 val64;
|
u64 val64;
|
||||||
|
|
||||||
msr_now = pkg_state_counter();
|
msr_now = pkg_state_counter();
|
||||||
tsc_now = rdtsc();
|
tsc_now = rdtsc();
|
||||||
jiffies_now = jiffies;
|
|
||||||
|
|
||||||
/* calculate pkg cstate vs tsc ratio */
|
/* calculate pkg cstate vs tsc ratio */
|
||||||
if (!msr_last || !tsc_last)
|
if (!msr_last || !tsc_last)
|
||||||
|
@ -485,7 +482,6 @@ static void poll_pkg_cstate(struct work_struct *dummy)
|
||||||
|
|
||||||
/* update record */
|
/* update record */
|
||||||
msr_last = msr_now;
|
msr_last = msr_now;
|
||||||
jiffies_last = jiffies_now;
|
|
||||||
tsc_last = tsc_now;
|
tsc_last = tsc_now;
|
||||||
|
|
||||||
if (true == clamping)
|
if (true == clamping)
|
||||||
|
|
|
@ -183,37 +183,37 @@ struct mtk_thermal {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* MT8173 thermal sensor data */
|
/* MT8173 thermal sensor data */
|
||||||
const int mt8173_bank_data[MT8173_NUM_ZONES][3] = {
|
static const int mt8173_bank_data[MT8173_NUM_ZONES][3] = {
|
||||||
{ MT8173_TS2, MT8173_TS3 },
|
{ MT8173_TS2, MT8173_TS3 },
|
||||||
{ MT8173_TS2, MT8173_TS4 },
|
{ MT8173_TS2, MT8173_TS4 },
|
||||||
{ MT8173_TS1, MT8173_TS2, MT8173_TSABB },
|
{ MT8173_TS1, MT8173_TS2, MT8173_TSABB },
|
||||||
{ MT8173_TS2 },
|
{ MT8173_TS2 },
|
||||||
};
|
};
|
||||||
|
|
||||||
const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = {
|
static const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = {
|
||||||
TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR2
|
TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR2
|
||||||
};
|
};
|
||||||
|
|
||||||
const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = {
|
static const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = {
|
||||||
TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3
|
TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3
|
||||||
};
|
};
|
||||||
|
|
||||||
const int mt8173_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
|
static const int mt8173_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
|
||||||
|
|
||||||
/* MT2701 thermal sensor data */
|
/* MT2701 thermal sensor data */
|
||||||
const int mt2701_bank_data[MT2701_NUM_SENSORS] = {
|
static const int mt2701_bank_data[MT2701_NUM_SENSORS] = {
|
||||||
MT2701_TS1, MT2701_TS2, MT2701_TSABB
|
MT2701_TS1, MT2701_TS2, MT2701_TSABB
|
||||||
};
|
};
|
||||||
|
|
||||||
const int mt2701_msr[MT2701_NUM_SENSORS_PER_ZONE] = {
|
static const int mt2701_msr[MT2701_NUM_SENSORS_PER_ZONE] = {
|
||||||
TEMP_MSR0, TEMP_MSR1, TEMP_MSR2
|
TEMP_MSR0, TEMP_MSR1, TEMP_MSR2
|
||||||
};
|
};
|
||||||
|
|
||||||
const int mt2701_adcpnp[MT2701_NUM_SENSORS_PER_ZONE] = {
|
static const int mt2701_adcpnp[MT2701_NUM_SENSORS_PER_ZONE] = {
|
||||||
TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2
|
TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2
|
||||||
};
|
};
|
||||||
|
|
||||||
const int mt2701_mux_values[MT2701_NUM_SENSORS] = { 0, 1, 16 };
|
static const int mt2701_mux_values[MT2701_NUM_SENSORS] = { 0, 1, 16 };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The MT8173 thermal controller has four banks. Each bank can read up to
|
* The MT8173 thermal controller has four banks. Each bank can read up to
|
||||||
|
|
|
@ -0,0 +1,335 @@
|
||||||
|
/*
|
||||||
|
* R-Car Gen3 THS thermal sensor driver
|
||||||
|
* Based on rcar_thermal.c and work from Hien Dang and Khiem Nguyen.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Renesas Electronics Corporation.
|
||||||
|
* Copyright (C) 2016 Sang Engineering
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
|
#include <linux/thermal.h>
|
||||||
|
|
||||||
|
/* Register offsets */
|
||||||
|
#define REG_GEN3_IRQSTR 0x04
|
||||||
|
#define REG_GEN3_IRQMSK 0x08
|
||||||
|
#define REG_GEN3_IRQCTL 0x0C
|
||||||
|
#define REG_GEN3_IRQEN 0x10
|
||||||
|
#define REG_GEN3_IRQTEMP1 0x14
|
||||||
|
#define REG_GEN3_IRQTEMP2 0x18
|
||||||
|
#define REG_GEN3_IRQTEMP3 0x1C
|
||||||
|
#define REG_GEN3_CTSR 0x20
|
||||||
|
#define REG_GEN3_THCTR 0x20
|
||||||
|
#define REG_GEN3_TEMP 0x28
|
||||||
|
#define REG_GEN3_THCODE1 0x50
|
||||||
|
#define REG_GEN3_THCODE2 0x54
|
||||||
|
#define REG_GEN3_THCODE3 0x58
|
||||||
|
|
||||||
|
/* CTSR bits */
|
||||||
|
#define CTSR_PONM BIT(8)
|
||||||
|
#define CTSR_AOUT BIT(7)
|
||||||
|
#define CTSR_THBGR BIT(5)
|
||||||
|
#define CTSR_VMEN BIT(4)
|
||||||
|
#define CTSR_VMST BIT(1)
|
||||||
|
#define CTSR_THSST BIT(0)
|
||||||
|
|
||||||
|
/* THCTR bits */
|
||||||
|
#define THCTR_PONM BIT(6)
|
||||||
|
#define THCTR_THSST BIT(0)
|
||||||
|
|
||||||
|
#define CTEMP_MASK 0xFFF
|
||||||
|
|
||||||
|
#define MCELSIUS(temp) ((temp) * 1000)
|
||||||
|
#define GEN3_FUSE_MASK 0xFFF
|
||||||
|
|
||||||
|
#define TSC_MAX_NUM 3
|
||||||
|
|
||||||
|
/* Structure for thermal temperature calculation */
|
||||||
|
struct equation_coefs {
|
||||||
|
int a1;
|
||||||
|
int b1;
|
||||||
|
int a2;
|
||||||
|
int b2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rcar_gen3_thermal_tsc {
|
||||||
|
void __iomem *base;
|
||||||
|
struct thermal_zone_device *zone;
|
||||||
|
struct equation_coefs coef;
|
||||||
|
struct mutex lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rcar_gen3_thermal_priv {
|
||||||
|
struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rcar_gen3_thermal_data {
|
||||||
|
void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc);
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline u32 rcar_gen3_thermal_read(struct rcar_gen3_thermal_tsc *tsc,
|
||||||
|
u32 reg)
|
||||||
|
{
|
||||||
|
return ioread32(tsc->base + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
|
||||||
|
u32 reg, u32 data)
|
||||||
|
{
|
||||||
|
iowrite32(data, tsc->base + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Linear approximation for temperature
|
||||||
|
*
|
||||||
|
* [reg] = [temp] * a + b => [temp] = ([reg] - b) / a
|
||||||
|
*
|
||||||
|
* The constants a and b are calculated using two triplets of int values PTAT
|
||||||
|
* and THCODE. PTAT and THCODE can either be read from hardware or use hard
|
||||||
|
* coded values from driver. The formula to calculate a and b are taken from
|
||||||
|
* BSP and sparsely documented and understood.
|
||||||
|
*
|
||||||
|
* Examining the linear formula and the formula used to calculate constants a
|
||||||
|
* and b while knowing that the span for PTAT and THCODE values are between
|
||||||
|
* 0x000 and 0xfff the largest integer possible is 0xfff * 0xfff == 0xffe001.
|
||||||
|
* Integer also needs to be signed so that leaves 7 bits for binary
|
||||||
|
* fixed point scaling.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FIXPT_SHIFT 7
|
||||||
|
#define FIXPT_INT(_x) ((_x) << FIXPT_SHIFT)
|
||||||
|
#define FIXPT_DIV(_a, _b) DIV_ROUND_CLOSEST(((_a) << FIXPT_SHIFT), (_b))
|
||||||
|
#define FIXPT_TO_MCELSIUS(_x) ((_x) * 1000 >> FIXPT_SHIFT)
|
||||||
|
|
||||||
|
#define RCAR3_THERMAL_GRAN 500 /* mili Celsius */
|
||||||
|
|
||||||
|
/* no idea where these constants come from */
|
||||||
|
#define TJ_1 96
|
||||||
|
#define TJ_3 -41
|
||||||
|
|
||||||
|
static void rcar_gen3_thermal_calc_coefs(struct equation_coefs *coef,
|
||||||
|
int *ptat, int *thcode)
|
||||||
|
{
|
||||||
|
int tj_2;
|
||||||
|
|
||||||
|
/* TODO: Find documentation and document constant calculation formula */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Division is not scaled in BSP and if scaled it might overflow
|
||||||
|
* the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled
|
||||||
|
*/
|
||||||
|
tj_2 = (FIXPT_INT((ptat[1] - ptat[2]) * 137)
|
||||||
|
/ (ptat[0] - ptat[2])) - FIXPT_INT(41);
|
||||||
|
|
||||||
|
coef->a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]),
|
||||||
|
tj_2 - FIXPT_INT(TJ_3));
|
||||||
|
coef->b1 = FIXPT_INT(thcode[2]) - coef->a1 * TJ_3;
|
||||||
|
|
||||||
|
coef->a2 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[0]),
|
||||||
|
tj_2 - FIXPT_INT(TJ_1));
|
||||||
|
coef->b2 = FIXPT_INT(thcode[0]) - coef->a2 * TJ_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rcar_gen3_thermal_round(int temp)
|
||||||
|
{
|
||||||
|
int result, round_offs;
|
||||||
|
|
||||||
|
round_offs = temp >= 0 ? RCAR3_THERMAL_GRAN / 2 :
|
||||||
|
-RCAR3_THERMAL_GRAN / 2;
|
||||||
|
result = (temp + round_offs) / RCAR3_THERMAL_GRAN;
|
||||||
|
return result * RCAR3_THERMAL_GRAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
|
||||||
|
{
|
||||||
|
struct rcar_gen3_thermal_tsc *tsc = devdata;
|
||||||
|
int mcelsius, val1, val2;
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
|
/* Read register and convert to mili Celsius */
|
||||||
|
mutex_lock(&tsc->lock);
|
||||||
|
|
||||||
|
reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;
|
||||||
|
|
||||||
|
val1 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, tsc->coef.a1);
|
||||||
|
val2 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2, tsc->coef.a2);
|
||||||
|
mcelsius = FIXPT_TO_MCELSIUS((val1 + val2) / 2);
|
||||||
|
|
||||||
|
mutex_unlock(&tsc->lock);
|
||||||
|
|
||||||
|
/* Make sure we are inside specifications */
|
||||||
|
if ((mcelsius < MCELSIUS(-40)) || (mcelsius > MCELSIUS(125)))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
/* Round value to device granularity setting */
|
||||||
|
*temp = rcar_gen3_thermal_round(mcelsius);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {
|
||||||
|
.get_temp = rcar_gen3_thermal_get_temp,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void r8a7795_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
|
||||||
|
{
|
||||||
|
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_THBGR);
|
||||||
|
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, 0x0);
|
||||||
|
|
||||||
|
usleep_range(1000, 2000);
|
||||||
|
|
||||||
|
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_PONM);
|
||||||
|
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);
|
||||||
|
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,
|
||||||
|
CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN);
|
||||||
|
|
||||||
|
usleep_range(100, 200);
|
||||||
|
|
||||||
|
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,
|
||||||
|
CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN |
|
||||||
|
CTSR_VMST | CTSR_THSST);
|
||||||
|
|
||||||
|
usleep_range(1000, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void r8a7796_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
|
||||||
|
{
|
||||||
|
u32 reg_val;
|
||||||
|
|
||||||
|
reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
|
||||||
|
reg_val &= ~THCTR_PONM;
|
||||||
|
rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
|
||||||
|
|
||||||
|
usleep_range(1000, 2000);
|
||||||
|
|
||||||
|
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);
|
||||||
|
reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
|
||||||
|
reg_val |= THCTR_THSST;
|
||||||
|
rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct rcar_gen3_thermal_data r8a7795_data = {
|
||||||
|
.thermal_init = r8a7795_thermal_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct rcar_gen3_thermal_data r8a7796_data = {
|
||||||
|
.thermal_init = r8a7796_thermal_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
|
||||||
|
{ .compatible = "renesas,r8a7795-thermal", .data = &r8a7795_data},
|
||||||
|
{ .compatible = "renesas,r8a7796-thermal", .data = &r8a7796_data},
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
|
||||||
|
|
||||||
|
static int rcar_gen3_thermal_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
|
||||||
|
pm_runtime_put(dev);
|
||||||
|
pm_runtime_disable(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct rcar_gen3_thermal_priv *priv;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct resource *res;
|
||||||
|
struct thermal_zone_device *zone;
|
||||||
|
int ret, i;
|
||||||
|
const struct rcar_gen3_thermal_data *match_data =
|
||||||
|
of_device_get_match_data(dev);
|
||||||
|
|
||||||
|
/* default values if FUSEs are missing */
|
||||||
|
/* TODO: Read values from hardware on supported platforms */
|
||||||
|
int ptat[3] = { 2351, 1509, 435 };
|
||||||
|
int thcode[TSC_MAX_NUM][3] = {
|
||||||
|
{ 3248, 2800, 2221 },
|
||||||
|
{ 3245, 2795, 2216 },
|
||||||
|
{ 3250, 2805, 2237 },
|
||||||
|
};
|
||||||
|
|
||||||
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, priv);
|
||||||
|
|
||||||
|
pm_runtime_enable(dev);
|
||||||
|
pm_runtime_get_sync(dev);
|
||||||
|
|
||||||
|
for (i = 0; i < TSC_MAX_NUM; i++) {
|
||||||
|
struct rcar_gen3_thermal_tsc *tsc;
|
||||||
|
|
||||||
|
tsc = devm_kzalloc(dev, sizeof(*tsc), GFP_KERNEL);
|
||||||
|
if (!tsc) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto error_unregister;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
|
||||||
|
if (!res)
|
||||||
|
break;
|
||||||
|
|
||||||
|
tsc->base = devm_ioremap_resource(dev, res);
|
||||||
|
if (IS_ERR(tsc->base)) {
|
||||||
|
ret = PTR_ERR(tsc->base);
|
||||||
|
goto error_unregister;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->tscs[i] = tsc;
|
||||||
|
mutex_init(&tsc->lock);
|
||||||
|
|
||||||
|
match_data->thermal_init(tsc);
|
||||||
|
rcar_gen3_thermal_calc_coefs(&tsc->coef, ptat, thcode[i]);
|
||||||
|
|
||||||
|
zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
|
||||||
|
&rcar_gen3_tz_of_ops);
|
||||||
|
if (IS_ERR(zone)) {
|
||||||
|
dev_err(dev, "Can't register thermal zone\n");
|
||||||
|
ret = PTR_ERR(zone);
|
||||||
|
goto error_unregister;
|
||||||
|
}
|
||||||
|
tsc->zone = zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_unregister:
|
||||||
|
rcar_gen3_thermal_remove(pdev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver rcar_gen3_thermal_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "rcar_gen3_thermal",
|
||||||
|
.of_match_table = rcar_gen3_thermal_dt_ids,
|
||||||
|
},
|
||||||
|
.probe = rcar_gen3_thermal_probe,
|
||||||
|
.remove = rcar_gen3_thermal_remove,
|
||||||
|
};
|
||||||
|
module_platform_driver(rcar_gen3_thermal_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_DESCRIPTION("R-Car Gen3 THS thermal sensor driver");
|
||||||
|
MODULE_AUTHOR("Wolfram Sang <wsa+renesas@sang-engineering.com>");
|
|
@ -1168,7 +1168,6 @@ static int exynos_of_sensor_conf(struct device_node *np,
|
||||||
pdata->default_temp_offset = (u8)value;
|
pdata->default_temp_offset = (u8)value;
|
||||||
|
|
||||||
of_property_read_u32(np, "samsung,tmu_cal_type", &pdata->cal_type);
|
of_property_read_u32(np, "samsung,tmu_cal_type", &pdata->cal_type);
|
||||||
of_property_read_u32(np, "samsung,tmu_cal_mode", &pdata->cal_mode);
|
|
||||||
|
|
||||||
of_node_put(np);
|
of_node_put(np);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -70,7 +70,6 @@ struct exynos_tmu_platform_data {
|
||||||
|
|
||||||
enum soc_type type;
|
enum soc_type type;
|
||||||
u32 cal_type;
|
u32 cal_type;
|
||||||
u32 cal_mode;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _EXYNOS_TMU_H */
|
#endif /* _EXYNOS_TMU_H */
|
||||||
|
|
|
@ -36,9 +36,8 @@ MODULE_AUTHOR("Zhang Rui");
|
||||||
MODULE_DESCRIPTION("Generic thermal management sysfs support");
|
MODULE_DESCRIPTION("Generic thermal management sysfs support");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|
||||||
static DEFINE_IDR(thermal_tz_idr);
|
static DEFINE_IDA(thermal_tz_ida);
|
||||||
static DEFINE_IDR(thermal_cdev_idr);
|
static DEFINE_IDA(thermal_cdev_ida);
|
||||||
static DEFINE_MUTEX(thermal_idr_lock);
|
|
||||||
|
|
||||||
static LIST_HEAD(thermal_tz_list);
|
static LIST_HEAD(thermal_tz_list);
|
||||||
static LIST_HEAD(thermal_cdev_list);
|
static LIST_HEAD(thermal_cdev_list);
|
||||||
|
@ -589,29 +588,6 @@ void thermal_zone_device_unbind_exception(struct thermal_zone_device *tz,
|
||||||
* - thermal zone devices lifecycle: registration, unregistration,
|
* - thermal zone devices lifecycle: registration, unregistration,
|
||||||
* binding, and unbinding.
|
* binding, and unbinding.
|
||||||
*/
|
*/
|
||||||
static int get_idr(struct idr *idr, struct mutex *lock, int *id)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (lock)
|
|
||||||
mutex_lock(lock);
|
|
||||||
ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
|
|
||||||
if (lock)
|
|
||||||
mutex_unlock(lock);
|
|
||||||
if (unlikely(ret < 0))
|
|
||||||
return ret;
|
|
||||||
*id = ret;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void release_idr(struct idr *idr, struct mutex *lock, int id)
|
|
||||||
{
|
|
||||||
if (lock)
|
|
||||||
mutex_lock(lock);
|
|
||||||
idr_remove(idr, id);
|
|
||||||
if (lock)
|
|
||||||
mutex_unlock(lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* thermal_zone_bind_cooling_device() - bind a cooling device to a thermal zone
|
* thermal_zone_bind_cooling_device() - bind a cooling device to a thermal zone
|
||||||
|
@ -685,15 +661,16 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
|
||||||
dev->target = THERMAL_NO_TARGET;
|
dev->target = THERMAL_NO_TARGET;
|
||||||
dev->weight = weight;
|
dev->weight = weight;
|
||||||
|
|
||||||
result = get_idr(&tz->idr, &tz->lock, &dev->id);
|
result = ida_simple_get(&tz->ida, 0, 0, GFP_KERNEL);
|
||||||
if (result)
|
if (result < 0)
|
||||||
goto free_mem;
|
goto free_mem;
|
||||||
|
|
||||||
|
dev->id = result;
|
||||||
sprintf(dev->name, "cdev%d", dev->id);
|
sprintf(dev->name, "cdev%d", dev->id);
|
||||||
result =
|
result =
|
||||||
sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
|
sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
|
||||||
if (result)
|
if (result)
|
||||||
goto release_idr;
|
goto release_ida;
|
||||||
|
|
||||||
sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
|
sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
|
||||||
sysfs_attr_init(&dev->attr.attr);
|
sysfs_attr_init(&dev->attr.attr);
|
||||||
|
@ -737,8 +714,8 @@ remove_trip_file:
|
||||||
device_remove_file(&tz->device, &dev->attr);
|
device_remove_file(&tz->device, &dev->attr);
|
||||||
remove_symbol_link:
|
remove_symbol_link:
|
||||||
sysfs_remove_link(&tz->device.kobj, dev->name);
|
sysfs_remove_link(&tz->device.kobj, dev->name);
|
||||||
release_idr:
|
release_ida:
|
||||||
release_idr(&tz->idr, &tz->lock, dev->id);
|
ida_simple_remove(&tz->ida, dev->id);
|
||||||
free_mem:
|
free_mem:
|
||||||
kfree(dev);
|
kfree(dev);
|
||||||
return result;
|
return result;
|
||||||
|
@ -785,7 +762,7 @@ unbind:
|
||||||
device_remove_file(&tz->device, &pos->weight_attr);
|
device_remove_file(&tz->device, &pos->weight_attr);
|
||||||
device_remove_file(&tz->device, &pos->attr);
|
device_remove_file(&tz->device, &pos->attr);
|
||||||
sysfs_remove_link(&tz->device.kobj, pos->name);
|
sysfs_remove_link(&tz->device.kobj, pos->name);
|
||||||
release_idr(&tz->idr, &tz->lock, pos->id);
|
ida_simple_remove(&tz->ida, pos->id);
|
||||||
kfree(pos);
|
kfree(pos);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -925,12 +902,13 @@ __thermal_cooling_device_register(struct device_node *np,
|
||||||
if (!cdev)
|
if (!cdev)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
|
result = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL);
|
||||||
if (result) {
|
if (result < 0) {
|
||||||
kfree(cdev);
|
kfree(cdev);
|
||||||
return ERR_PTR(result);
|
return ERR_PTR(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cdev->id = result;
|
||||||
strlcpy(cdev->type, type ? : "", sizeof(cdev->type));
|
strlcpy(cdev->type, type ? : "", sizeof(cdev->type));
|
||||||
mutex_init(&cdev->lock);
|
mutex_init(&cdev->lock);
|
||||||
INIT_LIST_HEAD(&cdev->thermal_instances);
|
INIT_LIST_HEAD(&cdev->thermal_instances);
|
||||||
|
@ -943,7 +921,7 @@ __thermal_cooling_device_register(struct device_node *np,
|
||||||
dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
|
dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
|
||||||
result = device_register(&cdev->device);
|
result = device_register(&cdev->device);
|
||||||
if (result) {
|
if (result) {
|
||||||
release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
|
ida_simple_remove(&thermal_cdev_ida, cdev->id);
|
||||||
kfree(cdev);
|
kfree(cdev);
|
||||||
return ERR_PTR(result);
|
return ERR_PTR(result);
|
||||||
}
|
}
|
||||||
|
@ -1070,7 +1048,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
|
||||||
|
|
||||||
mutex_unlock(&thermal_list_lock);
|
mutex_unlock(&thermal_list_lock);
|
||||||
|
|
||||||
release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
|
ida_simple_remove(&thermal_cdev_ida, cdev->id);
|
||||||
device_unregister(&cdev->device);
|
device_unregister(&cdev->device);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);
|
EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);
|
||||||
|
@ -1172,14 +1150,15 @@ thermal_zone_device_register(const char *type, int trips, int mask,
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
INIT_LIST_HEAD(&tz->thermal_instances);
|
INIT_LIST_HEAD(&tz->thermal_instances);
|
||||||
idr_init(&tz->idr);
|
ida_init(&tz->ida);
|
||||||
mutex_init(&tz->lock);
|
mutex_init(&tz->lock);
|
||||||
result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
|
result = ida_simple_get(&thermal_tz_ida, 0, 0, GFP_KERNEL);
|
||||||
if (result) {
|
if (result < 0) {
|
||||||
kfree(tz);
|
kfree(tz);
|
||||||
return ERR_PTR(result);
|
return ERR_PTR(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tz->id = result;
|
||||||
strlcpy(tz->type, type, sizeof(tz->type));
|
strlcpy(tz->type, type, sizeof(tz->type));
|
||||||
tz->ops = ops;
|
tz->ops = ops;
|
||||||
tz->tzp = tzp;
|
tz->tzp = tzp;
|
||||||
|
@ -1201,7 +1180,7 @@ thermal_zone_device_register(const char *type, int trips, int mask,
|
||||||
dev_set_name(&tz->device, "thermal_zone%d", tz->id);
|
dev_set_name(&tz->device, "thermal_zone%d", tz->id);
|
||||||
result = device_register(&tz->device);
|
result = device_register(&tz->device);
|
||||||
if (result) {
|
if (result) {
|
||||||
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
|
ida_simple_remove(&thermal_tz_ida, tz->id);
|
||||||
kfree(tz);
|
kfree(tz);
|
||||||
return ERR_PTR(result);
|
return ERR_PTR(result);
|
||||||
}
|
}
|
||||||
|
@ -1255,7 +1234,7 @@ thermal_zone_device_register(const char *type, int trips, int mask,
|
||||||
return tz;
|
return tz;
|
||||||
|
|
||||||
unregister:
|
unregister:
|
||||||
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
|
ida_simple_remove(&thermal_tz_ida, tz->id);
|
||||||
device_unregister(&tz->device);
|
device_unregister(&tz->device);
|
||||||
return ERR_PTR(result);
|
return ERR_PTR(result);
|
||||||
}
|
}
|
||||||
|
@ -1313,8 +1292,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
|
||||||
thermal_set_governor(tz, NULL);
|
thermal_set_governor(tz, NULL);
|
||||||
|
|
||||||
thermal_remove_hwmon_sysfs(tz);
|
thermal_remove_hwmon_sysfs(tz);
|
||||||
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
|
ida_simple_remove(&thermal_tz_ida, tz->id);
|
||||||
idr_destroy(&tz->idr);
|
ida_destroy(&tz->ida);
|
||||||
mutex_destroy(&tz->lock);
|
mutex_destroy(&tz->lock);
|
||||||
device_unregister(&tz->device);
|
device_unregister(&tz->device);
|
||||||
}
|
}
|
||||||
|
@ -1514,9 +1493,8 @@ unregister_class:
|
||||||
unregister_governors:
|
unregister_governors:
|
||||||
thermal_unregister_governors();
|
thermal_unregister_governors();
|
||||||
error:
|
error:
|
||||||
idr_destroy(&thermal_tz_idr);
|
ida_destroy(&thermal_tz_ida);
|
||||||
idr_destroy(&thermal_cdev_idr);
|
ida_destroy(&thermal_cdev_ida);
|
||||||
mutex_destroy(&thermal_idr_lock);
|
|
||||||
mutex_destroy(&thermal_list_lock);
|
mutex_destroy(&thermal_list_lock);
|
||||||
mutex_destroy(&thermal_governor_lock);
|
mutex_destroy(&thermal_governor_lock);
|
||||||
return result;
|
return result;
|
||||||
|
@ -1529,9 +1507,8 @@ static void __exit thermal_exit(void)
|
||||||
genetlink_exit();
|
genetlink_exit();
|
||||||
class_unregister(&thermal_class);
|
class_unregister(&thermal_class);
|
||||||
thermal_unregister_governors();
|
thermal_unregister_governors();
|
||||||
idr_destroy(&thermal_tz_idr);
|
ida_destroy(&thermal_tz_ida);
|
||||||
idr_destroy(&thermal_cdev_idr);
|
ida_destroy(&thermal_cdev_ida);
|
||||||
mutex_destroy(&thermal_idr_lock);
|
|
||||||
mutex_destroy(&thermal_list_lock);
|
mutex_destroy(&thermal_list_lock);
|
||||||
mutex_destroy(&thermal_governor_lock);
|
mutex_destroy(&thermal_governor_lock);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ config TI_SOC_THERMAL
|
||||||
config TI_THERMAL
|
config TI_THERMAL
|
||||||
bool "Texas Instruments SoCs thermal framework support"
|
bool "Texas Instruments SoCs thermal framework support"
|
||||||
depends on TI_SOC_THERMAL
|
depends on TI_SOC_THERMAL
|
||||||
depends on CPU_THERMAL
|
|
||||||
help
|
help
|
||||||
If you say yes here you want to get support for generic thermal
|
If you say yes here you want to get support for generic thermal
|
||||||
framework for the Texas Instruments on die bandgap temperature sensor.
|
framework for the Texas Instruments on die bandgap temperature sensor.
|
||||||
|
|
|
@ -54,7 +54,6 @@
|
||||||
#define DRA752_STD_FUSE_OPP_BGAP_CORE_OFFSET 0x8
|
#define DRA752_STD_FUSE_OPP_BGAP_CORE_OFFSET 0x8
|
||||||
#define DRA752_TEMP_SENSOR_CORE_OFFSET 0x154
|
#define DRA752_TEMP_SENSOR_CORE_OFFSET 0x154
|
||||||
#define DRA752_BANDGAP_THRESHOLD_CORE_OFFSET 0x1ac
|
#define DRA752_BANDGAP_THRESHOLD_CORE_OFFSET 0x1ac
|
||||||
#define DRA752_BANDGAP_TSHUT_CORE_OFFSET 0x1b8
|
|
||||||
#define DRA752_BANDGAP_CUMUL_DTEMP_CORE_OFFSET 0x1c4
|
#define DRA752_BANDGAP_CUMUL_DTEMP_CORE_OFFSET 0x1c4
|
||||||
#define DRA752_DTEMP_CORE_0_OFFSET 0x208
|
#define DRA752_DTEMP_CORE_0_OFFSET 0x208
|
||||||
#define DRA752_DTEMP_CORE_1_OFFSET 0x20c
|
#define DRA752_DTEMP_CORE_1_OFFSET 0x20c
|
||||||
|
@ -66,7 +65,6 @@
|
||||||
#define DRA752_STD_FUSE_OPP_BGAP_IVA_OFFSET 0x388
|
#define DRA752_STD_FUSE_OPP_BGAP_IVA_OFFSET 0x388
|
||||||
#define DRA752_TEMP_SENSOR_IVA_OFFSET 0x398
|
#define DRA752_TEMP_SENSOR_IVA_OFFSET 0x398
|
||||||
#define DRA752_BANDGAP_THRESHOLD_IVA_OFFSET 0x3a4
|
#define DRA752_BANDGAP_THRESHOLD_IVA_OFFSET 0x3a4
|
||||||
#define DRA752_BANDGAP_TSHUT_IVA_OFFSET 0x3ac
|
|
||||||
#define DRA752_BANDGAP_CUMUL_DTEMP_IVA_OFFSET 0x3b4
|
#define DRA752_BANDGAP_CUMUL_DTEMP_IVA_OFFSET 0x3b4
|
||||||
#define DRA752_DTEMP_IVA_0_OFFSET 0x3d0
|
#define DRA752_DTEMP_IVA_0_OFFSET 0x3d0
|
||||||
#define DRA752_DTEMP_IVA_1_OFFSET 0x3d4
|
#define DRA752_DTEMP_IVA_1_OFFSET 0x3d4
|
||||||
|
@ -78,7 +76,6 @@
|
||||||
#define DRA752_STD_FUSE_OPP_BGAP_MPU_OFFSET 0x4
|
#define DRA752_STD_FUSE_OPP_BGAP_MPU_OFFSET 0x4
|
||||||
#define DRA752_TEMP_SENSOR_MPU_OFFSET 0x14c
|
#define DRA752_TEMP_SENSOR_MPU_OFFSET 0x14c
|
||||||
#define DRA752_BANDGAP_THRESHOLD_MPU_OFFSET 0x1a4
|
#define DRA752_BANDGAP_THRESHOLD_MPU_OFFSET 0x1a4
|
||||||
#define DRA752_BANDGAP_TSHUT_MPU_OFFSET 0x1b0
|
|
||||||
#define DRA752_BANDGAP_CUMUL_DTEMP_MPU_OFFSET 0x1bc
|
#define DRA752_BANDGAP_CUMUL_DTEMP_MPU_OFFSET 0x1bc
|
||||||
#define DRA752_DTEMP_MPU_0_OFFSET 0x1e0
|
#define DRA752_DTEMP_MPU_0_OFFSET 0x1e0
|
||||||
#define DRA752_DTEMP_MPU_1_OFFSET 0x1e4
|
#define DRA752_DTEMP_MPU_1_OFFSET 0x1e4
|
||||||
|
@ -90,7 +87,6 @@
|
||||||
#define DRA752_STD_FUSE_OPP_BGAP_DSPEVE_OFFSET 0x384
|
#define DRA752_STD_FUSE_OPP_BGAP_DSPEVE_OFFSET 0x384
|
||||||
#define DRA752_TEMP_SENSOR_DSPEVE_OFFSET 0x394
|
#define DRA752_TEMP_SENSOR_DSPEVE_OFFSET 0x394
|
||||||
#define DRA752_BANDGAP_THRESHOLD_DSPEVE_OFFSET 0x3a0
|
#define DRA752_BANDGAP_THRESHOLD_DSPEVE_OFFSET 0x3a0
|
||||||
#define DRA752_BANDGAP_TSHUT_DSPEVE_OFFSET 0x3a8
|
|
||||||
#define DRA752_BANDGAP_CUMUL_DTEMP_DSPEVE_OFFSET 0x3b0
|
#define DRA752_BANDGAP_CUMUL_DTEMP_DSPEVE_OFFSET 0x3b0
|
||||||
#define DRA752_DTEMP_DSPEVE_0_OFFSET 0x3bc
|
#define DRA752_DTEMP_DSPEVE_0_OFFSET 0x3bc
|
||||||
#define DRA752_DTEMP_DSPEVE_1_OFFSET 0x3c0
|
#define DRA752_DTEMP_DSPEVE_1_OFFSET 0x3c0
|
||||||
|
@ -102,7 +98,6 @@
|
||||||
#define DRA752_STD_FUSE_OPP_BGAP_GPU_OFFSET 0x0
|
#define DRA752_STD_FUSE_OPP_BGAP_GPU_OFFSET 0x0
|
||||||
#define DRA752_TEMP_SENSOR_GPU_OFFSET 0x150
|
#define DRA752_TEMP_SENSOR_GPU_OFFSET 0x150
|
||||||
#define DRA752_BANDGAP_THRESHOLD_GPU_OFFSET 0x1a8
|
#define DRA752_BANDGAP_THRESHOLD_GPU_OFFSET 0x1a8
|
||||||
#define DRA752_BANDGAP_TSHUT_GPU_OFFSET 0x1b4
|
|
||||||
#define DRA752_BANDGAP_CUMUL_DTEMP_GPU_OFFSET 0x1c0
|
#define DRA752_BANDGAP_CUMUL_DTEMP_GPU_OFFSET 0x1c0
|
||||||
#define DRA752_DTEMP_GPU_0_OFFSET 0x1f4
|
#define DRA752_DTEMP_GPU_0_OFFSET 0x1f4
|
||||||
#define DRA752_DTEMP_GPU_1_OFFSET 0x1f8
|
#define DRA752_DTEMP_GPU_1_OFFSET 0x1f8
|
||||||
|
@ -173,10 +168,6 @@
|
||||||
#define DRA752_BANDGAP_THRESHOLD_HOT_MASK (0x3ff << 16)
|
#define DRA752_BANDGAP_THRESHOLD_HOT_MASK (0x3ff << 16)
|
||||||
#define DRA752_BANDGAP_THRESHOLD_COLD_MASK (0x3ff << 0)
|
#define DRA752_BANDGAP_THRESHOLD_COLD_MASK (0x3ff << 0)
|
||||||
|
|
||||||
/* DRA752.TSHUT_THRESHOLD */
|
|
||||||
#define DRA752_TSHUT_THRESHOLD_MUXCTRL_MASK BIT(31)
|
|
||||||
#define DRA752_TSHUT_THRESHOLD_HOT_MASK (0x3ff << 16)
|
|
||||||
#define DRA752_TSHUT_THRESHOLD_COLD_MASK (0x3ff << 0)
|
|
||||||
|
|
||||||
/* DRA752.BANDGAP_CUMUL_DTEMP_CORE */
|
/* DRA752.BANDGAP_CUMUL_DTEMP_CORE */
|
||||||
#define DRA752_BANDGAP_CUMUL_DTEMP_CORE_MASK (0xffffffff << 0)
|
#define DRA752_BANDGAP_CUMUL_DTEMP_CORE_MASK (0xffffffff << 0)
|
||||||
|
@ -216,8 +207,6 @@
|
||||||
#define DRA752_GPU_MAX_TEMP 125000
|
#define DRA752_GPU_MAX_TEMP 125000
|
||||||
#define DRA752_GPU_HYST_VAL 5000
|
#define DRA752_GPU_HYST_VAL 5000
|
||||||
/* interrupts thresholds */
|
/* interrupts thresholds */
|
||||||
#define DRA752_GPU_TSHUT_HOT 915
|
|
||||||
#define DRA752_GPU_TSHUT_COLD 900
|
|
||||||
#define DRA752_GPU_T_HOT 800
|
#define DRA752_GPU_T_HOT 800
|
||||||
#define DRA752_GPU_T_COLD 795
|
#define DRA752_GPU_T_COLD 795
|
||||||
|
|
||||||
|
@ -230,8 +219,6 @@
|
||||||
#define DRA752_MPU_MAX_TEMP 125000
|
#define DRA752_MPU_MAX_TEMP 125000
|
||||||
#define DRA752_MPU_HYST_VAL 5000
|
#define DRA752_MPU_HYST_VAL 5000
|
||||||
/* interrupts thresholds */
|
/* interrupts thresholds */
|
||||||
#define DRA752_MPU_TSHUT_HOT 915
|
|
||||||
#define DRA752_MPU_TSHUT_COLD 900
|
|
||||||
#define DRA752_MPU_T_HOT 800
|
#define DRA752_MPU_T_HOT 800
|
||||||
#define DRA752_MPU_T_COLD 795
|
#define DRA752_MPU_T_COLD 795
|
||||||
|
|
||||||
|
@ -244,8 +231,6 @@
|
||||||
#define DRA752_CORE_MAX_TEMP 125000
|
#define DRA752_CORE_MAX_TEMP 125000
|
||||||
#define DRA752_CORE_HYST_VAL 5000
|
#define DRA752_CORE_HYST_VAL 5000
|
||||||
/* interrupts thresholds */
|
/* interrupts thresholds */
|
||||||
#define DRA752_CORE_TSHUT_HOT 915
|
|
||||||
#define DRA752_CORE_TSHUT_COLD 900
|
|
||||||
#define DRA752_CORE_T_HOT 800
|
#define DRA752_CORE_T_HOT 800
|
||||||
#define DRA752_CORE_T_COLD 795
|
#define DRA752_CORE_T_COLD 795
|
||||||
|
|
||||||
|
@ -258,8 +243,6 @@
|
||||||
#define DRA752_DSPEVE_MAX_TEMP 125000
|
#define DRA752_DSPEVE_MAX_TEMP 125000
|
||||||
#define DRA752_DSPEVE_HYST_VAL 5000
|
#define DRA752_DSPEVE_HYST_VAL 5000
|
||||||
/* interrupts thresholds */
|
/* interrupts thresholds */
|
||||||
#define DRA752_DSPEVE_TSHUT_HOT 915
|
|
||||||
#define DRA752_DSPEVE_TSHUT_COLD 900
|
|
||||||
#define DRA752_DSPEVE_T_HOT 800
|
#define DRA752_DSPEVE_T_HOT 800
|
||||||
#define DRA752_DSPEVE_T_COLD 795
|
#define DRA752_DSPEVE_T_COLD 795
|
||||||
|
|
||||||
|
@ -272,8 +255,6 @@
|
||||||
#define DRA752_IVA_MAX_TEMP 125000
|
#define DRA752_IVA_MAX_TEMP 125000
|
||||||
#define DRA752_IVA_HYST_VAL 5000
|
#define DRA752_IVA_HYST_VAL 5000
|
||||||
/* interrupts thresholds */
|
/* interrupts thresholds */
|
||||||
#define DRA752_IVA_TSHUT_HOT 915
|
|
||||||
#define DRA752_IVA_TSHUT_COLD 900
|
|
||||||
#define DRA752_IVA_T_HOT 800
|
#define DRA752_IVA_T_HOT 800
|
||||||
#define DRA752_IVA_T_COLD 795
|
#define DRA752_IVA_T_COLD 795
|
||||||
|
|
||||||
|
|
|
@ -49,9 +49,6 @@ dra752_core_temp_sensor_registers = {
|
||||||
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_CORE_OFFSET,
|
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_CORE_OFFSET,
|
||||||
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
|
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
|
||||||
.threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
|
.threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
|
||||||
.tshut_threshold = DRA752_BANDGAP_TSHUT_CORE_OFFSET,
|
|
||||||
.tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
|
|
||||||
.tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
|
|
||||||
.bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
|
.bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
|
||||||
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
|
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
|
||||||
.status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_CORE_MASK,
|
.status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_CORE_MASK,
|
||||||
|
@ -85,9 +82,6 @@ dra752_iva_temp_sensor_registers = {
|
||||||
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_IVA_OFFSET,
|
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_IVA_OFFSET,
|
||||||
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
|
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
|
||||||
.threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
|
.threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
|
||||||
.tshut_threshold = DRA752_BANDGAP_TSHUT_IVA_OFFSET,
|
|
||||||
.tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
|
|
||||||
.tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
|
|
||||||
.bgap_status = DRA752_BANDGAP_STATUS_2_OFFSET,
|
.bgap_status = DRA752_BANDGAP_STATUS_2_OFFSET,
|
||||||
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
|
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
|
||||||
.status_hot_mask = DRA752_BANDGAP_STATUS_2_HOT_IVA_MASK,
|
.status_hot_mask = DRA752_BANDGAP_STATUS_2_HOT_IVA_MASK,
|
||||||
|
@ -121,9 +115,6 @@ dra752_mpu_temp_sensor_registers = {
|
||||||
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_MPU_OFFSET,
|
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_MPU_OFFSET,
|
||||||
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
|
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
|
||||||
.threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
|
.threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
|
||||||
.tshut_threshold = DRA752_BANDGAP_TSHUT_MPU_OFFSET,
|
|
||||||
.tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
|
|
||||||
.tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
|
|
||||||
.bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
|
.bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
|
||||||
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
|
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
|
||||||
.status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_MPU_MASK,
|
.status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_MPU_MASK,
|
||||||
|
@ -157,9 +148,6 @@ dra752_dspeve_temp_sensor_registers = {
|
||||||
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_DSPEVE_OFFSET,
|
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_DSPEVE_OFFSET,
|
||||||
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
|
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
|
||||||
.threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
|
.threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
|
||||||
.tshut_threshold = DRA752_BANDGAP_TSHUT_DSPEVE_OFFSET,
|
|
||||||
.tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
|
|
||||||
.tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
|
|
||||||
.bgap_status = DRA752_BANDGAP_STATUS_2_OFFSET,
|
.bgap_status = DRA752_BANDGAP_STATUS_2_OFFSET,
|
||||||
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
|
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
|
||||||
.status_hot_mask = DRA752_BANDGAP_STATUS_2_HOT_DSPEVE_MASK,
|
.status_hot_mask = DRA752_BANDGAP_STATUS_2_HOT_DSPEVE_MASK,
|
||||||
|
@ -193,9 +181,6 @@ dra752_gpu_temp_sensor_registers = {
|
||||||
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_GPU_OFFSET,
|
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_GPU_OFFSET,
|
||||||
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
|
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
|
||||||
.threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
|
.threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
|
||||||
.tshut_threshold = DRA752_BANDGAP_TSHUT_GPU_OFFSET,
|
|
||||||
.tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
|
|
||||||
.tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
|
|
||||||
.bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
|
.bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
|
||||||
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
|
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
|
||||||
.status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_GPU_MASK,
|
.status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_GPU_MASK,
|
||||||
|
@ -211,8 +196,6 @@ dra752_gpu_temp_sensor_registers = {
|
||||||
|
|
||||||
/* Thresholds and limits for DRA752 MPU temperature sensor */
|
/* Thresholds and limits for DRA752 MPU temperature sensor */
|
||||||
static struct temp_sensor_data dra752_mpu_temp_sensor_data = {
|
static struct temp_sensor_data dra752_mpu_temp_sensor_data = {
|
||||||
.tshut_hot = DRA752_MPU_TSHUT_HOT,
|
|
||||||
.tshut_cold = DRA752_MPU_TSHUT_COLD,
|
|
||||||
.t_hot = DRA752_MPU_T_HOT,
|
.t_hot = DRA752_MPU_T_HOT,
|
||||||
.t_cold = DRA752_MPU_T_COLD,
|
.t_cold = DRA752_MPU_T_COLD,
|
||||||
.min_freq = DRA752_MPU_MIN_FREQ,
|
.min_freq = DRA752_MPU_MIN_FREQ,
|
||||||
|
@ -226,8 +209,6 @@ static struct temp_sensor_data dra752_mpu_temp_sensor_data = {
|
||||||
|
|
||||||
/* Thresholds and limits for DRA752 GPU temperature sensor */
|
/* Thresholds and limits for DRA752 GPU temperature sensor */
|
||||||
static struct temp_sensor_data dra752_gpu_temp_sensor_data = {
|
static struct temp_sensor_data dra752_gpu_temp_sensor_data = {
|
||||||
.tshut_hot = DRA752_GPU_TSHUT_HOT,
|
|
||||||
.tshut_cold = DRA752_GPU_TSHUT_COLD,
|
|
||||||
.t_hot = DRA752_GPU_T_HOT,
|
.t_hot = DRA752_GPU_T_HOT,
|
||||||
.t_cold = DRA752_GPU_T_COLD,
|
.t_cold = DRA752_GPU_T_COLD,
|
||||||
.min_freq = DRA752_GPU_MIN_FREQ,
|
.min_freq = DRA752_GPU_MIN_FREQ,
|
||||||
|
@ -241,8 +222,6 @@ static struct temp_sensor_data dra752_gpu_temp_sensor_data = {
|
||||||
|
|
||||||
/* Thresholds and limits for DRA752 CORE temperature sensor */
|
/* Thresholds and limits for DRA752 CORE temperature sensor */
|
||||||
static struct temp_sensor_data dra752_core_temp_sensor_data = {
|
static struct temp_sensor_data dra752_core_temp_sensor_data = {
|
||||||
.tshut_hot = DRA752_CORE_TSHUT_HOT,
|
|
||||||
.tshut_cold = DRA752_CORE_TSHUT_COLD,
|
|
||||||
.t_hot = DRA752_CORE_T_HOT,
|
.t_hot = DRA752_CORE_T_HOT,
|
||||||
.t_cold = DRA752_CORE_T_COLD,
|
.t_cold = DRA752_CORE_T_COLD,
|
||||||
.min_freq = DRA752_CORE_MIN_FREQ,
|
.min_freq = DRA752_CORE_MIN_FREQ,
|
||||||
|
@ -256,8 +235,6 @@ static struct temp_sensor_data dra752_core_temp_sensor_data = {
|
||||||
|
|
||||||
/* Thresholds and limits for DRA752 DSPEVE temperature sensor */
|
/* Thresholds and limits for DRA752 DSPEVE temperature sensor */
|
||||||
static struct temp_sensor_data dra752_dspeve_temp_sensor_data = {
|
static struct temp_sensor_data dra752_dspeve_temp_sensor_data = {
|
||||||
.tshut_hot = DRA752_DSPEVE_TSHUT_HOT,
|
|
||||||
.tshut_cold = DRA752_DSPEVE_TSHUT_COLD,
|
|
||||||
.t_hot = DRA752_DSPEVE_T_HOT,
|
.t_hot = DRA752_DSPEVE_T_HOT,
|
||||||
.t_cold = DRA752_DSPEVE_T_COLD,
|
.t_cold = DRA752_DSPEVE_T_COLD,
|
||||||
.min_freq = DRA752_DSPEVE_MIN_FREQ,
|
.min_freq = DRA752_DSPEVE_MIN_FREQ,
|
||||||
|
@ -271,8 +248,6 @@ static struct temp_sensor_data dra752_dspeve_temp_sensor_data = {
|
||||||
|
|
||||||
/* Thresholds and limits for DRA752 IVA temperature sensor */
|
/* Thresholds and limits for DRA752 IVA temperature sensor */
|
||||||
static struct temp_sensor_data dra752_iva_temp_sensor_data = {
|
static struct temp_sensor_data dra752_iva_temp_sensor_data = {
|
||||||
.tshut_hot = DRA752_IVA_TSHUT_HOT,
|
|
||||||
.tshut_cold = DRA752_IVA_TSHUT_COLD,
|
|
||||||
.t_hot = DRA752_IVA_T_HOT,
|
.t_hot = DRA752_IVA_T_HOT,
|
||||||
.t_cold = DRA752_IVA_T_COLD,
|
.t_cold = DRA752_IVA_T_COLD,
|
||||||
.min_freq = DRA752_IVA_MIN_FREQ,
|
.min_freq = DRA752_IVA_MIN_FREQ,
|
||||||
|
@ -416,8 +391,7 @@ int dra752_adc_to_temp[DRA752_ADC_END_VALUE - DRA752_ADC_START_VALUE + 1] = {
|
||||||
|
|
||||||
/* DRA752 data */
|
/* DRA752 data */
|
||||||
const struct ti_bandgap_data dra752_data = {
|
const struct ti_bandgap_data dra752_data = {
|
||||||
.features = TI_BANDGAP_FEATURE_TSHUT_CONFIG |
|
.features = TI_BANDGAP_FEATURE_FREEZE_BIT |
|
||||||
TI_BANDGAP_FEATURE_FREEZE_BIT |
|
|
||||||
TI_BANDGAP_FEATURE_TALERT |
|
TI_BANDGAP_FEATURE_TALERT |
|
||||||
TI_BANDGAP_FEATURE_COUNTER_DELAY |
|
TI_BANDGAP_FEATURE_COUNTER_DELAY |
|
||||||
TI_BANDGAP_FEATURE_HISTORY_BUFFER |
|
TI_BANDGAP_FEATURE_HISTORY_BUFFER |
|
||||||
|
|
|
@ -0,0 +1,258 @@
|
||||||
|
/*
|
||||||
|
* ZTE's zx2967 family thermal sensor driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 ZTE Ltd.
|
||||||
|
*
|
||||||
|
* Author: Baoyou Xie <baoyou.xie@linaro.org>
|
||||||
|
*
|
||||||
|
* License terms: GNU General Public License (GPL) version 2
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/iopoll.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/thermal.h>
|
||||||
|
|
||||||
|
/* Power Mode: 0->low 1->high */
|
||||||
|
#define ZX2967_THERMAL_POWER_MODE 0
|
||||||
|
#define ZX2967_POWER_MODE_LOW 0
|
||||||
|
#define ZX2967_POWER_MODE_HIGH 1
|
||||||
|
|
||||||
|
/* DCF Control Register */
|
||||||
|
#define ZX2967_THERMAL_DCF 0x4
|
||||||
|
#define ZX2967_DCF_EN BIT(1)
|
||||||
|
#define ZX2967_DCF_FREEZE BIT(0)
|
||||||
|
|
||||||
|
/* Selection Register */
|
||||||
|
#define ZX2967_THERMAL_SEL 0x8
|
||||||
|
|
||||||
|
/* Control Register */
|
||||||
|
#define ZX2967_THERMAL_CTRL 0x10
|
||||||
|
|
||||||
|
#define ZX2967_THERMAL_READY BIT(12)
|
||||||
|
#define ZX2967_THERMAL_TEMP_MASK GENMASK(11, 0)
|
||||||
|
#define ZX2967_THERMAL_ID_MASK 0x18
|
||||||
|
#define ZX2967_THERMAL_ID 0x10
|
||||||
|
|
||||||
|
#define ZX2967_GET_TEMP_TIMEOUT_US (100 * 1024)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct zx2967_thermal_priv - zx2967 thermal sensor private structure
|
||||||
|
* @tzd: struct thermal_zone_device where the sensor is registered
|
||||||
|
* @lock: prevents read sensor in parallel
|
||||||
|
* @clk_topcrm: topcrm clk structure
|
||||||
|
* @clk_apb: apb clk structure
|
||||||
|
* @regs: pointer to base address of the thermal sensor
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct zx2967_thermal_priv {
|
||||||
|
struct thermal_zone_device *tzd;
|
||||||
|
struct mutex lock;
|
||||||
|
struct clk *clk_topcrm;
|
||||||
|
struct clk *clk_apb;
|
||||||
|
void __iomem *regs;
|
||||||
|
struct device *dev;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int zx2967_thermal_get_temp(void *data, int *temp)
|
||||||
|
{
|
||||||
|
void __iomem *regs;
|
||||||
|
struct zx2967_thermal_priv *priv = data;
|
||||||
|
u32 val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!priv->tzd)
|
||||||
|
return -EAGAIN;
|
||||||
|
|
||||||
|
regs = priv->regs;
|
||||||
|
mutex_lock(&priv->lock);
|
||||||
|
writel_relaxed(ZX2967_POWER_MODE_LOW,
|
||||||
|
regs + ZX2967_THERMAL_POWER_MODE);
|
||||||
|
writel_relaxed(ZX2967_DCF_EN, regs + ZX2967_THERMAL_DCF);
|
||||||
|
|
||||||
|
val = readl_relaxed(regs + ZX2967_THERMAL_SEL);
|
||||||
|
val &= ~ZX2967_THERMAL_ID_MASK;
|
||||||
|
val |= ZX2967_THERMAL_ID;
|
||||||
|
writel_relaxed(val, regs + ZX2967_THERMAL_SEL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Must wait for a while, surely it's a bit odd.
|
||||||
|
* otherwise temperature value we got has a few deviation, even if
|
||||||
|
* the THERMAL_READY bit is set.
|
||||||
|
*/
|
||||||
|
usleep_range(100, 300);
|
||||||
|
ret = readx_poll_timeout(readl, regs + ZX2967_THERMAL_CTRL,
|
||||||
|
val, val & ZX2967_THERMAL_READY, 300,
|
||||||
|
ZX2967_GET_TEMP_TIMEOUT_US);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(priv->dev, "Thermal sensor data timeout\n");
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
writel_relaxed(ZX2967_DCF_FREEZE | ZX2967_DCF_EN,
|
||||||
|
regs + ZX2967_THERMAL_DCF);
|
||||||
|
val = readl_relaxed(regs + ZX2967_THERMAL_CTRL)
|
||||||
|
& ZX2967_THERMAL_TEMP_MASK;
|
||||||
|
writel_relaxed(ZX2967_POWER_MODE_HIGH,
|
||||||
|
regs + ZX2967_THERMAL_POWER_MODE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate temperature
|
||||||
|
* In dts, slope is multiplied by 1000.
|
||||||
|
*/
|
||||||
|
*temp = DIV_ROUND_CLOSEST(((s32)val + priv->tzd->tzp->offset) * 1000,
|
||||||
|
priv->tzd->tzp->slope);
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
mutex_unlock(&priv->lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct thermal_zone_of_device_ops zx2967_of_thermal_ops = {
|
||||||
|
.get_temp = zx2967_thermal_get_temp,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int zx2967_thermal_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct zx2967_thermal_priv *priv;
|
||||||
|
struct resource *res;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
priv->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
if (IS_ERR(priv->regs))
|
||||||
|
return PTR_ERR(priv->regs);
|
||||||
|
|
||||||
|
priv->clk_topcrm = devm_clk_get(&pdev->dev, "topcrm");
|
||||||
|
if (IS_ERR(priv->clk_topcrm)) {
|
||||||
|
ret = PTR_ERR(priv->clk_topcrm);
|
||||||
|
dev_err(&pdev->dev, "failed to get topcrm clock: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(priv->clk_topcrm);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "failed to enable topcrm clock: %d\n",
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->clk_apb = devm_clk_get(&pdev->dev, "apb");
|
||||||
|
if (IS_ERR(priv->clk_apb)) {
|
||||||
|
ret = PTR_ERR(priv->clk_apb);
|
||||||
|
dev_err(&pdev->dev, "failed to get apb clock: %d\n", ret);
|
||||||
|
goto disable_clk_topcrm;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(priv->clk_apb);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "failed to enable apb clock: %d\n",
|
||||||
|
ret);
|
||||||
|
goto disable_clk_topcrm;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_init(&priv->lock);
|
||||||
|
priv->tzd = thermal_zone_of_sensor_register(&pdev->dev,
|
||||||
|
0, priv, &zx2967_of_thermal_ops);
|
||||||
|
|
||||||
|
if (IS_ERR(priv->tzd)) {
|
||||||
|
ret = PTR_ERR(priv->tzd);
|
||||||
|
dev_err(&pdev->dev, "failed to register sensor: %d\n", ret);
|
||||||
|
goto disable_clk_all;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->tzd->tzp->slope == 0) {
|
||||||
|
thermal_zone_of_sensor_unregister(&pdev->dev, priv->tzd);
|
||||||
|
dev_err(&pdev->dev, "coefficients of sensor is invalid\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto disable_clk_all;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->dev = &pdev->dev;
|
||||||
|
platform_set_drvdata(pdev, priv);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
disable_clk_all:
|
||||||
|
clk_disable_unprepare(priv->clk_apb);
|
||||||
|
disable_clk_topcrm:
|
||||||
|
clk_disable_unprepare(priv->clk_topcrm);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zx2967_thermal_exit(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct zx2967_thermal_priv *priv = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
thermal_zone_of_sensor_unregister(&pdev->dev, priv->tzd);
|
||||||
|
clk_disable_unprepare(priv->clk_topcrm);
|
||||||
|
clk_disable_unprepare(priv->clk_apb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id zx2967_thermal_id_table[] = {
|
||||||
|
{ .compatible = "zte,zx296718-thermal" },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, zx2967_thermal_id_table);
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static int zx2967_thermal_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
|
struct zx2967_thermal_priv *priv = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
if (priv && priv->clk_topcrm)
|
||||||
|
clk_disable_unprepare(priv->clk_topcrm);
|
||||||
|
|
||||||
|
if (priv && priv->clk_apb)
|
||||||
|
clk_disable_unprepare(priv->clk_apb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zx2967_thermal_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
|
struct zx2967_thermal_priv *priv = platform_get_drvdata(pdev);
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = clk_prepare_enable(priv->clk_topcrm);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
error = clk_prepare_enable(priv->clk_apb);
|
||||||
|
if (error) {
|
||||||
|
clk_disable_unprepare(priv->clk_topcrm);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(zx2967_thermal_pm_ops,
|
||||||
|
zx2967_thermal_suspend, zx2967_thermal_resume);
|
||||||
|
|
||||||
|
static struct platform_driver zx2967_thermal_driver = {
|
||||||
|
.probe = zx2967_thermal_probe,
|
||||||
|
.remove = zx2967_thermal_exit,
|
||||||
|
.driver = {
|
||||||
|
.name = "zx2967_thermal",
|
||||||
|
.of_match_table = zx2967_thermal_id_table,
|
||||||
|
.pm = &zx2967_thermal_pm_ops,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(zx2967_thermal_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
|
||||||
|
MODULE_DESCRIPTION("ZTE zx2967 thermal driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -194,7 +194,7 @@ struct thermal_attr {
|
||||||
* @governor: pointer to the governor for this thermal zone
|
* @governor: pointer to the governor for this thermal zone
|
||||||
* @governor_data: private pointer for governor data
|
* @governor_data: private pointer for governor data
|
||||||
* @thermal_instances: list of &struct thermal_instance of this thermal zone
|
* @thermal_instances: list of &struct thermal_instance of this thermal zone
|
||||||
* @idr: &struct idr to generate unique id for this zone's cooling
|
* @ida: &struct ida to generate unique id for this zone's cooling
|
||||||
* devices
|
* devices
|
||||||
* @lock: lock to protect thermal_instances list
|
* @lock: lock to protect thermal_instances list
|
||||||
* @node: node in thermal_tz_list (in thermal_core.c)
|
* @node: node in thermal_tz_list (in thermal_core.c)
|
||||||
|
@ -227,7 +227,7 @@ struct thermal_zone_device {
|
||||||
struct thermal_governor *governor;
|
struct thermal_governor *governor;
|
||||||
void *governor_data;
|
void *governor_data;
|
||||||
struct list_head thermal_instances;
|
struct list_head thermal_instances;
|
||||||
struct idr idr;
|
struct ida ida;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
struct delayed_work poll_queue;
|
struct delayed_work poll_queue;
|
||||||
|
|
Loading…
Reference in New Issue