summaryrefslogtreecommitdiff
authorTao Zeng <tao.zeng@amlogic.com>2015-01-15 09:50:05 (GMT)
committer Sandy luo <sandy.luo@amlogic.com>2015-01-15 10:28:10 (GMT)
commitf4fe0e805aaf7207760ed5b5fe53805b729e31da (patch)
tree8ffeb71db7a549e5361fc44438f576864523f4e7
parent0a70e65d4c57cbac3d4235ced0857fe5d51748a2 (diff)
downloadthermal-f4fe0e805aaf7207760ed5b5fe53805b729e31da.zip
thermal-f4fe0e805aaf7207760ed5b5fe53805b729e31da.tar.gz
thermal-f4fe0e805aaf7207760ed5b5fe53805b729e31da.tar.bz2
PD #94468: strip structures realted with kernel to avoid problem of differnet KERNEL CONFIG
Change-Id: I446b5564479589ce284ef87b9ebe47a6d5919576
Diffstat
-rw-r--r--amlogic_thermal.h105
-rw-r--r--amlogic_thermal.o_shipped654
-rwxr-xr-xamlogic_thermal_module.c1053
3 files changed, 1356 insertions, 456 deletions
diff --git a/amlogic_thermal.h b/amlogic_thermal.h
new file mode 100644
index 0000000..a987ee3
--- a/dev/null
+++ b/amlogic_thermal.h
@@ -0,0 +1,105 @@
+
+#ifndef __AMLOGIC_THERMAL_H__
+#define __AMLOGIC_THERMAL_H__
+
+struct record_buf {
+ int idx;
+ int max;
+ unsigned long cool_flag;
+ unsigned int *op;
+};
+
+struct cpu_stat_monitor {
+ unsigned int total_cpu_freq;
+ unsigned int total_gpu_freq;
+ unsigned int total_cpu_cores;
+ unsigned int total_gpu_cores;
+ unsigned int avg_cpu_freq;
+ unsigned int avg_gpu_freq;
+ unsigned int avg_cpu_cores;
+ unsigned int avg_gpu_cores;
+ unsigned int filter_temp;
+};
+
+struct aml_virtual_thermal {
+ unsigned int freq;
+ unsigned int temp_time[4];
+};
+
+struct aml_virtual_thermal_device {
+ int count;
+ struct aml_virtual_thermal *thermal;
+};
+
+struct temp_trip{
+ unsigned int temperature;
+ unsigned int cpu_upper_freq;
+ unsigned int cpu_lower_freq;
+ int cpu_upper_level;
+ int cpu_lower_level;
+ unsigned int gpu_upper_freq;
+ unsigned int gpu_lower_freq;
+ int gpu_upper_level;
+ int gpu_lower_level;
+ int cpu_core_num;
+ int cpu_core_upper;
+ int gpu_core_num;
+ int gpu_core_upper;
+};
+
+struct amlogic_thermal_platform_data {
+ const char *name;
+ struct temp_trip *tmp_trip;
+ unsigned int temp_trip_count;
+ unsigned int current_temp;
+ unsigned int idle_interval;
+ unsigned int trim_flag;
+ unsigned int virtual_thermal_en;
+ unsigned int keep_mode;
+ unsigned int keep_mode_threshold;
+ unsigned int keep_mode_ini_state[4];
+ unsigned int keep_mode_cur_state[4];
+ unsigned int keep_mode_max_state[4];
+ unsigned int keep_mode_max_range[4];
+ unsigned int freq_sample_period;
+ struct record_buf op_buf;
+ struct cpu_stat_monitor monitor;
+ struct thermal_zone_device *therm_dev;
+ struct thermal_cooling_device *cpu_cool_dev;
+ struct thermal_cooling_device *gpu_cool_dev;
+ struct thermal_cooling_device *cpucore_cool_dev;
+ struct thermal_cooling_device *gpucore_cool_dev;
+ enum thermal_device_mode mode;
+ struct mutex lock;
+ struct delayed_work thermal_work;
+};
+
+struct temp_level{
+ unsigned int temperature;
+ int cpu_high_freq;
+ int cpu_low_freq;
+ int gpu_high_freq;
+ int gpu_low_freq;
+ int cpu_core_num;
+ int gpu_core_num;
+};
+
+struct freq_trip_table {
+ unsigned int freq_state;
+};
+
+void *thermal_alloc(size_t len);
+extern int thermal_debug_enable;
+extern int high_temp_protect;
+extern atomic_t freq_update_flag;
+
+void thermal_atomic_set(atomic_t *a, int);
+void thermal_lock(struct mutex *lock);
+void thermal_unlock(struct mutex *lock);
+void keep_mode_set_mode(struct amlogic_thermal_platform_data *);
+void keep_mode_bind(struct amlogic_thermal_platform_data *, unsigned long , int );
+void keep_mode_work(struct amlogic_thermal_platform_data *, int);
+void keep_mode_update_threshold(struct amlogic_thermal_platform_data *, int );
+void keep_mode_temp_level_init(struct amlogic_thermal_platform_data *, struct temp_level *);
+
+#endif /* __AMLOGIC_THERMAL_H__ */
diff --git a/amlogic_thermal.o_shipped b/amlogic_thermal.o_shipped
index ee79aaa..69821cb 100644
--- a/amlogic_thermal.o_shipped
+++ b/amlogic_thermal.o_shipped
@@ -1,160 +1,56 @@
-ELF
-
-
- a`c
-
+ELF
+ B/
+ a`c

- e
- P
- `
-D40 @
- @0
-
-
-d
-
-103/
-103/
-
-q@0
-
-10
- D
-
-
-
-<,
-=
- 
-(
-
-0$ 
--
-
-0, 
-T
-
-L
-lT
-0/P0
-40Lp
-!
-L
-
-
-  0똀D$
- =
-8p
-80D(
-8p
-#
-,
-$
-D@J
-
-,
- 040
-
-
-
-v
- C
-,
-!
-pL
-
+ e
+
+
+L P0d
+l
+0/|0
+0p
+!
+
+
+<
+
+
+xQ
+p
+0
+
+
+#
+
+
+D@@D
+
+
+
+
+
+
+
+ C
+
+
+
+
+H!
+ pA
+0
+
+
+
-
-4
- ,0
-0
-
-
-
-
-0
-
-
-
-A 
-F Hh0
-
-H 0
-HT 0
-
-`0T
-0
- t3
- B/
-
-  0
-  
-0 0 0 
-00< 
-0 0 0
-0 0   0
-  
-  
-0$ 0
-0$ 0  
-0, 0
-, 0
-
-
-
-
-
-
-p
-p
-p
-
-
-
-
-
-
-
-
-
-0d0
-|U
-
- 0 H#1
-,d
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-%s unbinding %s
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+A 0 
+
+
@@ -166,309 +62,157 @@ p
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-;
-T
-f
-x
-
-
-
--
-'
-
-"
-
- ^+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-& )
-
-
-
-
-
-
-
-x
-
-(
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-ЀIPw
-ЀIPw
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-IQ
-IPt
-
-
-
-IQt
-
-
-
-IQ
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+"
+$
+%
+ 
+'
+
+
+ !
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+
+
+
+s
+" 
+
+
+
+!
+
+
+!
+i
+'
+8
+
+
+
+
+
+
+7
+$
+
+
+
+
+
+
+
+
+
+
+
+*
+
 : ; 
-
-
-
-
-
-
-B 
-
-B 
-
+
+
+
+
+
+
+B 
+
+
+
B
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-Ѐ
-|
-
-
-
-fwJQy.
-.-/+0//-/M,//--0
-.//-/Ng3)1,0{}fJ-LhI/gK,/1+K0-//g-/~..~..~../~.1.0~..~.5
-JvJ/0,0Lg00,0'OQy.Qy.5y.5T.,f/~.[=K/-0-K-/KK/I/K-/KM0l..m.gKKj/-/-/0d///~\g/')v.+.z.1K4)-KM,0Nv. J1,h/KiJfg|J.|.-/~J(2M
-fu.
-.u.
-f-/2{f6x.g5y.Qz.gggKO,L0K////JK1g.
-.u.J wffK-//j/-/4KI$*2/k.}..g}JI/- /-.uf
-f&
-A "
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-(
-`
-d
-k
-l
-u
-{
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+.-/+0//-/M,//--0
+JvJ3,,0L*2/00,0'OQy.Qy.5y.5T.,/~.[=K/-0-Kh-/KK/e/g-/Ki0l..m.gtKKj/-/-/0d///~@g/')v.+.z.1K4)-KM,0Nv. JKKg/K000,L/Ka!J
+
+A "
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+:
+@
+G
+H
+I
diff --git a/amlogic_thermal_module.c b/amlogic_thermal_module.c
index c065c90..8bbc63e 100755
--- a/amlogic_thermal_module.c
+++ b/amlogic_thermal_module.c
@@ -45,7 +45,1058 @@
#include <linux/gpucore_cooling.h>
#include <linux/thermal_core.h>
#include <mach/thermal.h>
-extern struct platform_driver amlogic_thermal_driver;
+#include "amlogic_thermal.h"
+
+#define DBG_VIRTUAL 0
+int thermal_debug_enable = 0;
+int high_temp_protect = 0;
+atomic_t freq_update_flag;
+EXPORT_SYMBOL(thermal_debug_enable);
+EXPORT_SYMBOL(high_temp_protect);
+EXPORT_SYMBOL(freq_update_flag);
+
+#define THERMAL_DBG(format,args...) \
+ if (thermal_debug_enable) { \
+ printk("[THERMAL]"format, ##args); \
+ }
+
+static struct aml_virtual_thermal_device cpu_virtual_thermal = {};
+static struct aml_virtual_thermal_device gpu_virtual_thermal = {};
+static unsigned int report_interval[4] = {};
+
+/* CPU Zone information */
+#define PANIC_ZONE 4
+#define WARN_ZONE 3
+#define MONITOR_ZONE 2
+#define SAFE_ZONE 1
+
+#define GET_ZONE(trip) (trip + 2)
+#define GET_TRIP(zone) (zone - 2)
+
+static void amlogic_unregister_thermal(struct amlogic_thermal_platform_data *pdata);
+static int amlogic_register_thermal(struct amlogic_thermal_platform_data *pdata);
+
+void thermal_lock(struct mutex *lock)
+{
+ mutex_lock(lock);
+}
+EXPORT_SYMBOL(thermal_lock);
+
+void thermal_unlock(struct mutex *lock)
+{
+ mutex_unlock(lock);
+}
+EXPORT_SYMBOL(thermal_unlock);
+
+/* Get mode callback functions for thermal zone */
+static int amlogic_get_mode(struct thermal_zone_device *thermal,
+ enum thermal_device_mode *mode)
+{
+ struct amlogic_thermal_platform_data *pdata= thermal->devdata;
+
+ if (pdata)
+ *mode = pdata->mode;
+ return 0;
+}
+
+/* Set mode callback functions for thermal zone */
+static int amlogic_set_mode(struct thermal_zone_device *thermal,
+ enum thermal_device_mode mode)
+{
+ struct amlogic_thermal_platform_data *pdata= thermal->devdata;
+ struct cpucore_cooling_device *cpucore_device =NULL;
+ struct gpucore_cooling_device *gpucore_device = NULL;
+ if(!pdata)
+ return -EINVAL;
+
+ //mutex_lock(&pdata->therm_dev->lock);
+
+ if (mode == THERMAL_DEVICE_ENABLED){
+ pdata->therm_dev->polling_delay = pdata->idle_interval;
+ if(pdata->cpucore_cool_dev){
+ cpucore_device=pdata->cpucore_cool_dev->devdata;
+ cpucore_device->stop_flag=0;
+ }
+ if(pdata->gpucore_cool_dev){
+ gpucore_device=pdata->gpucore_cool_dev->devdata;
+ gpucore_device->stop_flag=0;
+ }
+ if (pdata->keep_mode) { // start work
+ schedule_delayed_work(&pdata->thermal_work, msecs_to_jiffies(100));
+ }
+ }
+ else{
+ pdata->therm_dev->polling_delay = 0;
+ if (pdata->keep_mode) {
+ cancel_delayed_work_sync(&pdata->thermal_work);
+ keep_mode_set_mode(pdata);
+ }
+ if(pdata->cpucore_cool_dev)
+ pdata->cpucore_cool_dev->ops->set_cur_state(pdata->cpucore_cool_dev,(0|CPU_STOP));
+ if(pdata->gpucore_cool_dev)
+ pdata->gpucore_cool_dev->ops->set_cur_state(pdata->gpucore_cool_dev,(0|GPU_STOP));
+ }
+
+ //mutex_unlock(&pdata->therm_dev->lock);
+
+ pdata->mode = mode;
+ thermal_zone_device_update(pdata->therm_dev);
+ pr_info("thermal polling set for duration=%d msec\n",
+ pdata->therm_dev->polling_delay);
+ return 0;
+}
+
+/* Get trip type callback functions for thermal zone */
+static int amlogic_get_trip_type(struct thermal_zone_device *thermal, int trip,
+ enum thermal_trip_type *type)
+{
+ if(trip < thermal->trips-1)
+ *type = THERMAL_TRIP_ACTIVE;
+ else if(trip == thermal->trips-1)
+ *type = THERMAL_TRIP_CRITICAL;
+ else
+ return -EINVAL;
+ return 0;
+}
+
+/* Get trip temperature callback functions for thermal zone */
+static int amlogic_get_trip_temp(struct thermal_zone_device *thermal, int trip,
+ unsigned long *temp)
+{
+ struct amlogic_thermal_platform_data *pdata= thermal->devdata;
+
+ if(trip > pdata->temp_trip_count ||trip<0)
+ return -EINVAL;
+ mutex_lock(&pdata->lock);
+ *temp =pdata->tmp_trip[trip].temperature;
+ /* convert the temperature into millicelsius */
+ mutex_unlock(&pdata->lock);
+
+ return 0;
+}
+
+static int amlogic_set_trip_temp(struct thermal_zone_device *thermal, int trip,
+ unsigned long temp)
+{
+ struct amlogic_thermal_platform_data *pdata= thermal->devdata;
+
+ if(trip > pdata->temp_trip_count ||trip<0)
+ return -EINVAL;
+ mutex_lock(&pdata->lock);
+ pdata->tmp_trip[trip].temperature=temp;
+ /* convert the temperature into millicelsius */
+ mutex_unlock(&pdata->lock);
+ return 0;
+}
+
+/* Get critical temperature callback functions for thermal zone */
+static int amlogic_get_crit_temp(struct thermal_zone_device *thermal,
+ unsigned long *temp)
+{
+ int ret;
+ /* Panic zone */
+ ret =amlogic_get_trip_temp(thermal, thermal->trips-1, temp);
+
+ return ret;
+}
+
+
+/* Bind callback functions for thermal zone */
+static int amlogic_bind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ int ret = 0, i;
+ struct amlogic_thermal_platform_data *pdata= thermal->devdata;
+ int id;
+ char type[THERMAL_NAME_LENGTH];
+ unsigned long max;
+
+ if (!sscanf(cdev->type, "thermal-%7s-%d", type,&id))
+ return -EINVAL;
+ if(!strcmp(type,"cpufreq")){
+ /* Bind the thermal zone to the cpufreq cooling device */
+ for (i = 0; i < pdata->temp_trip_count; i++) {
+ if(pdata->tmp_trip[0].cpu_upper_level==THERMAL_CSTATE_INVALID)
+ {
+ printk("disable cpu cooling device by dtd\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ if (thermal_zone_bind_cooling_device(thermal, i, cdev,
+ pdata->tmp_trip[i].cpu_upper_level,
+ pdata->tmp_trip[i].cpu_lower_level)) {
+ pr_err("error binding cdev inst %d\n", i);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+ pr_info("%s bind %s okay !\n",thermal->type,cdev->type);
+ if (pdata->keep_mode) {
+ cdev->ops->get_max_state(cdev, &max);
+ keep_mode_bind(pdata, max, 0);
+ }
+ }
+
+ if(!strcmp(type,"gpufreq")){
+ struct gpufreq_cooling_device *gpufreq_dev=
+ (struct gpufreq_cooling_device *)cdev->devdata;
+ /* Bind the thermal zone to the cpufreq cooling device */
+ for (i = 0; i < pdata->temp_trip_count; i++) {
+ if(!gpufreq_dev->get_gpu_freq_level){
+ ret = -EINVAL;
+ pr_info("invalidate pointer %p\n",gpufreq_dev->get_gpu_freq_level);
+ goto out;
+ }
+ pdata->tmp_trip[i].gpu_lower_level=gpufreq_dev->get_gpu_freq_level(pdata->tmp_trip[i].gpu_upper_freq);
+ pdata->tmp_trip[i].gpu_upper_level=gpufreq_dev->get_gpu_freq_level(pdata->tmp_trip[i].gpu_lower_freq);
+ printk("pdata->tmp_trip[%d].gpu_lower_level=%d\n",i,pdata->tmp_trip[i].gpu_lower_level);
+ printk("pdata->tmp_trip[%d].gpu_upper_level=%d\n",i,pdata->tmp_trip[i].gpu_upper_level);
+ if(pdata->tmp_trip[0].gpu_lower_level==THERMAL_CSTATE_INVALID)
+ {
+ printk("disable gpu cooling device by dtd\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ if (thermal_zone_bind_cooling_device(thermal, i, cdev,
+ pdata->tmp_trip[i].gpu_upper_level,
+ pdata->tmp_trip[i].gpu_lower_level)) {
+ pr_err("error binding cdev inst %d\n", i);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+ pdata->gpu_cool_dev=cdev;
+ pr_info("%s bind %s okay !\n",thermal->type,cdev->type);
+ if (pdata->keep_mode) {
+ cdev->ops->get_max_state(cdev, &max);
+ keep_mode_bind(pdata, max, 1);
+ }
+ }
+
+ if(!strcmp(type,"cpucore")){
+ /* Bind the thermal zone to the cpufreq cooling device */
+ struct cpucore_cooling_device *cpucore_dev=
+ (struct cpucore_cooling_device *)cdev->devdata;
+ for (i = 0; i < pdata->temp_trip_count; i++) {
+ if(pdata->tmp_trip[0].cpu_core_num==THERMAL_CSTATE_INVALID)
+ {
+ printk("disable cpu cooling device by dtd\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ if(pdata->tmp_trip[i].cpu_core_num !=-1)
+ pdata->tmp_trip[i].cpu_core_upper=cpucore_dev->max_cpu_core_num-pdata->tmp_trip[i].cpu_core_num;
+ else
+ pdata->tmp_trip[i].cpu_core_upper=pdata->tmp_trip[i].cpu_core_num;
+ printk("tmp_trip[%d].cpu_core_upper=%d\n",i,pdata->tmp_trip[i].cpu_core_upper);
+ if (thermal_zone_bind_cooling_device(thermal, i, cdev,
+ pdata->tmp_trip[i].cpu_core_upper,
+ pdata->tmp_trip[i].cpu_core_upper)) {
+ pr_err("error binding cdev inst %d\n", i);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+ pr_info("%s bind %s okay !\n",thermal->type,cdev->type);
+ if (pdata->keep_mode) {
+ cdev->ops->get_max_state(cdev, &max);
+ keep_mode_bind(pdata, max, 2);
+ }
+ }
+
+ if(!strcmp(type,"gpucore")){
+ /* Bind the thermal zone to the cpufreq cooling device */
+ struct gpucore_cooling_device *gpucore_dev=
+ (struct gpucore_cooling_device *)cdev->devdata;
+ for (i = 0; i < pdata->temp_trip_count; i++) {
+ if(pdata->tmp_trip[0].cpu_core_num==THERMAL_CSTATE_INVALID)
+ {
+ printk("disable cpu cooling device by dtd\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ if(pdata->tmp_trip[i].gpu_core_num != -1)
+ pdata->tmp_trip[i].gpu_core_upper=gpucore_dev->max_gpu_core_num-pdata->tmp_trip[i].gpu_core_num;
+ else
+ pdata->tmp_trip[i].gpu_core_upper=pdata->tmp_trip[i].gpu_core_num;
+
+ printk("tmp_trip[%d].gpu_core_upper=%d\n",i,pdata->tmp_trip[i].gpu_core_upper);
+ if (thermal_zone_bind_cooling_device(thermal, i, cdev,
+ pdata->tmp_trip[i].gpu_core_upper,
+ pdata->tmp_trip[i].gpu_core_upper)) {
+ pr_err("error binding cdev inst %d\n", i);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+ pdata->gpucore_cool_dev=cdev;
+ pr_info("%s bind %s okay !\n",thermal->type,cdev->type);
+ if (pdata->keep_mode) {
+ cdev->ops->get_max_state(cdev, &max);
+ keep_mode_bind(pdata, max, 3);
+ }
+ }
+ return ret;
+out:
+ return ret;
+}
+
+/* Unbind callback functions for thermal zone */
+static int amlogic_unbind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ int i;
+ if(thermal && cdev){
+ struct amlogic_thermal_platform_data *pdata= thermal->devdata;
+ for (i = 0; i < pdata->temp_trip_count; i++) {
+ pr_info("\n%s unbinding %s ",thermal->type,cdev->type);
+ if (thermal_zone_unbind_cooling_device(thermal, i, cdev)) {
+ pr_err(" error %d \n", i);
+ return -EINVAL;
+ }
+ pr_info(" okay\n");
+ return 0;
+ }
+ }else{
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+#define ABS(a) ((a) > 0 ? (a) : -(a))
+
+void *thermal_alloc(size_t len)
+{
+ return kzalloc(len, GFP_KERNEL);
+}
+EXPORT_SYMBOL(thermal_alloc);
+
+static void thermal_work(struct work_struct *work)
+{
+ struct cpufreq_policy *policy = cpufreq_cpu_get(0);
+ struct amlogic_thermal_platform_data *pdata;
+ int cpu_freq = 0;
+
+ pdata = container_of((struct delayed_work *)work, struct amlogic_thermal_platform_data, thermal_work);
+ if (policy) {
+ cpu_freq = policy->cur;
+ }
+ keep_mode_work(pdata, cpu_freq);
+ if (pdata->mode == THERMAL_DEVICE_ENABLED) { // no need to do this work again if thermal disabled
+ schedule_delayed_work(&pdata->thermal_work, msecs_to_jiffies(100));
+ }
+}
+
+static int aml_virtaul_thermal_probe(struct platform_device *pdev, struct amlogic_thermal_platform_data *pdata)
+{
+ int ret, len, cells;
+ struct property *prop;
+ void *buf;
+
+ if (!of_property_read_bool(pdev->dev.of_node, "use_virtual_thermal")) {
+ printk("%s, virtual thermal is not enabled\n", __func__);
+ pdata->virtual_thermal_en = 0;
+ return 0;
+ } else {
+ printk("%s, virtual thermal enabled\n", __func__);
+ }
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "freq_sample_period",
+ &pdata->freq_sample_period);
+ if (ret) {
+ printk("%s, get freq_sample_period failed, us 30 as default\n", __func__);
+ pdata->freq_sample_period = 30;
+ } else {
+ printk("%s, get freq_sample_period with value:%d\n", __func__, pdata->freq_sample_period);
+ }
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "report_time",
+ report_interval, sizeof(report_interval) / sizeof(u32));
+ if (ret) {
+ printk("%s, get report_time failed\n", __func__);
+ goto error;
+ } else {
+ printk("[virtual_thermal] report interval:%4d, %4d, %4d, %4d\n",
+ report_interval[0], report_interval[1], report_interval[2], report_interval[3]);
+ }
+ /*
+ * read cpu_virtal
+ */
+ prop = of_find_property(pdev->dev.of_node, "cpu_virtual", &len);
+ if (!prop) {
+ printk("%s, cpu virtual not found\n", __func__);
+ goto error;
+ }
+ cells = len / sizeof(struct aml_virtual_thermal);
+ buf = kzalloc(len, GFP_KERNEL);
+ if (!buf) {
+ printk("%s, no memory\n", __func__);
+ return -ENOMEM;
+ }
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "cpu_virtual",
+ buf, len/sizeof(u32));
+ if (ret) {
+ printk("%s, read cpu_virtual failed\n", __func__);
+ kfree(buf);
+ goto error;
+ }
+ cpu_virtual_thermal.count = cells;
+ cpu_virtual_thermal.thermal = buf;
+
+ /*
+ * read gpu_virtal
+ */
+ prop = of_find_property(pdev->dev.of_node, "gpu_virtual", &len);
+ if (!prop) {
+ printk("%s, gpu virtual not found\n", __func__);
+ goto error;
+ }
+ cells = len / sizeof(struct aml_virtual_thermal);
+ buf = kzalloc(len, GFP_KERNEL);
+ if (!buf) {
+ printk("%s, no memory\n", __func__);
+ return -ENOMEM;
+ }
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "gpu_virtual",
+ buf, len/sizeof(u32));
+ if (ret) {
+ printk("%s, read gpu_virtual failed\n", __func__);
+ kfree(buf);
+ goto error;
+ }
+ gpu_virtual_thermal.count = cells;
+ gpu_virtual_thermal.thermal = buf;
+
+#if DBG_VIRTUAL
+ printk("cpu_virtal cells:%d, table:\n", cpu_virtual_thermal.count);
+ for (len = 0; len < cpu_virtual_thermal.count; len++) {
+ printk("%2d, %8d, %4d, %4d, %4d, %4d\n",
+ len,
+ cpu_virtual_thermal.thermal[len].freq,
+ cpu_virtual_thermal.thermal[len].temp_time[0],
+ cpu_virtual_thermal.thermal[len].temp_time[1],
+ cpu_virtual_thermal.thermal[len].temp_time[2],
+ cpu_virtual_thermal.thermal[len].temp_time[3]);
+ }
+ printk("gpu_virtal cells:%d, table:\n", gpu_virtual_thermal.count);
+ for (len = 0; len < gpu_virtual_thermal.count; len++) {
+ printk("%2d, %8d, %4d, %4d, %4d, %4d\n",
+ len,
+ gpu_virtual_thermal.thermal[len].freq,
+ gpu_virtual_thermal.thermal[len].temp_time[0],
+ gpu_virtual_thermal.thermal[len].temp_time[1],
+ gpu_virtual_thermal.thermal[len].temp_time[2],
+ gpu_virtual_thermal.thermal[len].temp_time[3]);
+ }
+#endif
+
+ pdata->virtual_thermal_en = 1;
+ return 0;
+
+error:
+ pdata->virtual_thermal_en = 0;
+ return -1;
+}
+
+static void aml_virtual_thermal_remove(struct amlogic_thermal_platform_data *pdata)
+{
+ kfree(cpu_virtual_thermal.thermal);
+ kfree(gpu_virtual_thermal.thermal);
+ pdata->virtual_thermal_en = 0;
+}
+
+static int check_freq_level(struct aml_virtual_thermal_device *dev, unsigned int freq)
+{
+ int i = 0;
+
+ if (freq >= dev->thermal[dev->count-1].freq) {
+ return dev->count - 1;
+ }
+ for (i = 0; i < dev->count - 1; i++) {
+ if (freq > dev->thermal[i].freq && freq <= dev->thermal[i + 1].freq) {
+ return i + 1;
+ }
+ }
+ return 0;
+}
+
+static int check_freq_level_cnt(unsigned int cnt)
+{
+ int i;
+
+ if (cnt >= report_interval[3]) {
+ return 3;
+ }
+ for (i = 0; i < 3; i++) {
+ if (cnt >= report_interval[i] && cnt < report_interval[i + 1]) {
+ return i;
+ }
+ }
+ return 0;
+}
+
+static unsigned long aml_cal_virtual_temp(struct amlogic_thermal_platform_data *pdata)
+{
+ static unsigned int cpu_freq_level_cnt = 0, gpu_freq_level_cnt = 0;
+ static unsigned int last_cpu_freq_level = 0, last_gpu_freq_level = 0;
+ static unsigned int cpu_temp = 40, gpu_temp = 40; // default set to 40 when at homescreen
+ unsigned int curr_cpu_avg_freq, curr_gpu_avg_freq;
+ int curr_cpu_freq_level, curr_gpu_freq_level;
+ int cnt_level, level_diff;
+ int temp_update = 0, final_temp;
+
+ /*
+ * CPU temp
+ */
+ if (atomic_read(&freq_update_flag)) {
+ curr_cpu_avg_freq = pdata->monitor.avg_cpu_freq;
+ curr_cpu_freq_level = check_freq_level(&cpu_virtual_thermal, curr_cpu_avg_freq);
+ level_diff = curr_cpu_freq_level - last_cpu_freq_level;
+ if (ABS(level_diff) <= 1) { // freq change is not large
+ cpu_freq_level_cnt++;
+ cnt_level = check_freq_level_cnt(cpu_freq_level_cnt);
+ cpu_temp = cpu_virtual_thermal.thermal[curr_cpu_freq_level].temp_time[cnt_level];
+#if DBG_VIRTUAL
+ printk("%s, cur_freq:%7d, freq_level:%d, cnt_level:%d, cnt:%d, cpu_temp:%d\n",
+ __func__, curr_cpu_avg_freq, curr_cpu_freq_level, cnt_level, cpu_freq_level_cnt, cpu_temp);
+#endif
+ } else { // level not match
+ cpu_temp = cpu_virtual_thermal.thermal[curr_cpu_freq_level].temp_time[0];
+#if DBG_VIRTUAL
+ printk("%s, cur_freq:%7d, cur_level:%d, last_level:%d, last_cnt_level:%d, cpu_temp:%d\n",
+ __func__, curr_cpu_avg_freq, curr_cpu_freq_level, last_cpu_freq_level, cpu_freq_level_cnt, cpu_temp);
+#endif
+ cpu_freq_level_cnt = 0;
+ }
+ last_cpu_freq_level = curr_cpu_freq_level;
+
+ curr_gpu_avg_freq = pdata->monitor.avg_gpu_freq;
+ curr_gpu_freq_level = check_freq_level(&gpu_virtual_thermal, curr_gpu_avg_freq);
+ level_diff = curr_gpu_freq_level - last_gpu_freq_level;
+ if (ABS(level_diff) <= 1) { // freq change is not large
+ gpu_freq_level_cnt++;
+ cnt_level = check_freq_level_cnt(gpu_freq_level_cnt);
+ gpu_temp = gpu_virtual_thermal.thermal[curr_gpu_freq_level].temp_time[cnt_level];
+#if DBG_VIRTUAL
+ printk("%s, cur_freq:%7d, freq_level:%d, cnt_level:%d, cnt:%d, gpu_temp:%d\n",
+ __func__, curr_gpu_avg_freq, curr_gpu_freq_level, cnt_level, gpu_freq_level_cnt, gpu_temp);
+#endif
+ } else { // level not match
+ gpu_temp = gpu_virtual_thermal.thermal[curr_gpu_freq_level].temp_time[0];
+ gpu_freq_level_cnt = 0;
+#if DBG_VIRTUAL
+ printk("%s, cur_freq:%7d, cur_level:%d, last_level:%d, gpu_temp:%d\n",
+ __func__, curr_gpu_avg_freq, curr_gpu_freq_level, last_gpu_freq_level, gpu_temp);
+#endif
+ }
+ last_gpu_freq_level = curr_gpu_freq_level;
+
+ atomic_set(&freq_update_flag, 0);
+ temp_update = 1;
+ }
+
+ if (cpu_temp <= 0 && gpu_temp <= 0) {
+ printk("%s, Bug here, cpu & gpu temp can't be 0, cpu_temp:%d, gpu_temp:%d\n", __func__, cpu_temp, gpu_temp);
+ final_temp = 40;
+ }
+ final_temp = (cpu_temp >= gpu_temp ? cpu_temp : gpu_temp);
+ if (temp_update) {
+#if DBG_VIRTUAL
+ printk("final temp:%d\n", final_temp);
+#endif
+ }
+ return final_temp;
+}
+
+/* Get temperature callback functions for thermal zone */
+static int amlogic_get_temp(struct thermal_zone_device *thermal,
+ unsigned long *temp)
+{
+ struct amlogic_thermal_platform_data *pdata = thermal->devdata;
+
+ if (pdata->trim_flag) {
+ *temp = (unsigned long)get_cpu_temp();
+ pdata->current_temp = *temp;
+ } else if (pdata->virtual_thermal_en) {
+ *temp = aml_cal_virtual_temp(pdata);
+ } else {
+ *temp = 45; // fix cpu temperature to 45 if not trimed && disable virtual thermal
+ }
+ return 0;
+}
+
+/* Get the temperature trend */
+static int amlogic_get_trend(struct thermal_zone_device *thermal,
+ int trip, enum thermal_trend *trend)
+{
+ return 1;
+}
+/* Operation callback functions for thermal zone */
+static struct thermal_zone_device_ops const amlogic_dev_ops = {
+ .bind = amlogic_bind,
+ .unbind = amlogic_unbind,
+ .get_temp = amlogic_get_temp,
+ .get_trend = amlogic_get_trend,
+ .get_mode = amlogic_get_mode,
+ .set_mode = amlogic_set_mode,
+ .get_trip_type = amlogic_get_trip_type,
+ .get_trip_temp = amlogic_get_trip_temp,
+ .set_trip_temp = amlogic_set_trip_temp,
+ .get_crit_temp = amlogic_get_crit_temp,
+};
+
+/*
+ * sysfs for keep_mode
+ */
+#ifdef CONFIG_CPU_FREQ_GOV_HOTPLUG // for DEBUG
+extern unsigned int max_cpu_num;
+static ssize_t max_cpu_num_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", max_cpu_num);
+}
+#endif
+
+static ssize_t thermal_debug_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", thermal_debug_enable);
+}
+
+static ssize_t thermal_debug_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int32_t data = simple_strtol(buf, NULL, 10);
+
+ if (data) {
+ thermal_debug_enable = 1;
+ } else {
+ thermal_debug_enable = 0;
+ }
+ return count;
+}
+
+static ssize_t keep_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device);
+ struct amlogic_thermal_platform_data *pdata = tz->devdata;
+
+ return sprintf(buf, "%s\n", pdata->keep_mode ? "enabled": "disabled");
+}
+
+static ssize_t keep_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device);
+ struct amlogic_thermal_platform_data *pdata = tz->devdata;
+ if (!strncmp(buf, "enabled", sizeof("enabled") - 1)) {
+ pdata->keep_mode = 1;
+ } else if (!strncmp(buf, "disabled", sizeof("disabled") - 1)) {
+ pdata->keep_mode = 0;
+ }
+ return count;
+}
+
+static ssize_t keep_mode_threshold_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device);
+ struct amlogic_thermal_platform_data *pdata = tz->devdata;
+
+ return sprintf(buf, "%d\n", pdata->keep_mode_threshold);
+}
+
+static ssize_t keep_mode_threshold_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device);
+ struct amlogic_thermal_platform_data *pdata = tz->devdata;
+ int32_t data = simple_strtol(buf, NULL, 10);
+
+ if (data > 200) {
+ printk("input is %d, seems too large, invalid\n", data);
+ }
+ keep_mode_update_threshold(pdata, data);
+ printk("set keep_mode_threshold to %d\n", data);
+ return count;
+}
+
+static ssize_t high_temp_protect_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", high_temp_protect);
+}
+
+static ssize_t high_temp_protect_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device);
+ struct amlogic_thermal_platform_data *pdata = tz->devdata;
+ int32_t data = simple_strtol(buf, NULL, 10);
+
+ high_temp_protect = data ? 1 : 0;
+ if (high_temp_protect) {
+ pdata->tmp_trip[1].temperature = pdata->keep_mode_threshold + 25;
+ } else {
+ pdata->tmp_trip[1].temperature = 260;
+ }
+ printk("high temperature protect %s\n", high_temp_protect ? "enabled" : "disabled");
+ return count;
+}
+
+static struct device_attribute amlogic_thermal_attr[] = {
+#ifdef CONFIG_CPU_FREQ_GOV_HOTPLUG
+ __ATTR(max_cpu_num, 0444, max_cpu_num_show, NULL),
+#endif
+ __ATTR(thermal_debug, 0644, thermal_debug_show, thermal_debug_store),
+ __ATTR(keep_mode, 0644, keep_mode_show, keep_mode_store),
+ __ATTR(keep_mode_threshold, 0644, keep_mode_threshold_show, keep_mode_threshold_store),
+ __ATTR(high_temp_protect, 0644, high_temp_protect_show, high_temp_protect_store)
+};
+
+/* Register with the in-kernel thermal management */
+static int amlogic_register_thermal(struct amlogic_thermal_platform_data *pdata)
+{
+ int ret=0, j;
+ struct cpumask mask_val;
+
+ memset(&mask_val,0,sizeof(struct cpumask));
+ cpumask_set_cpu(0, &mask_val);
+ pdata->cpu_cool_dev= cpufreq_cooling_register(&mask_val);
+ if (IS_ERR(pdata->cpu_cool_dev)) {
+ pr_err("Failed to register cpufreq cooling device\n");
+ ret = -EINVAL;
+ goto err_unregister;
+ }
+ pdata->cpucore_cool_dev = cpucore_cooling_register();
+ if (IS_ERR(pdata->cpucore_cool_dev)) {
+ pr_err("Failed to register cpufreq cooling device\n");
+ ret = -EINVAL;
+ goto err_unregister;
+ }
+
+ pdata->therm_dev = thermal_zone_device_register(pdata->name,
+ pdata->temp_trip_count, ((1 << pdata->temp_trip_count) - 1), pdata, &amlogic_dev_ops, NULL, 0,
+ pdata->idle_interval);
+
+ if (IS_ERR(pdata->therm_dev)) {
+ pr_err("Failed to register thermal zone device, err:%p\n", pdata->therm_dev);
+ ret = -EINVAL;
+ goto err_unregister;
+ }
+
+ if (pdata->keep_mode) { // create sysfs for keep_mode
+ for (j = 0; j < ARRAY_SIZE(amlogic_thermal_attr); j++) {
+ device_create_file(&pdata->therm_dev->device, &amlogic_thermal_attr[j]);
+ }
+ }
+ pr_info("amlogic: Kernel Thermal management registered\n");
+
+ return 0;
+
+err_unregister:
+ amlogic_unregister_thermal(pdata);
+ return ret;
+}
+
+/* Un-Register with the in-kernel thermal management */
+static void amlogic_unregister_thermal(struct amlogic_thermal_platform_data *pdata)
+{
+ if (pdata->therm_dev)
+ thermal_zone_device_unregister(pdata->therm_dev);
+ if (pdata->cpu_cool_dev)
+ cpufreq_cooling_unregister(pdata->cpu_cool_dev);
+
+ pr_info("amlogic: Kernel Thermal management unregistered\n");
+}
+
+int get_desend(void)
+{
+ int i;
+ unsigned int freq = CPUFREQ_ENTRY_INVALID;
+ int descend = -1;
+ struct cpufreq_frequency_table *table =
+ cpufreq_frequency_get_table(0);
+
+ if (!table)
+ return -EINVAL;
+
+ for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ /* ignore invalid entries */
+ if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
+ continue;
+
+ /* ignore duplicate entry */
+ if (freq == table[i].frequency)
+ continue;
+
+ /* get the frequency order */
+ if (freq != CPUFREQ_ENTRY_INVALID && descend == -1){
+ descend = !!(freq > table[i].frequency);
+ break;
+ }
+
+ freq = table[i].frequency;
+ }
+ return descend;
+}
+int fix_to_freq(int freqold,int descend)
+{
+ int i;
+ unsigned int freq = CPUFREQ_ENTRY_INVALID;
+ struct cpufreq_frequency_table *table =
+ cpufreq_frequency_get_table(0);
+
+ if (!table)
+ return -EINVAL;
+
+ for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ /* ignore invalid entry */
+ if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
+ continue;
+
+ /* ignore duplicate entry */
+ if (freq == table[i].frequency)
+ continue;
+ freq = table[i].frequency;
+ if(descend){
+ if(freqold>=table[i+1].frequency && freqold<=table[i].frequency)
+ return table[i+1].frequency;
+ }
+ else{
+ if(freqold>=table[i].frequency && freqold<=table[i+1].frequency)
+ return table[i].frequency;
+ }
+ }
+ return -EINVAL;
+}
+
+void thermal_atomic_set(atomic_t *a, int value)
+{
+ atomic_set(a, 1);
+}
+EXPORT_SYMBOL(thermal_atomic_set);
+
+static struct amlogic_thermal_platform_data * amlogic_thermal_init_from_dts(struct platform_device *pdev, int trim_flag)
+{
+ int i = 0, ret = -1, val = 0, cells, descend, error = 0;
+ struct property *prop;
+ struct temp_level *tmp_level = NULL;
+ struct amlogic_thermal_platform_data *pdata = NULL;
+
+ if(!of_property_read_u32(pdev->dev.of_node, "trip_point", &val)){
+ //INIT FROM DTS
+ pdata=kzalloc(sizeof(*pdata),GFP_KERNEL);
+ if(!pdata){
+ goto err;
+ }
+ memset((void* )pdata,0,sizeof(*pdata));
+ ret=of_property_read_u32(pdev->dev.of_node, "#thermal-cells", &val);
+ if(ret){
+ dev_err(&pdev->dev, "dt probe #thermal-cells failed: %d\n", ret);
+ goto err;
+ }
+ printk("#thermal-cells=%d\n",val);
+ cells=val;
+
+ /*
+ * process for KEEP_MODE and virtual thermal
+ * Logic: If virtual thermal is enabled, then ignore keep_mode
+ *
+ */
+ pdata->trim_flag = trim_flag;
+ if (!pdata->trim_flag) { // chip is not trimmed, use virtual thermal
+ aml_virtaul_thermal_probe(pdev, pdata);
+ } else if (of_property_read_bool(pdev->dev.of_node, "keep_mode")) {
+ if (of_property_read_u32(pdev->dev.of_node, "keep_mode_threshold", &pdata->keep_mode_threshold)) {
+ printk("ERROR:keep_mode is set but not found 'keep_mode_threshold'\n");
+ error = 1;
+ }
+ if (of_property_read_u32_array(pdev->dev.of_node,
+ "keep_mode_max_range",
+ pdata->keep_mode_max_range,
+ sizeof(pdata->keep_mode_max_range)/sizeof(u32))) {
+ printk("ERROR:keep_mode is set but not found 'keep_mode_max_range'\n");
+ error = 1;
+ }
+ if (!error && pdata->trim_flag) { // keep mode should not used for virtual thermal right now
+ printk("keep_mode enabled\n");
+ printk("keep_mode_max_range: [%7d, %3d, %d, %d]\n",
+ pdata->keep_mode_max_range[0], pdata->keep_mode_max_range[1],
+ pdata->keep_mode_max_range[2], pdata->keep_mode_max_range[3]);
+ pdata->keep_mode = 1;
+ pdata->freq_sample_period = 5;
+ }
+ } else {
+ printk("keep_mode is disabled\n");
+ }
+ if(pdata->keep_mode || !pdata->trim_flag){
+ INIT_DELAYED_WORK(&pdata->thermal_work, thermal_work);
+ schedule_delayed_work(&pdata->thermal_work, msecs_to_jiffies(100));
+ atomic_set(&freq_update_flag, 0);
+ }
+
+ prop = of_find_property(pdev->dev.of_node, "trip_point", &val);
+ if (!prop){
+ dev_err(&pdev->dev, "read %s length error\n","trip_point");
+ goto err;
+ }
+ if (pdata->keep_mode) {
+ pdata->temp_trip_count = 2;
+ } else {
+ pdata->temp_trip_count=val/cells/sizeof(u32);
+ }
+ printk("pdata->temp_trip_count=%d\n",pdata->temp_trip_count);
+ tmp_level=kzalloc(sizeof(*tmp_level)*pdata->temp_trip_count,GFP_KERNEL);
+ pdata->tmp_trip=kzalloc(sizeof(struct temp_trip)*pdata->temp_trip_count,GFP_KERNEL);
+ if(!tmp_level){
+ goto err;
+ }
+
+ if (pdata->keep_mode) { // keep mode only need one point
+ keep_mode_temp_level_init(pdata, tmp_level);
+ } else {
+ ret=of_property_read_u32_array(pdev->dev.of_node,"trip_point",(u32 *)tmp_level,val/sizeof(u32));
+ if (ret){
+ dev_err(&pdev->dev, "read %s data error\n","trip_point");
+ goto err;
+ }
+ }
+ descend=get_desend();
+ for (i = 0; i < pdata->temp_trip_count; i++) {
+ printk("temperature=%d on trip point=%d\n",tmp_level[i].temperature,i);
+ pdata->tmp_trip[i].temperature=tmp_level[i].temperature;
+ printk("fixing high_freq=%d to ",tmp_level[i].cpu_high_freq);
+ tmp_level[i].cpu_high_freq=fix_to_freq(tmp_level[i].cpu_high_freq,descend);
+ pdata->tmp_trip[i].cpu_lower_level=cpufreq_cooling_get_level(0,tmp_level[i].cpu_high_freq);
+ printk("%d at trip point %d,level=%d\n",tmp_level[i].cpu_high_freq,i,pdata->tmp_trip[i].cpu_lower_level);
+
+ printk("fixing low_freq=%d to ",tmp_level[i].cpu_low_freq);
+ tmp_level[i].cpu_low_freq=fix_to_freq(tmp_level[i].cpu_low_freq,descend);
+ pdata->tmp_trip[i].cpu_upper_level=cpufreq_cooling_get_level(0,tmp_level[i].cpu_low_freq);
+ printk("%d at trip point %d,level=%d\n",tmp_level[i].cpu_low_freq,i,pdata->tmp_trip[i].cpu_upper_level);
+ pdata->tmp_trip[i].gpu_lower_freq=tmp_level[i].gpu_low_freq;
+ pdata->tmp_trip[i].gpu_upper_freq=tmp_level[i].gpu_high_freq;
+ printk("gpu[%d].gpu_high_freq=%d,tmp_level[%d].gpu_high_freq=%d\n",i,tmp_level[i].gpu_high_freq,i,tmp_level[i].gpu_low_freq);
+
+ pdata->tmp_trip[i].cpu_core_num=tmp_level[i].cpu_core_num;
+ printk("cpu[%d] core num==%d\n",i,pdata->tmp_trip[i].cpu_core_num);
+ pdata->tmp_trip[i].gpu_core_num=tmp_level[i].gpu_core_num;
+ printk("gpu[%d] core num==%d\n",i,pdata->tmp_trip[i].gpu_core_num);
+ }
+
+ ret= of_property_read_u32(pdev->dev.of_node, "idle_interval", &val);
+ if (ret){
+ dev_err(&pdev->dev, "read %s error\n","idle_interval");
+ goto err;
+ }
+ pdata->idle_interval=val;
+ printk("idle interval=%d\n",pdata->idle_interval);
+ ret=of_property_read_string(pdev->dev.of_node,"dev_name",&pdata->name);
+ if (ret){
+ dev_err(&pdev->dev, "read %s error\n","dev_name");
+ goto err;
+ }
+ printk("pdata->name:%s, pdata:%p\n",pdata->name, pdata);
+ pdata->mode=THERMAL_DEVICE_ENABLED;
+ if(tmp_level)
+ kfree(tmp_level);
+ printk("%s, %d\n", __func__, __LINE__);
+ return pdata;
+ }
+err:
+ if(tmp_level)
+ kfree(tmp_level);
+ if(pdata)
+ kfree(pdata);
+ pdata= NULL;
+ return pdata;
+}
+
+static struct amlogic_thermal_platform_data * amlogic_thermal_initialize(struct platform_device *pdev, int trim_flag)
+{
+ struct amlogic_thermal_platform_data *pdata=NULL;
+ pdata=amlogic_thermal_init_from_dts(pdev, trim_flag);
+ printk("%s, %d, pdata:%p\n", __func__, __LINE__, pdata);
+ return pdata;
+}
+
+static const struct of_device_id amlogic_thermal_match[] = {
+ {
+ .compatible = "amlogic-thermal",
+ },
+};
+
+static int amlogic_thermal_probe(struct platform_device *pdev)
+{
+ int ret, trim_flag;
+ struct amlogic_thermal_platform_data *pdata=NULL;
+
+ ret=thermal_firmware_init();
+ if(ret<0){
+ printk("%s, this chip is not trimmed, use virtual thermal\n", __func__);
+ trim_flag = 0;
+ }else{
+ printk("%s, this chip is trimmed, use thermal\n", __func__);
+ trim_flag = 1;
+ }
+
+ dev_info(&pdev->dev, "amlogic thermal probe start\n");
+ pdata = amlogic_thermal_initialize(pdev, trim_flag);
+ if (!pdata) {
+ dev_err(&pdev->dev, "Failed to initialize thermal\n");
+ goto err;
+ }
+ mutex_init(&pdata->lock);
+ pdev->dev.platform_data=pdata;
+ platform_set_drvdata(pdev, pdata);
+ ret = amlogic_register_thermal(pdata);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register thermal interface\n");
+ goto err;
+ }
+ dev_info(&pdev->dev, "amlogic thermal probe done\n");
+ return 0;
+err:
+ platform_set_drvdata(pdev, NULL);
+ return ret;
+}
+
+static int amlogic_thermal_remove(struct platform_device *pdev)
+{
+ struct amlogic_thermal_platform_data *pdata = platform_get_drvdata(pdev);
+
+ aml_virtual_thermal_remove(pdata);
+
+ amlogic_unregister_thermal(pdata);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int amlogic_thermal_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int amlogic_thermal_resume(struct device *dev)
+{
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(amlogic_thermal_pm,
+ amlogic_thermal_suspend, amlogic_thermal_resume);
+#define amlogic_thermal_PM (&amlogic_thermal_pm)
+#else
+#define amlogic_thermal_PM NULL
+#endif
+
+struct platform_driver amlogic_thermal_driver = {
+ .driver = {
+ .name = "amlogic-thermal",
+ .owner = THIS_MODULE,
+ .pm = amlogic_thermal_PM,
+ .of_match_table = of_match_ptr(amlogic_thermal_match),
+ },
+ .probe = amlogic_thermal_probe,
+ .remove = amlogic_thermal_remove,
+};
static int __init amlogic_thermal_driver_init(void)
{