Merge branches 'thermal-core', 'thermal-soc', 'thermal-intel' and 'ida-conversion' into next
This commit is contained in:
Коммит
6fefe19f58
|
@ -17,6 +17,12 @@ Required properties:
|
|||
calibration data, as specified by the SoC reference manual.
|
||||
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.
|
||||
- #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:
|
||||
|
||||
|
@ -60,4 +66,5 @@ tmu@f0000 {
|
|||
|
||||
0x00030000 0x00000012
|
||||
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
|
||||
0x00030002 0x00000019
|
||||
0x00030003 0x00000024>;
|
||||
#thermal-sensor-cells = <0>;
|
||||
#thermal-sensor-cells = <1>;
|
||||
};
|
||||
|
||||
thermal-zones {
|
||||
|
@ -430,7 +430,7 @@
|
|||
polling-delay-passive = <1000>;
|
||||
polling-delay = <5000>;
|
||||
|
||||
thermal-sensors = <&tmu>;
|
||||
thermal-sensors = <&tmu 0>;
|
||||
|
||||
trips {
|
||||
cpu_alert: cpu-alert {
|
||||
|
|
|
@ -526,7 +526,7 @@
|
|||
|
||||
0x00030000 0x00000012
|
||||
0x00030001 0x0000001d>;
|
||||
#thermal-sensor-cells = <0>;
|
||||
#thermal-sensor-cells = <1>;
|
||||
};
|
||||
|
||||
thermal-zones {
|
||||
|
@ -534,7 +534,7 @@
|
|||
polling-delay-passive = <1000>;
|
||||
polling-delay = <5000>;
|
||||
|
||||
thermal-sensors = <&tmu>;
|
||||
thermal-sensors = <&tmu 2>;
|
||||
|
||||
trips {
|
||||
cpu_alert: cpu-alert {
|
||||
|
|
|
@ -245,6 +245,15 @@ config RCAR_THERMAL
|
|||
Enable this to plug the R-Car thermal sensor driver into the Linux
|
||||
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
|
||||
tristate "Temperature sensor on Marvell Kirkwood SoCs"
|
||||
depends on MACH_KIRKWOOD || COMPILE_TEST
|
||||
|
@ -436,4 +445,12 @@ depends on (ARCH_QCOM && OF) || COMPILE_TEST
|
|||
source "drivers/thermal/qcom/Kconfig"
|
||||
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
|
||||
|
|
|
@ -31,6 +31,7 @@ obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o
|
|||
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
|
||||
obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_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-y += samsung/
|
||||
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_MTK_THERMAL) += mtk_thermal.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) \
|
||||
container_of(x, struct clock_cooling_device, clk_rate_change_nb)
|
||||
static DEFINE_IDR(clock_idr);
|
||||
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);
|
||||
}
|
||||
static DEFINE_IDA(clock_ida);
|
||||
|
||||
/* 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))
|
||||
return ERR_CAST(ccdev->clk);
|
||||
|
||||
ret = clock_cooling_get_idr(&ccdev->id);
|
||||
if (ret)
|
||||
return ERR_PTR(-EINVAL);
|
||||
ret = ida_simple_get(&clock_ida, 0, 0, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
ccdev->id = ret;
|
||||
|
||||
snprintf(dev_name, sizeof(dev_name), "thermal-clock-%d", ccdev->id);
|
||||
|
||||
cdev = thermal_cooling_device_register(dev_name, ccdev,
|
||||
&clock_cooling_ops);
|
||||
if (IS_ERR(cdev)) {
|
||||
release_idr(ccdev->id);
|
||||
ida_simple_remove(&clock_ida, ccdev->id);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
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 */
|
||||
ret = dev_pm_opp_init_cpufreq_table(dev, &ccdev->freq_table);
|
||||
if (ret) {
|
||||
release_idr(ccdev->id);
|
||||
ida_simple_remove(&clock_ida, ccdev->id);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
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);
|
||||
|
||||
thermal_cooling_device_unregister(ccdev->cdev);
|
||||
release_idr(ccdev->id);
|
||||
ida_simple_remove(&clock_ida, ccdev->id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clock_cooling_unregister);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/thermal.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpu.h>
|
||||
|
@ -104,50 +105,13 @@ struct cpufreq_cooling_device {
|
|||
struct device *cpu_dev;
|
||||
get_static_t plat_get_static_power;
|
||||
};
|
||||
static DEFINE_IDR(cpufreq_idr);
|
||||
static DEFINE_MUTEX(cooling_cpufreq_lock);
|
||||
static DEFINE_IDA(cpufreq_ida);
|
||||
|
||||
static unsigned int cpufreq_dev_count;
|
||||
|
||||
static DEFINE_MUTEX(cooling_list_lock);
|
||||
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 */
|
||||
|
||||
/**
|
||||
|
@ -886,11 +850,12 @@ __cpufreq_cooling_register(struct device_node *np,
|
|||
cooling_ops = &cpufreq_cooling_ops;
|
||||
}
|
||||
|
||||
ret = get_idr(&cpufreq_idr, &cpufreq_dev->id);
|
||||
if (ret) {
|
||||
ret = ida_simple_get(&cpufreq_ida, 0, 0, GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
cool_dev = ERR_PTR(ret);
|
||||
goto free_power_table;
|
||||
}
|
||||
cpufreq_dev->id = ret;
|
||||
|
||||
/* Fill freq-table in descending order of frequencies */
|
||||
for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) {
|
||||
|
@ -910,27 +875,24 @@ __cpufreq_cooling_register(struct device_node *np,
|
|||
cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev,
|
||||
cooling_ops);
|
||||
if (IS_ERR(cool_dev))
|
||||
goto remove_idr;
|
||||
goto remove_ida;
|
||||
|
||||
cpufreq_dev->clipped_freq = cpufreq_dev->freq_table[0];
|
||||
cpufreq_dev->cool_dev = cool_dev;
|
||||
|
||||
mutex_lock(&cooling_cpufreq_lock);
|
||||
|
||||
mutex_lock(&cooling_list_lock);
|
||||
list_add(&cpufreq_dev->node, &cpufreq_dev_list);
|
||||
mutex_unlock(&cooling_list_lock);
|
||||
|
||||
/* Register the notifier for first cpufreq cooling device */
|
||||
if (!cpufreq_dev_count++)
|
||||
cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
mutex_unlock(&cooling_cpufreq_lock);
|
||||
mutex_unlock(&cooling_list_lock);
|
||||
|
||||
goto put_policy;
|
||||
|
||||
remove_idr:
|
||||
release_idr(&cpufreq_idr, cpufreq_dev->id);
|
||||
remove_ida:
|
||||
ida_simple_remove(&cpufreq_ida, cpufreq_dev->id);
|
||||
free_power_table:
|
||||
kfree(cpufreq_dev->dyn_power_table);
|
||||
free_table:
|
||||
|
@ -1072,20 +1034,17 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
|||
|
||||
cpufreq_dev = cdev->devdata;
|
||||
|
||||
mutex_lock(&cooling_list_lock);
|
||||
/* Unregister the notifier for the last cpufreq cooling device */
|
||||
mutex_lock(&cooling_cpufreq_lock);
|
||||
if (!--cpufreq_dev_count)
|
||||
cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
|
||||
mutex_lock(&cooling_list_lock);
|
||||
list_del(&cpufreq_dev->node);
|
||||
mutex_unlock(&cooling_list_lock);
|
||||
|
||||
mutex_unlock(&cooling_cpufreq_lock);
|
||||
|
||||
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->time_in_idle_timestamp);
|
||||
kfree(cpufreq_dev->time_in_idle);
|
||||
|
|
|
@ -21,14 +21,14 @@
|
|||
#include <linux/devfreq.h>
|
||||
#include <linux/devfreq_cooling.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
#include <trace/events/thermal.h>
|
||||
|
||||
static DEFINE_MUTEX(devfreq_lock);
|
||||
static DEFINE_IDR(devfreq_idr);
|
||||
static DEFINE_IDA(devfreq_ida);
|
||||
|
||||
/**
|
||||
* struct devfreq_cooling_device - Devfreq cooling device
|
||||
|
@ -57,42 +57,6 @@ struct devfreq_cooling_device {
|
|||
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
|
||||
* @dfc: Pointer to devfreq we are operating on
|
||||
|
@ -496,9 +460,10 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
|
|||
if (err)
|
||||
goto free_dfc;
|
||||
|
||||
err = get_idr(&devfreq_idr, &dfc->id);
|
||||
if (err)
|
||||
err = ida_simple_get(&devfreq_ida, 0, 0, GFP_KERNEL);
|
||||
if (err < 0)
|
||||
goto free_tables;
|
||||
dfc->id = err;
|
||||
|
||||
snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id);
|
||||
|
||||
|
@ -509,15 +474,15 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
|
|||
dev_err(df->dev.parent,
|
||||
"Failed to register devfreq cooling device (%d)\n",
|
||||
err);
|
||||
goto release_idr;
|
||||
goto release_ida;
|
||||
}
|
||||
|
||||
dfc->cdev = cdev;
|
||||
|
||||
return cdev;
|
||||
|
||||
release_idr:
|
||||
release_idr(&devfreq_idr, dfc->id);
|
||||
release_ida:
|
||||
ida_simple_remove(&devfreq_ida, dfc->id);
|
||||
free_tables:
|
||||
kfree(dfc->power_table);
|
||||
kfree(dfc->freq_table);
|
||||
|
@ -565,7 +530,7 @@ void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
|||
dfc = cdev->devdata;
|
||||
|
||||
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->freq_table);
|
||||
|
||||
|
|
|
@ -489,6 +489,10 @@ static int imx_thermal_probe(struct platform_device *pdev)
|
|||
data->tempmon = map;
|
||||
|
||||
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 */
|
||||
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 tsc_last;
|
||||
static unsigned long jiffies_last;
|
||||
|
||||
u64 msr_now;
|
||||
unsigned long jiffies_now;
|
||||
u64 tsc_now;
|
||||
u64 val64;
|
||||
|
||||
msr_now = pkg_state_counter();
|
||||
tsc_now = rdtsc();
|
||||
jiffies_now = jiffies;
|
||||
|
||||
/* calculate pkg cstate vs tsc ratio */
|
||||
if (!msr_last || !tsc_last)
|
||||
|
@ -485,7 +482,6 @@ static void poll_pkg_cstate(struct work_struct *dummy)
|
|||
|
||||
/* update record */
|
||||
msr_last = msr_now;
|
||||
jiffies_last = jiffies_now;
|
||||
tsc_last = tsc_now;
|
||||
|
||||
if (true == clamping)
|
||||
|
|
|
@ -183,37 +183,37 @@ struct mtk_thermal {
|
|||
};
|
||||
|
||||
/* 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_TS4 },
|
||||
{ MT8173_TS1, MT8173_TS2, MT8173_TSABB },
|
||||
{ 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
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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 */
|
||||
const int mt2701_bank_data[MT2701_NUM_SENSORS] = {
|
||||
static const int mt2701_bank_data[MT2701_NUM_SENSORS] = {
|
||||
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
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
||||
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);
|
||||
return 0;
|
||||
|
|
|
@ -70,7 +70,6 @@ struct exynos_tmu_platform_data {
|
|||
|
||||
enum soc_type type;
|
||||
u32 cal_type;
|
||||
u32 cal_mode;
|
||||
};
|
||||
|
||||
#endif /* _EXYNOS_TMU_H */
|
||||
|
|
|
@ -36,9 +36,8 @@ MODULE_AUTHOR("Zhang Rui");
|
|||
MODULE_DESCRIPTION("Generic thermal management sysfs support");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static DEFINE_IDR(thermal_tz_idr);
|
||||
static DEFINE_IDR(thermal_cdev_idr);
|
||||
static DEFINE_MUTEX(thermal_idr_lock);
|
||||
static DEFINE_IDA(thermal_tz_ida);
|
||||
static DEFINE_IDA(thermal_cdev_ida);
|
||||
|
||||
static LIST_HEAD(thermal_tz_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,
|
||||
* 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
|
||||
|
@ -685,15 +661,16 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
|
|||
dev->target = THERMAL_NO_TARGET;
|
||||
dev->weight = weight;
|
||||
|
||||
result = get_idr(&tz->idr, &tz->lock, &dev->id);
|
||||
if (result)
|
||||
result = ida_simple_get(&tz->ida, 0, 0, GFP_KERNEL);
|
||||
if (result < 0)
|
||||
goto free_mem;
|
||||
|
||||
dev->id = result;
|
||||
sprintf(dev->name, "cdev%d", dev->id);
|
||||
result =
|
||||
sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
|
||||
if (result)
|
||||
goto release_idr;
|
||||
goto release_ida;
|
||||
|
||||
sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
|
||||
sysfs_attr_init(&dev->attr.attr);
|
||||
|
@ -737,8 +714,8 @@ remove_trip_file:
|
|||
device_remove_file(&tz->device, &dev->attr);
|
||||
remove_symbol_link:
|
||||
sysfs_remove_link(&tz->device.kobj, dev->name);
|
||||
release_idr:
|
||||
release_idr(&tz->idr, &tz->lock, dev->id);
|
||||
release_ida:
|
||||
ida_simple_remove(&tz->ida, dev->id);
|
||||
free_mem:
|
||||
kfree(dev);
|
||||
return result;
|
||||
|
@ -785,7 +762,7 @@ unbind:
|
|||
device_remove_file(&tz->device, &pos->weight_attr);
|
||||
device_remove_file(&tz->device, &pos->attr);
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
@ -925,12 +902,13 @@ __thermal_cooling_device_register(struct device_node *np,
|
|||
if (!cdev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
|
||||
if (result) {
|
||||
result = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL);
|
||||
if (result < 0) {
|
||||
kfree(cdev);
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
||||
cdev->id = result;
|
||||
strlcpy(cdev->type, type ? : "", sizeof(cdev->type));
|
||||
mutex_init(&cdev->lock);
|
||||
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);
|
||||
result = device_register(&cdev->device);
|
||||
if (result) {
|
||||
release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
|
||||
ida_simple_remove(&thermal_cdev_ida, cdev->id);
|
||||
kfree(cdev);
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
@ -1070,7 +1048,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
|
|||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
||||
INIT_LIST_HEAD(&tz->thermal_instances);
|
||||
idr_init(&tz->idr);
|
||||
ida_init(&tz->ida);
|
||||
mutex_init(&tz->lock);
|
||||
result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
|
||||
if (result) {
|
||||
result = ida_simple_get(&thermal_tz_ida, 0, 0, GFP_KERNEL);
|
||||
if (result < 0) {
|
||||
kfree(tz);
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
||||
tz->id = result;
|
||||
strlcpy(tz->type, type, sizeof(tz->type));
|
||||
tz->ops = ops;
|
||||
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);
|
||||
result = device_register(&tz->device);
|
||||
if (result) {
|
||||
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
|
||||
ida_simple_remove(&thermal_tz_ida, tz->id);
|
||||
kfree(tz);
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
@ -1255,7 +1234,7 @@ thermal_zone_device_register(const char *type, int trips, int mask,
|
|||
return tz;
|
||||
|
||||
unregister:
|
||||
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
|
||||
ida_simple_remove(&thermal_tz_ida, tz->id);
|
||||
device_unregister(&tz->device);
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
@ -1313,8 +1292,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
|
|||
thermal_set_governor(tz, NULL);
|
||||
|
||||
thermal_remove_hwmon_sysfs(tz);
|
||||
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
|
||||
idr_destroy(&tz->idr);
|
||||
ida_simple_remove(&thermal_tz_ida, tz->id);
|
||||
ida_destroy(&tz->ida);
|
||||
mutex_destroy(&tz->lock);
|
||||
device_unregister(&tz->device);
|
||||
}
|
||||
|
@ -1514,9 +1493,8 @@ unregister_class:
|
|||
unregister_governors:
|
||||
thermal_unregister_governors();
|
||||
error:
|
||||
idr_destroy(&thermal_tz_idr);
|
||||
idr_destroy(&thermal_cdev_idr);
|
||||
mutex_destroy(&thermal_idr_lock);
|
||||
ida_destroy(&thermal_tz_ida);
|
||||
ida_destroy(&thermal_cdev_ida);
|
||||
mutex_destroy(&thermal_list_lock);
|
||||
mutex_destroy(&thermal_governor_lock);
|
||||
return result;
|
||||
|
@ -1529,9 +1507,8 @@ static void __exit thermal_exit(void)
|
|||
genetlink_exit();
|
||||
class_unregister(&thermal_class);
|
||||
thermal_unregister_governors();
|
||||
idr_destroy(&thermal_tz_idr);
|
||||
idr_destroy(&thermal_cdev_idr);
|
||||
mutex_destroy(&thermal_idr_lock);
|
||||
ida_destroy(&thermal_tz_ida);
|
||||
ida_destroy(&thermal_cdev_ida);
|
||||
mutex_destroy(&thermal_list_lock);
|
||||
mutex_destroy(&thermal_governor_lock);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ config TI_SOC_THERMAL
|
|||
config TI_THERMAL
|
||||
bool "Texas Instruments SoCs thermal framework support"
|
||||
depends on TI_SOC_THERMAL
|
||||
depends on CPU_THERMAL
|
||||
help
|
||||
If you say yes here you want to get support for generic thermal
|
||||
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_TEMP_SENSOR_CORE_OFFSET 0x154
|
||||
#define DRA752_BANDGAP_THRESHOLD_CORE_OFFSET 0x1ac
|
||||
#define DRA752_BANDGAP_TSHUT_CORE_OFFSET 0x1b8
|
||||
#define DRA752_BANDGAP_CUMUL_DTEMP_CORE_OFFSET 0x1c4
|
||||
#define DRA752_DTEMP_CORE_0_OFFSET 0x208
|
||||
#define DRA752_DTEMP_CORE_1_OFFSET 0x20c
|
||||
|
@ -66,7 +65,6 @@
|
|||
#define DRA752_STD_FUSE_OPP_BGAP_IVA_OFFSET 0x388
|
||||
#define DRA752_TEMP_SENSOR_IVA_OFFSET 0x398
|
||||
#define DRA752_BANDGAP_THRESHOLD_IVA_OFFSET 0x3a4
|
||||
#define DRA752_BANDGAP_TSHUT_IVA_OFFSET 0x3ac
|
||||
#define DRA752_BANDGAP_CUMUL_DTEMP_IVA_OFFSET 0x3b4
|
||||
#define DRA752_DTEMP_IVA_0_OFFSET 0x3d0
|
||||
#define DRA752_DTEMP_IVA_1_OFFSET 0x3d4
|
||||
|
@ -78,7 +76,6 @@
|
|||
#define DRA752_STD_FUSE_OPP_BGAP_MPU_OFFSET 0x4
|
||||
#define DRA752_TEMP_SENSOR_MPU_OFFSET 0x14c
|
||||
#define DRA752_BANDGAP_THRESHOLD_MPU_OFFSET 0x1a4
|
||||
#define DRA752_BANDGAP_TSHUT_MPU_OFFSET 0x1b0
|
||||
#define DRA752_BANDGAP_CUMUL_DTEMP_MPU_OFFSET 0x1bc
|
||||
#define DRA752_DTEMP_MPU_0_OFFSET 0x1e0
|
||||
#define DRA752_DTEMP_MPU_1_OFFSET 0x1e4
|
||||
|
@ -90,7 +87,6 @@
|
|||
#define DRA752_STD_FUSE_OPP_BGAP_DSPEVE_OFFSET 0x384
|
||||
#define DRA752_TEMP_SENSOR_DSPEVE_OFFSET 0x394
|
||||
#define DRA752_BANDGAP_THRESHOLD_DSPEVE_OFFSET 0x3a0
|
||||
#define DRA752_BANDGAP_TSHUT_DSPEVE_OFFSET 0x3a8
|
||||
#define DRA752_BANDGAP_CUMUL_DTEMP_DSPEVE_OFFSET 0x3b0
|
||||
#define DRA752_DTEMP_DSPEVE_0_OFFSET 0x3bc
|
||||
#define DRA752_DTEMP_DSPEVE_1_OFFSET 0x3c0
|
||||
|
@ -102,7 +98,6 @@
|
|||
#define DRA752_STD_FUSE_OPP_BGAP_GPU_OFFSET 0x0
|
||||
#define DRA752_TEMP_SENSOR_GPU_OFFSET 0x150
|
||||
#define DRA752_BANDGAP_THRESHOLD_GPU_OFFSET 0x1a8
|
||||
#define DRA752_BANDGAP_TSHUT_GPU_OFFSET 0x1b4
|
||||
#define DRA752_BANDGAP_CUMUL_DTEMP_GPU_OFFSET 0x1c0
|
||||
#define DRA752_DTEMP_GPU_0_OFFSET 0x1f4
|
||||
#define DRA752_DTEMP_GPU_1_OFFSET 0x1f8
|
||||
|
@ -173,10 +168,6 @@
|
|||
#define DRA752_BANDGAP_THRESHOLD_HOT_MASK (0x3ff << 16)
|
||||
#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 */
|
||||
#define DRA752_BANDGAP_CUMUL_DTEMP_CORE_MASK (0xffffffff << 0)
|
||||
|
@ -216,8 +207,6 @@
|
|||
#define DRA752_GPU_MAX_TEMP 125000
|
||||
#define DRA752_GPU_HYST_VAL 5000
|
||||
/* interrupts thresholds */
|
||||
#define DRA752_GPU_TSHUT_HOT 915
|
||||
#define DRA752_GPU_TSHUT_COLD 900
|
||||
#define DRA752_GPU_T_HOT 800
|
||||
#define DRA752_GPU_T_COLD 795
|
||||
|
||||
|
@ -230,8 +219,6 @@
|
|||
#define DRA752_MPU_MAX_TEMP 125000
|
||||
#define DRA752_MPU_HYST_VAL 5000
|
||||
/* interrupts thresholds */
|
||||
#define DRA752_MPU_TSHUT_HOT 915
|
||||
#define DRA752_MPU_TSHUT_COLD 900
|
||||
#define DRA752_MPU_T_HOT 800
|
||||
#define DRA752_MPU_T_COLD 795
|
||||
|
||||
|
@ -244,8 +231,6 @@
|
|||
#define DRA752_CORE_MAX_TEMP 125000
|
||||
#define DRA752_CORE_HYST_VAL 5000
|
||||
/* interrupts thresholds */
|
||||
#define DRA752_CORE_TSHUT_HOT 915
|
||||
#define DRA752_CORE_TSHUT_COLD 900
|
||||
#define DRA752_CORE_T_HOT 800
|
||||
#define DRA752_CORE_T_COLD 795
|
||||
|
||||
|
@ -258,8 +243,6 @@
|
|||
#define DRA752_DSPEVE_MAX_TEMP 125000
|
||||
#define DRA752_DSPEVE_HYST_VAL 5000
|
||||
/* interrupts thresholds */
|
||||
#define DRA752_DSPEVE_TSHUT_HOT 915
|
||||
#define DRA752_DSPEVE_TSHUT_COLD 900
|
||||
#define DRA752_DSPEVE_T_HOT 800
|
||||
#define DRA752_DSPEVE_T_COLD 795
|
||||
|
||||
|
@ -272,8 +255,6 @@
|
|||
#define DRA752_IVA_MAX_TEMP 125000
|
||||
#define DRA752_IVA_HYST_VAL 5000
|
||||
/* interrupts thresholds */
|
||||
#define DRA752_IVA_TSHUT_HOT 915
|
||||
#define DRA752_IVA_TSHUT_COLD 900
|
||||
#define DRA752_IVA_T_HOT 800
|
||||
#define DRA752_IVA_T_COLD 795
|
||||
|
||||
|
|
|
@ -49,9 +49,6 @@ dra752_core_temp_sensor_registers = {
|
|||
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_CORE_OFFSET,
|
||||
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_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,
|
||||
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_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,
|
||||
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_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,
|
||||
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_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,
|
||||
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_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,
|
||||
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_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,
|
||||
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_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,
|
||||
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_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,
|
||||
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_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,
|
||||
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_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 */
|
||||
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_cold = DRA752_MPU_T_COLD,
|
||||
.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 */
|
||||
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_cold = DRA752_GPU_T_COLD,
|
||||
.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 */
|
||||
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_cold = DRA752_CORE_T_COLD,
|
||||
.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 */
|
||||
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_cold = DRA752_DSPEVE_T_COLD,
|
||||
.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 */
|
||||
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_cold = DRA752_IVA_T_COLD,
|
||||
.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 */
|
||||
const struct ti_bandgap_data dra752_data = {
|
||||
.features = TI_BANDGAP_FEATURE_TSHUT_CONFIG |
|
||||
TI_BANDGAP_FEATURE_FREEZE_BIT |
|
||||
.features = TI_BANDGAP_FEATURE_FREEZE_BIT |
|
||||
TI_BANDGAP_FEATURE_TALERT |
|
||||
TI_BANDGAP_FEATURE_COUNTER_DELAY |
|
||||
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_data: private pointer for governor data
|
||||
* @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
|
||||
* @lock: lock to protect thermal_instances list
|
||||
* @node: node in thermal_tz_list (in thermal_core.c)
|
||||
|
@ -227,7 +227,7 @@ struct thermal_zone_device {
|
|||
struct thermal_governor *governor;
|
||||
void *governor_data;
|
||||
struct list_head thermal_instances;
|
||||
struct idr idr;
|
||||
struct ida ida;
|
||||
struct mutex lock;
|
||||
struct list_head node;
|
||||
struct delayed_work poll_queue;
|
||||
|
|
Загрузка…
Ссылка в новой задаче