static int exynos_pm_notifier(struct notifier_block *notifier,
			unsigned long pm_event, void *v)
{
	switch (pm_event) {
	case PM_SUSPEND_PREPARE:
		is_suspending = true;
		exynos_tmu_call_notifier(TMU_COLD);
		exynos_tmu_call_notifier(tmu_old_state);
		exynos_check_mif_noti_state(MEM_TH_TEMP2 - 1);
		exynos_gpu_call_notifier(GPU_COLD);
		break;
	case PM_POST_SUSPEND:
		is_suspending = false;
		break;
	}

	return NOTIFY_OK;
}
Esempio n. 2
0
static int exynos_pm_notifier(struct notifier_block *notifier,
			unsigned long pm_event, void *v)
{
	switch (pm_event) {
	case PM_SUSPEND_PREPARE:
		exynos_tmu_call_notifier(1, old_hot);
		break;
	case PM_POST_SUSPEND:
		break;
	}

	return NOTIFY_OK;
}
Esempio n. 3
0
static int exynos_tmu_read(struct exynos_tmu_data *data)
{
	u8 temp_code;
	int temp, i, max = INT_MIN, min = INT_MAX;
	int cold_event = 0;
	int hot_event = 0;
	enum tmu_noti_state_t cur_state;

	if (!th_zone || !th_zone->therm_dev)
		return -EPERM;

	mutex_lock(&data->lock);
	clk_enable(data->clk);

	for (i = 0; i < EXYNOS_TMU_COUNT; i++) {
		temp_code = readb(data->base[i] + EXYNOS_TMU_REG_CURRENT_TEMP);
		temp = code_to_temp(data, temp_code, i);
		if (temp < 0)
			continue;

		if (temp > max)
			max = temp;
		if (temp < min)
			min = temp;
	}

	clk_disable(data->clk);
	mutex_unlock(&data->lock);

	/* check current tmu state */
	if (min <= COLD_TEMP && !old_cold)
		cold_event = 1;

	if (max >= HOT_CRITICAL_TEMP)
		cur_state = TMU_CRITICAL;
	else if (max > HOT_NORMAL_TEMP && max < HOT_CRITICAL_TEMP)
		cur_state = TMU_HOT;
	else if (max <= HOT_NORMAL_TEMP)
		cur_state = TMU_NORMAL;
	else
		cur_state = TMU_NORMAL;

	if (old_hot != cur_state)
		hot_event = cur_state;

	th_zone->therm_dev->last_temperature = max;

	exynos_tmu_call_notifier(cold_event, hot_event);

	return max;
}
static int exynos_tmu_read(struct exynos_tmu_data *data)
{
	u8 temp_code;
	int temp, i;
	int cold_event = old_cold;
	int hot_event = old_hot;
	int alltemp[EXYNOS_TMU_COUNT] = {0,};

	if (!th_zone || !th_zone->therm_dev)
		return -EPERM;

	mutex_lock(&data->lock);
	clk_enable(data->clk);

	for (i = 0; i < EXYNOS_TMU_COUNT; i++) {
		temp_code = readb(data->base[i] + EXYNOS_TMU_REG_CURRENT_TEMP);
		temp = code_to_temp(data, temp_code);
		alltemp[i] = temp;
	}

	clk_disable(data->clk);
	mutex_unlock(&data->lock);

	if (temp <= THRESH_MEM_TEMP0)
		cold_event = TMU_COLD;
	else
		cold_event = TMU_NORMAL;

	if (old_hot != TMU_THR_LV3 && temp >= THRESH_MEM_TEMP2)
		hot_event = TMU_THR_LV3;
	else if (old_hot != TMU_THR_LV2 && (temp >= THRESH_MEM_TEMP1 && temp < THRESH_MEM_TEMP2))
		hot_event = TMU_THR_LV2;
	else if (old_hot != TMU_THR_LV1 && (temp >= THRESH_MEM_TEMP0 && temp < THRESH_MEM_TEMP1))
		hot_event = TMU_THR_LV1;

	sec_debug_aux_log(SEC_DEBUG_AUXLOG_THERMAL_CHANGE, "[TMU] %d", temp);
	//printk("[TMU] %s : Thermal Read %d C", __func__, temp); Found it!
#ifdef CONFIG_EXYNOS4_EXPORT_TEMP
	tmu_curr_temperature = temp;
#endif
	th_zone->therm_dev->last_temperature = temp;
	exynos_tmu_call_notifier(cold_event, hot_event);
	sec_debug_aux_log(SEC_DEBUG_AUXLOG_THERMAL_CHANGE, "[TMU] alltemp[0]: %d", alltemp[0]);

	return temp;
}
static void exynos_check_tmu_noti_state(int min_temp, int max_temp)
{
	enum tmu_noti_state_t cur_state;

	/* check current temperature state */
	if (max_temp > HOT_CRITICAL_TEMP)
		cur_state = TMU_CRITICAL;
	else if (max_temp > HOT_NORMAL_TEMP && max_temp <= HOT_CRITICAL_TEMP)
		cur_state = TMU_HOT;
	else if (max_temp > COLD_TEMP && max_temp <= HOT_NORMAL_TEMP)
		cur_state = TMU_NORMAL;
	else
		cur_state = TMU_COLD;

	if (min_temp <= COLD_TEMP)
		cur_state = TMU_COLD;

	exynos_tmu_call_notifier(cur_state);
}
static int __devinit exynos_tmu_probe(struct platform_device *pdev)
{
	struct exynos_tmu_data *data;
	struct exynos_tmu_platform_data *pdata = pdev->dev.platform_data;
	int ret, i;

	is_suspending = false;

	if (!pdata)
		pdata = exynos_get_driver_data(pdev);

	if (!pdata) {
		dev_err(&pdev->dev, "No platform init data supplied.\n");
		return -ENODEV;
	}
	data = kzalloc(sizeof(struct exynos_tmu_data), GFP_KERNEL);
	if (!data) {
		dev_err(&pdev->dev, "Failed to allocate driver structure\n");
		return -ENOMEM;
	}
#ifdef CONFIG_ARM_EXYNOS_MP_CPUFREQ
	exynos_cpufreq_init_register_notifier(&exynos_cpufreq_nb);
#endif
	INIT_WORK(&data->irq_work, exynos_tmu_work);

	for (i = 0; i < EXYNOS_TMU_COUNT; i++) {
		data->irq[i] = platform_get_irq(pdev, i);
		if (data->irq[i] < 0) {
			ret = data->irq[i];
			dev_err(&pdev->dev, "Failed to get platform irq\n");
			goto err_free;
		}

		data->mem[i] = platform_get_resource(pdev, IORESOURCE_MEM, i);
		if (!data->mem[i]) {
			ret = -ENOENT;
			dev_err(&pdev->dev, "Failed to get platform resource\n");
			goto err_free;
		}

		data->mem[i] = request_mem_region(data->mem[i]->start,
				resource_size(data->mem[i]), pdev->name);
		if (!data->mem[i]) {
			ret = -ENODEV;
			dev_err(&pdev->dev, "Failed to request memory region\n");
			goto err_free;
		}

		data->base[i] = ioremap(data->mem[i]->start, resource_size(data->mem[i]));
		if (!data->base[i]) {
			ret = -ENODEV;
			dev_err(&pdev->dev, "Failed to ioremap memory\n");
			goto err_mem_region;
		}

		ret = request_irq(data->irq[i], exynos_tmu_irq,
				IRQF_TRIGGER_RISING, "exynos-tmu", data);
		if (ret) {
			dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq[i]);
			goto err_io_remap;
		}
	}

	data->clk = clk_get(NULL, pdata->clk_name);

	if (IS_ERR(data->clk)) {
		ret = PTR_ERR(data->clk);
		dev_err(&pdev->dev, "Failed to get clock\n");
		goto err_irq;
	}

	if (pdata->type == SOC_ARCH_EXYNOS5 ||
				pdata->type == SOC_ARCH_EXYNOS4||
				pdata->type == SOC_ARCH_EXYNOS3)
		data->soc = pdata->type;
	else {
		ret = -EINVAL;
		dev_err(&pdev->dev, "Platform not supported\n");
		goto err_clk;
	}

	data->pdata = pdata;
	platform_set_drvdata(pdev, data);
	mutex_init(&data->lock);

	for (i = 0; i < EXYNOS_TMU_COUNT; i++)
		exynos_tmu_get_efuse(pdev, i);

	/*TMU initialization*/
	for (i = 0; i < EXYNOS_TMU_COUNT; i++) {
		ret = exynos_tmu_initialize(pdev, i);
		if (ret) {
			dev_err(&pdev->dev, "Failed to initialize TMU[%d]\n", i);
			goto err_clk;
		}

		exynos_tmu_control(pdev, i, true);
		exynos_tmu_regdump(pdev, i);
	}

	/*Register the sensor with thermal management interface*/
	(&exynos_sensor_conf)->private_data = data;
	exynos_sensor_conf.trip_data.trip_count = pdata->trigger_level0_en +
		pdata->trigger_level1_en + pdata->trigger_level2_en + pdata->trigger_level3_en;

	for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++)
		exynos_sensor_conf.trip_data.trip_val[i] =
			pdata->threshold + pdata->trigger_levels[i];
	exynos_sensor_conf.cooling_data.freq_clip_count = pdata->freq_tab_count;

	for (i = 0; i < pdata->freq_tab_count; i++) {
		exynos_sensor_conf.cooling_data.freq_data[i].freq_clip_max =
			pdata->freq_tab[i].freq_clip_max;
		exynos_sensor_conf.cooling_data.freq_data[i].temp_level =
			pdata->freq_tab[i].temp_level;
		if (pdata->freq_tab[i].mask_val)
			exynos_sensor_conf.cooling_data.freq_data[i].mask_val =
				pdata->freq_tab[i].mask_val;
		else
			exynos_sensor_conf.cooling_data.freq_data[i].mask_val =
				cpu_all_mask;

	}

	for (i = 0; i <= THERMAL_TRIP_CRITICAL; i++)
		exynos_sensor_conf.cooling_data.size[i] = pdata->size[i];

#ifdef CONFIG_ARM_EXYNOS_MP_CPUFREQ
	exynos_sensor_conf.cooling_data_kfc.freq_clip_count = pdata->freq_tab_count;
	for (i = 0; i < pdata->freq_tab_count; i++) {
		exynos_sensor_conf.cooling_data_kfc.freq_data[i].freq_clip_max =
			pdata->freq_tab_kfc[i].freq_clip_max;
		exynos_sensor_conf.cooling_data_kfc.freq_data[i].temp_level =
			pdata->freq_tab_kfc[i].temp_level;
		if (pdata->freq_tab_kfc[i].mask_val)
			exynos_sensor_conf.cooling_data_kfc.freq_data[i].mask_val =
				pdata->freq_tab_kfc[i].mask_val;
		else
			exynos_sensor_conf.cooling_data_kfc.freq_data[i].mask_val =
				cpu_all_mask;
	}

	for (i = 0; i <= THERMAL_TRIP_CRITICAL; i++)
		exynos_sensor_conf.cooling_data_kfc.size[i] = pdata->size[i];

#endif

	register_pm_notifier(&exynos_pm_nb);

	exynos_tmu_pdev = pdev;

#ifndef CONFIG_ARM_EXYNOS_MP_CPUFREQ
	ret = exynos_register_thermal(&exynos_sensor_conf);
	if (ret) {
		dev_err(&pdev->dev, "Failed to register thermal interface\n");
		goto err_clk;
	}

	th_zone->exynos4_dev = pdev;
	ret = sysfs_create_group(&pdev->dev.kobj, &exynos_thermal_sensor_attr_group);
	if (ret)
		dev_err(&pdev->dev, "cannot create thermal sensor attributes\n");
#endif

	/* For low temperature compensation when boot time */
	exynos_tmu_call_notifier(TMU_COLD);
	exynos_gpu_call_notifier(GPU_COLD);

	return 0;
err_clk:
	platform_set_drvdata(pdev, NULL);
	clk_put(data->clk);
err_irq:
	for (i = 0; i < EXYNOS_TMU_COUNT; i++) {
		if (data->irq[i])
			free_irq(data->irq[i], data);
	}
err_io_remap:
	for (i = 0; i < EXYNOS_TMU_COUNT; i++) {
		if (data->base[i])
			iounmap(data->base[i]);
	}
err_mem_region:
	for (i = 0; i < EXYNOS_TMU_COUNT; i++) {
		if (data->mem[i])
			release_mem_region(data->mem[i]->start, resource_size(data->mem[i]));
	}
err_free:
	kfree(data);
#ifdef CONFIG_ARM_EXYNOS_MP_CPUFREQ
	exynos_cpufreq_init_unregister_notifier(&exynos_cpufreq_nb);
#endif

	return ret;
}
static int exynos_tmu_read(struct exynos_tmu_data *data)
{
	u8 temp_code;
	int temp, i, max = INT_MIN, min = INT_MAX, gpu_temp = 0;

#ifdef CONFIG_ARM_EXYNOS5410_BUS_DEVFREQ
	enum tmu_noti_state_t cur_state;
#endif
	int alltemp[EXYNOS_TMU_COUNT] = {0,};

	if (!th_zone || !th_zone->therm_dev)
		return -EPERM;

	mutex_lock(&data->lock);
	clk_enable(data->clk);

	for (i = 0; i < EXYNOS_TMU_COUNT; i++) {
		temp_code = readb(data->base[i] + EXYNOS_TMU_REG_CURRENT_TEMP);
		temp = code_to_temp(data, temp_code, i);
		if (temp < 0)
			temp = 0;
		alltemp[i] = temp;

		if (temp > max)
			max = temp;
		if (temp < min)
			min = temp;
		if (soc_is_exynos5420() && i == EXYNOS_GPU_NUMBER)
			gpu_temp = temp;
	}
#ifdef CONFIG_SOC_EXYNOS5260
	if (alltemp[EXYNOS_GPU0_NUMBER] > alltemp[EXYNOS_GPU1_NUMBER])
		gpu_temp = alltemp[EXYNOS_GPU0_NUMBER];
	else
		gpu_temp = alltemp[EXYNOS_GPU1_NUMBER];
#endif

	clk_disable(data->clk);
	mutex_unlock(&data->lock);

#ifdef CONFIG_ARM_EXYNOS5410_BUS_DEVFREQ
	if (min <= COLD_TEMP)
		cur_state = TMU_COLD;

	if (max >= HOT_110)
		cur_state = TMU_110;
	else if (max > HOT_95 && max < HOT_110)
		cur_state = TMU_109;
	else if (max <= HOT_95)
		cur_state = TMU_95;

	if (cur_state >= HOT_95)
		pr_info("[TMU] POLLING: temp=%d, cpu=%d, int=%d, mif=%d, hot_event(for aref)=%d\n",
			max, g_cpufreq, g_intfreq, g_miffreq, cur_state);
	g_count++;

	/* to probe thermal run away caused by fimc-is */
	if ((max >= 112 && tmu_old_state == TMU_110)
			&& g_cam_err_count && g_intfreq == 800000) {
		cur_state = TMU_111;
	}
	exynos_tmu_call_notifier(cur_state);
#endif

	if (soc_is_exynos5420()) {
		/* check temperature state */
		exynos_check_tmu_noti_state(min, max);
		exynos_check_gpu_noti_state(gpu_temp);

#ifdef CONFIG_ARM_EXYNOS5420_BUS_DEVFREQ
		if (!check_mif_probed())
			goto out;
#endif
		exynos_check_mif_noti_state(max);
	}

	if (soc_is_exynos5260()) {
		exynos_check_tmu_noti_state(min, max);
		exynos_check_gpu_noti_state(gpu_temp);
		exynos_check_mif_noti_state(max);
	}

#ifdef CONFIG_ARM_EXYNOS5420_BUS_DEVFREQ
out:
#endif
	th_zone->therm_dev->last_temperature = max * MCELSIUS;
	DTM_DBG("[TMU] TMU0 = %d, TMU1 = %d, TMU2 = %d, TMU3 = %d, TMU4 = %d  -------  CPU : %d  ,  GPU : %d\n",
			alltemp[0], alltemp[1], alltemp[2], alltemp[3], alltemp[4], max, gpu_temp);

	return max;
}
static int __devinit exynos_tmu_probe(struct platform_device *pdev)
{
	struct exynos_tmu_platform_data *pdata = pdev->dev.platform_data;
	int ret, i, count = 0;
	int trigger_level_en[TRIP_EN_COUNT];

	if (!pdata)
		pdata = exynos_get_driver_data(pdev);

	if (!pdata) {
		dev_err(&pdev->dev, "No platform init data supplied.\n");
		return -ENODEV;
	}
	tmudata = kzalloc(sizeof(struct exynos_tmu_data), GFP_KERNEL);
	if (!tmudata) {
		dev_err(&pdev->dev, "Failed to allocate driver structure\n");
		return -ENOMEM;
	}

	INIT_WORK(&tmudata->irq_work, exynos_tmu_work);

#ifndef CONFIG_ARM_TRUSTZONE
	/* ioremap for drex base address */
	exynos4_base_drex0 = ioremap(EXYNOS4_PA_DMC0_4X12, SZ_64K);
	exynos4_base_drex1 = ioremap(EXYNOS4_PA_DMC1_4X12, SZ_64K);
	if(!exynos4_base_drex0 || !exynos4_base_drex1) {
		ret = -ENOMEM;
		goto err_drex_ioremap;
	}
#endif

	for (i = 0; i < EXYNOS_TMU_COUNT; i++) {
		tmudata->irq[i] = platform_get_irq(pdev, i);
		if (tmudata->irq[i] < 0) {
			ret = tmudata->irq[i];
			dev_err(&pdev->dev, "Failed to get platform irq\n");
			goto err_get_resource;
		}

		tmudata->mem[i] = platform_get_resource(pdev, IORESOURCE_MEM, i);
		if (!tmudata->mem[i]) {
			ret = -ENOENT;
			dev_err(&pdev->dev, "Failed to get platform resource\n");
			goto err_get_resource;
		}

		tmudata->mem[i] = request_mem_region(tmudata->mem[i]->start,
				resource_size(tmudata->mem[i]), pdev->name);
		if (!tmudata->mem[i]) {
			ret = -ENODEV;
			dev_err(&pdev->dev, "Failed to request memory region\n");
			goto err_mem_region;
		}

		tmudata->base[i] = ioremap(tmudata->mem[i]->start, resource_size(tmudata->mem[i]));
		if (!tmudata->base[i]) {
			ret = -ENODEV;
			dev_err(&pdev->dev, "Failed to ioremap memory\n");
			goto err_io_remap;
		}

		ret = request_irq(tmudata->irq[i], exynos_tmu_irq,
				IRQF_TRIGGER_RISING, "exynos-tmu", tmudata);
		if (ret) {
			dev_err(&pdev->dev, "Failed to request irq: %d\n", tmudata->irq[i]);
			goto err_irq;
		}
	}

	tmudata->clk = clk_get(NULL, "tmu");
	if (IS_ERR(tmudata->clk)) {
		ret = PTR_ERR(tmudata->clk);
		dev_err(&pdev->dev, "Failed to get clock\n");
		goto err_clk;
	}

	if (pdata->type == SOC_ARCH_EXYNOS5 ||
				pdata->type == SOC_ARCH_EXYNOS4)
		tmudata->soc = pdata->type;
	else {
		ret = -EINVAL;
		dev_err(&pdev->dev, "Platform not supported\n");
		goto err_soc_type;
	}

	tmudata->pdata = pdata;
	platform_set_drvdata(pdev, tmudata);
	mutex_init(&tmudata->lock);

	for (i = 0; i < EXYNOS_TMU_COUNT; i++) {
		ret = exynos_tmu_initialize(pdev, i);
		if (ret) {
			dev_err(&pdev->dev, "Failed to initialize TMU[%d]\n", i);
			goto err_tmu;
		}

		exynos_tmu_control(pdev, i, true);
	}

	/*Register the sensor with thermal management interface*/
	(&exynos_sensor_conf)->private_data = tmudata;
	exynos_sensor_conf.trip_data.trip_count = pdata->trigger_level0_en +
			pdata->trigger_level1_en + pdata->trigger_level2_en +
			pdata->trigger_level3_en;

	trigger_level_en[0] = pdata->trigger_level0_en;
	trigger_level_en[1] = pdata->trigger_level1_en;
	trigger_level_en[2] = pdata->trigger_level2_en;
	trigger_level_en[3] = pdata->trigger_level3_en;

	for (i = 0; i < TRIP_EN_COUNT; i++) {
		if (trigger_level_en[i]) {
			exynos_sensor_conf.trip_data.trip_val[count] =
				pdata->threshold + pdata->trigger_levels[i];
			count++;
		}
	}

	exynos_sensor_conf.cooling_data.freq_clip_count =
						pdata->freq_tab_count;

	for (i = 0; i <= THERMAL_TRIP_CRITICAL; i++)
		exynos_sensor_conf.cooling_data.size[i] = pdata->size[i];

	for (i = 0; i < pdata->freq_tab_count; i++) {
		exynos_sensor_conf.cooling_data.freq_data[i].freq_clip_max =
					pdata->freq_tab[i].freq_clip_max;
		exynos_sensor_conf.cooling_data.freq_data[i].temp_level =
					pdata->freq_tab[i].temp_level;
		exynos_sensor_conf.cooling_data.freq_data[i].mask_val = cpu_all_mask;
	}

	register_pm_notifier(&exynos_pm_nb);

	ret = exynos_register_thermal(&exynos_sensor_conf);
	if (ret) {
		dev_err(&pdev->dev, "Failed to register thermal interface\n");
		goto err_register;
	}

	th_zone->exynos4_dev = pdev;

	/* For low temperature compensation when boot time */
	exynos_tmu_call_notifier(1, 0);
	
#ifdef CONFIG_EXYNOS4_EXPORT_TEMP
	tmu_curr_temperature = 35; // seems reasonable :-|
#endif

	return 0;

err_register:
	unregister_pm_notifier(&exynos_pm_nb);
err_tmu:
	platform_set_drvdata(pdev, NULL);
err_soc_type:
	clk_put(tmudata->clk);
err_clk:
	for (i = 0; i < EXYNOS_TMU_COUNT; i++) {
		if (tmudata->irq[i])
			free_irq(tmudata->irq[i], tmudata);
	}
err_irq:
	for (i = 0; i < EXYNOS_TMU_COUNT; i++) {
		if (tmudata->base[i])
			iounmap(tmudata->base[i]);
	}
err_io_remap:
	for (i = 0; i < EXYNOS_TMU_COUNT; i++) {
		if (tmudata->mem[i])
			release_mem_region(tmudata->mem[i]->start, resource_size(tmudata->mem[i]));
	}
err_mem_region:
err_get_resource:
#ifndef  CONFIG_ARM_TRUSTZONE
	iounmap(exynos4_base_drex0);
	iounmap(exynos4_base_drex1);
err_drex_ioremap:
	kfree(tmudata);
#endif

	return ret;
}