static int isl_read_adc(int channel, int *mv_reading)
{
	int ret;
	void *h;
	struct adc_chan_result adc_chan_result;
	struct completion  conv_complete_evt;

	pr_debug("%s: called for %d\n", __func__, channel);
	ret = adc_channel_open(channel, &h);
	if (ret) {
		pr_err("%s: couldnt open channel %d ret=%d\n",
					__func__, channel, ret);
		goto out;
	}
	init_completion(&conv_complete_evt);
	ret = adc_channel_request_conv(h, &conv_complete_evt);
	if (ret) {
		pr_err("%s: couldnt request conv channel %d ret=%d\n",
						__func__, channel, ret);
		goto out;
	}
	ret = wait_for_completion_interruptible(&conv_complete_evt);
	if (ret) {
		pr_err("%s: wait interrupted channel %d ret=%d\n",
						__func__, channel, ret);
		goto out;
	}
	ret = adc_channel_read_result(h, &adc_chan_result);
	if (ret) {
		pr_err("%s: couldnt read result channel %d ret=%d\n",
						__func__, channel, ret);
		goto out;
	}
	ret = adc_channel_close(h);
	if (ret)
		pr_err("%s: couldnt close channel %d ret=%d\n",
					__func__, channel, ret);
	if (mv_reading)
		*mv_reading = (int)adc_chan_result.measurement;

	pr_debug("%s: done for %d\n", __func__, channel);
	return adc_chan_result.physical;
out:
	*mv_reading = 0;
	pr_debug("%s: done with error for %d\n", __func__, channel);
	return -EINVAL;

}
Exemple #2
0
static int check_analog_mpp(int channel,int *mv_reading)                   // read adc value 
{
	int ret;
	void *h;
	struct adc_chan_result adc_chan_result;
	struct completion  conv_complete_evt;
	dbg_func_in();
	ret = adc_channel_open(channel, &h);
	if (ret) {
		pr_err("%s: couldnt open channel %d ret=%d\n",
				__func__, channel, ret);
		goto out;
	}
	init_completion(&conv_complete_evt);
	ret = adc_channel_request_conv(h, &conv_complete_evt);
	if (ret) {
		pr_err("%s: couldnt request conv channel %d ret=%d\n",
				__func__, channel, ret);
		goto out;
	}
	wait_for_completion(&conv_complete_evt);
	ret = adc_channel_read_result(h, &adc_chan_result);
	if (ret) {
		pr_err("%s: couldnt read result channel %d ret=%d\n",
				__func__, channel, ret);
		goto out;
	}
	ret = adc_channel_close(h);
	if (ret) {
		pr_err("%s: couldnt close channel %d ret=%d\n",
				__func__, channel, ret);
	}
	if (mv_reading)
		*mv_reading = adc_chan_result.measurement;

	pr_debug("%s: done for %d\n", __func__, channel);
	dbg_func_out();
	return adc_chan_result.physical;
out:
	pr_debug("%s: done for %d\n", __func__, channel);
	return -EINVAL;
}
static int pm8058_configure_switch(struct pm8058_othc *dd)
{
	int rc, i;

	if (dd->othc_support_n_switch == true) {
		/* n-switch support */
		rc = adc_channel_open(dd->switch_config->adc_channel,
							&dd->adc_handle);
		if (rc) {
			pr_err("Unable to open ADC channel\n");
			return -ENODEV;
		}

		for (i = 0; i < dd->switch_config->num_keys; i++) {
			input_set_capability(dd->othc_ipd, EV_KEY,
				dd->switch_config->switch_info[i].key_code);
		}
	} else /* Only single switch supported */
		input_set_capability(dd->othc_ipd, EV_KEY, KEY_MEDIA);

	return 0;
}
static int __devinit pmic8058_tm_probe(struct platform_device *pdev)
{
	DECLARE_COMPLETION_ONSTACK(wait);
	struct pm8058_tm_device *tmdev;
	struct pm8058_chip *pm_chip;
	unsigned int irq;
	int rc;

	pm_chip = platform_get_drvdata(pdev);
	if (pm_chip == NULL) {
		pr_err("%s: no driver data passed in.\n", __func__);
		return -EFAULT;
	}

	irq = platform_get_irq(pdev, 0);
	if (!irq) {
		pr_err("%s: no IRQ passed in.\n", __func__);
		return -EFAULT;
	}

	tmdev = kzalloc(sizeof *tmdev, GFP_KERNEL);
	if (tmdev == NULL) {
		pr_err("%s: kzalloc() failed.\n", __func__);
		return -ENOMEM;
	}

	rc = adc_channel_open(PM8058_TEMP_ADC_CH, &(tmdev->adc_handle));
	if (rc < 0) {
		pr_err("%s: adc_channel_open() failed.\n", __func__);
		kfree(tmdev);
		return rc;
	}

	/* calibrate the die temperature sensor */
	if (adc_calib_request(tmdev->adc_handle, &wait) == CALIB_STARTED)
		wait_for_completion(&wait);

	tmdev->pm_chip = pm_chip;
	tmdev->tz_dev = thermal_zone_device_register("pm8058_tz",
						     PM8058_TRIP_NUM, tmdev,
						     &pm8058_thermal_zone_ops,
						     0, 0, 0, 0);
	if (tmdev->tz_dev == NULL) {
		pr_err("%s: thermal_zone_device_register() failed.\n",
		       __func__);
		adc_channel_close(tmdev->adc_handle);
		kfree(tmdev);
		return -ENODEV;
	}

	rc = pm8058_tm_init_reg(tmdev);
	pm8058_tm_shutdown_override(tmdev->pm_chip, SOFTWARE_OVERRIDE_DISABLED);
	if (rc < 0) {
		thermal_zone_device_unregister(tmdev->tz_dev);
		adc_channel_close(tmdev->adc_handle);
		kfree(tmdev);
		return rc;
	}

	/* start in HW control, switch to SW control when user changes mode */
	tmdev->mode = THERMAL_DEVICE_DISABLED;
	thermal_zone_device_update(tmdev->tz_dev);

	platform_set_drvdata(pdev, tmdev);

	rc = request_threaded_irq(irq, NULL, pm8058_tm_isr,
			 IRQF_TRIGGER_RISING | IRQF_DISABLED,
			 "pm8058-tm-irq", tmdev);
	if (rc < 0) {
		pr_err("%s: request_irq(%d) FAIL: %d\n", __func__, irq, rc);
		thermal_zone_device_unregister(tmdev->tz_dev);
		platform_set_drvdata(pdev, tmdev->pm_chip);
		adc_channel_close(tmdev->adc_handle);
		kfree(tmdev);
		return rc;
	}
	tmdev->irq = irq;

	pr_notice("%s: OK\n", __func__);
	return 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;

	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;
	}

	wait_for_completion(&wait);

	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;

	return 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;

	/* Mask software override requests if they are not allowed. */
	if (!chip->cdata.allow_software_override)
		mode = THERMAL_DEVICE_DISABLED;

	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 delayed_work *dwork
		= container_of(work, struct delayed_work, work);
	struct pm8xxx_tm_chip *chip
		= container_of(dwork, struct pm8xxx_tm_chip, irq_work);
	unsigned long temp = 0;
	int rc, stage, thresh;
	u8 reg;

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

	/* 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);
	}

	stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
		>> TEMP_ALARM_CTRL_STATUS_SHIFT;
	thresh = (reg & TEMP_ALARM_CTRL_THRESH_MASK)
		>> TEMP_ALARM_CTRL_THRESH_SHIFT;

	thermal_zone_device_update(chip->tz_dev);

	if (stage != chip->prev_stage) {
		chip->prev_stage = stage;

		switch (chip->cdata.adc_type) {
		case PM8XXX_TM_ADC_NONE:
			rc = pm8xxx_tz_get_temp_no_adc(chip->tz_dev, &temp);
			break;
		case PM8XXX_TM_ADC_PM8058_ADC:
			rc = pm8xxx_tz_get_temp_pm8058_adc(chip->tz_dev, &temp);
			break;
		case PM8XXX_TM_ADC_PM8XXX_ADC:
			rc = pm8xxx_tz_get_temp_pm8xxx_adc(chip->tz_dev, &temp);
			break;
		}
		if (rc < 0)
			goto bail;

		pr_crit("%s: PMIC Temp Alarm - stage=%u, threshold=%u, temp=%lu mC\n",
			chip->cdata.tm_name, stage, thresh, temp);

		/* Notify user space */
		sysfs_notify(&chip->tz_dev->device.kobj, NULL, "type");
	}

bail:
	return;
}

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

	schedule_delayed_work(&chip->irq_work,
		msecs_to_jiffies(STATUS_REGISTER_DELAY_MS) + 1);

	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 temperature alarm module to be always on.  This ensures
	 * that die temperature monitoring is active even if CXO is disabled
	 * (i.e. when sleep_b is low).  This is necessary since CXO can be
	 * disabled while the system is still heavily loaded.  Also, using
	 * the alway-on instead of PWM-enabled configurations ensures that the
	 * die temperature can be measured by the PMIC ADC without reconfiguring
	 * the temperature alarm module first.
	 */
	rc = pm8xxx_tm_write_pwm(chip, TEMP_ALARM_PWM_EN_ALWAYS);

	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;
}
Exemple #6
0
static int pm8058_configure_othc(struct pm8058_othc *dd)
{
	int rc;
	u8 reg, value;
	u32 value1;
	u16 base_addr = dd->othc_base;
	struct othc_hsed_config *hsed_config = dd->othc_pdata->hsed_config;

	/* Intialize the OTHC module */
	/* Control Register 1*/
	rc = pm8058_read(dd->pm_chip, base_addr, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* set iDAC high current threshold */
	value = (hsed_config->othc_highcurr_thresh_uA / 100) - 2;
	reg =  (reg & PM8058_OTHC_HIGH_CURR_MASK) | value;

	rc = pm8058_write(dd->pm_chip, base_addr, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* Control register 2*/
	rc = pm8058_read(dd->pm_chip, base_addr + 1, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	value = dd->othc_pdata->micbias_enable;
	reg &= PM8058_OTHC_EN_SIG_MASK;
	reg |= (value << PM8058_OTHC_EN_SIG_SHIFT);

	value = 0;
	value1 = (hsed_config->othc_hyst_prediv_us << 10) / USEC_PER_SEC;
	while (value1 != 0) {
		value1 = value1 >> 1;
		value++;
	}
	if (value > 7) {
		pr_err("%s: Invalid input argument - othc_hyst_prediv_us \n",
								__func__);
		return -EINVAL;
	}
	reg &= PM8058_OTHC_HYST_PREDIV_MASK;
	reg |= (value << PM8058_OTHC_HYST_PREDIV_SHIFT);

	value = 0;
	value1 = (hsed_config->othc_period_clkdiv_us << 10) / USEC_PER_SEC;
	while (value1 != 1) {
		value1 = value1 >> 1;
		value++;
	}
	if (value > 8) {
		pr_err("%s: Invalid input argument - othc_period_clkdiv_us \n",
								__func__);
		return -EINVAL;
	}
	reg = (reg &  PM8058_OTHC_CLK_PREDIV_MASK) | (value - 1);

	rc = pm8058_write(dd->pm_chip, base_addr + 1, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* Control register 3 */
	rc = pm8058_read(dd->pm_chip, base_addr + 2 , &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	value = hsed_config->othc_hyst_clk_us /
					hsed_config->othc_hyst_prediv_us;
	if (value > 15) {
		pr_err("%s: Invalid input argument - othc_hyst_prediv_us \n",
								__func__);
		return -EINVAL;
	}
	reg &= PM8058_OTHC_HYST_CLK_MASK;
	reg |= value << PM8058_OTHC_HYST_CLK_SHIFT;

	value = hsed_config->othc_period_clk_us /
					hsed_config->othc_period_clkdiv_us;
	if (value > 15) {
		pr_err("%s: Invalid input argument - othc_hyst_prediv_us \n",
								__func__);
		return -EINVAL;
	}
	reg = (reg & PM8058_OTHC_PERIOD_CLK_MASK) | value;

	rc = pm8058_write(dd->pm_chip, base_addr + 2, &reg, 1);
	if (rc < 0) {
		pr_err("%s: PM8058 read failed \n", __func__);
		return rc;
	}

	/* Configure the ADC if n_switch_headset is supported */
	if (dd->othc_support_n_switch == true) {
		rc = adc_channel_open(dd->switch_config->adc_channel,
							&dd->adc_handle);
		if (rc) {
			pr_err("%s: Unable to open ADC channel\n", __func__);
			return -ENODEV;
		}
		pr_debug("%s: ADC channel open SUCCESS\n", __func__);
	}

	return 0;
}
Exemple #7
0
static int batt_read_adc(int channel, int *mv_reading)
{
	int ret;
	void *h;
	struct adc_chan_result adc_chan_result;
	struct completion  conv_complete_evt;
#ifdef CONFIG_LGE_PM
    int wait_ret;
#endif

	pr_debug("%s: called for %d\n", __func__, channel);
	ret = adc_channel_open(channel, &h);
	if (ret) {
		pr_err("%s: couldnt open channel %d ret=%d\n",
					__func__, channel, ret);
		goto out;
	}
	init_completion(&conv_complete_evt);
	ret = adc_channel_request_conv(h, &conv_complete_evt);
	if (ret) {
		pr_err("%s: couldnt request conv channel %d ret=%d\n",
						__func__, channel, ret);
		goto out;
	}
#ifdef CONFIG_LGE_PM
    wait_ret = wait_for_completion_timeout(&conv_complete_evt, 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(&conv_complete_evt);
#endif

	ret = adc_channel_read_result(h, &adc_chan_result);
	if (ret) {
		pr_err("%s: couldnt read result channel %d ret=%d\n",
						__func__, channel, ret);
		goto out;
	}
	ret = adc_channel_close(h);
	if (ret) {
		pr_err("%s: couldnt close channel %d ret=%d\n",
						__func__, channel, ret);
	}
	if (mv_reading)
		*mv_reading = adc_chan_result.measurement;

	pr_debug("%s: done for %d\n", __func__, channel);
	return adc_chan_result.physical;
out:
	pr_debug("%s: done for %d\n", __func__, channel);
	return -EINVAL;

#ifdef CONFIG_LGE_PM
sanity_out:

    pm8058_xoadc_clear_recentQ();

	ret = adc_channel_close(h);
	if (ret) {
		pr_err("%s: couldnt close channel %d ret=%d\n",
						__func__, channel, ret);
	}
    
    if(channel == CHANNEL_ADC_BATT_THERM)
    {
        printk(KERN_ERR "============== batt temp adc read fail so default temp ===============\n");
	    if (mv_reading)
		    *mv_reading = MSM_CHARGER_GAUGE_MISSING_TEMP_ADC;
        return MSM_CHARGER_GAUGE_MISSING_TEMP;
    }
    else if(channel == CHANNEL_ADC_ACC)
    {
        printk(KERN_ERR "============== ACC adc read fail so default usb ===============\n");
        return CHANNEL_ADC_ACC_MISSING;
    }
    else
    {
        printk(KERN_ERR "============== adc read fail  ===============\n");
	    return -EINVAL;
    }
#endif
}
static int
pm8058_configure_accessory(struct pm8058_othc *dd)
{
#if 0
	int i, rc;
	char name[OTHC_GPIO_MAX_LEN];

	/*
	 * Not bailing out if the gpio_* configure calls fail. This is required
	 * as multiple accessories are detected by the same gpio.
	 */
	for (i = 0; i < dd->num_accessories; i++) {
		if (dd->accessory_info[i].enabled == false)
			continue;
		if (dd->accessory_info[i].detect_flags & OTHC_GPIO_DETECT) {
			snprintf(name, OTHC_GPIO_MAX_LEN, "%s%d",
							"othc_acc_gpio_", i);
			rc = gpio_request(dd->accessory_info[i].gpio, name);
			if (rc) {
				pr_err("Unable to request GPIO [%d]\n",
						dd->accessory_info[i].gpio);
				continue;
			}
			rc = gpio_direction_input(dd->accessory_info[i].gpio);
			if (rc) {
				pr_err("Unable to set-direction GPIO [%d]\n",
						dd->accessory_info[i].gpio);
				gpio_free(dd->accessory_info[i].gpio);
				continue;
			}
		}
		input_set_capability(dd->othc_ipd, EV_SW,
					dd->accessory_info[i].key_code);
	}

	if (dd->accessories_adc_support) {
		/*
		 * Check if 3 switch is supported. If both are using the same
		 * ADC channel, the same handle can be used.
		 */
		if (dd->othc_support_n_switch) {
			if (dd->adc_handle != NULL &&
				(dd->accessories_adc_channel ==
				 dd->switch_config->adc_channel))
				dd->accessory_adc_handle = dd->adc_handle;
		} else {
			rc = adc_channel_open(dd->accessories_adc_channel,
						&dd->accessory_adc_handle);
			if (rc) {
				pr_err("Unable to open ADC channel\n");
				rc = -ENODEV;
				goto accessory_adc_fail;
			}
		}
		if (dd->video_out_gpio != 0) {
			rc = gpio_request(dd->video_out_gpio, "vout_enable");
			if (rc < 0) {
				pr_err("request VOUT gpio failed (%d)\n", rc);
				goto accessory_adc_fail;
			}
			rc = gpio_direction_output(dd->video_out_gpio, 0);
			if (rc < 0) {
				pr_err("direction_out failed (%d)\n", rc);
				goto accessory_adc_fail;
			}
		}

	}

	return 0;

accessory_adc_fail:
	for (i = 0; i < dd->num_accessories; i++) {
		if (dd->accessory_info[i].enabled == false)
			continue;
		gpio_free(dd->accessory_info[i].gpio);
	}
	return rc;
#endif
       return 0;
}
Exemple #9
0
u32 lightsensor_get_adc(int channel)
{
	int ret;
	void *h;
	struct adc_chan_result adc_chan_result;
	struct completion  conv_complete_evt;
#ifdef CONFIG_SEC_DEBUG_PM8058_ADC
	static int retry_cnt;
#endif
	pr_debug("%s: called for %d\n", __func__, channel);
	ret = adc_channel_open(channel, &h);
	if (ret) {
		pr_err("%s: couldnt open channel %d ret=%d\n",
					__func__, channel, ret);
		goto out;
	}
	init_completion(&conv_complete_evt);
	ret = adc_channel_request_conv(h, &conv_complete_evt);
	if (ret) {
		pr_err("%s: couldnt request conv channel %d ret=%d\n",
						__func__, channel, ret);
		goto out;
	}
	ret = wait_for_completion_interruptible_timeout(&conv_complete_evt, 5*HZ);
	if (!ret) {
		pr_err("%s: wait interrupted channel %d ret=%d\n",
						__func__, channel, ret);
#ifdef CONFIG_SEC_DEBUG_PM8058_ADC_VERBOSE
		adc_dbg_info_timer(0);
#else
		pm8058_xoadc_clear_recentQ();
#ifdef CONFIG_SEC_DEBUG_PM8058_ADC
		if(retry_cnt++ >= 10)
			adc_dbg_info_timer(0);
#endif
#endif
		goto out;
	}
#ifdef CONFIG_SEC_DEBUG_PM8058_ADC
	retry_cnt = 0;
#endif
	ret = adc_channel_read_result(h, &adc_chan_result);
	if (ret) {
		pr_err("%s: couldnt read result channel %d ret=%d\n",
						__func__, channel, ret);
		goto out;
	}
	ret = adc_channel_close(h);
	if (ret) {
		pr_err("%s: couldnt close channel %d ret=%d\n",
						__func__, channel, ret);
	}

	pr_debug("%s: done for %d\n", __func__, channel);
//	return adc_chan_result.physical;
	return adc_chan_result.measurement;

out:
	pr_debug("%s: done for %d\n", __func__, channel);
	return -EINVAL;

}
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;

	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;
	}

	wait_for_completion(&wait);

	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;

	return 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 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 */
	sysfs_notify(&chip->tz_dev->device.kobj, NULL, "type");

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;
}
static int Check_ADC_MPP(int *nValue) {
	int err=0,ret=0,result=0;
	void *h;
	struct adc_chan_result adc_chan_result;
	//long  timeout=0;

	struct completion  conv_complete_evt;
	struct pm8xxx_mpp_config_data sky_handset_analog_adc = {
						.type	= PM8XXX_MPP_TYPE_A_INPUT,
					.level	= PM8XXX_MPP_AIN_AMUX_CH5,	
					.control = PM8XXX_MPP_AOUT_CTRL_DISABLE,
				};

	mutex_lock(&headset_adc_lock);

	ret=gpio_get_value_cansleep(hspd->ear_det);	
	if(ret!=hspd->ear_det_active) {
		printk("EARJACK_DET %d\n",ret);
		mutex_unlock(&headset_adc_lock);
		return -1;
	}

#if AT1_BDVER_GE(AT1_WS22) 
	if(hspd->curr_state == MSM_HEADSET) {
		Remote_Interrupt_Enable(0);
		msleep(1);
	}
#endif
		
	//sys_gpio= PM8901_GPIO_PM_TO_SYS(mpp);
	//err=pm8058_mpp_config_analog_input(XOADC_MPP_3,PM_MPP_AIN_AMUX_CH5, PM_MPP_AOUT_CTL_DISABLE);
	err = pm8xxx_mpp_config(PM8058_MPP_PM_TO_SYS(XOADC_MPP_3), &sky_handset_analog_adc);
	if(err) {
		printk("pm8058_mpp_config_analog_input() err=%d\n",err);
		mutex_unlock(&headset_adc_lock);
		return -1;
	}

	ret = adc_channel_open(CHANNEL_ADC_HDSET, &h);
	if(ret) {
		printk("couldn't open channel %d ret=%d\n",CHANNEL_ADC_HDSET,ret);
		mutex_unlock(&headset_adc_lock);
		return -1;
	}

	init_completion(&conv_complete_evt);

	ret = adc_channel_request_conv(h, &conv_complete_evt);
	if(ret) {
		printk("couldn't request convert channel %d ret=%d\n",CHANNEL_ADC_HDSET,ret);
		result=-2;
		goto check_adc_out;
	}

	wait_for_completion(&conv_complete_evt);

/*
	timeout=wait_for_completion_timeout(&conv_complete_evt,msecs_to_jiffies(100));
	if(timeout<=0) {
		printk("headset ADC timeout\n");
		result=-3;
		goto check_adc_out;
	}
*/

	ret = adc_channel_read_result(h, &adc_chan_result);
	if(ret) {
		printk("could't read result channel %d ret=%d\n",CHANNEL_ADC_HDSET,ret);
		result=-4;
		goto check_adc_out;
	}


	*nValue=(int)adc_chan_result.measurement;

check_adc_out:
	
	ret = adc_channel_close(h);
	if(ret) {
		printk("could't close channel %d ret=%d\n",CHANNEL_ADC_HDSET,ret);
		mutex_unlock(&headset_adc_lock);
		return -1;
	}

#if AT1_BDVER_GE(AT1_WS22) 
	if(hspd->curr_state == MSM_HEADSET) {
		Remote_Interrupt_Enable(1);
	}
#endif

	//printk("ADC value=%d, physical=%d\n",(int)adc_chan_result.measurement,adc_chan_result.physical);
	mutex_unlock(&headset_adc_lock);
	return result;		
}
static int semc_battery_read_adc(int channel, int *read_measurement,
				int *read_physical)
{
	struct power_supply *ps = power_supply_get_by_name(SEMC_BDATA_NAME);
	struct data_info *di = container_of(ps, struct data_info, bdata_ps);
	int ret;
	void *h;
	struct adc_chan_result adc_chan_result;
	struct completion  conv_complete_evt;

	if (!read_measurement && !read_physical)
		return -EINVAL;

	dev_dbg(di->dev, "called for %d\n", channel);
	ret = adc_channel_open(channel, &h);
	if (ret) {
		dev_err(di->dev, "couldnt open channel %d ret=%d\n",
			channel, ret);
		goto out;
	}
	init_completion(&conv_complete_evt);
	ret = adc_channel_request_conv(h, &conv_complete_evt);
	if (ret) {
		dev_err(di->dev, "couldnt request conv channel %d ret=%d\n",
			channel, ret);
		adc_channel_close(h);
		goto out;
	}
	ret = wait_for_completion_interruptible(&conv_complete_evt);
	if (ret) {
		dev_err(di->dev, "wait interrupted channel %d ret=%d\n",
			channel, ret);
		adc_channel_close(h);
		goto out;
	}
	ret = adc_channel_read_result(h, &adc_chan_result);
	if (ret) {
		dev_err(di->dev, "couldnt read result channel %d ret=%d\n",
			channel, ret);
		adc_channel_close(h);
		goto out;
	}
	ret = adc_channel_close(h);
	if (ret)
		dev_err(di->dev, "couldnt close channel %d ret=%d\n",
			channel, ret);
	if (read_measurement) {
		*read_measurement = (int)adc_chan_result.measurement;
		dev_dbg(di->dev, "done for %d measurement=%d\n",
			channel, *read_measurement);
	}
	if (read_physical) {
		*read_physical = adc_chan_result.physical;
		dev_dbg(di->dev, "done for %d physical=%d\n",
			channel, *read_physical);
	}
	return ret;
out:
	dev_dbg(di->dev, "done for %d\n", channel);
	return ret;

}