From 7c91850945e9671ad0f7dd148bbcadcb2c7e4e8d Mon Sep 17 00:00:00 2001 From: Hyeonseong Gil Date: Mon, 9 May 2016 15:22:25 +0900 Subject: [PATCH] thermal: exynos: Added cold event. Resolved migration conflicts from kernel 4.9 to 4.14. Change-Id: Ie3397c0359dc0b220ac03f3c552cc1852415f0c2 Signed-off-by: Hyeonseong Gil --- drivers/thermal/cpu_cooling.c | 38 +++++++++++++++ drivers/thermal/samsung/exynos_tmu.c | 72 ++++++++++++++++++++++++++++ include/linux/thermal.h | 1 + 3 files changed, 111 insertions(+) diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 815b6f10d56a..dc35593a0d5b 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -34,6 +34,8 @@ #include +#include + /* * Cooling state <-> CPUFreq frequency * @@ -61,6 +63,10 @@ struct freq_table { u32 power; }; +static BLOCKING_NOTIFIER_HEAD(cpu_notifier); + +static enum tmu_noti_state_t cpu_tstate = TMU_NORMAL; + /** * struct time_in_idle - Idle time stats * @time: previous reading of the absolute time that this cpu was idle @@ -593,6 +599,30 @@ static int cpufreq_power2state(struct thermal_cooling_device *cdev, return 0; } +static int cpufreq_set_cur_temp(struct thermal_cooling_device *cdev, + bool suspended, int temp) +{ + enum tmu_noti_state_t tstate; + unsigned int on; + + if (suspended || temp < EXYNOS_COLD_TEMP) { + tstate = TMU_COLD; + on = 1; + } else { + tstate = TMU_NORMAL; + on = 0; + } + + if (cpu_tstate == tstate) + return 0; + + cpu_tstate = tstate; + + blocking_notifier_call_chain(&cpu_notifier, TMU_COLD, &on); + + return 0; +} + /* Bind cpufreq callbacks to thermal cooling device ops */ static struct thermal_cooling_device_ops cpufreq_cooling_ops = { @@ -615,6 +645,11 @@ static struct notifier_block thermal_cpufreq_notifier_block = { .notifier_call = cpufreq_thermal_notifier, }; +int exynos_tmu_add_notifier(struct notifier_block *n) +{ + return blocking_notifier_chain_register(&cpu_notifier, n); +} + static unsigned int find_next_max(struct cpufreq_frequency_table *table, unsigned int prev_max) { @@ -703,6 +738,9 @@ __cpufreq_cooling_register(struct device_node *np, } cpufreq_cdev->id = ret; + if (cpufreq_cdev->id == 0) + cpufreq_cooling_ops.set_cur_temp = cpufreq_set_cur_temp; + snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", cpufreq_cdev->id); diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 4da916c80e55..03988c90cedd 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "exynos_tmu.h" #include "../thermal_core.h" @@ -94,6 +95,12 @@ #define EXYNOS_TMU_REG_EMUL_CON (0x160) #define MCELSIUS 1000 + +static bool suspended; +static DEFINE_MUTEX (thermal_suspend_lock); + +/* list of multiple instance for each thermal sensor */ +static LIST_HEAD(dtm_dev_list); /** * struct exynos_tmu_data : A structure to hold the private data of the TMU driver @@ -128,6 +135,7 @@ struct exynos_tmu_data { struct thermal_zone_device *tzd; unsigned int ntrip; struct thermal_cooling_device *cool_dev; + struct list_head node; int (*tmu_initialize)(struct platform_device *pdev); void (*tmu_control)(struct platform_device *pdev, bool on); @@ -402,6 +410,7 @@ static void exynos8890_tmu_control(struct platform_device *pdev, bool on) static int exynos_get_temp(void *p, int *temp) { struct exynos_tmu_data *data = p; + struct thermal_cooling_device *cdev; if (!data || !data->tmu_read) return -EINVAL; @@ -412,6 +421,18 @@ static int exynos_get_temp(void *p, int *temp) mutex_unlock(&data->lock); + cdev = data->cool_dev; + + if (!cdev) + return 0; + + mutex_lock(&thermal_suspend_lock); + + if (cdev->ops->set_cur_temp) + cdev->ops->set_cur_temp(cdev, suspended, *temp / 1000); + + mutex_unlock(&thermal_suspend_lock); + return 0; } @@ -525,6 +546,38 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id) return IRQ_HANDLED; } +static int exynos_pm_notifier(struct notifier_block *notifier, + unsigned long event, void *v) +{ + struct exynos_tmu_data *devnode; + struct thermal_cooling_device *cdev; + + switch (event) { + case PM_SUSPEND_PREPARE: + mutex_lock(&thermal_suspend_lock); + suspended = true; + list_for_each_entry(devnode, &dtm_dev_list, node) { + cdev = devnode->cool_dev; + + if (cdev && cdev->ops->set_cur_temp) + cdev->ops->set_cur_temp(cdev, suspended, 0); + } + mutex_unlock(&thermal_suspend_lock); + break; + case PM_POST_SUSPEND: + mutex_lock(&thermal_suspend_lock); + suspended = false; + mutex_unlock(&thermal_suspend_lock); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block exynos_tmu_pm_notifier = { + .notifier_call = exynos_pm_notifier, +}; + static const struct of_device_id exynos_tmu_match[] = { { .compatible = "samsung,exynos8890-tmu", }, { /* sentinel */ }, @@ -725,6 +778,13 @@ static int exynos_tmu_probe(struct platform_device *pdev) exynos_tmu_control(pdev, true); + mutex_lock(&data->lock); + list_add_tail(&data->node, &dtm_dev_list); + mutex_unlock(&data->lock); + + if (list_is_singular(&dtm_dev_list)) + register_pm_notifier(&exynos_tmu_pm_notifier); + if (!IS_ERR(data->tzd)) data->tzd->ops->set_mode(data->tzd, THERMAL_DEVICE_ENABLED); @@ -740,10 +800,22 @@ static int exynos_tmu_remove(struct platform_device *pdev) { struct exynos_tmu_data *data = platform_get_drvdata(pdev); struct thermal_zone_device *tzd = data->tzd; + struct exynos_tmu_data *devnode; + + if (list_is_singular(&dtm_dev_list)) + unregister_pm_notifier(&exynos_tmu_pm_notifier); thermal_zone_of_sensor_unregister(&pdev->dev, tzd); exynos_tmu_control(pdev, false); + mutex_lock(&data->lock); + list_for_each_entry(devnode, &dtm_dev_list, node) { + if (devnode->id == data->id) { + list_del(&devnode->node); + } + } + mutex_unlock(&data->lock); + return 0; } diff --git a/include/linux/thermal.h b/include/linux/thermal.h index fd5b959c753c..905af30d4944 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -140,6 +140,7 @@ struct thermal_cooling_device_ops { struct thermal_zone_device *, unsigned long, u32 *); int (*power2state)(struct thermal_cooling_device *, struct thermal_zone_device *, u32, unsigned long *); + int (*set_cur_temp) (struct thermal_cooling_device *, bool, int); }; struct thermal_cooling_device { -- 2.20.1