static int ab8500_gpadc_read()

in adc/ab8500-gpadc.c [386:629]


static int ab8500_gpadc_read(struct ab8500_gpadc *gpadc,
			     const struct ab8500_gpadc_chan_info *ch,
			     int *ibat)
{
	int ret;
	int looplimit = 0;
	unsigned long completion_timeout;
	u8 val;
	u8 low_data, high_data, low_data2, high_data2;
	u8 ctrl1;
	u8 ctrl23;
	unsigned int delay_min = 0;
	unsigned int delay_max = 0;
	u8 data_low_addr, data_high_addr;

	if (!gpadc)
		return -ENODEV;

	/* check if conversion is supported */
	if ((gpadc->irq_sw <= 0) && !ch->hardware_control)
		return -ENOTSUPP;
	if ((gpadc->irq_hw <= 0) && ch->hardware_control)
		return -ENOTSUPP;

	/* Enable vddadc by grabbing PM runtime */
	pm_runtime_get_sync(gpadc->dev);

	/* Check if ADC is not busy, lock and proceed */
	do {
		ret = abx500_get_register_interruptible(gpadc->dev,
			AB8500_GPADC, AB8500_GPADC_STAT_REG, &val);
		if (ret < 0)
			goto out;
		if (!(val & AB8500_GPADC_STAT_BUSY))
			break;
		msleep(20);
	} while (++looplimit < 10);
	if (looplimit >= 10 && (val & AB8500_GPADC_STAT_BUSY)) {
		dev_err(gpadc->dev, "gpadc_conversion: GPADC busy");
		ret = -EINVAL;
		goto out;
	}

	/* Enable GPADC */
	ctrl1 = AB8500_GPADC_CTRL1_ENABLE;

	/* Select the channel source and set average samples */
	switch (ch->avg_sample) {
	case 1:
		ctrl23 = ch->id | AB8500_GPADC_CTRL2_AVG_1;
		break;
	case 4:
		ctrl23 = ch->id | AB8500_GPADC_CTRL2_AVG_4;
		break;
	case 8:
		ctrl23 = ch->id | AB8500_GPADC_CTRL2_AVG_8;
		break;
	default:
		ctrl23 = ch->id | AB8500_GPADC_CTRL2_AVG_16;
		break;
	}

	if (ch->hardware_control) {
		ret = abx500_set_register_interruptible(gpadc->dev,
				AB8500_GPADC, AB8500_GPADC_CTRL3_REG, ctrl23);
		ctrl1 |= AB8500_GPADC_CTRL1_TRIG_ENA;
		if (ch->falling_edge)
			ctrl1 |= AB8500_GPADC_CTRL1_TRIG_EDGE;
	} else {
		ret = abx500_set_register_interruptible(gpadc->dev,
				AB8500_GPADC, AB8500_GPADC_CTRL2_REG, ctrl23);
	}
	if (ret < 0) {
		dev_err(gpadc->dev,
			"gpadc_conversion: set avg samples failed\n");
		goto out;
	}

	/*
	 * Enable ADC, buffering, select rising edge and enable ADC path
	 * charging current sense if it needed, ABB 3.0 needs some special
	 * treatment too.
	 */
	switch (ch->id) {
	case AB8500_GPADC_CHAN_MAIN_CHARGER_CURRENT:
	case AB8500_GPADC_CHAN_USB_CHARGER_CURRENT:
		ctrl1 |= AB8500_GPADC_CTRL1_BUF_ENA |
			AB8500_GPADC_CTRL1_ICHAR_ENA;
		break;
	case AB8500_GPADC_CHAN_BAT_TEMP:
		if (!is_ab8500_2p0_or_earlier(gpadc->ab8500)) {
			ctrl1 |= AB8500_GPADC_CTRL1_BUF_ENA |
				AB8500_GPADC_CTRL1_BTEMP_PULL_UP;
			/*
			 * Delay might be needed for ABB8500 cut 3.0, if not,
			 * remove when hardware will be available
			 */
			delay_min = 1000; /* Delay in micro seconds */
			delay_max = 10000; /* large range optimises sleepmode */
			break;
		}
		fallthrough;
	default:
		ctrl1 |= AB8500_GPADC_CTRL1_BUF_ENA;
		break;
	}

	/* Write configuration to control register 1 */
	ret = abx500_set_register_interruptible(gpadc->dev,
		AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ctrl1);
	if (ret < 0) {
		dev_err(gpadc->dev,
			"gpadc_conversion: set Control register failed\n");
		goto out;
	}

	if (delay_min != 0)
		usleep_range(delay_min, delay_max);

	if (ch->hardware_control) {
		/* Set trigger delay timer */
		ret = abx500_set_register_interruptible(gpadc->dev,
			AB8500_GPADC, AB8500_GPADC_AUTO_TIMER_REG,
			ch->trig_timer);
		if (ret < 0) {
			dev_err(gpadc->dev,
				"gpadc_conversion: trig timer failed\n");
			goto out;
		}
		completion_timeout = 2 * HZ;
		data_low_addr = AB8500_GPADC_AUTODATAL_REG;
		data_high_addr = AB8500_GPADC_AUTODATAH_REG;
	} else {
		/* Start SW conversion */
		ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
			AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
			AB8500_GPADC_CTRL1_START_SW_CONV,
			AB8500_GPADC_CTRL1_START_SW_CONV);
		if (ret < 0) {
			dev_err(gpadc->dev,
				"gpadc_conversion: start s/w conv failed\n");
			goto out;
		}
		completion_timeout = msecs_to_jiffies(AB8500_GPADC_CONVERSION_TIME);
		data_low_addr = AB8500_GPADC_MANDATAL_REG;
		data_high_addr = AB8500_GPADC_MANDATAH_REG;
	}

	/* Wait for completion of conversion */
	if (!wait_for_completion_timeout(&gpadc->complete,
			completion_timeout)) {
		dev_err(gpadc->dev,
			"timeout didn't receive GPADC conv interrupt\n");
		ret = -EINVAL;
		goto out;
	}

	/* Read the converted RAW data */
	ret = abx500_get_register_interruptible(gpadc->dev,
			AB8500_GPADC, data_low_addr, &low_data);
	if (ret < 0) {
		dev_err(gpadc->dev,
			"gpadc_conversion: read low data failed\n");
		goto out;
	}

	ret = abx500_get_register_interruptible(gpadc->dev,
		AB8500_GPADC, data_high_addr, &high_data);
	if (ret < 0) {
		dev_err(gpadc->dev,
			"gpadc_conversion: read high data failed\n");
		goto out;
	}

	/* Check if double conversion is required */
	if ((ch->id == AB8500_GPADC_CHAN_BAT_CTRL_AND_IBAT) ||
	    (ch->id == AB8500_GPADC_CHAN_VBAT_MEAS_AND_IBAT) ||
	    (ch->id == AB8500_GPADC_CHAN_VBAT_TRUE_MEAS_AND_IBAT) ||
	    (ch->id == AB8500_GPADC_CHAN_BAT_TEMP_AND_IBAT)) {

		if (ch->hardware_control) {
			/* not supported */
			ret = -ENOTSUPP;
			dev_err(gpadc->dev,
				"gpadc_conversion: only SW double conversion supported\n");
			goto out;
		} else {
			/* Read the converted RAW data 2 */
			ret = abx500_get_register_interruptible(gpadc->dev,
				AB8500_GPADC, AB8540_GPADC_MANDATA2L_REG,
				&low_data2);
			if (ret < 0) {
				dev_err(gpadc->dev,
					"gpadc_conversion: read sw low data 2 failed\n");
				goto out;
			}

			ret = abx500_get_register_interruptible(gpadc->dev,
				AB8500_GPADC, AB8540_GPADC_MANDATA2H_REG,
				&high_data2);
			if (ret < 0) {
				dev_err(gpadc->dev,
					"gpadc_conversion: read sw high data 2 failed\n");
				goto out;
			}
			if (ibat != NULL) {
				*ibat = (high_data2 << 8) | low_data2;
			} else {
				dev_warn(gpadc->dev,
					"gpadc_conversion: ibat not stored\n");
			}

		}
	}

	/* Disable GPADC */
	ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
		AB8500_GPADC_CTRL1_REG, AB8500_GPADC_CTRL1_DISABLE);
	if (ret < 0) {
		dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n");
		goto out;
	}

	/* This eventually drops the regulator */
	pm_runtime_mark_last_busy(gpadc->dev);
	pm_runtime_put_autosuspend(gpadc->dev);

	return (high_data << 8) | low_data;

out:
	/*
	 * It has shown to be needed to turn off the GPADC if an error occurs,
	 * otherwise we might have problem when waiting for the busy bit in the
	 * GPADC status register to go low. In V1.1 there wait_for_completion
	 * seems to timeout when waiting for an interrupt.. Not seen in V2.0
	 */
	(void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
		AB8500_GPADC_CTRL1_REG, AB8500_GPADC_CTRL1_DISABLE);
	pm_runtime_put(gpadc->dev);
	dev_err(gpadc->dev,
		"gpadc_conversion: Failed to AD convert channel %d\n", ch->id);

	return ret;
}