diff --git a/Documentation/devicetree/bindings/thermal/imx-thermal.txt b/Documentation/devicetree/bindings/thermal/imx-thermal.txt index 541c25e49abf..1f0f67234a91 100644 --- a/Documentation/devicetree/bindings/thermal/imx-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/imx-thermal.txt @@ -8,10 +8,14 @@ Required properties: calibration data, e.g. OCOTP on imx6q. The details about calibration data can be found in SoC Reference Manual. +Optional properties: +- clocks : thermal sensor's clock source. + Example: tempmon { compatible = "fsl,imx6q-tempmon"; fsl,tempmon = <&anatop>; fsl,tempmon-data = <&ocotp>; + clocks = <&clks 172>; }; diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 77a962f1837b..deab7baeeb72 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -7,6 +7,7 @@ * */ +#include #include #include #include @@ -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, @@ -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); diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index 8f181b3f842b..67b608ef2cb2 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c @@ -206,6 +206,15 @@ static void find_target_mwait(void) } +static bool has_pkg_state_counter(void) +{ + u64 tmp; + return !rdmsrl_safe(MSR_PKG_C2_RESIDENCY, &tmp) || + !rdmsrl_safe(MSR_PKG_C3_RESIDENCY, &tmp) || + !rdmsrl_safe(MSR_PKG_C6_RESIDENCY, &tmp) || + !rdmsrl_safe(MSR_PKG_C7_RESIDENCY, &tmp); +} + static u64 pkg_state_counter(void) { u64 val; @@ -500,7 +509,7 @@ static int start_power_clamp(void) struct task_struct *thread; /* check if pkg cstate counter is completely 0, abort in this case */ - if (!pkg_state_counter()) { + if (!has_pkg_state_counter()) { pr_err("pkg cstate counter not functional, abort\n"); return -EINVAL; } diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index a621e90cbf40..338a88bf6662 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -781,6 +781,9 @@ emul_temp_store(struct device *dev, struct device_attribute *attr, ret = tz->ops->set_emul_temp(tz, temperature); } + if (!ret) + thermal_zone_device_update(tz); + return ret ? ret : count; } static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);