summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorBai Ping <b51503@freescale.com>2015-09-22 21:46:59 +0800
committerNitin Garg <nitin.garg@nxp.com>2016-01-14 11:01:37 -0600
commit128a269b183441b4fe89ba82e99084011921c047 (patch)
tree20ad7363626398eb09dc39a63124d79d67bfc554 /drivers
parent57271271368b16aee295d8f9bb56371cae9fa3e9 (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) Signed-off-by: Bai Ping <b51503@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/thermal/imx_thermal.c63
1 files changed, 61 insertions, 2 deletions
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 1de711737afa..24678dcfc2d4 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -6,7 +6,7 @@
* published by the Free Software Foundation.
*
*/
-
+#include <linux/busfreq-imx.h>
#include <linux/clk.h>
#include <linux/cpu_cooling.h>
#include <linux/delay.h>
@@ -229,9 +229,12 @@ struct imx_thermal_data {
bool irq_enabled;
int irq;
struct clk *thermal_clk;
+ struct mutex mutex;
const struct thermal_soc_data *socdata;
};
+static struct imx_thermal_data *imx_thermal_data;
+
static void imx_set_panic_temp(struct imx_thermal_data *data,
signed long panic_temp)
{
@@ -279,6 +282,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *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);
@@ -289,6 +293,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *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,
@@ -320,11 +325,13 @@ static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *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;
}
@@ -359,6 +366,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp)
data->irq_enabled = true;
enable_irq(data->irq);
}
+ mutex_unlock(&data->mutex);
return 0;
}
@@ -654,6 +662,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)
{
const struct of_device_id *of_id =
@@ -666,6 +720,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)) {
@@ -693,7 +748,6 @@ static int imx_thermal_probe(struct platform_device *pdev)
if (data->irq < 0)
return data->irq;
-
platform_set_drvdata(pdev, data);
ret = imx_get_sensor_data(pdev);
@@ -761,6 +815,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,
@@ -804,6 +859,10 @@ static int imx_thermal_probe(struct platform_device *pdev)
data->irq_enabled = true;
data->mode = THERMAL_DEVICE_ENABLED;
+ /* register the busfreq notifier called in low bus freq */
+ if (data->socdata->version != TEMPMON_IMX7)
+ register_busfreq_notifier(&thermal_notifier);
+
return 0;
}