static int pm8xxx_tz_get_temp_no_adc(struct thermal_zone_device *thermal,
				     unsigned long *temp)
{
	struct pm8xxx_tm_chip *chip = thermal->devdata;
	int rc;

	if (!chip || !temp)
		return -EINVAL;

	rc = pm8xxx_tm_update_temp_no_adc(chip);
	if (rc < 0)
		return rc;

	*temp = chip->temp;

	return 0;
}
示例#2
0
static int pm8xxx_tz_get_temp_pm8xxx_adc(struct thermal_zone_device *thermal,
				      unsigned long *temp)
{
	struct pm8xxx_tm_chip *chip = thermal->devdata;
	struct pm8xxx_adc_chan_result result = {
		.physical = 0lu,
	};
	int rc;

	if (!chip || !temp)
		return -EINVAL;

	*temp = chip->temp;

	rc = pm8xxx_adc_read(chip->cdata.adc_channel, &result);
	if (rc < 0) {
		pr_err("%s: adc_channel_read_result() failed, rc = %d\n",
			chip->cdata.tm_name, rc);
		return rc;
	}

	*temp = result.physical;
	chip->temp = result.physical;

	return 0;
}

static int pm8xxx_tz_get_mode(struct thermal_zone_device *thermal,
			      enum thermal_device_mode *mode)
{
	struct pm8xxx_tm_chip *chip = thermal->devdata;

	if (!chip || !mode)
		return -EINVAL;

	*mode = chip->mode;

	return 0;
}

static int pm8xxx_tz_set_mode(struct thermal_zone_device *thermal,
			      enum thermal_device_mode mode)
{
	struct pm8xxx_tm_chip *chip = thermal->devdata;

	if (!chip)
		return -EINVAL;

	if (mode != chip->mode) {
		if (mode == THERMAL_DEVICE_ENABLED)
			pm8xxx_tm_shutdown_override(chip,
						    SOFTWARE_OVERRIDE_ENABLED);
		else
			pm8xxx_tm_shutdown_override(chip,
						    SOFTWARE_OVERRIDE_DISABLED);
	}
	chip->mode = mode;

	return 0;
}

static int pm8xxx_tz_get_trip_type(struct thermal_zone_device *thermal,
				   int trip, enum thermal_trip_type *type)
{
	if (trip < 0 || !type)
		return -EINVAL;

	switch (trip) {
	case TRIP_STAGE3:
		*type = THERMAL_TRIP_CRITICAL;
		break;
	case TRIP_STAGE2:
		*type = THERMAL_TRIP_HOT;
		break;
	case TRIP_STAGE1:
		*type = THERMAL_TRIP_HOT;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static int pm8xxx_tz_get_trip_temp(struct thermal_zone_device *thermal,
				   int trip, unsigned long *temp)
{
	struct pm8xxx_tm_chip *chip = thermal->devdata;
	int thresh_temp;

	if (!chip || trip < 0 || !temp)
		return -EINVAL;

	thresh_temp = chip->thresh * TEMP_THRESH_STEP +
			TEMP_THRESH_MIN;

	switch (trip) {
	case TRIP_STAGE3:
		thresh_temp += 2 * TEMP_STAGE_STEP;
		break;
	case TRIP_STAGE2:
		thresh_temp += TEMP_STAGE_STEP;
		break;
	case TRIP_STAGE1:
		break;
	default:
		return -EINVAL;
	}

	*temp = thresh_temp;

	return 0;
}

static int pm8xxx_tz_get_crit_temp(struct thermal_zone_device *thermal,
				   unsigned long *temp)
{
	struct pm8xxx_tm_chip *chip = thermal->devdata;

	if (!chip || !temp)
		return -EINVAL;

	*temp = chip->thresh * TEMP_THRESH_STEP + TEMP_THRESH_MIN +
		2 * TEMP_STAGE_STEP;

	return 0;
}

static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_no_adc = {
	.get_temp = pm8xxx_tz_get_temp_no_adc,
	.get_mode = pm8xxx_tz_get_mode,
	.set_mode = pm8xxx_tz_set_mode,
	.get_trip_type = pm8xxx_tz_get_trip_type,
	.get_trip_temp = pm8xxx_tz_get_trip_temp,
	.get_crit_temp = pm8xxx_tz_get_crit_temp,
};

static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_pm8xxx_adc = {
	.get_temp = pm8xxx_tz_get_temp_pm8xxx_adc,
	.get_mode = pm8xxx_tz_get_mode,
	.set_mode = pm8xxx_tz_set_mode,
	.get_trip_type = pm8xxx_tz_get_trip_type,
	.get_trip_temp = pm8xxx_tz_get_trip_temp,
	.get_crit_temp = pm8xxx_tz_get_crit_temp,
};

static void pm8xxx_tm_work(struct work_struct *work)
{
	struct pm8xxx_tm_chip *chip
		= container_of(work, struct pm8xxx_tm_chip, irq_work);
	int rc;
	u8 reg;

	rc = pm8xxx_tm_read_ctrl(chip, &reg);
	if (rc < 0)
		goto bail;

	if (chip->cdata.adc_type == PM8XXX_TM_ADC_NONE) {
		rc = pm8xxx_tm_update_temp_no_adc(chip);
		if (rc < 0)
			goto bail;
		pr_info("%s: Temp Alarm - stage=%u, threshold=%u, "
			"temp=%lu mC\n", chip->cdata.tm_name, chip->stage,
			chip->thresh, chip->temp);
	} else {
		chip->stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
				>> TEMP_ALARM_CTRL_STATUS_SHIFT;
		chip->thresh = (reg & TEMP_ALARM_CTRL_THRESH_MASK)
				>> TEMP_ALARM_CTRL_THRESH_SHIFT;
		pr_info("%s: Temp Alarm - stage=%u, threshold=%u\n",
			chip->cdata.tm_name, chip->stage, chip->thresh);
	}

	/* Clear status bits. */
	if (reg & (TEMP_ALARM_CTRL_ST2_SD | TEMP_ALARM_CTRL_ST3_SD)) {
		reg &= ~(TEMP_ALARM_CTRL_ST2_SD | TEMP_ALARM_CTRL_ST3_SD
			 | TEMP_ALARM_CTRL_STATUS_MASK);

		pm8xxx_tm_write_ctrl(chip, reg);
	}

	thermal_zone_device_update(chip->tz_dev);

	/* Notify user space */
	if (chip->mode == THERMAL_DEVICE_ENABLED)
		kobject_uevent(&chip->tz_dev->device.kobj, KOBJ_CHANGE);

bail:
	enable_irq(chip->tempstat_irq);
	enable_irq(chip->overtemp_irq);
}

static irqreturn_t pm8xxx_tm_isr(int irq, void *data)
{
	struct pm8xxx_tm_chip *chip = data;

	disable_irq_nosync(chip->tempstat_irq);
	disable_irq_nosync(chip->overtemp_irq);
	schedule_work(&chip->irq_work);

	return IRQ_HANDLED;
}

static int pm8xxx_tm_init_reg(struct pm8xxx_tm_chip *chip)
{
	int rc;
	u8 reg;

	rc = pm8xxx_tm_read_ctrl(chip, &reg);
	if (rc < 0)
		return rc;

	chip->stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
			>> TEMP_ALARM_CTRL_STATUS_SHIFT;
	chip->temp = 0;

	/* Use temperature threshold set 0: (105, 125, 145) */
	chip->thresh = 0;
	reg = (chip->thresh << TEMP_ALARM_CTRL_THRESH_SHIFT)
		& TEMP_ALARM_CTRL_THRESH_MASK;
	rc = pm8xxx_tm_write_ctrl(chip, reg);
	if (rc < 0)
		return rc;

	/*
	 * Set the PMIC alarm module PWM to have a frequency of 8 Hz. This
	 * helps cut down on the number of unnecessary interrupts fired when
	 * changing between thermal stages.  Also, Enable the over temperature
	 * PWM whenever the PMIC is enabled.
	 */
	reg =  (1 << TEMP_ALARM_PWM_EN_SHIFT)
		| (3 << TEMP_ALARM_PWM_PER_PRE_SHIFT)
		| (3 << TEMP_ALARM_PWM_PER_DIV_SHIFT);

	rc = pm8xxx_tm_write_pwm(chip, reg);

	return rc;
}
示例#3
0
static int pm8xxx_tz_get_temp_pm8058_adc(struct thermal_zone_device *thermal,
			      unsigned long *temp)
{
	struct pm8xxx_tm_chip *chip = thermal->devdata;
	DECLARE_COMPLETION_ONSTACK(wait);
	struct adc_chan_result adc_result = {
		.physical = 0lu,
	};
	int rc;
#ifdef CONFIG_LGE_PM	/*                                        */
	int wait_ret;
#endif

	if (!chip || !temp)
		return -EINVAL;

	*temp = chip->temp;

	rc = adc_channel_request_conv(chip->adc_handle, &wait);
	if (rc < 0) {
		pr_err("%s: adc_channel_request_conv() failed, rc = %d\n",
			__func__, rc);
		return rc;
	}

#ifdef CONFIG_LGE_PM	/*                                        */
	wait_ret = wait_for_completion_timeout(&wait, msecs_to_jiffies(MSM_PMIC_ADC_READ_TIMEOUT));
	if(wait_ret <= 0)
	{
		printk(KERN_ERR "===%s: failed to adc wait for completion!===\n",__func__);
		goto sanity_out;
	}
#else
	wait_for_completion(&wait);
#endif

	rc = adc_channel_read_result(chip->adc_handle, &adc_result);
	if (rc < 0) {
		pr_err("%s: adc_channel_read_result() failed, rc = %d\n",
			__func__, rc);
		return rc;
	}

	*temp = adc_result.physical;
	chip->temp = adc_result.physical;

#if defined(CONFIG_MACH_LGE_325_BOARD_SKT) || defined(CONFIG_MACH_LGE_325_BOARD_LGU)	/*                                        */
	if (chip->temp > 46000)
	{
		printk("%s: pmic_die_temp = %ld  temp_range = %d \n", __func__, *temp, pmic_die_temp_range);
		pmic_die_temp_range = 3;
	}
	else if  (chip->temp > 44000)
		pmic_die_temp_range = 2;
	else if  (chip->temp > 39000)
		pmic_die_temp_range = 1;
	else
		pmic_die_temp_range = 0;
#endif

	return 0;

#ifdef CONFIG_LGE_PM	/*                                        */
sanity_out:

	pm8058_xoadc_clear_recentQ();

	*temp = MSM_CHARGER_GAUGE_MISSING_TEMP;
	chip->temp = MSM_CHARGER_GAUGE_MISSING_TEMP;

	printk(KERN_ERR "============== batt temp adc read fail so default temp ===============\n");
	return 0;
#endif
}

static int pm8xxx_tz_get_temp_pm8xxx_adc(struct thermal_zone_device *thermal,
				      unsigned long *temp)
{
	struct pm8xxx_tm_chip *chip = thermal->devdata;
	struct pm8xxx_adc_chan_result result = {
		.physical = 0lu,
	};
	int rc;

	if (!chip || !temp)
		return -EINVAL;

	*temp = chip->temp;

	rc = pm8xxx_adc_read(chip->cdata.adc_channel, &result);
	if (rc < 0) {
		pr_err("%s: adc_channel_read_result() failed, rc = %d\n",
			chip->cdata.tm_name, rc);
		return rc;
	}

	*temp = result.physical;
	chip->temp = result.physical;

	return 0;
}

static int pm8xxx_tz_get_mode(struct thermal_zone_device *thermal,
			      enum thermal_device_mode *mode)
{
	struct pm8xxx_tm_chip *chip = thermal->devdata;

	if (!chip || !mode)
		return -EINVAL;

	*mode = chip->mode;

	return 0;
}

static int pm8xxx_tz_set_mode(struct thermal_zone_device *thermal,
			      enum thermal_device_mode mode)
{
	struct pm8xxx_tm_chip *chip = thermal->devdata;

	if (!chip)
		return -EINVAL;

	if (mode != chip->mode) {
		if (mode == THERMAL_DEVICE_ENABLED)
			pm8xxx_tm_shutdown_override(chip,
						    SOFTWARE_OVERRIDE_ENABLED);
		else
			pm8xxx_tm_shutdown_override(chip,
						    SOFTWARE_OVERRIDE_DISABLED);
	}
	chip->mode = mode;

	return 0;
}

static int pm8xxx_tz_get_trip_type(struct thermal_zone_device *thermal,
				   int trip, enum thermal_trip_type *type)
{
	if (trip < 0 || !type)
		return -EINVAL;

	switch (trip) {
	case TRIP_STAGE3:
		*type = THERMAL_TRIP_CRITICAL;
		break;
	case TRIP_STAGE2:
		*type = THERMAL_TRIP_HOT;
		break;
	case TRIP_STAGE1:
		*type = THERMAL_TRIP_HOT;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static int pm8xxx_tz_get_trip_temp(struct thermal_zone_device *thermal,
				   int trip, unsigned long *temp)
{
	struct pm8xxx_tm_chip *chip = thermal->devdata;
	int thresh_temp;

	if (!chip || trip < 0 || !temp)
		return -EINVAL;

	thresh_temp = chip->thresh * TEMP_THRESH_STEP +
			TEMP_THRESH_MIN;

	switch (trip) {
	case TRIP_STAGE3:
		thresh_temp += 2 * TEMP_STAGE_STEP;
		break;
	case TRIP_STAGE2:
		thresh_temp += TEMP_STAGE_STEP;
		break;
	case TRIP_STAGE1:
		break;
	default:
		return -EINVAL;
	}

	*temp = thresh_temp;

	return 0;
}

static int pm8xxx_tz_get_crit_temp(struct thermal_zone_device *thermal,
				   unsigned long *temp)
{
	struct pm8xxx_tm_chip *chip = thermal->devdata;

	if (!chip || !temp)
		return -EINVAL;

	*temp = chip->thresh * TEMP_THRESH_STEP + TEMP_THRESH_MIN +
		2 * TEMP_STAGE_STEP;

	return 0;
}

static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_no_adc = {
	.get_temp = pm8xxx_tz_get_temp_no_adc,
	.get_mode = pm8xxx_tz_get_mode,
	.set_mode = pm8xxx_tz_set_mode,
	.get_trip_type = pm8xxx_tz_get_trip_type,
	.get_trip_temp = pm8xxx_tz_get_trip_temp,
	.get_crit_temp = pm8xxx_tz_get_crit_temp,
};

static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_pm8xxx_adc = {
	.get_temp = pm8xxx_tz_get_temp_pm8xxx_adc,
	.get_mode = pm8xxx_tz_get_mode,
	.set_mode = pm8xxx_tz_set_mode,
	.get_trip_type = pm8xxx_tz_get_trip_type,
	.get_trip_temp = pm8xxx_tz_get_trip_temp,
	.get_crit_temp = pm8xxx_tz_get_crit_temp,
};

static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_pm8058_adc = {
	.get_temp = pm8xxx_tz_get_temp_pm8058_adc,
	.get_mode = pm8xxx_tz_get_mode,
	.set_mode = pm8xxx_tz_set_mode,
	.get_trip_type = pm8xxx_tz_get_trip_type,
	.get_trip_temp = pm8xxx_tz_get_trip_temp,
	.get_crit_temp = pm8xxx_tz_get_crit_temp,
};

static void pm8xxx_tm_work(struct work_struct *work)
{
	struct pm8xxx_tm_chip *chip
		= container_of(work, struct pm8xxx_tm_chip, irq_work);
	int rc;
	u8 reg;

	rc = pm8xxx_tm_read_ctrl(chip, &reg);
	if (rc < 0)
		goto bail;

	if (chip->cdata.adc_type == PM8XXX_TM_ADC_NONE) {
		rc = pm8xxx_tm_update_temp_no_adc(chip);
		if (rc < 0)
			goto bail;
		pr_info("%s: Temp Alarm - stage=%u, threshold=%u, "
			"temp=%lu mC\n", chip->cdata.tm_name, chip->stage,
			chip->thresh, chip->temp);
	} else {
		chip->stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
				>> TEMP_ALARM_CTRL_STATUS_SHIFT;
		chip->thresh = (reg & TEMP_ALARM_CTRL_THRESH_MASK)
				>> TEMP_ALARM_CTRL_THRESH_SHIFT;
		pr_info("%s: Temp Alarm - stage=%u, threshold=%u\n",
			chip->cdata.tm_name, chip->stage, chip->thresh);
	}

	/* Clear status bits. */
	if (reg & (TEMP_ALARM_CTRL_ST2_SD | TEMP_ALARM_CTRL_ST3_SD)) {
		reg &= ~(TEMP_ALARM_CTRL_ST2_SD | TEMP_ALARM_CTRL_ST3_SD
			 | TEMP_ALARM_CTRL_STATUS_MASK);

		pm8xxx_tm_write_ctrl(chip, reg);
	}

	thermal_zone_device_update(chip->tz_dev);

	/* Notify user space */
	if (chip->mode == THERMAL_DEVICE_ENABLED)
		kobject_uevent(&chip->tz_dev->device.kobj, KOBJ_CHANGE);

bail:
	enable_irq(chip->tempstat_irq);
	enable_irq(chip->overtemp_irq);
}

static irqreturn_t pm8xxx_tm_isr(int irq, void *data)
{
	struct pm8xxx_tm_chip *chip = data;

	disable_irq_nosync(chip->tempstat_irq);
	disable_irq_nosync(chip->overtemp_irq);
	schedule_work(&chip->irq_work);

	return IRQ_HANDLED;
}

static int pm8xxx_tm_init_reg(struct pm8xxx_tm_chip *chip)
{
	int rc;
	u8 reg;

	rc = pm8xxx_tm_read_ctrl(chip, &reg);
	if (rc < 0)
		return rc;

	chip->stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
			>> TEMP_ALARM_CTRL_STATUS_SHIFT;
	chip->temp = 0;

	/* Use temperature threshold set 0: (105, 125, 145) */
	chip->thresh = 0;
	reg = (chip->thresh << TEMP_ALARM_CTRL_THRESH_SHIFT)
		& TEMP_ALARM_CTRL_THRESH_MASK;
	rc = pm8xxx_tm_write_ctrl(chip, reg);
	if (rc < 0)
		return rc;

	/*
	 * Set the PMIC alarm module PWM to have a frequency of 8 Hz. This
	 * helps cut down on the number of unnecessary interrupts fired when
	 * changing between thermal stages.  Also, Enable the over temperature
	 * PWM whenever the PMIC is enabled.
	 */
	reg =  (1 << TEMP_ALARM_PWM_EN_SHIFT)
		| (3 << TEMP_ALARM_PWM_PER_PRE_SHIFT)
		| (3 << TEMP_ALARM_PWM_PER_DIV_SHIFT);

	rc = pm8xxx_tm_write_pwm(chip, reg);

	return rc;
}

static int pm8xxx_init_adc(struct pm8xxx_tm_chip *chip, bool enable)
{
	int rc = 0;

	if (chip->cdata.adc_type == PM8XXX_TM_ADC_PM8058_ADC) {
		if (enable) {
			rc = adc_channel_open(chip->cdata.adc_channel,
						&(chip->adc_handle));
			if (rc < 0)
				pr_err("adc_channel_open() failed.\n");
		} else {
			adc_channel_close(chip->adc_handle);
		}
	}

	return rc;
}