static int tmu_debug_show(struct seq_file *s, void *unused) { struct tmu_info *info = s->private; char *cur_tmu_state; seq_printf(s, "Current Temperature : %d\n", get_cur_temp(info)); switch (info->tmu_state) { case TMU_STATUS_INIT: case TMU_STATUS_NORMAL: cur_tmu_state = "TMU_STATUS_NORMAL"; break; case TMU_STATUS_THROTTLED: cur_tmu_state = "TMU_STATUS_THROTTLED"; break; case TMU_STATUS_TRIPPED: cur_tmu_state = "TMU_STATUS_TRIPPED"; break; default: cur_tmu_state = "INVALID STATUS"; break; } seq_printf(s, "Current TMU State : %s\n", cur_tmu_state); seq_printf(s, "Memory Throttling : %s\n", info->mem_throttled ? "throttled" : "unthrottled"); seq_printf(s, "Memory throttle auto refresh time : %d ns\n", info->auto_refresh_mem_throttle); seq_printf(s, "Normal auto refresh time : %d ns\n", info->auto_refresh_normal); seq_printf(s, "TMU monitoring sample rate : %d ms\n", info->sampling_rate); return 0; }
/* * Monitors status of the TMU device and exynos temperature * * @param temp pointer to the current temperature value * @return enum tmu_status_t value, code indicating event to execute */ enum tmu_status_t tmu_monitor(int *temp) { int cur_temp; struct tmu_data *data = &gbl_info.data; if (gbl_info.tmu_state == TMU_STATUS_INIT) return TMU_STATUS_INIT; /* Read current temperature of the SOC */ cur_temp = get_cur_temp(&gbl_info); *temp = cur_temp; /* Temperature code lies between min 25 and max 125 */ if (cur_temp >= data->ts.start_tripping && cur_temp <= data->ts.max_val) { return TMU_STATUS_TRIPPED; } else if (cur_temp >= data->ts.start_warning) { return TMU_STATUS_WARNING; } else if (cur_temp < data->ts.start_warning && cur_temp >= data->ts.min_val) { return TMU_STATUS_NORMAL; } else { /* Temperature code does not lie between min 25 and max 125 */ gbl_info.tmu_state = TMU_STATUS_INIT; debug("EXYNOS_TMU: Thermal reading failed\n"); return TMU_STATUS_INIT; } }
/* * Monitors status of the TMU device and exynos temperature * * @info TMU info * @temp pointer to the current temperature value * @return enum tmu_status_t value, code indicating event to execute */ enum tmu_status_t tmu_monitor(struct tmu_info *info, int *temp) { if (info->tmu_state == TMU_STATUS_INIT) return -1; int cur_temp; struct tmu_data *data = &info->data; /* Read current temperature of the SOC */ cur_temp = get_cur_temp(info); *temp = cur_temp; /* Temperature code lies between min 25 and max 125 */ if (cur_temp >= data->ts.start_tripping && cur_temp <= data->ts.max_val) return TMU_STATUS_TRIPPED; else if (cur_temp >= data->ts.start_warning) return TMU_STATUS_WARNING; else if (cur_temp < data->ts.start_warning && cur_temp >= data->ts.min_val) return TMU_STATUS_NORMAL; /* Temperature code does not lie between min 25 and max 125 */ else { info->tmu_state = TMU_STATUS_INIT; printk(BIOS_DEBUG, "EXYNOS_TMU: Thermal reading failed\n"); return -1; } return 0; }
static void tmu_monitor(struct work_struct *work) { struct delayed_work *delayed_work = to_delayed_work(work); struct tmu_info *info = container_of(delayed_work, struct tmu_info, polling); struct tmu_data *data = info->dev->platform_data; int cur_temp; cur_temp = get_cur_temp(info); dev_dbg(info->dev, "Current: %dc, FLAG=%d\n", cur_temp, info->tmu_state); mutex_lock(&tmu_lock); switch (info->tmu_state) { case TMU_STATUS_NORMAL: exynos_thermal_unthrottle(); enable_irq(info->irq); goto out; case TMU_STATUS_THROTTLED: if (cur_temp >= data->ts.start_tripping) info->tmu_state = TMU_STATUS_TRIPPED; else if (cur_temp > data->ts.stop_throttle) exynos_thermal_throttle(); else info->tmu_state = TMU_STATUS_NORMAL; break; case TMU_STATUS_TRIPPED: if (cur_temp >= data->ts.start_emergency) panic("Emergency thermal shutdown: temp=%d\n", cur_temp); if (cur_temp >= data->ts.start_tripping) pr_err("thermal tripped: temp=%d\n", cur_temp); else info->tmu_state = TMU_STATUS_THROTTLED; break; default: break; } /* Memory throttling */ if (cur_temp >= data->ts.start_mem_throttle && !info->mem_throttled) { set_refresh_period(FREQ_IN_PLL, info->auto_refresh_mem_throttle); info->mem_throttled = true; dev_dbg(info->dev, "set auto refresh period %dns\n", info->auto_refresh_mem_throttle); } else if (cur_temp <= data->ts.stop_mem_throttle && info->mem_throttled) { set_refresh_period(FREQ_IN_PLL, info->auto_refresh_normal); info->mem_throttled = false; dev_dbg(info->dev, "set auto refresh period %dns\n", info->auto_refresh_normal); } queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, info->sampling_rate); out: mutex_unlock(&tmu_lock); }
/* Sysfs interface for thermal information */ static ssize_t show_temperature(struct device *dev, struct device_attribute *attr, char *buf) { struct tmu_info *info = dev_get_drvdata(dev); int temperature; if (!dev) return -ENODEV; temperature = get_cur_temp(info); return sprintf(buf, "%d\n", temperature); }
static void cur_temp_monitor(struct work_struct *work) { int cur_temp; struct delayed_work *delayed_work = to_delayed_work(work); struct tmu_info *info = container_of(delayed_work, struct tmu_info, monitor); cur_temp = get_cur_temp(info); pr_info("current temp = %d\n", cur_temp); queue_delayed_work_on(0, tmu_monitor_wq, &info->monitor, info->sampling_rate); }
static void cur_temp_monitor(struct work_struct *work) { unsigned char cur_temp; struct delayed_work *delayed_work = to_delayed_work(work); struct tmu_info *info = container_of(delayed_work, struct tmu_info, monitor); cur_temp = get_cur_temp(info); pr_info("current temp = %d\n", cur_temp); queue_delayed_work_on(0, tmu_monitor_wq, &info->monitor, usecs_to_jiffies(1000 * 1000)); }
static void tmu_monitor(struct work_struct *work) { struct delayed_work *delayed_work = to_delayed_work(work); struct tmu_info *info = container_of(delayed_work, struct tmu_info, polling); struct tmu_data *data = info->dev->platform_data; int cur_temp; cur_temp = get_cur_temp(info); dev_dbg(info->dev, "Current: %dc, FLAG=%d\n", cur_temp, info->tmu_state); mutex_lock(&tmu_lock); switch (info->tmu_state) { case TMU_STATUS_NORMAL: exynos_thermal_unthrottle(); enable_irq(info->irq); goto out; case TMU_STATUS_THROTTLED: if (cur_temp >= data->ts.start_tripping) info->tmu_state = TMU_STATUS_TRIPPED; else if (cur_temp > data->ts.stop_throttle) exynos_thermal_throttle(); else info->tmu_state = TMU_STATUS_NORMAL; break; case TMU_STATUS_TRIPPED: if (cur_temp >= data->ts.start_emergency) panic("Emergency thermal shutdown: temp=%d\n", cur_temp); if (cur_temp >= data->ts.start_tripping) { pr_err("thermal tripped: temp=%d\n", cur_temp); /* Throttle twice while tripping */ exynos_thermal_throttle(); } else { info->tmu_state = TMU_STATUS_THROTTLED; } /* Throttle when tripped */ exynos_thermal_throttle(); break; default: break; } queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, info->sampling_rate); out: mutex_unlock(&tmu_lock); }
static void tmu_work_out(struct work_struct *work) { struct delayed_work *dw = to_delayed_work(work); struct s_hkdk_tmu *hkdk_tmu = container_of(dw, struct s_hkdk_tmu, tmu_work); get_cur_temp(hkdk_tmu); if (hkdk_tmu->TMU_TEMP1 == false && hkdk_tmu->curr_temp >= TMU_TEMP1_START) { pr_info("HKDK Stage 1 Kick In\n"); hkdk_tmu->TMU_TEMP1 = true; hack_setcpu_frequency(TMU_TEMP1_CPU_SPEED); goto out; } if (hkdk_tmu->TMU_TEMP1 == true && hkdk_tmu->curr_temp <= TMU_TEMP1_STOP) { pr_info("HKDK Stage 1 Kick out\n"); hkdk_tmu->TMU_TEMP1 = false; hack_setcpu_frequency(TMU_MAX_FREQ); goto out; } if (hkdk_tmu->TMU_TEMP2 == false && hkdk_tmu->curr_temp >= TMU_TEMP2_START) { pr_info("HKDK Stage 2 Kick in\n"); hkdk_tmu->TMU_TEMP2 = true; hack_setcpu_frequency(TMU_TEMP2_CPU_SPEED); goto out; } if (hkdk_tmu->TMU_TEMP2 == true && hkdk_tmu->curr_temp <= TMU_TEMP2_STOP) { pr_info("HKDK Stage 2 Kick out\n"); hkdk_tmu->TMU_TEMP2 = false; hack_setcpu_frequency(TMU_TEMP1_CPU_SPEED); goto out; } goto out; out: disable_irq_nosync(hkdk_tmu->irq); queue_delayed_work_on(0, tmu_wq, &hkdk_tmu->tmu_work, usecs_to_jiffies(1500 * 1000)); }
static irqreturn_t tmu_irq(int irq, void *id) { struct tmu_info *info = id; unsigned int status; disable_irq_nosync(irq); status = __raw_readl(info->tmu_base + INTSTAT); /* To handle multiple interrupt pending, * interrupt by high temperature are serviced with priority. */ #if defined(CONFIG_TC_VOLTAGE) if (status & INTSTAT_FALL0) { pr_info("TC interrupt occured..!\n"); __raw_writel(INTCLEAR_FALL0, info->tmu_base + INTCLEAR); info->tmu_state = TMU_STATUS_TC; } else if (status & INTSTAT_RISE2) { #else if (status & INTSTAT_RISE2) { #endif pr_info("Tripping interrupt occured..!\n"); info->tmu_state = TMU_STATUS_TRIPPED; __raw_writel(INTCLEAR_RISE2, info->tmu_base + INTCLEAR); } else if (status & INTSTAT_RISE1) { pr_info("Warning interrupt occured..!\n"); __raw_writel(INTCLEAR_RISE1, info->tmu_base + INTCLEAR); info->tmu_state = TMU_STATUS_WARNING; } else if (status & INTSTAT_RISE0) { pr_info("Throttling interrupt occured..!\n"); __raw_writel(INTCLEAR_RISE0, info->tmu_base + INTCLEAR); info->tmu_state = TMU_STATUS_THROTTLED; } else { pr_err("%s: TMU interrupt error\n", __func__); return -ENODEV; } queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, usecs_to_jiffies(1 * 1000)); return IRQ_HANDLED; } static irqreturn_t exynos4210_tmu_irq(int irq, void *id) { struct tmu_info *info = id; unsigned int status; disable_irq_nosync(irq); status = __raw_readl(info->tmu_base + INTSTAT); if (status & INTSTAT2) { pr_info("Tripping interrupt occured..!\n"); info->tmu_state = TMU_STATUS_TRIPPED; __raw_writel(INTCLEAR2, info->tmu_base + INTCLEAR); } else if (status & INTSTAT1) { pr_info("Warning interrupt occured..!\n"); __raw_writel(INTCLEAR1, info->tmu_base + INTCLEAR); info->tmu_state = TMU_STATUS_WARNING; } else if (status & INTSTAT0) { pr_info("Throttling interrupt occured..!\n"); __raw_writel(INTCLEAR0, info->tmu_base + INTCLEAR); info->tmu_state = TMU_STATUS_THROTTLED; } else { pr_err("%s: TMU interrupt error\n", __func__); return -ENODEV; } queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, usecs_to_jiffies(1000)); return IRQ_HANDLED; } static int __devinit tmu_probe(struct platform_device *pdev) { struct tmu_info *info; struct resource *res; int ret = 0; pr_debug("%s: probe=%p\n", __func__, pdev); info = kzalloc(sizeof(struct tmu_info), GFP_KERNEL); if (!info) { dev_err(&pdev->dev, "failed to alloc memory!\n"); ret = -ENOMEM; goto err_nomem; } pr_emerg("TMU: Memory Allocation Sucessful\n"); platform_set_drvdata(pdev, info); pr_emerg("TMU: Platform data set\n"); info->dev = &pdev->dev; pr_emerg("TMU: Copied the Dev access Information \n"); info->irq = platform_get_irq(pdev, 0); if (info->irq < 0) { dev_err(&pdev->dev, "no irq for thermal\n"); ret = -ENOENT; goto err_noirq; } if (soc_is_exynos4210()) ret = request_irq(info->irq, exynos4210_tmu_irq, IRQF_DISABLED, "tmu interrupt", info); else ret = request_irq(info->irq, tmu_irq, IRQF_DISABLED, "tmu interrupt", info); if (ret) { dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq, ret); goto err_noirq; } pr_emerg("TMU: IRQ Granted!\n"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "failed to get memory region resource\n"); ret = -ENODEV; goto err_nores; } pr_emerg("TMU: IO Resource alloced on Memory\n"); info->ioarea = request_mem_region(res->start, res->end-res->start+1, pdev->name); if (!(info->ioarea)) { dev_err(&pdev->dev, "failed to reserve memory region\n"); ret = -EBUSY; goto err_nores; } pr_emerg("TMU: Memory area resersed\n"); info->tmu_base = ioremap(res->start, (res->end - res->start) + 1); if (!(info->tmu_base)) { dev_err(&pdev->dev, "failed ioremap()\n"); ret = -EINVAL; goto err_nomap; } pr_emerg("TMU: IO Memory Remapped\n"); if (thermal_create_sysfs_file(&pdev->dev)) goto err_sysfs; pr_emerg("TMU: Created Sysfs\n"); tmu_monitor_wq = create_freezable_workqueue("tmu"); if (!tmu_monitor_wq) { dev_err(&pdev->dev, "Creation of tmu_monitor_wq failed\n"); ret = -EFAULT; goto err_wq; } pr_emerg("TMU: Workqueue Created\n"); INIT_DELAYED_WORK_DEFERRABLE(&info->polling, tmu_monitor); pr_emerg("TMU: Work Created\n"); #ifdef CONFIG_TMU_DEBUG INIT_DELAYED_WORK_DEFERRABLE(&info->monitor, cur_temp_monitor); #endif print_temperature_params(info); pr_emerg("TMU: Printed Parameters\n"); ret = tmu_initialize(pdev); if (ret < 0) goto err_noinit; #ifdef CONFIG_TMU_DEBUG queue_delayed_work_on(0, tmu_monitor_wq, &info->monitor, info->sampling_rate); #endif pr_info("Tmu Initialization is sucessful...!\n"); return ret; err_noinit: destroy_workqueue(tmu_monitor_wq); err_wq: thermal_remove_sysfs_file(&pdev->dev); err_sysfs: iounmap(info->tmu_base); err_nomap: release_resource(info->ioarea); err_nores: free_irq(info->irq, info); err_noirq: kfree(info); info = NULL; err_nomem: dev_err(&pdev->dev, "initialization failed.\n"); return ret; } static int __devinit tmu_remove(struct platform_device *pdev) { struct tmu_info *info = platform_get_drvdata(pdev); cancel_delayed_work(&info->polling); destroy_workqueue(tmu_monitor_wq); thermal_remove_sysfs_file(&pdev->dev); iounmap(info->tmu_base); release_resource(info->ioarea); free_irq(info->irq, (void *)pdev); kfree(info); info = NULL; pr_info("%s is removed\n", dev_name(&pdev->dev)); return 0; } #ifdef CONFIG_PM static int tmu_suspend(struct platform_device *pdev, pm_message_t state) { struct tmu_info *info = platform_get_drvdata(pdev); pm_tmu_save(info); return 0; } static int tmu_resume(struct platform_device *pdev) { struct tmu_info *info = platform_get_drvdata(pdev); #if defined(CONFIG_TC_VOLTAGE) struct tmu_data *data = info->dev->platform_data; #endif pm_tmu_restore(info); #if defined(CONFIG_TC_VOLTAGE) /* s/w workaround for fast service when interrupt is not occured, * such as current temp is lower than tc interrupt temperature * or current temp is continuosly increased. */ mdelay(1); if (get_cur_temp(info) <= data->ts.start_tc) { disable_irq_nosync(info->irq); if (exynos_tc_volt(info, 1) < 0) pr_err("%s\n", __func__); info->tmu_state = TMU_STATUS_TC; already_limit = 1; queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, usecs_to_jiffies(1 * 1000)); } #endif return 0; } #else #define tmu_suspend NULL #define tmu_resume NULL #endif static struct platform_driver tmu_driver = { .probe = tmu_probe, .remove = tmu_remove, .suspend = tmu_suspend, .resume = tmu_resume, .driver = { .name = "tmu", .owner = THIS_MODULE, }, }; static int __init tmu_driver_init(void) { return platform_driver_register(&tmu_driver); } late_initcall(tmu_driver_init);
static int exynos_tmu_init(struct tmu_info *info) { struct tmu_data *data = info->dev->platform_data; unsigned int te_temp, con; unsigned int temp_throttle, temp_warning, temp_trip; unsigned int hw_temp_trip; unsigned int rising_thr = 0, cooling_thr = 0; /* must reload for using efuse value at EXYNOS4212 */ __raw_writel(TRIMINFO_RELOAD, info->tmu_base + TRIMINFO_CON); /* get the compensation parameter */ te_temp = __raw_readl(info->tmu_base + TRIMINFO); info->te1 = te_temp & TRIM_INFO_MASK; info->te2 = ((te_temp >> 8) & TRIM_INFO_MASK); if ((EFUSE_MIN_VALUE > info->te1) || (info->te1 > EFUSE_MAX_VALUE) || (info->te2 != 0)) info->te1 = data->efuse_value; /*Get rising Threshold and Set interrupt level*/ temp_throttle = data->ts.start_throttle + info->te1 - TMU_DC_VALUE; temp_warning = data->ts.start_warning + info->te1 - TMU_DC_VALUE; temp_trip = data->ts.start_tripping + info->te1 - TMU_DC_VALUE; hw_temp_trip = data->ts.start_hw_tripping + info->te1 - TMU_DC_VALUE; rising_thr = (temp_throttle | (temp_warning<<8) | \ (temp_trip<<16) | (hw_temp_trip<<24)); __raw_writel(rising_thr, info->tmu_base + THD_TEMP_RISE); #if defined(CONFIG_TC_VOLTAGE) /* Get set temperature for tc_voltage and set falling interrupt * trigger level */ cooling_thr = data->ts.start_tc + info->te1 - TMU_DC_VALUE; #endif __raw_writel(cooling_thr, info->tmu_base + THD_TEMP_FALL); /* Set TMU status */ info->tmu_state = TMU_STATUS_INIT; /* Set frequecny level */ exynos_cpufreq_get_level(data->cpulimit.throttle_freq, &info->throttle_freq); exynos_cpufreq_get_level(data->cpulimit.warning_freq, &info->warning_freq); /* Map auto_refresh_rate of normal & tq0 mode */ info->auto_refresh_tq0 = get_refresh_interval(FREQ_IN_PLL, AUTO_REFRESH_PERIOD_TQ0); info->auto_refresh_normal = get_refresh_interval(FREQ_IN_PLL, AUTO_REFRESH_PERIOD_NORMAL); /* To poll current temp, set sampling rate */ info->sampling_rate = usecs_to_jiffies(200 * 1000); #if defined(CONFIG_TC_VOLTAGE) /* Temperature compensated voltage */ if (exynos_find_cpufreq_level_by_volt(data->temp_compensate.arm_volt, &info->cpulevel_tc) < 0) { pr_err("cpufreq_get_level error\n"); return -EINVAL; } #ifdef CONFIG_BUSFREQ_OPP /* To lock bus frequency in OPP mode */ info->bus_dev = dev_get("exynos-busfreq"); if (info->bus_dev < 0) { pr_err("Failed to get_dev\n"); return -EINVAL; } if (exynos4x12_find_busfreq_by_volt(data->temp_compensate.bus_volt, &info->busfreq_tc)) { pr_err("get_busfreq_value error\n"); } #endif if (mali_voltage_lock_init()) { pr_err("Failed to initialize mail voltage lock.\n"); return -EINVAL; } pr_info("%s: cpufreq_level[%d], busfreq_value[%d]\n", __func__, info->cpulevel_tc, info->busfreq_tc); #endif /* Need to initail regsiter setting after getting parameter info */ /* [28:23] vref [11:8] slope - Tunning parameter */ __raw_writel(data->slope, info->tmu_base + TMU_CON); __raw_writel((CLEAR_RISE_INT | CLEAR_FALL_INT), \ info->tmu_base + INTCLEAR); /* TMU core enable and HW trpping enable */ con = __raw_readl(info->tmu_base + TMU_CON); con &= ~(HW_TRIP_MODE); con |= (HW_TRIPPING_EN | MUX_ADDR_VALUE<<20 | CORE_EN); __raw_writel(con, info->tmu_base + TMU_CON); /* Because temperature sensing time is appro 940us, * tmu is enabled and 1st valid sample can get 1ms after. */ mdelay(1); te_temp = __raw_readl(S5P_PMU_PS_HOLD_CONTROL); te_temp |= S5P_PS_HOLD_EN; __raw_writel(te_temp, S5P_PMU_PS_HOLD_CONTROL); /*LEV0 LEV1 LEV2 interrupt enable */ __raw_writel(INTEN_RISE0 | INTEN_RISE1 | INTEN_RISE2, \ info->tmu_base + INTEN); #if defined(CONFIG_TC_VOLTAGE) te_temp = __raw_readl(info->tmu_base + INTEN); te_temp |= INTEN_FALL0; __raw_writel(te_temp, info->tmu_base + INTEN); /* s/w workaround for fast service when interrupt is not occured, * such as current temp is lower than tc interrupt temperature * or current temp is continuosly increased. */ if (get_cur_temp(info) <= data->ts.start_tc) { disable_irq_nosync(info->irq); if (exynos_tc_volt(info, 1) < 0) pr_err("%s\n", __func__); info->tmu_state = TMU_STATUS_TC; already_limit = 1; queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, usecs_to_jiffies(1000)); } #endif return 0; }
static void tmu_monitor(struct work_struct *work) { struct delayed_work *delayed_work = to_delayed_work(work); struct tmu_info *info = container_of(delayed_work, struct tmu_info, polling); struct tmu_data *data = info->dev->platform_data; int cur_temp; cur_temp = get_cur_temp(info); #ifdef CONFIG_TMU_DEBUG cancel_delayed_work(&info->monitor); pr_info("Current: %dc, FLAG=%d\n", cur_temp, info->tmu_state); #endif mutex_lock(&tmu_lock); switch (info->tmu_state) { #if defined(CONFIG_TC_VOLTAGE) case TMU_STATUS_TC: if (cur_temp >= data->ts.stop_tc) { if (exynos_tc_volt(info, 0) < 0) pr_err("%s\n", __func__); info->tmu_state = TMU_STATUS_NORMAL; already_limit = 0; pr_info("TC limit is released!!\n"); } else if (cur_temp <= data->ts.start_tc && !already_limit) { if (exynos_tc_volt(info, 1) < 0) pr_err("%s\n", __func__); already_limit = 1; } break; #endif case TMU_STATUS_NORMAL: #ifdef CONFIG_TMU_DEBUG queue_delayed_work_on(0, tmu_monitor_wq, &info->monitor, info->sampling_rate); #endif __raw_writel((CLEAR_RISE_INT|CLEAR_FALL_INT), info->tmu_base + INTCLEAR); enable_irq(info->irq); mutex_unlock(&tmu_lock); return; case TMU_STATUS_THROTTLED: if (cur_temp >= data->ts.start_warning) { info->tmu_state = TMU_STATUS_WARNING; exynos_cpufreq_upper_limit_free(DVFS_LOCK_ID_TMU); already_limit = 0; } else if (cur_temp > data->ts.stop_throttle && cur_temp < data->ts.start_warning && !already_limit) { exynos_cpufreq_upper_limit(DVFS_LOCK_ID_TMU, info->throttle_freq); already_limit = 1; } else if (cur_temp <= data->ts.stop_throttle) { info->tmu_state = TMU_STATUS_NORMAL; exynos_cpufreq_upper_limit_free(DVFS_LOCK_ID_TMU); pr_info("Freq limit is released!!\n"); already_limit = 0; } break; case TMU_STATUS_WARNING: if (cur_temp >= data->ts.start_tripping) { info->tmu_state = TMU_STATUS_TRIPPED; already_limit = 0; } else if (cur_temp > data->ts.stop_warning && \ cur_temp < data->ts.start_tripping && !already_limit) { exynos_cpufreq_upper_limit(DVFS_LOCK_ID_TMU, info->warning_freq); already_limit = 1; } else if (cur_temp <= data->ts.stop_warning) { info->tmu_state = TMU_STATUS_THROTTLED; exynos_cpufreq_upper_limit_free(DVFS_LOCK_ID_TMU); already_limit = 0; } break; case TMU_STATUS_TRIPPED: mutex_unlock(&tmu_lock); tmu_tripped_cb(); return; default: break; } /* memory throttling */ if (cur_temp >= data->ts.start_mem_throttle && !(auto_refresh_changed)) { pr_info("set auto_refresh 1.95us\n"); set_refresh_rate(info->auto_refresh_tq0); auto_refresh_changed = 1; } else if (cur_temp <= (data->ts.stop_mem_throttle) && (auto_refresh_changed)) { pr_info("set auto_refresh 3.9us\n"); set_refresh_rate(info->auto_refresh_normal); auto_refresh_changed = 0; } queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, info->sampling_rate); mutex_unlock(&tmu_lock); return; }
static void tmu_monitor(struct work_struct *work) { struct delayed_work *delayed_work = to_delayed_work(work); struct tmu_info *info = container_of(delayed_work, struct tmu_info, polling); struct tmu_data *data = info->dev->platform_data; unsigned char cur_temp; #ifdef CONFIG_TMU_DEBUG cancel_delayed_work(&info->monitor); #endif cur_temp = get_cur_temp(info); pr_info("Current: %dc, FLAG=%d\n", cur_temp, info->tmu_state); switch (info->tmu_state) { case TMU_STATUS_NORMAL: #ifdef CONFIG_TMU_DEBUG queue_delayed_work_on(0, tmu_monitor_wq, &info->monitor, usecs_to_jiffies(1000 * 1000)); #endif cancel_delayed_work(&info->polling); enable_irq(info->irq); break; case TMU_STATUS_THROTTLED: if (cur_temp >= data->ts.start_warning) info->tmu_state = TMU_STATUS_WARNING; else if (cur_temp > data->ts.stop_throttle && cur_temp < data->ts.start_warning) exynos_cpufreq_upper_limit(DVFS_LOCK_ID_TMU, data->cpulimit.throttle_freq); else if (cur_temp <= data->ts.stop_throttle) { info->tmu_state = TMU_STATUS_NORMAL; exynos_cpufreq_upper_limit_free(DVFS_LOCK_ID_TMU); } queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, usecs_to_jiffies(500 * 1000)); break; case TMU_STATUS_WARNING: if (cur_temp >= data->ts.start_tripping) info->tmu_state = TMU_STATUS_TRIPPED; else if (cur_temp > data->ts.stop_warning && \ cur_temp < data->ts.start_tripping) exynos_cpufreq_upper_limit(DVFS_LOCK_ID_TMU, data->cpulimit.warning_freq); else if (cur_temp <= data->ts.stop_warning) { info->tmu_state = TMU_STATUS_THROTTLED; exynos_cpufreq_upper_limit_free(DVFS_LOCK_ID_TMU); } queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, usecs_to_jiffies(500 * 1000)); break; case TMU_STATUS_TRIPPED: tmu_tripped_cb(); queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, usecs_to_jiffies(5000 * 1000)); default: break; } return; }