summaryrefslogtreecommitdiffstats
path: root/drivers/thermal
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@s-opensource.com>2017-03-06 10:49:34 +0100
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2017-03-06 10:49:34 +0100
commit700ea5e0e0dd70420a04e703ff264cc133834cba (patch)
treed217b0d90d014953ea10ab7d88809660d2da8a64 /drivers/thermal
parent[media] media: ti-vpe: vpe: allow use of user specified stride (diff)
parentLinux 4.11-rc1 (diff)
downloadlinux-700ea5e0e0dd70420a04e703ff264cc133834cba.tar.xz
linux-700ea5e0e0dd70420a04e703ff264cc133834cba.zip
Merge tag 'v4.11-rc1' into patchwork
Linux 4.11-rc1 * tag 'v4.11-rc1': (10730 commits) Linux 4.11-rc1 strparser: destroy workqueue on module exit Documentation/sphinx: fix primary_domain configuration docs: Fix htmldocs build failure doc/ko_KR/memory-barriers: Update control-dependencies section pcieaer doc: update the link Documentation: Update path to sysrq.txt sfc: fix IPID endianness in TSOv2 sfc: avoid max() in array size rds: remove unnecessary returned value check rxrpc: Fix potential NULL-pointer exception nfp: correct DMA direction in XDP DMA sync nfp: don't tell FW about the reserved buffer space net: ethernet: bgmac: mac address change bug net: ethernet: bgmac: init sequence bug xen-netback: don't vfree() queues under spinlock xen-netback: keep a local pointer for vif in backend_disconnect() netfilter: nf_tables: don't call nfnetlink_set_err() if nfnetlink_send() fails netfilter: nft_set_rbtree: incorrect assumption on lower interval lookups netfilter: nf_conntrack_sip: fix wrong memory initialisation ...
Diffstat (limited to 'drivers/thermal')
-rw-r--r--drivers/thermal/Kconfig17
-rw-r--r--drivers/thermal/Makefile2
-rw-r--r--drivers/thermal/clock_cooling.c50
-rw-r--r--drivers/thermal/cpu_cooling.c113
-rw-r--r--drivers/thermal/devfreq_cooling.c68
-rw-r--r--drivers/thermal/imx_thermal.c4
-rw-r--r--drivers/thermal/intel_powerclamp.c5
-rw-r--r--drivers/thermal/mtk_thermal.c16
-rw-r--r--drivers/thermal/rcar_gen3_thermal.c335
-rw-r--r--drivers/thermal/samsung/exynos_tmu.c1
-rw-r--r--drivers/thermal/samsung/exynos_tmu.h1
-rw-r--r--drivers/thermal/thermal_core.c75
-rw-r--r--drivers/thermal/ti-soc-thermal/Kconfig1
-rw-r--r--drivers/thermal/ti-soc-thermal/dra752-bandgap.h19
-rw-r--r--drivers/thermal/ti-soc-thermal/dra752-thermal-data.c28
-rw-r--r--drivers/thermal/zx2967_thermal.c258
16 files changed, 712 insertions, 281 deletions
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index c2c056cc7ea5..776b34396144 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -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
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 6a3d7b573036..7adae2029355 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -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
diff --git a/drivers/thermal/clock_cooling.c b/drivers/thermal/clock_cooling.c
index ed5dd0e88657..56711c25584d 100644
--- a/drivers/thermal/clock_cooling.c
+++ b/drivers/thermal/clock_cooling.c
@@ -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);
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 9ce0e9eef923..91048eeca28b 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -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 */
/**
@@ -297,8 +261,6 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
if (!power_table)
return -ENOMEM;
- rcu_read_lock();
-
for (freq = 0, i = 0;
opp = dev_pm_opp_find_freq_ceil(dev, &freq), !IS_ERR(opp);
freq++, i++) {
@@ -306,13 +268,13 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
u64 power;
if (i >= num_opps) {
- rcu_read_unlock();
ret = -EAGAIN;
goto free_power_table;
}
freq_mhz = freq / 1000000;
voltage_mv = dev_pm_opp_get_voltage(opp) / 1000;
+ dev_pm_opp_put(opp);
/*
* Do the multiplication with MHz and millivolt so as
@@ -328,8 +290,6 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
power_table[i].power = power;
}
- rcu_read_unlock();
-
if (i != num_opps) {
ret = PTR_ERR(opp);
goto free_power_table;
@@ -433,13 +393,10 @@ static int get_static_power(struct cpufreq_cooling_device *cpufreq_device,
return 0;
}
- rcu_read_lock();
-
opp = dev_pm_opp_find_freq_exact(cpufreq_device->cpu_dev, freq_hz,
true);
voltage = dev_pm_opp_get_voltage(opp);
-
- rcu_read_unlock();
+ dev_pm_opp_put(opp);
if (voltage == 0) {
dev_warn_ratelimited(cpufreq_device->cpu_dev,
@@ -652,31 +609,39 @@ static int cpufreq_state2power(struct thermal_cooling_device *cdev,
unsigned long state, u32 *power)
{
unsigned int freq, num_cpus;
- cpumask_t cpumask;
+ cpumask_var_t cpumask;
u32 static_power, dynamic_power;
int ret;
struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
- cpumask_and(&cpumask, &cpufreq_device->allowed_cpus, cpu_online_mask);
- num_cpus = cpumask_weight(&cpumask);
+ if (!alloc_cpumask_var(&cpumask, GFP_KERNEL))
+ 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 */
if (num_cpus == 0) {
*power = 0;
- return 0;
+ ret = 0;
+ goto out;
}
freq = cpufreq_device->freq_table[state];
- if (!freq)
- return -EINVAL;
+ if (!freq) {
+ ret = -EINVAL;
+ goto out;
+ }
dynamic_power = cpu_freq_to_power(cpufreq_device, freq) * num_cpus;
ret = get_static_power(cpufreq_device, tz, freq, &static_power);
if (ret)
- return ret;
+ goto out;
*power = static_power + dynamic_power;
- return 0;
+out:
+ free_cpumask_var(cpumask);
+ return ret;
}
/**
@@ -802,16 +767,20 @@ __cpufreq_cooling_register(struct device_node *np,
struct cpufreq_cooling_device *cpufreq_dev;
char dev_name[THERMAL_NAME_LENGTH];
struct cpufreq_frequency_table *pos, *table;
- struct cpumask temp_mask;
+ cpumask_var_t temp_mask;
unsigned int freq, i, num_cpus;
int ret;
struct thermal_cooling_device_ops *cooling_ops;
- cpumask_and(&temp_mask, clip_cpus, cpu_online_mask);
- policy = cpufreq_cpu_get(cpumask_first(&temp_mask));
+ if (!alloc_cpumask_var(&temp_mask, GFP_KERNEL))
+ return ERR_PTR(-ENOMEM);
+
+ cpumask_and(temp_mask, clip_cpus, cpu_online_mask);
+ policy = cpufreq_cpu_get(cpumask_first(temp_mask));
if (!policy) {
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;
@@ -874,11 +843,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++) {
@@ -898,27 +868,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:
@@ -931,7 +898,8 @@ free_cdev:
kfree(cpufreq_dev);
put_policy:
cpufreq_cpu_put(policy);
-
+free_cpumask:
+ free_cpumask_var(temp_mask);
return cool_dev;
}
@@ -1059,20 +1027,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);
diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c
index 5a737fd5f1aa..7743a78d4723 100644
--- a/drivers/thermal/devfreq_cooling.c
+++ b/drivers/thermal/devfreq_cooling.c
@@ -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
@@ -58,42 +58,6 @@ struct devfreq_cooling_device {
};
/**
- * 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
* @cdev_state: cooling device state we're setting
@@ -113,15 +77,15 @@ static int partition_enable_opps(struct devfreq_cooling_device *dfc,
unsigned int freq = dfc->freq_table[i];
bool want_enable = i >= cdev_state ? true : false;
- rcu_read_lock();
opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable);
- rcu_read_unlock();
if (PTR_ERR(opp) == -ERANGE)
continue;
else if (IS_ERR(opp))
return PTR_ERR(opp);
+ dev_pm_opp_put(opp);
+
if (want_enable)
ret = dev_pm_opp_enable(dev, freq);
else
@@ -221,15 +185,12 @@ get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq)
if (!dfc->power_ops->get_static_power)
return 0;
- rcu_read_lock();
-
opp = dev_pm_opp_find_freq_exact(dev, freq, true);
if (IS_ERR(opp) && (PTR_ERR(opp) == -ERANGE))
opp = dev_pm_opp_find_freq_exact(dev, freq, false);
voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */
-
- rcu_read_unlock();
+ dev_pm_opp_put(opp);
if (voltage == 0) {
dev_warn_ratelimited(dev,
@@ -412,18 +373,14 @@ static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc)
unsigned long power_dyn, voltage;
struct dev_pm_opp *opp;
- rcu_read_lock();
-
opp = dev_pm_opp_find_freq_floor(dev, &freq);
if (IS_ERR(opp)) {
- rcu_read_unlock();
ret = PTR_ERR(opp);
goto free_tables;
}
voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */
-
- rcu_read_unlock();
+ dev_pm_opp_put(opp);
if (dfc->power_ops) {
power_dyn = get_dynamic_power(dfc, freq, voltage);
@@ -496,9 +453,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 +467,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 +523,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);
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 06912f0602b7..fb648a45754e 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -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) {
diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c
index df64692e9e64..d718cd179ddb 100644
--- a/drivers/thermal/intel_powerclamp.c
+++ b/drivers/thermal/intel_powerclamp.c
@@ -50,6 +50,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/sched/rt.h>
+#include <uapi/linux/sched/types.h>
#include <asm/nmi.h>
#include <asm/msr.h>
@@ -461,16 +462,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 +483,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)
diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c
index 34169c32d495..1aff7fde54b1 100644
--- a/drivers/thermal/mtk_thermal.c
+++ b/drivers/thermal/mtk_thermal.c
@@ -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
diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c
new file mode 100644
index 000000000000..d33c845244b1
--- /dev/null
+++ b/drivers/thermal/rcar_gen3_thermal.c
@@ -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>");
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index ad1186dd6132..7b8ef09d2b3c 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -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;
diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
index 440c7140b660..5149c2a3030c 100644
--- a/drivers/thermal/samsung/exynos_tmu.h
+++ b/drivers/thermal/samsung/exynos_tmu.h
@@ -70,7 +70,6 @@ struct exynos_tmu_platform_data {
enum soc_type type;
u32 cal_type;
- u32 cal_mode;
};
#endif /* _EXYNOS_TMU_H */
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 655591316a88..11f0675cb7e5 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -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);
}
diff --git a/drivers/thermal/ti-soc-thermal/Kconfig b/drivers/thermal/ti-soc-thermal/Kconfig
index ea8283f08aa6..fe0e877f84d0 100644
--- a/drivers/thermal/ti-soc-thermal/Kconfig
+++ b/drivers/thermal/ti-soc-thermal/Kconfig
@@ -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.
diff --git a/drivers/thermal/ti-soc-thermal/dra752-bandgap.h b/drivers/thermal/ti-soc-thermal/dra752-bandgap.h
index 6b0f2b1160f7..a31e4b5e82cd 100644
--- a/drivers/thermal/ti-soc-thermal/dra752-bandgap.h
+++ b/drivers/thermal/ti-soc-thermal/dra752-bandgap.h
@@ -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
diff --git a/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c b/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c
index 58b5c6694cd4..118d7d847715 100644
--- a/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c
+++ b/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c
@@ -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 |
diff --git a/drivers/thermal/zx2967_thermal.c b/drivers/thermal/zx2967_thermal.c
new file mode 100644
index 000000000000..a5670ad2cfc8
--- /dev/null
+++ b/drivers/thermal/zx2967_thermal.c
@@ -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");