aboutsummaryrefslogtreecommitdiff
path: root/drivers/thermal/imx_thermal.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-01-24 17:13:49 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-24 17:13:49 -0800
commit91466574be1a3701fab4abf5ac1539b556575a81 (patch)
tree89373ef6b0c9e024a9688207b832552dfbcca666 /drivers/thermal/imx_thermal.c
parent09da8dfa98682d871987145ed11e3232accac860 (diff)
parentc698a4492f01127ca90fc28cd5157f3d616fe4ff (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
Pull thermal management updates from Zhang Rui: "This time, the biggest change is the work of representing hardware thermal properties in device tree infrastructure. This work includes the introduction of a device tree bindings for describing the hardware thermal behavior and limits, and also a parser to read and interpret the data, and build thermal zones and thermal binding parameters. It also contains three examples on how to use the new representation on sensor devices, using three different drivers to accomplish it. One driver is in thermal subsystem, the TI SoC thermal, and the other two drivers are in hwmon subsystem. Actually, this would be the first step of the complete work because we still need to check other potential drivers to be converted and then validate the proposed API. But the reason why I include it in this pull request is that, first, this change does not hurt any others without using this approach, second, the principle and concept of this change would not break after converting the remaining drivers. BTW, as you can see, there are several points in this change that do not belong to thermal subsystem. Because it has been suggested by Guenter R that in such cases, it is recommended to send the complete series via one single subsystem. Specifics: - representing hardware thermal properties in device tree infrastructure - fix a regression that the imx thermal driver breaks system suspend. - introduce ACPI INT3403 thermal driver to retrieve temperature data from the INT3403 ACPI device object present on some systems. - introduce debug statement for thermal core and step_wise governor. - assorted fixes and cleanups for thermal core, cpu cooling, exynos thrmal, intel powerclamp and imx thermal driver" * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: (34 commits) thermal: remove const flag from .ops of imx thermal Thermal: update thermal zone device after setting emul_temp intel_powerclamp: Fix cstate counter detection. thermal: imx: add necessary clk operation Thermal cpu cooling: return error if no valid cpu frequency entry thermal: fix cpu_cooling max_level behavior thermal: rcar-thermal: Enable driver compilation with COMPILE_TEST thermal: debug: add debug statement for core and step_wise thermal: imx_thermal: add module device table drivers: thermal: Mark function as static in x86_pkg_temp_thermal.c thermal:samsung: fix compilation warning thermal: imx: correct suspend/resume flow thermal: exynos: fix error return code Thermal: ACPI INT3403 thermal driver MAINTAINERS: add thermal bindings entry in thermal domain arm: dts: make OMAP4460 bandgap node to belong to OCP arm: dts: make OMAP443x bandgap node to belong to OCP arm: dts: add cooling properties on omap5 cpu node arm: dts: add omap5 thermal data arm: dts: add omap5 CORE thermal data ...
Diffstat (limited to 'drivers/thermal/imx_thermal.c')
-rw-r--r--drivers/thermal/imx_thermal.c54
1 files changed, 39 insertions, 15 deletions
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 1d6c801c1eb9..45af765a3198 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -7,6 +7,7 @@
*
*/
+#include <linux/clk.h>
#include <linux/cpu_cooling.h>
#include <linux/cpufreq.h>
#include <linux/delay.h>
@@ -73,6 +74,7 @@ struct imx_thermal_data {
unsigned long last_temp;
bool irq_enabled;
int irq;
+ struct clk *thermal_clk;
};
static void imx_set_alarm_temp(struct imx_thermal_data *data,
@@ -284,7 +286,7 @@ static int imx_unbind(struct thermal_zone_device *tz,
return 0;
}
-static const struct thermal_zone_device_ops imx_tz_ops = {
+static struct thermal_zone_device_ops imx_tz_ops = {
.bind = imx_bind,
.unbind = imx_unbind,
.get_temp = imx_get_temp,
@@ -457,6 +459,22 @@ static int imx_thermal_probe(struct platform_device *pdev)
return ret;
}
+ data->thermal_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(data->thermal_clk)) {
+ dev_warn(&pdev->dev, "failed to get thermal clk!\n");
+ } else {
+ /*
+ * Thermal sensor needs clk on to get correct value, normally
+ * we should enable its clk before taking measurement and disable
+ * clk after measurement is done, but if alarm function is enabled,
+ * hardware will auto measure the temperature periodically, so we
+ * need to keep the clk always on for alarm function.
+ */
+ ret = clk_prepare_enable(data->thermal_clk);
+ if (ret)
+ dev_warn(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
+ }
+
/* Enable measurements at ~ 10 Hz */
regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ);
measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */
@@ -478,6 +496,8 @@ static int imx_thermal_remove(struct platform_device *pdev)
/* Disable measurements */
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
+ if (!IS_ERR(data->thermal_clk))
+ clk_disable_unprepare(data->thermal_clk);
thermal_zone_device_unregister(data->tz);
cpufreq_cooling_unregister(data->cdev);
@@ -490,27 +510,30 @@ static int imx_thermal_suspend(struct device *dev)
{
struct imx_thermal_data *data = dev_get_drvdata(dev);
struct regmap *map = data->tempmon;
- u32 val;
- regmap_read(map, TEMPSENSE0, &val);
- if ((val & TEMPSENSE0_POWER_DOWN) == 0) {
- /*
- * If a measurement is taking place, wait for a long enough
- * time for it to finish, and then check again. If it still
- * does not finish, something must go wrong.
- */
- udelay(50);
- regmap_read(map, TEMPSENSE0, &val);
- if ((val & TEMPSENSE0_POWER_DOWN) == 0)
- return -ETIMEDOUT;
- }
+ /*
+ * Need to disable thermal sensor, otherwise, when thermal core
+ * try to get temperature before thermal sensor resume, a wrong
+ * temperature will be read as the thermal sensor is powered
+ * down.
+ */
+ regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
+ regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
+ data->mode = THERMAL_DEVICE_DISABLED;
return 0;
}
static int imx_thermal_resume(struct device *dev)
{
- /* Nothing to do for now */
+ struct imx_thermal_data *data = dev_get_drvdata(dev);
+ struct regmap *map = data->tempmon;
+
+ /* Enabled thermal sensor after resume */
+ regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
+ regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
+ data->mode = THERMAL_DEVICE_ENABLED;
+
return 0;
}
#endif
@@ -522,6 +545,7 @@ static const struct of_device_id of_imx_thermal_match[] = {
{ .compatible = "fsl,imx6q-tempmon", },
{ /* end */ }
};
+MODULE_DEVICE_TABLE(of, of_imx_thermal_match);
static struct platform_driver imx_thermal = {
.driver = {