static void omap_configure_temp_sensor_thresholds(struct omap_temp_sensor
						  *temp_sensor)
{
	u32 temp = 0, t_hot, t_cold, tshut_hot, tshut_cold;

#ifdef CONFIG_OMAP_TEMP_CONTROL
	t_hot = temp_to_adc_conversion(temp_limit);
	t_cold = temp_to_adc_conversion(temp_limit - (BGAP_THRESHOLD_T_HOT - BGAP_THRESHOLD_T_COLD));
#else
	t_hot = temp_to_adc_conversion(BGAP_THRESHOLD_T_HOT);
	t_cold = temp_to_adc_conversion(BGAP_THRESHOLD_T_COLD);
#endif

	if ((t_hot == -EINVAL) || (t_cold == -EINVAL)) {
		pr_err("%s:Temp thresholds out of bounds\n", __func__);
		return;
	}
	temp |= ((t_hot << OMAP4_T_HOT_SHIFT) | (t_cold << OMAP4_T_COLD_SHIFT));
	omap_temp_sensor_writel(temp_sensor, temp, BGAP_THRESHOLD_OFFSET);

	tshut_hot = temp_to_adc_conversion(TSHUT_THRESHOLD_TSHUT_HOT);
	tshut_cold = temp_to_adc_conversion(TSHUT_THRESHOLD_TSHUT_COLD);
	if ((tshut_hot == -EINVAL) || (tshut_cold == -EINVAL)) {
		pr_err("%s:Temp shutdown thresholds out of bounds\n", __func__);
		return;
	}
	temp |= ((tshut_hot << OMAP4_TSHUT_HOT_SHIFT)
			| (tshut_cold << OMAP4_TSHUT_COLD_SHIFT));
	omap_temp_sensor_writel(temp_sensor, temp, BGAP_TSHUT_OFFSET);
}
static void omap_temp_sensor_force_single_read(
				struct omap_temp_sensor *temp_sensor)
{
	int temp = 0, counter = 1000;

	/* Select single conversion mode */
	temp = omap_temp_sensor_readl(temp_sensor, BGAP_CTRL_OFFSET);
	temp &= ~(OMAP4_SINGLE_MODE_MASK);
	omap_temp_sensor_writel(temp_sensor, temp, BGAP_CTRL_OFFSET);
	/* Start of Conversion = 1 */
	temp = omap_temp_sensor_readl(temp_sensor, TEMP_SENSOR_CTRL_OFFSET);
	temp |= OMAP4_BGAP_TEMP_SENSOR_SOC_MASK;
	omap_temp_sensor_writel(temp_sensor, temp, TEMP_SENSOR_CTRL_OFFSET);
	/* Wait until DTEMP is updated */
	temp = omap_temp_sensor_readl(temp_sensor, TEMP_SENSOR_CTRL_OFFSET);
	temp &= (OMAP4_BGAP_TEMP_SENSOR_DTEMP_MASK);
	while ((temp == 0) && --counter) {
		temp = omap_temp_sensor_readl(temp_sensor,
			TEMP_SENSOR_CTRL_OFFSET);
		temp &= (OMAP4_BGAP_TEMP_SENSOR_DTEMP_MASK);
	}
	/* Start of Conversion = 0 */
	temp = omap_temp_sensor_readl(temp_sensor, TEMP_SENSOR_CTRL_OFFSET);
	temp &= ~(OMAP4_BGAP_TEMP_SENSOR_SOC_MASK);
	omap_temp_sensor_writel(temp_sensor, temp, TEMP_SENSOR_CTRL_OFFSET);
}
Пример #3
0
static void omap_configure_temp_sensor_thresholds(struct omap_temp_sensor
						  *temp_sensor)
{
	u32 temp = 0, t_hot, t_cold, tshut_hot, tshut_cold;

	if (temp_limit > 0) {
	  cold_threshold = temp_limit - 4000;
	  hot_threshold = temp_limit;
	}
	t_hot = temp_to_adc_conversion(hot_threshold);
	t_cold = temp_to_adc_conversion(cold_threshold);

	if ((t_hot == -EINVAL) || (t_cold == -EINVAL)) {
		pr_err("%s:Temp thresholds out of bounds\n", __func__);
		return;
	}
	temp |= ((t_hot << OMAP4_T_HOT_SHIFT) | (t_cold << OMAP4_T_COLD_SHIFT));
	omap_temp_sensor_writel(temp_sensor, temp, BGAP_THRESHOLD_OFFSET);

	tshut_hot = temp_to_adc_conversion(TSHUT_THRESHOLD_TSHUT_HOT);
	tshut_cold = temp_to_adc_conversion(TSHUT_THRESHOLD_TSHUT_COLD);
	if ((tshut_hot == -EINVAL) || (tshut_cold == -EINVAL)) {
		pr_err("%s:Temp shutdown thresholds out of bounds\n", __func__);
		return;
	}
	temp |= ((tshut_hot << OMAP4_TSHUT_HOT_SHIFT)
			| (tshut_cold << OMAP4_TSHUT_COLD_SHIFT));
	omap_temp_sensor_writel(temp_sensor, temp, BGAP_TSHUT_OFFSET);
}
static int omap_set_thresholds(struct omap_temp_sensor *temp_sensor,
					int min, int max)
{
	int reg_val = 0;
	int new_cold;
	int new_hot;
	int curr_temp = 0;

	/* A too low value is not acceptable for the thresholds */
	if ((min < OMAP_MIN_TEMP) || (max < OMAP_MIN_TEMP)) {
		pr_err("%s:Min or Max is invalid %d %d\n", __func__,
			min, max);
		return -EINVAL;
	}

	if (max < min) {
		pr_err("%s:Min is greater then the max\n", __func__);
		return -EINVAL;
	}

	new_hot = temp_to_adc_conversion(max);
	new_cold = temp_to_adc_conversion(min);

	if ((new_hot == -EINVAL) || (new_cold == -EINVAL)) {
		pr_err("%s: New thresh value is out of range\n", __func__);
		return -EINVAL;
	}

	reg_val = ((new_hot << OMAP4_T_HOT_SHIFT) |
			(new_cold << OMAP4_T_COLD_SHIFT));
	omap_temp_sensor_writel(temp_sensor, reg_val, BGAP_THRESHOLD_OFFSET);

	curr_temp = temp_to_adc_conversion(temp_sensor->therm_fw->current_temp);

	if (new_hot >= curr_temp) {
		reg_val = omap_temp_sensor_readl(temp_sensor, BGAP_CTRL_OFFSET);
		reg_val |= OMAP4_MASK_HOT_MASK;
		omap_temp_sensor_writel(temp_sensor, reg_val, BGAP_CTRL_OFFSET);
	}

	if (new_cold <= curr_temp) {
		reg_val = omap_temp_sensor_readl(temp_sensor, BGAP_CTRL_OFFSET);
		reg_val |= OMAP4_MASK_COLD_MASK;
		omap_temp_sensor_writel(temp_sensor, reg_val, BGAP_CTRL_OFFSET);
	}

	if (curr_temp > new_cold && curr_temp < new_hot) {
		reg_val = omap_temp_sensor_readl(temp_sensor, BGAP_CTRL_OFFSET);
		reg_val |= (OMAP4_MASK_COLD_MASK | OMAP4_MASK_HOT_MASK);
		omap_temp_sensor_writel(temp_sensor, reg_val, BGAP_CTRL_OFFSET);
	}

	return 0;
}
Пример #5
0
static irqreturn_t omap_talert_irq_handler(int irq, void *data)
{
	struct omap_temp_sensor *temp_sensor = (struct omap_temp_sensor *)data;
	int t_hot, t_cold, temp_offset;

	t_hot = omap_temp_sensor_readl(temp_sensor, BGAP_STATUS_OFFSET)
	    & OMAP4_HOT_FLAG_MASK;
	t_cold = omap_temp_sensor_readl(temp_sensor, BGAP_STATUS_OFFSET)
	    & OMAP4_COLD_FLAG_MASK;
	temp_offset = omap_temp_sensor_readl(temp_sensor, BGAP_CTRL_OFFSET);
	if (t_hot) {
		if (throttle_enabled) {
			omap_thermal_throttle();
			schedule_delayed_work(&temp_sensor->throttle_work,
				msecs_to_jiffies(THROTTLE_DELAY_MS));
			temp_offset &= ~(OMAP4_MASK_HOT_MASK);
			temp_offset |= OMAP4_MASK_COLD_MASK;
		} else {
			pr_info("[franciscofranco] %p - temperature is over the threshold, but throttling is disabled.", __func__);
		}
	} else if (t_cold) {
		if (throttle_enabled) {
			cancel_delayed_work_sync(&temp_sensor->throttle_work);
			omap_thermal_unthrottle();
			temp_offset &= ~(OMAP4_MASK_COLD_MASK);
			temp_offset |= OMAP4_MASK_HOT_MASK;
		} else {
			pr_info("[franciscofranco] %p - temperature is below the threshold, but throttling is disabled.", __func__);
		}
	}

	omap_temp_sensor_writel(temp_sensor, temp_offset, BGAP_CTRL_OFFSET);

	return IRQ_HANDLED;
}
static int omap_temp_sensor_disable(struct omap_temp_sensor *temp_sensor)
{
	u32 temp;
	u32 ret = 0;
	unsigned long flags;

	spin_lock_irqsave(&temp_sensor->lock, flags);

	if (!temp_sensor->clk_on) {
		pr_debug("%s: clock already off\n", __func__);
		goto out;
	}
	temp = omap_temp_sensor_readl(temp_sensor,
				TEMP_SENSOR_CTRL_OFFSET);
	temp |= OMAP4430_BGAP_TEMPSOFF;

	/* write BGAP_TEMPSOFF should be set to 1 before gating clock */
	omap_temp_sensor_writel(temp_sensor, temp,
				TEMP_SENSOR_CTRL_OFFSET);

	ret = pm_runtime_put_sync_suspend(&temp_sensor->pdev->dev);
	if (ret) {
		pr_err("%s:put sync failed\n", __func__);
		ret = -EINVAL;
		goto out;
	}
	temp_sensor->clk_on = 0;

out:
	spin_unlock_irqrestore(&temp_sensor->lock, flags);
	return ret;
}
Пример #7
0
static irqreturn_t omap_talert_irq_handler(int irq, void *data)
{
	struct omap_temp_sensor *temp_sensor = (struct omap_temp_sensor *)data;
	int t_hot, t_cold, temp_offset;

	t_hot = omap_temp_sensor_readl(temp_sensor, BGAP_STATUS_OFFSET)
	    & OMAP4_HOT_FLAG_MASK;
	t_cold = omap_temp_sensor_readl(temp_sensor, BGAP_STATUS_OFFSET)
	    & OMAP4_COLD_FLAG_MASK;
	temp_offset = omap_temp_sensor_readl(temp_sensor, BGAP_CTRL_OFFSET);
	if (t_hot) {
		omap_thermal_throttle();
		schedule_delayed_work(&temp_sensor->throttle_work,
			msecs_to_jiffies(THROTTLE_DELAY_MS));
		temp_offset &= ~(OMAP4_MASK_HOT_MASK);
		temp_offset |= OMAP4_MASK_COLD_MASK;
	} else if (t_cold) {
		cancel_delayed_work_sync(&temp_sensor->throttle_work);
		omap_thermal_unthrottle();
		temp_offset &= ~(OMAP4_MASK_COLD_MASK);
		temp_offset |= OMAP4_MASK_HOT_MASK;
	}

	omap_temp_sensor_writel(temp_sensor, temp_offset, BGAP_CTRL_OFFSET);

	return IRQ_HANDLED;
}
static ssize_t set_temp_crit_hyst(struct device *dev,
			struct device_attribute *devattr,
			const char *buf, size_t count)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct omap_temp_sensor *temp_sensor = platform_get_drvdata(pdev);
	u32 temp, reg_val;
	long val;

	if (strict_strtol(buf, 10, &val)) {
		count = -EINVAL;
		goto out;
	}
	temp = temp_to_adc_conversion(val);
	if ((temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE)) {
		pr_err("invalid range\n");
		count = -EINVAL;
		goto out;
	}

	mutex_lock(&temp_sensor->sensor_mutex);
	reg_val = omap_temp_sensor_readl(temp_sensor, BGAP_TSHUT_OFFSET);
	reg_val = reg_val & ~(OMAP4_TSHUT_COLD_MASK);
	reg_val = reg_val | (temp << OMAP4_TSHUT_COLD_SHIFT);
	omap_temp_sensor_writel(temp_sensor, reg_val, BGAP_TSHUT_OFFSET);
	mutex_unlock(&temp_sensor->sensor_mutex);

out:
	return count;
}
static void omap_temp_sensor_restore_ctxt(struct omap_temp_sensor *temp_sensor)
{
	omap_temp_sensor_writel(temp_sensor,
				temp_sensor_context.temp_sensor_ctrl,
				TEMP_SENSOR_CTRL_OFFSET);
	omap_temp_sensor_writel(temp_sensor,
				temp_sensor_context.bg_ctrl,
				BGAP_CTRL_OFFSET);
	omap_temp_sensor_writel(temp_sensor,
				temp_sensor_context.bg_counter,
				BGAP_COUNTER_OFFSET);
	omap_temp_sensor_writel(temp_sensor,
				temp_sensor_context.bg_threshold,
				BGAP_THRESHOLD_OFFSET);
	omap_temp_sensor_writel(temp_sensor,
				temp_sensor_context.temp_sensor_tshut_threshold,
				BGAP_TSHUT_OFFSET);
}
static void omap_configure_temp_sensor_counter(struct omap_temp_sensor
					       *temp_sensor, u32 counter)
{
	u32 val;

	val = omap_temp_sensor_readl(temp_sensor, BGAP_COUNTER_OFFSET);
	val = val & ~(OMAP4_COUNTER_MASK);
	val = val | (counter << OMAP4_COUNTER_SHIFT);
	omap_temp_sensor_writel(temp_sensor, val, BGAP_COUNTER_OFFSET);
}
static void omap_enable_continuous_mode(struct omap_temp_sensor *temp_sensor)
{
	u32 val;

	val = omap_temp_sensor_readl(temp_sensor, BGAP_CTRL_OFFSET);

	val = val | (1 << OMAP4_SINGLE_MODE_SHIFT);

	omap_temp_sensor_writel(temp_sensor, val, BGAP_CTRL_OFFSET);
}
static void omap_enable_continuous_mode(struct omap_temp_sensor *temp_sensor)
{
	u32 val;

	val = omap_temp_sensor_readl(temp_sensor, TEMP_SENSOR_CTRL_OFFSET);

	val = val | OMAP4430_BGAP_TEMP_SENSOR_CONTCONV;

	omap_temp_sensor_writel(temp_sensor, val, TEMP_SENSOR_CTRL_OFFSET);
}
static void omap_configure_temp_sensor_thresholds(struct omap_temp_sensor
						  *temp_sensor)
{
	u32 temp = 0, t_hot, t_cold, tshut_hot, tshut_cold;

	t_hot = temp_to_adc_conversion(BGAP_THRESHOLD_T_HOT);
	t_cold = temp_to_adc_conversion(BGAP_THRESHOLD_T_COLD);

	if ((t_hot == -EINVAL) || (t_cold == -EINVAL)) {
		pr_err("%s:Temp thresholds out of bounds\n", __func__);
		return;
	}
	temp = ((t_hot << OMAP4_T_HOT_SHIFT) | (t_cold << OMAP4_T_COLD_SHIFT));
	omap_temp_sensor_writel(temp_sensor, temp, BGAP_THRESHOLD_OFFSET);

	/*
	 * Prevent multiple writing to one time writable register, assuming
	 * that no one wrote zero into it before.
	 */

	if (cpu_is_omap447x() &&
		omap_temp_sensor_readl(temp_sensor, BGAP_TSHUT_OFFSET) != 0) {
		pr_debug("%s:Shutdown thresholds are already set\n", __func__);
		return;
	}

	tshut_hot = temp_to_adc_conversion(TSHUT_THRESHOLD_TSHUT_HOT);
	tshut_cold = temp_to_adc_conversion(TSHUT_THRESHOLD_TSHUT_COLD);
	if ((tshut_hot == -EINVAL) || (tshut_cold == -EINVAL)) {
		pr_err("%s:Temp shutdown thresholds out of bounds\n", __func__);
		return;
	}
	temp = ((tshut_hot << OMAP4_TSHUT_HOT_SHIFT)
			| (tshut_cold << OMAP4_TSHUT_COLD_SHIFT));
	omap_temp_sensor_writel(temp_sensor, temp, BGAP_TSHUT_OFFSET);

	if (omap_temp_sensor_readl(temp_sensor, BGAP_TSHUT_OFFSET) != temp)
		pr_err("%s:Shutdown thresholds can't be set\n", __func__);
}
static int omap_read_current_temp(struct omap_temp_sensor *temp_sensor)
{
	int adc, val;

	val = omap_temp_sensor_readl(temp_sensor, TEMP_SENSOR_CTRL_OFFSET);
	val |= OMAP4430_BGAP_TEMP_SENSOR_SOC;

	/* Start the Conversion */
	omap_temp_sensor_writel(temp_sensor, val, TEMP_SENSOR_CTRL_OFFSET);
	/* Wait for end of Conversion
	 * Conversion time is about 11-14 32K cycles (~0.5us)
	 * After some testing, for some reason EOCZ bit (8) is always low
	 * even when no conversion ongoing. Don't check it then ...
	 */
	usleep_range(1000, 1100);

	val = omap_temp_sensor_readl(temp_sensor, TEMP_SENSOR_CTRL_OFFSET);
	val &= ~OMAP4430_BGAP_TEMP_SENSOR_SOC;
	/* Stop the Conversion */
	omap_temp_sensor_writel(temp_sensor, val, TEMP_SENSOR_CTRL_OFFSET);

	adc = omap_temp_sensor_readl(temp_sensor, TEMP_SENSOR_CTRL_OFFSET);

	adc &= OMAP4430_BGAP_TEMP_SENSOR_DTEMP_MASK;

	if (!temp_sensor->is_efuse_valid)
		pr_err_once("%s: Invalid EFUSE, Non-trimmed BGAP,"
			    "Temp not accurate\n", __func__);

	if (adc < 0 || adc > 128) {
		pr_err("%s:Invalid adc code reported by the sensor %d",
			__func__, adc);
		return -EINVAL;
	}

	return adc_to_temp_conversion(adc);
}
static int omap_update_measure_rate(struct omap_temp_sensor *temp_sensor,
					int rate)
{
	u32 reg_val;
	int frequency;

	frequency = (rate * temp_sensor->clk_rate) / 1000;
	reg_val = omap_temp_sensor_readl(temp_sensor, BGAP_COUNTER_OFFSET);

	reg_val &= ~(OMAP4_COUNTER_MASK);
	reg_val |= frequency;
	omap_temp_sensor_writel(temp_sensor, reg_val, BGAP_COUNTER_OFFSET);

	return rate;
}
static irqreturn_t omap_talert_irq_handler(int irq, void *data)
{
	struct omap_temp_sensor *temp_sensor = (struct omap_temp_sensor *)data;
	int t_hot, t_cold, temp_offset, temp;
	char env_temp[20];
	char env_zone[20];
        char *envp[] = { env_temp, env_zone, NULL };

	t_hot = omap_temp_sensor_readl(temp_sensor, BGAP_STATUS_OFFSET)
	    & OMAP4_HOT_FLAG_MASK;
	t_cold = omap_temp_sensor_readl(temp_sensor, BGAP_STATUS_OFFSET)
	    & OMAP4_COLD_FLAG_MASK;
	temp_offset = omap_temp_sensor_readl(temp_sensor, BGAP_CTRL_OFFSET);
	if (t_hot) {
		temp_offset &= ~(OMAP4_MASK_HOT_MASK);
		temp_offset |= OMAP4_MASK_COLD_MASK;
	} else if (t_cold) {
		temp_offset &= ~(OMAP4_MASK_COLD_MASK);
		temp_offset |= OMAP4_MASK_HOT_MASK;
	}

	omap_temp_sensor_writel(temp_sensor, temp_offset, BGAP_CTRL_OFFSET);
	temp = omap_temp_sensor_readl(temp_sensor, TEMP_SENSOR_CTRL_OFFSET);
	temp &= (OMAP4_BGAP_TEMP_SENSOR_DTEMP_MASK);

	if (!temp_sensor->is_efuse_valid)
		pr_err_once("Non-trimmed BGAP, Temp not accurate\n");

	/* look up for temperature in the table and return the
	   temperature */
	if (temp < OMAP_ADC_START_VALUE || temp > OMAP_ADC_END_VALUE) {
		pr_err("invalid adc code reported by the sensor %d\n", temp);
	} else {
		temp_sensor->therm_fw->current_temp =
				adc_to_temp[temp - OMAP_ADC_START_VALUE];
		thermal_sensor_set_temp(temp_sensor->therm_fw);
		snprintf(env_temp, 20, "TEMP=%d",thermal_sensor_get_hotspot_temp(temp_sensor->therm_fw)/1000);
                envp[0] = env_temp;
		snprintf(env_zone, 20, "ZONE=%d",thermal_sensor_get_zone(temp_sensor->therm_fw));
                envp[1] = env_zone;
		kobject_uevent_env(&temp_sensor->dev->kobj, KOBJ_CHANGE, envp);
	}

	return IRQ_HANDLED;
}
static int omap_temp_sensor_disable(struct omap_temp_sensor *temp_sensor)
{
	u32 temp;
	u32 ret = 0;
	u32 counter = 1000;
	unsigned long flags;

	spin_lock_irqsave(&temp_sensor->lock, flags);

	if (!temp_sensor->clk_on) {
		pr_debug("%s:clock already off\n", __func__);
		goto out;
	}
	temp = omap_temp_sensor_readl(temp_sensor,
				TEMP_SENSOR_CTRL_OFFSET);
	temp |= OMAP4_BGAP_TEMPSOFF_MASK;

	/* write BGAP_TEMPSOFF should be set to 1 before gating clock */
	omap_temp_sensor_writel(temp_sensor, temp,
				TEMP_SENSOR_CTRL_OFFSET);
	temp = omap_temp_sensor_readl(temp_sensor, BGAP_STATUS_OFFSET);

	/* wait till the clean stop bit is set */
	while ((temp & OMAP4_CLEAN_STOP_MASK) && --counter)
		temp = omap_temp_sensor_readl(temp_sensor,
						BGAP_STATUS_OFFSET);
	if (counter == 0)
		pr_err("%s:timeout counter for clean stop expired\n", __func__);
	/* Gate the clock */
	ret = pm_runtime_put_sync_suspend(&temp_sensor->pdev->dev);
	if (ret) {
		pr_err("%s:put sync failed\n", __func__);
		ret = -EINVAL;
		goto out;
	}
	temp_sensor->clk_on = 0;

out:
	spin_unlock_irqrestore(&temp_sensor->lock, flags);
	return ret;
}
static int omap_temp_sensor_enable(struct omap_temp_sensor *temp_sensor)
{
	u32 temp;
	u32 ret = 0;
	unsigned long clk_rate;

	unsigned long flags;

	spin_lock_irqsave(&temp_sensor->lock, flags);

	if (temp_sensor->clk_on) {
		pr_debug("%s: clock already on\n", __func__);
		goto out;
	}

	ret = pm_runtime_get_sync(&temp_sensor->pdev->dev);
	if (ret) {
		pr_err("%s:get sync failed\n", __func__);
		ret = -EINVAL;
		goto out;
	}

	clk_set_rate(temp_sensor->clock, 1000000);
	clk_rate = clk_get_rate(temp_sensor->clock);
	temp_sensor->clk_rate = clk_rate;

	temp = omap_temp_sensor_readl(temp_sensor,
					TEMP_SENSOR_CTRL_OFFSET);
	temp &= ~OMAP4430_BGAP_TEMPSOFF;

	/* write BGAP_TEMPSOFF should be reset to 0 */
	omap_temp_sensor_writel(temp_sensor, temp,
				TEMP_SENSOR_CTRL_OFFSET);
	temp_sensor->clk_on = 1;

out:
	spin_unlock_irqrestore(&temp_sensor->lock, flags);
	return ret;
}
static void omap_temp_sensor_restore_ctxt(struct omap_temp_sensor *temp_sensor)
{
	omap_temp_sensor_writel(temp_sensor,
				temp_sensor_context.temp_sensor_ctrl,
				TEMP_SENSOR_CTRL_OFFSET);
}
static void omap_temp_sensor_restore_ctxt(struct omap_temp_sensor *temp_sensor)
{
	int temp = 0;

	/* if all registers have been lost */
	if ((omap_temp_sensor_readl(temp_sensor, BGAP_THRESHOLD_OFFSET) == 0) &&
	    (omap_temp_sensor_readl(temp_sensor, BGAP_COUNTER_OFFSET) == 0)) {
		omap_temp_sensor_writel(temp_sensor,
					temp_sensor_context.bg_threshold,
					BGAP_THRESHOLD_OFFSET);
		omap_temp_sensor_writel(temp_sensor,
					temp_sensor_context.tshut_threshold,
					BGAP_TSHUT_OFFSET);
		/*
		 * Force immediate temperature measurement and update of the
		 * BGAP_TEMP_SENSOR_DTEMP bitfield before completing the full
		 * context restoration.
		 * This ensures that HW does not generate spurious thermal alert
		 * when restoring the mask bits: if the BGAP_TEMP_SENSOR_DTEMP
		 * bitfield in CONTROL_TEMP_SENSOR register is not yet
		 * initialized, the comparison done by the HW logic (against the
		 * temperature thresholds) will generate an unexpected thermal
		 * alert.
		 */
		omap_temp_sensor_force_single_read(temp_sensor);

		/* Complete context restoration */
		temp_sensor_context.temp_sensor_ctrl &=
			~(OMAP4_BGAP_TEMPSOFF_MASK);
		omap_temp_sensor_writel(temp_sensor,
					temp_sensor_context.temp_sensor_ctrl,
					TEMP_SENSOR_CTRL_OFFSET);
		omap_temp_sensor_writel(temp_sensor,
					temp_sensor_context.bg_counter,
					BGAP_COUNTER_OFFSET);
		omap_temp_sensor_writel(temp_sensor,
					temp_sensor_context.bg_ctrl,
					BGAP_CTRL_OFFSET);
	} else { /* registers have not been reset but DTEMP is not yet valid */
		temp = omap_temp_sensor_readl(temp_sensor,
			TEMP_SENSOR_CTRL_OFFSET);
		temp &= (OMAP4_BGAP_TEMP_SENSOR_DTEMP_MASK);
		if (temp == 0) {
			/* BGAP_TEMPSOFF should be reset to 0 */
			temp = omap_temp_sensor_readl(temp_sensor,
					TEMP_SENSOR_CTRL_OFFSET);
			temp &= ~(OMAP4_BGAP_TEMPSOFF_MASK);
			omap_temp_sensor_writel(temp_sensor, temp,
				TEMP_SENSOR_CTRL_OFFSET);
			udelay(5);	/* wait for 5 us */

			omap_temp_sensor_force_single_read(temp_sensor);

			/* Select continous conversion mode */
			temp = omap_temp_sensor_readl(temp_sensor,
						BGAP_CTRL_OFFSET);
			temp |= OMAP4_SINGLE_MODE_MASK;
			omap_temp_sensor_writel(temp_sensor, temp,
						BGAP_CTRL_OFFSET);
		}
	}
}
static int __devinit omap_temp_sensor_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct omap_temp_sensor_pdata *pdata = pdev->dev.platform_data;
	struct omap_temp_sensor *temp_sensor;
	struct resource *mem;
	int ret = 0, val;

	if (!pdata) {
		dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
		return -EINVAL;
	}

	temp_sensor = kzalloc(sizeof(struct omap_temp_sensor), GFP_KERNEL);
	if (!temp_sensor)
		return -ENOMEM;

	spin_lock_init(&temp_sensor->lock);
	mutex_init(&temp_sensor->sensor_mutex);

	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!mem) {
		dev_err(&pdev->dev, "%s:no mem resource\n", __func__);
		ret = -EINVAL;
		goto plat_res_err;
	}

	temp_sensor->irq = platform_get_irq_byname(pdev, "thermal_alert");
	if (temp_sensor->irq < 0) {
		dev_err(&pdev->dev, "%s:Cannot get thermal alert irq\n",
			__func__);
		ret = -EINVAL;
		goto get_irq_err;
	}

	ret = gpio_request_one(OMAP_TSHUT_GPIO, GPIOF_DIR_IN,
		"thermal_shutdown");
	if (ret) {
		dev_err(&pdev->dev, "%s: Could not get tshut_gpio\n",
			__func__);
		goto tshut_gpio_req_err;
	}

	temp_sensor->tshut_irq = gpio_to_irq(OMAP_TSHUT_GPIO);
	if (temp_sensor->tshut_irq < 0) {
		dev_err(&pdev->dev, "%s:Cannot get thermal shutdown irq\n",
			__func__);
		ret = -EINVAL;
		goto get_tshut_irq_err;
	}

	temp_sensor->phy_base = pdata->offset;
	temp_sensor->pdev = pdev;
	temp_sensor->dev = dev;

	pm_runtime_enable(dev);
	pm_runtime_irq_safe(dev);


	kobject_uevent(&pdev->dev.kobj, KOBJ_ADD);
	platform_set_drvdata(pdev, temp_sensor);


	/*
	 * check if the efuse has a non-zero value if not
	 * it is an untrimmed sample and the temperatures
	 * may not be accurate */
	if (omap_readl(OMAP4_CTRL_MODULE_CORE +
			OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_BGAP))
		temp_sensor->is_efuse_valid = 1;

	temp_sensor->clock = clk_get(&temp_sensor->pdev->dev, "fck");
	if (IS_ERR(temp_sensor->clock)) {
		ret = PTR_ERR(temp_sensor->clock);
		pr_err("%s:Unable to get fclk: %d\n", __func__, ret);
		ret = -EINVAL;
		goto clk_get_err;
	}

	ret = omap_temp_sensor_enable(temp_sensor);
	if (ret) {
		dev_err(&pdev->dev, "%s:Cannot enable temp sensor\n", __func__);
		goto sensor_enable_err;
	}

	temp_sensor->therm_fw = kzalloc(sizeof(struct thermal_dev), GFP_KERNEL);
	if (temp_sensor->therm_fw) {
		temp_sensor->therm_fw->name = "omap_ondie_sensor";
		temp_sensor->therm_fw->domain_name = "cpu";
		temp_sensor->therm_fw->dev = temp_sensor->dev;
		temp_sensor->therm_fw->dev_ops = &omap_sensor_ops;
		thermal_sensor_dev_register(temp_sensor->therm_fw);
	} else {
		dev_err(&pdev->dev, "%s:Cannot alloc memory for thermal fw\n",
			__func__);
		ret = -ENOMEM;
		goto therm_fw_alloc_err;
	}

	omap_enable_continuous_mode(temp_sensor, 1);
	omap_configure_temp_sensor_thresholds(temp_sensor);
	/* 1 ms */
	omap_configure_temp_sensor_counter(temp_sensor, 1);

	/* Wait till the first conversion is done wait for at least 1ms */
	mdelay(2);

	/* Read the temperature once due to hw issue*/
	omap_report_temp(temp_sensor->therm_fw);

	/* Set 250 milli-seconds time as default counter */
	omap_configure_temp_sensor_counter(temp_sensor,
					temp_sensor->clk_rate * 250 / 1000);
	ret = sysfs_create_group(&pdev->dev.kobj,
				 &omap_temp_sensor_group);
	if (ret) {
		dev_err(&pdev->dev, "could not create sysfs files\n");
		goto sysfs_create_err;
	}

	ret = request_threaded_irq(temp_sensor->irq, NULL,
			omap_talert_irq_handler,
			IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
			"temp_sensor", (void *)temp_sensor);
	if (ret) {
		dev_err(&pdev->dev, "Request threaded irq failed.\n");
		goto req_irq_err;
	}

	ret = request_threaded_irq(temp_sensor->tshut_irq, NULL,
			omap_tshut_irq_handler,
			IRQF_TRIGGER_RISING | IRQF_ONESHOT,
			"tshut", (void *)temp_sensor);
	if (ret) {
		dev_err(&pdev->dev, "Request threaded irq failed for TSHUT.\n");
		goto tshut_irq_req_err;
	}

	/* unmask the T_COLD and unmask T_HOT at init */
	val = omap_temp_sensor_readl(temp_sensor, BGAP_CTRL_OFFSET);
	val |= OMAP4_MASK_COLD_MASK;
	val |= OMAP4_MASK_HOT_MASK;
	omap_temp_sensor_writel(temp_sensor, val, BGAP_CTRL_OFFSET);

	dev_info(&pdev->dev, "%s : '%s'\n", temp_sensor->therm_fw->name,
			pdata->name);

	temp_sensor_pm = temp_sensor;
	return 0;

tshut_irq_req_err:
	free_irq(temp_sensor->irq, temp_sensor);
req_irq_err:
	kobject_uevent(&temp_sensor->dev->kobj, KOBJ_REMOVE);
	sysfs_remove_group(&temp_sensor->dev->kobj, &omap_temp_sensor_group);
sysfs_create_err:
	thermal_sensor_dev_unregister(temp_sensor->therm_fw);
	kfree(temp_sensor->therm_fw);
	if (temp_sensor->clock)
		clk_put(temp_sensor->clock);
	platform_set_drvdata(pdev, NULL);
therm_fw_alloc_err:
	omap_temp_sensor_disable(temp_sensor);
sensor_enable_err:
	clk_put(temp_sensor->clock);
clk_get_err:
	pm_runtime_disable(&pdev->dev);
get_tshut_irq_err:
	gpio_free(OMAP_TSHUT_GPIO);
tshut_gpio_req_err:
get_irq_err:
plat_res_err:
	mutex_destroy(&temp_sensor->sensor_mutex);
	kfree(temp_sensor);
	return ret;
}
/*
 * Check if the die sensor is cooling down. If it's higher than
 * t_hot since the last throttle then throttle it again.
 * OMAP junction temperature could stay for a long time in an
 * unacceptable temperature range. The idea here is to check after
 * t_hot->throttle the system really came below t_hot else re-throttle
 * and keep doing till it's under t_hot temp range.
 */
static void throttle_delayed_work_fn(struct work_struct *work)
{
	int curr;
	struct omap_temp_sensor *temp_sensor =
				container_of(work, struct omap_temp_sensor,
					     throttle_work.work);
	curr = omap_read_current_temp(temp_sensor);

#ifdef CONFIG_OMAP_TEMP_CONTROL
	if (curr >= temp_limit || curr < 0) {
#else
	if (curr >= BGAP_THRESHOLD_T_HOT || curr < 0) {
#endif
		pr_warn("%s: OMAP temp read %d exceeds the threshold\n",
			__func__, curr);
		omap_thermal_throttle();
		schedule_delayed_work(&temp_sensor->throttle_work,
			msecs_to_jiffies(THROTTLE_DELAY_MS));
	} else {
		schedule_delayed_work(&temp_sensor->throttle_work,
			msecs_to_jiffies(THROTTLE_DELAY_MS));
	}
}

static irqreturn_t omap_tshut_irq_handler(int irq, void *data)
{
	struct omap_temp_sensor *temp_sensor = (struct omap_temp_sensor *)data;

	/* Need to handle thermal mgmt in bootloader
	 * to avoid restart again at kernel level
	 */
	if (temp_sensor->is_efuse_valid) {
		pr_emerg("%s: Thermal shutdown reached rebooting device\n",
			__func__);
		kernel_restart(NULL);
	} else {
		pr_err("%s:Invalid EFUSE, Non-trimmed BGAP\n", __func__);
	}

	return IRQ_HANDLED;
}

static irqreturn_t omap_talert_irq_handler(int irq, void *data)
{
	struct omap_temp_sensor *temp_sensor = (struct omap_temp_sensor *)data;
	int t_hot, t_cold, temp_offset;

	t_hot = omap_temp_sensor_readl(temp_sensor, BGAP_STATUS_OFFSET)
	    & OMAP4_HOT_FLAG_MASK;
	t_cold = omap_temp_sensor_readl(temp_sensor, BGAP_STATUS_OFFSET)
	    & OMAP4_COLD_FLAG_MASK;
	temp_offset = omap_temp_sensor_readl(temp_sensor, BGAP_CTRL_OFFSET);
	if (t_hot) {
		omap_thermal_throttle();
		schedule_delayed_work(&temp_sensor->throttle_work,
			msecs_to_jiffies(THROTTLE_DELAY_MS));
		temp_offset &= ~(OMAP4_MASK_HOT_MASK);
		temp_offset |= OMAP4_MASK_COLD_MASK;
	} else if (t_cold) {
		cancel_delayed_work_sync(&temp_sensor->throttle_work);
		omap_thermal_unthrottle();
		temp_offset &= ~(OMAP4_MASK_COLD_MASK);
		temp_offset |= OMAP4_MASK_HOT_MASK;
	}

	omap_temp_sensor_writel(temp_sensor, temp_offset, BGAP_CTRL_OFFSET);

	return IRQ_HANDLED;
}

static int __devinit omap_temp_sensor_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct omap_temp_sensor_pdata *pdata = pdev->dev.platform_data;
	struct omap_temp_sensor *temp_sensor;
	struct resource *mem;
	int ret = 0, val;

	if (!pdata) {
		dev_err(dev, "%s: platform data missing\n", __func__);
		return -EINVAL;
	}

	temp_sensor = kzalloc(sizeof(struct omap_temp_sensor), GFP_KERNEL);
	if (!temp_sensor)
		return -ENOMEM;

	spin_lock_init(&temp_sensor->lock);

	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!mem) {
		dev_err(dev, "%s:no mem resource\n", __func__);
		ret = -EINVAL;
		goto plat_res_err;
	}

	temp_sensor->irq = platform_get_irq_byname(pdev, "thermal_alert");
	if (temp_sensor->irq < 0) {
		dev_err(dev, "%s:Cannot get thermal alert irq\n",
			__func__);
		ret = -EINVAL;
		goto get_irq_err;
	}

	ret = gpio_request_one(OMAP_TSHUT_GPIO, GPIOF_DIR_IN,
		"thermal_shutdown");
	if (ret) {
		dev_err(dev, "%s: Could not get tshut_gpio\n",
			__func__);
		goto tshut_gpio_req_err;
	}

	temp_sensor->tshut_irq = gpio_to_irq(OMAP_TSHUT_GPIO);
	if (temp_sensor->tshut_irq < 0) {
		dev_err(dev, "%s:Cannot get thermal shutdown irq\n",
			__func__);
		ret = -EINVAL;
		goto get_tshut_irq_err;
	}

	temp_sensor->phy_base = pdata->offset;
	temp_sensor->pdev = pdev;
	temp_sensor->dev = dev;

	pm_runtime_enable(dev);
	pm_runtime_irq_safe(dev);

	/*
	 * check if the efuse has a non-zero value if not
	 * it is an untrimmed sample and the temperatures
	 * may not be accurate */
	if (omap_readl(OMAP4_CTRL_MODULE_CORE +
			OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_BGAP))
		temp_sensor->is_efuse_valid = 1;

	temp_sensor->clock = clk_get(&temp_sensor->pdev->dev, "fck");
	if (IS_ERR(temp_sensor->clock)) {
		ret = PTR_ERR(temp_sensor->clock);
		pr_err("%s:Unable to get fclk: %d\n", __func__, ret);
		ret = -EINVAL;
		goto clk_get_err;
	}

	/* Init delayed work for throttle decision */
	INIT_DELAYED_WORK(&temp_sensor->throttle_work,
			  throttle_delayed_work_fn);

	platform_set_drvdata(pdev, temp_sensor);

	ret = omap_temp_sensor_enable(temp_sensor);
	if (ret) {
		dev_err(dev, "%s:Cannot enable temp sensor\n", __func__);
		goto sensor_enable_err;
	}

	omap_enable_continuous_mode(temp_sensor);
	omap_configure_temp_sensor_thresholds(temp_sensor);
	/* 1 ms */
	omap_configure_temp_sensor_counter(temp_sensor, 1);

	/* Wait till the first conversion is done wait for at least 1ms */
	mdelay(2);

	/* Read the temperature once due to hw issue*/
	omap_read_current_temp(temp_sensor);

	/* Set 2 seconds time as default counter */
	omap_configure_temp_sensor_counter(temp_sensor,
						temp_sensor->clk_rate * 2);
	ret = request_threaded_irq(temp_sensor->irq, NULL,
			omap_talert_irq_handler,
			IRQF_TRIGGER_RISING | IRQF_ONESHOT,
			"temp_sensor", (void *)temp_sensor);
	if (ret) {
		dev_err(dev, "Request threaded irq failed.\n");
		goto req_irq_err;
	}

	ret = request_threaded_irq(temp_sensor->tshut_irq, NULL,
			omap_tshut_irq_handler,
			IRQF_TRIGGER_RISING | IRQF_ONESHOT,
			"tshut", (void *)temp_sensor);
	if (ret) {
		dev_err(dev, "Request threaded irq failed for TSHUT.\n");
		goto tshut_irq_req_err;
	}

	ret = sysfs_create_group(&pdev->dev.kobj, &omap_temp_sensor_group);
	if (ret) {
		dev_err(&pdev->dev, "could not create sysfs files\n");
		goto sysfs_create_err;
	}

	/* unmask the T_COLD and unmask T_HOT at init */
	val = omap_temp_sensor_readl(temp_sensor, BGAP_CTRL_OFFSET);
	val |= OMAP4_MASK_COLD_MASK;
	val |= OMAP4_MASK_HOT_MASK;
	omap_temp_sensor_writel(temp_sensor, val, BGAP_CTRL_OFFSET);

	dev_info(dev, "%s probed", pdata->name);

	temp_sensor_pm = temp_sensor;

#ifdef CONFIG_OMAP_TEMP_CONTROL
	ctrl_sensor = temp_sensor;
	tempcontrol_registerlimit(temp_limit);
#endif

	return 0;

sysfs_create_err:
	free_irq(temp_sensor->tshut_irq, temp_sensor);
	cancel_delayed_work_sync(&temp_sensor->throttle_work);
tshut_irq_req_err:
	free_irq(temp_sensor->irq, temp_sensor);
req_irq_err:
	platform_set_drvdata(pdev, NULL);
	omap_temp_sensor_disable(temp_sensor);
sensor_enable_err:
	clk_put(temp_sensor->clock);
clk_get_err:
	pm_runtime_disable(dev);
get_tshut_irq_err:
	gpio_free(OMAP_TSHUT_GPIO);
tshut_gpio_req_err:
get_irq_err:
plat_res_err:
	kfree(temp_sensor);
	return ret;
}

static int __devexit omap_temp_sensor_remove(struct platform_device *pdev)
{
	struct omap_temp_sensor *temp_sensor = platform_get_drvdata(pdev);

	sysfs_remove_group(&pdev->dev.kobj, &omap_temp_sensor_group);
	cancel_delayed_work_sync(&temp_sensor->throttle_work);
	omap_temp_sensor_disable(temp_sensor);
	clk_put(temp_sensor->clock);
	platform_set_drvdata(pdev, NULL);
	if (temp_sensor->irq)
		free_irq(temp_sensor->irq, temp_sensor);
	if (temp_sensor->tshut_irq)
		free_irq(temp_sensor->tshut_irq, temp_sensor);
	kfree(temp_sensor);

	return 0;
}

#ifdef CONFIG_PM
static void omap_temp_sensor_save_ctxt(struct omap_temp_sensor *temp_sensor)
{
	temp_sensor_context.temp_sensor_ctrl =
	    omap_temp_sensor_readl(temp_sensor, TEMP_SENSOR_CTRL_OFFSET);
	temp_sensor_context.bg_ctrl =
	    omap_temp_sensor_readl(temp_sensor, BGAP_CTRL_OFFSET);
	temp_sensor_context.bg_counter =
	    omap_temp_sensor_readl(temp_sensor, BGAP_COUNTER_OFFSET);
	temp_sensor_context.bg_threshold =
	    omap_temp_sensor_readl(temp_sensor, BGAP_THRESHOLD_OFFSET);
	temp_sensor_context.temp_sensor_tshut_threshold =
	    omap_temp_sensor_readl(temp_sensor, BGAP_TSHUT_OFFSET);
}