diff options
author | Bai Ping <b51503@freescale.com> | 2015-09-22 21:46:59 +0800 |
---|---|---|
committer | Nitin Garg <nitin.garg@nxp.com> | 2016-01-14 11:01:37 -0600 |
commit | 128a269b183441b4fe89ba82e99084011921c047 (patch) | |
tree | 20ad7363626398eb09dc39a63124d79d67bfc554 /drivers | |
parent | 57271271368b16aee295d8f9bb56371cae9fa3e9 (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.c | 63 |
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; } |