summaryrefslogtreecommitdiff
path: root/drivers/thermal
diff options
context:
space:
mode:
authorBai Ping <b51503@freescale.com>2015-09-22 21:46:59 +0800
committerJason Liu <jason.hui.liu@nxp.com>2019-02-12 10:23:16 +0800
commitaa83ecb07666e72980a50d04e5f2a5b9faebadc9 (patch)
tree9287aeae1c9923d34b4f0133bdc3a200df17a1a1 /drivers/thermal
parentc3f776f0f7b3cc533e7bfd0247a5cae19ed853e2 (diff)
MLK-11600 thermal: imx: notify thermal driver in low_bus_freq_mode
As thermal sensor alarm function needs PLL3 to be always on, but low power idle needs all PLLs to be off, they are exclusive. Low power idle is only enabled when system staying at low bus mode which means the overall system power consumption is NOT high, thermal alarm function can be disabled in this mode to allow low power idle to be entered, and thermal sensor will still use polling mechanism to monitor the system temperature. Add busfreq notify to achieve this goal. (this patch is copied from commit dd3d1e6c6ff0) Also unregister the busfreq_notifier when the thermal driver is removed. Signed-off-by: Bai Ping <ping.bai@nxp.com>
Diffstat (limited to 'drivers/thermal')
-rw-r--r--drivers/thermal/imx_thermal.c68
1 files changed, 66 insertions, 2 deletions
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index cb5b78cb6afa..91acd0edf500 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -1,12 +1,12 @@
/*
- * Copyright 2013-2015 Freescale Semiconductor, Inc.
+ * Copyright 2013-2016 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
-
+#include <linux/busfreq-imx.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/cpu_cooling.h>
@@ -231,10 +231,13 @@ struct imx_thermal_data {
bool irq_enabled;
int irq;
struct clk *thermal_clk;
+ struct mutex mutex;
const struct thermal_soc_data *socdata;
const char *temp_grade;
};
+static struct imx_thermal_data *imx_thermal_data;
+
static void imx_set_panic_temp(struct imx_thermal_data *data,
int panic_temp)
{
@@ -282,6 +285,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
bool wait;
u32 val;
+ mutex_lock(&data->mutex);
if (data->mode == THERMAL_DEVICE_ENABLED) {
/* Check if a measurement is currently in progress */
regmap_read(map, soc_data->temp_data, &val);
@@ -292,6 +296,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
* temperature sensor, enable measurements, take a reading,
* disable measurements, power off the temperature sensor.
*/
+ clk_prepare_enable(data->thermal_clk);
regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
soc_data->power_down_mask);
regmap_write(map, soc_data->sensor_ctrl + REG_SET,
@@ -323,11 +328,13 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
soc_data->measure_temp_mask);
regmap_write(map, soc_data->sensor_ctrl + REG_SET,
soc_data->power_down_mask);
+ clk_disable_unprepare(data->thermal_clk);
}
if (data->socdata->version != TEMPMON_IMX7 &&
((val & soc_data->temp_valid_mask) == 0)) {
dev_dbg(&tz->device, "temp measurement never finished\n");
+ mutex_unlock(&data->mutex);
return -EAGAIN;
}
@@ -362,6 +369,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
data->irq_enabled = true;
enable_irq(data->irq);
}
+ mutex_unlock(&data->mutex);
return 0;
}
@@ -681,6 +689,52 @@ static const struct of_device_id of_imx_thermal_match[] = {
};
MODULE_DEVICE_TABLE(of, of_imx_thermal_match);
+static int thermal_notifier_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ const struct thermal_soc_data *soc_data = imx_thermal_data->socdata;
+ struct regmap *map = imx_thermal_data->tempmon;
+
+ mutex_lock(&imx_thermal_data->mutex);
+
+ switch (event) {
+ /*
+ * In low_bus_freq_mode, the thermal sensor auto measurement
+ * can be disabled to low the power consumption.
+ */
+ case LOW_BUSFREQ_ENTER:
+ regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
+ soc_data->measure_temp_mask);
+ regmap_write(map, soc_data->sensor_ctrl + REG_SET,
+ soc_data->power_down_mask);
+ imx_thermal_data->mode = THERMAL_DEVICE_DISABLED;
+ disable_irq(imx_thermal_data->irq);
+ clk_disable_unprepare(imx_thermal_data->thermal_clk);
+ break;
+
+ /* Enabled thermal auto measurement when exiting low_bus_freq_mode */
+ case LOW_BUSFREQ_EXIT:
+ clk_prepare_enable(imx_thermal_data->thermal_clk);
+ regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
+ soc_data->power_down_mask);
+ regmap_write(map, soc_data->sensor_ctrl + REG_SET,
+ soc_data->measure_temp_mask);
+ imx_thermal_data->mode = THERMAL_DEVICE_ENABLED;
+ enable_irq(imx_thermal_data->irq);
+ break;
+
+ default:
+ break;
+ }
+ mutex_unlock(&imx_thermal_data->mutex);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block thermal_notifier = {
+ .notifier_call = thermal_notifier_event,
+};
+
static int imx_thermal_probe(struct platform_device *pdev)
{
struct imx_thermal_data *data;
@@ -691,6 +745,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
+ imx_thermal_data = data;
map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "fsl,tempmon");
if (IS_ERR(map)) {
@@ -797,6 +852,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
return ret;
}
+ mutex_init(&data->mutex);
data->tz = thermal_zone_device_register("imx_thermal_zone",
IMX_TRIP_NUM,
BIT(IMX_TRIP_PASSIVE), data,
@@ -851,6 +907,10 @@ static int imx_thermal_probe(struct platform_device *pdev)
return ret;
}
+ /* register the busfreq notifier called in low bus freq */
+ if (data->socdata->version != TEMPMON_IMX7)
+ register_busfreq_notifier(&thermal_notifier);
+
return 0;
}
@@ -865,6 +925,10 @@ static int imx_thermal_remove(struct platform_device *pdev)
if (!IS_ERR(data->thermal_clk))
clk_disable_unprepare(data->thermal_clk);
+ /* unregister the busfreq notifier called in low bus freq */
+ if (data->socdata->version != TEMPMON_IMX7)
+ unregister_busfreq_notifier(&thermal_notifier);
+
thermal_zone_device_unregister(data->tz);
cpufreq_cooling_unregister(data->cdev[0]);
devfreq_cooling_unregister(data->cdev[1]);