static int __init mtk_cooler_amutt_init(void)
{
    int err = 0, i = 0;

    mtk_cooler_amutt_dprintk("[%s]\n", __func__);

    for (; i <COOLER_STEPS; i++)
        opp_func[i] = amutt_backoff;

    amutt.cur_level = 0;
    amutt.max_level = COOLER_STEPS-1;
    amutt.opp_func_array = &opp_func[0];

    err = amutt_proc_register();
    if(err)
        return err;

    err = mtk_cooler_amutt_register_ltf();
    if (err)
        goto err_unreg;

    return 0;

err_unreg:
    mtk_cooler_amutt_unregister_ltf();
    return err;
}
static int amutt_cooler_lower_get_cur_state(struct thermal_cooling_device *cool_dev,
             unsigned long *pv)
{
    *pv = cl_lower_dev_state;
    mtk_cooler_amutt_dprintk("[%s] %lu\n", __func__, *pv);
    return 0;
}
/* +amutt_cooler_upper_ops+ */
static int amutt_cooler_upper_get_max_state(struct thermal_cooling_device *cool_dev,
             unsigned long *pv)
{
    *pv = 1;
    mtk_cooler_amutt_dprintk("[%s] %d\n", __func__, *pv);
    return 0;
}
static void __exit mtk_cooler_amutt_exit(void)
{
    mtk_cooler_amutt_dprintk("[%s]\n", __func__);

    /* remove the proc file */
    //remove_proc_entry("amutt", NULL);

    mtk_cooler_amutt_unregister_ltf();
}
static int mtk_cooler_amutt_register_ltf(void)
{
  mtk_cooler_amutt_dprintk("[%s]\n", __func__);

  cl_upper_dev = mtk_thermal_cooling_device_register("cl-amutt-upper", NULL,
			    &amutt_cooler_upper_ops);

  cl_lower_dev = mtk_thermal_cooling_device_register("cl-amutt-lower", NULL,
			    &amutt_cooler_lower_ops);

  return 0;
}
static int amutt_proc_register(void)
{
    struct proc_dir_entry *entry = NULL;
    struct proc_dir_entry *amutt_proc_dir = NULL;

    mtk_cooler_amutt_dprintk("[%s]\n", __func__);

    amutt_proc_dir = mtk_thermal_get_proc_drv_therm_dir_entry();
    if (!amutt_proc_dir) {
        mtk_cooler_amutt_dprintk("[%s]: mkdir /proc/driver/thermal failed\n", __func__);
    } else {
        entry = proc_create("clamutt_param", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, amutt_proc_dir, &amutt_param_fops);
        if (entry) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
            proc_set_user(entry, 0, 1000);
#else
            entry->gid = 1000;
#endif
        }

        entry = proc_create("clamutt_asparam", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, amutt_proc_dir, &amutt_asparam_fops);
        if (entry) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
            proc_set_user(entry, 0, 1000);
#else
            entry->gid = 1000;
#endif
        }

        entry = proc_create("clamutt_dbg", S_IRUSR | S_IWUSR, amutt_proc_dir, &amutt_dbg_fops);
        if (entry) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
            proc_set_user(entry, 0, 1000);
#else
            entry->gid = 1000;
#endif
        }
    }
    return 0;
}
static void mtk_cooler_amutt_unregister_ltf(void)
{
    mtk_cooler_amutt_dprintk("[%s]\n", __func__);

    if (cl_upper_dev) {
        mtk_thermal_cooling_device_unregister(cl_upper_dev);
        cl_upper_dev = NULL;
    }

    if (cl_lower_dev) {
        mtk_thermal_cooling_device_unregister(cl_lower_dev);
        cl_lower_dev = NULL;
    }
}
static int amutt_cooler_lower_set_cur_state(struct thermal_cooling_device *cool_dev,
             unsigned long v)
{
	int ret = 0;

	mtk_cooler_amutt_dprintk("[%s] %lu\n", __func__, v);

	cl_lower_dev_state = (unsigned int)v;

	if (cl_lower_dev_state == 1) {
		ret = judge_throttling(0, 1, polling_interval);
	} else {
		ret = judge_throttling(0, 0, polling_interval);
	}
	if (ret != 0) 
	    mtk_cooler_amutt_dprintk_always("[%s] ret=%d\n", __func__, ret);
	return ret;
}
// index --> 0, lower; 1, upper
// is_on --> 0, off; 1, on
static int judge_throttling(int index, int is_on, int interval)
{
	/*
	 *     throttling_stat
	 *        2 ( upper=1,lower=1 )
	 * UPPER ----
	 *        1 ( upper=0,lower=1 )
	 * LOWER ----
	 *        0 ( upper=0,lower=0 )
	 */
	static unsigned int throttling_pre_stat = 0;
	static int mail_box[2] = {-1,-1};

	static bool is_reset = false;

	//unsigned long cur_thro = tx_throughput;
	//static unsigned long thro_constraint = 99 * 1000;

	int cur_wifi_stat = 0;

	mtk_cooler_amutt_dprintk("[%s]+ [0]=%d, [1]=%d || [%d] is %s\n", __func__, mail_box[0], mail_box[1],
											index, (is_on==1?"ON":"OFF"));
	mail_box[index] = is_on;

	if (mail_box[0] >= 0 && mail_box[1] >= 0) {
		cur_wifi_stat = mail_box[0] + mail_box[1];

		switch(cur_wifi_stat) {
			case HIGH_STAT:
				if (throttling_pre_stat < HIGH_STAT) {
				    // 1st down throttle
				    int new_step = 
				        down_throttle(&amutt, up_step);

					mtk_cooler_amutt_dprintk_always("LOW/MID-->HIGH: step %d\n", new_step);
					
					throttling_pre_stat = HIGH_STAT;
					over_up_time = 0;
				} else if (throttling_pre_stat == HIGH_STAT) {
				    // keep down throttle
					over_up_time++;
					if ( (over_up_time * interval) >= up_duration) {
					    int new_step = 
    				        down_throttle(&amutt, up_step);

						mtk_cooler_amutt_dprintk_always("HIGH-->HIGH: step %d\n", new_step);

					    over_up_time = 0;
					}
				} else {
					mtk_cooler_amutt_dprintk("[%s] Error state1=%d!!\n", __func__, throttling_pre_stat);
				}
				mtk_cooler_amutt_dprintk_always("case2 time=%d\n", over_up_time);
			break;

			case MID_STAT:
				if (throttling_pre_stat == LOW_STAT) {
					below_low_time = 0;
					throttling_pre_stat = MID_STAT;
					mtk_cooler_amutt_dprintk_always("[%s] Go up!!\n", __func__);
				} else if (throttling_pre_stat == HIGH_STAT) {
					over_up_time = 0;
					throttling_pre_stat = MID_STAT;
					mtk_cooler_amutt_dprintk_always("[%s] Go down!!\n", __func__);
				} else {
					throttling_pre_stat = MID_STAT;
					mtk_cooler_amutt_dprintk("[%s] pre_stat=%d!!\n", __func__, throttling_pre_stat);
				}
			break;

			case LOW_STAT:
				if (throttling_pre_stat > LOW_STAT) {
				    // 1st up throttle
				    int new_step = 
				        up_throttle(&amutt, low_step);

					mtk_cooler_amutt_dprintk_always("MID/HIGH-->LOW: step %d\n", new_step);
					throttling_pre_stat = LOW_STAT;
					below_low_time = 0;
					low_rst_time = 0;
					is_reset = false;
				} else if (throttling_pre_stat == LOW_STAT) {
					below_low_time++;
					if ( (below_low_time*interval) >= low_duration) {
						if (low_rst_time >= low_rst_max && !is_reset) {
						    // rst
                            rst_throttle(&amutt);
						    
							mtk_cooler_amutt_dprintk_always("over rst time=%d\n", low_rst_time);

							low_rst_time = low_rst_max;
							is_reset = true;
						} else if(!is_reset) {
						    // keep up throttle
                            int new_step = 
				                up_throttle(&amutt, low_step);
						    
							low_rst_time++;

							mtk_cooler_amutt_dprintk_always("LOW-->LOW: step %d\n", new_step);

							below_low_time = 0;
						} else {
							mtk_cooler_amutt_dprintk("Have reset, no control!!");
						}
					}
				} else {
					mtk_cooler_amutt_dprintk_always("[%s] Error state3 %d!!\n", __func__, throttling_pre_stat);
				}
				mtk_cooler_amutt_dprintk("case0 time=%d, rst=%d %d\n", below_low_time, low_rst_time, is_reset);
			break;

			default:
				mtk_cooler_amutt_dprintk_always("[%s] Error cur_wifi_stat=%d!!\n", __func__, cur_wifi_stat);
			break;
		}

		mail_box[0] = UNK_STAT;
		mail_box[1] = UNK_STAT;
	} else {
		mtk_cooler_amutt_dprintk("[%s] dont get all info!!\n", __func__);
	}
	return 0;
}