コード例 #1
0
ファイル: tmu-exynos.c プロジェクト: droidroidz/Manta_kernel
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;
}
コード例 #2
0
ファイル: exynos-tmu.c プロジェクト: JamesAng/ub
/*
 * 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;
	}
}
コード例 #3
0
ファイル: tmu.c プロジェクト: tidatida/coreboot
/*
 * 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;
}
コード例 #4
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);
}
コード例 #5
0
/* 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);
}
コード例 #6
0
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);
}
コード例 #7
0
ファイル: tmu_exynos.c プロジェクト: 0x7678/SJKernel-gn2
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));
}
コード例 #8
0
ファイル: tmu-exynos.c プロジェクト: droidroidz/Manta_kernel
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);
}
コード例 #9
0
ファイル: hkdk_tmu.c プロジェクト: rslotte/OGS-Arm
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));

}
コード例 #10
0
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);
コード例 #11
0
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;
}
コード例 #12
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;
}
コード例 #13
0
ファイル: tmu_exynos.c プロジェクト: 0x7678/SJKernel-gn2
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;
}