Merge "hwmon: qpnp-adc: Add PMIC QPNP VADC Driver" into msm-3.4
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
new file mode 100644
index 0000000..2ba7341
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -0,0 +1,98 @@
+Qualcomm's QPNP PMIC Voltage ADC Arbiter
+
+QPNP PMIC Voltage ADC (VADC) provides interface to clients to read
+Voltage. A 15 bit ADC is used for Voltage measurements. There are multiple
+peripherals to the VADC and the scope of the driver is to provide interface
+for the USR peripheral of the VADC.
+
+VADC node
+
+Required properties:
+- compatible : should be "qcom,qpnp-vadc" for Voltage ADC driver.
+- reg : offset and length of the PMIC Aribter register map.
+- interrupts : The USR bank peripheral VADC interrupt.
+- qcom,adc-bit-resolution : Bit resolution of the ADC.
+- qcom,adc-vdd-reference : Voltage reference used by the ADC.
+
+Channel nodes
+NOTE: Atleast one Channel node is required.
+
+Required properties:
+- label : Channel name used for sysfs entry.
+- qcom,channel-num : Channel number associated to the AMUX input.
+- qcom,decimation : Sampling rate to use for the individual channel measurement.
+		    Select from following unsigned int.
+		    0 : 512
+		    1 : 1K
+		    2 : 2K
+		    3 : 4K
+- qcom,pre-div-channel-scaling : Pre-div used for the channel before the signal
+				 is being measured.
+- qcom,calibration-type : Reference voltage to use for channel calibration.
+			  Channel calibration is dependendent on the channel.
+			  Certain channels like XO_THERM, BATT_THERM use ratiometric
+			  calibration. Most other channels fall under absolute calibration.
+			  Select from the following strings.
+			  "absolute" : Uses the 625mv and 1.25V reference channels.
+			  "ratiometric" : Uses the reference Voltage/GND for calibration.
+- qcom,scale-function : Scaling function used to convert raw ADC code to units specific to
+			a given channel.
+			Select from the following unsigned int.
+			0 : Default scaling to convert raw adc code to voltage.
+			1 : Conversion to temperature based on btm parameters.
+			2 : Returns result in milli degree's Centigrade.
+			3 : Returns current across 0.1 ohm resistor.
+			4 : Returns XO thermistor voltage in degree's Centigrade.
+- qcom,hw-settle-time : Settling period for the channel before ADC read.
+			Select from the following unsigned int.
+			0 : 0us
+			1 : 100us
+			2 : 200us
+			3 : 300us
+			4 : 400us
+			5 : 500us
+			6 : 600us
+			7 : 700us
+			8 : 800us
+			9 : 900us
+			0xa : 1ms
+			0xb : 2ms
+			0xc : 4ms
+			0xd : 6ms
+			0xe : 8ms
+			0xf : 10ms
+- qcom,fast-avg-setup : Average number of samples to be used for measurement. Fast averaging
+			provides the option to obtain a single measurement from the ADC that
+			is an average of multiple samples. The value selected is 2^(value)
+			Select from the following unsigned int.
+			0 : 1
+			1 : 2
+			2 : 4
+			3 : 8
+			4 : 16
+			5 : 32
+			6 : 64
+			7 : 128
+			8 : 256
+
+Example:
+	/* Main Node */
+	qcom,vadc@3100 {
+                        compatible = "qcom,qpnp-vadc";
+                        reg = <0x3100 0x100>;
+                        interrupts = <0x0 0x31 0x0>;
+                        qcom,adc-bit-resolution = <15>;
+                        qcom,adc-vdd-reference = <1800>;
+
+			/* Channel Node */
+                        chan@0 {
+                                label = "usb_in";
+                                qcom,channel-num = <0>;
+                                qcom,decimation = <0>;
+                                qcom,pre-div-channel-scaling = <20>;
+                                qcom,calibration-type = "absolute";
+                                qcom,scale-function = <0>;
+                                qcom,hw-settle-time = <0>;
+                                qcom,fast-avg-setup = <0>;
+                        };
+	};
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index b050db2..53fec5b 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -868,6 +868,16 @@
 	  Provides interface for measuring the current on specific power rails
 	  through the channels on ADC1158 ADC
 
+config SENSORS_QPNP_ADC_VOLTAGE
+	tristate "Support for Qualcomm QPNP Voltage ADC"
+	depends on SPMI
+	help
+	  This is the VADC arbiter driver for Qualcomm QPNP ADC Chip.
+
+	  The driver supports reading the HKADC, XOADC through the ADC AMUX arbiter.
+	  The VADC includes support for the conversion sequencer. The driver supports
+	  reading the ADC through the AMUX channels for external pull-ups simultaneously.
+
 config SENSORS_PC87360
 	tristate "National Semiconductor PC87360 family"
 	depends on !PPC
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 228c4e9..2ff9454 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -130,6 +130,7 @@
 obj-$(CONFIG_SENSORS_MSM_ADC)	+= msm_adc.o m_adcproc.o
 obj-$(CONFIG_SENSORS_PM8XXX_ADC)	+= pm8xxx-adc.o pm8xxx-adc-scale.o
 obj-$(CONFIG_SENSORS_EPM_ADC)	+= epm_adc.o
+obj-$(CONFIG_SENSORS_QPNP_ADC_VOLTAGE)	+= qpnp-adc-voltage.o qpnp-adc-common.o
 
 obj-$(CONFIG_PMBUS)		+= pmbus/
 
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
new file mode 100644
index 0000000..c8fe798
--- /dev/null
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -0,0 +1,258 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/hwmon.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/spmi.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
+#include <linux/qpnp/qpnp-adc.h>
+#include <linux/platform_device.h>
+
+/* Min ADC code represets 0V */
+#define QPNP_VADC_MIN_ADC_CODE			0x6000
+/* Max ADC code represents full-scale range of 1.8V */
+#define QPNP_VADC_MAX_ADC_CODE			0xA800
+
+int32_t qpnp_adc_scale_default(int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	bool negative_rawfromoffset = 0, negative_offset = 0;
+	int64_t scale_voltage = 0;
+
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties
+		|| !adc_chan_result)
+		return -EINVAL;
+
+	scale_voltage = (adc_code -
+		chan_properties->adc_graph[CALIB_ABSOLUTE].adc_gnd)
+		* chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
+	if (scale_voltage < 0) {
+		negative_offset = 1;
+		scale_voltage = -scale_voltage;
+	}
+	do_div(scale_voltage,
+		chan_properties->adc_graph[CALIB_ABSOLUTE].dy);
+	if (negative_offset)
+		scale_voltage = -scale_voltage;
+	scale_voltage += chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
+
+	if (scale_voltage < 0) {
+		if (adc_properties->bipolar) {
+			scale_voltage = -scale_voltage;
+			negative_rawfromoffset = 1;
+		} else {
+			scale_voltage = 0;
+		}
+	}
+
+	adc_chan_result->measurement = scale_voltage *
+				chan_properties->offset_gain_denominator;
+
+	/* do_div only perform positive integer division! */
+	do_div(adc_chan_result->measurement,
+				chan_properties->offset_gain_numerator);
+
+	if (negative_rawfromoffset)
+		adc_chan_result->measurement = -adc_chan_result->measurement;
+
+	/*
+	 * Note: adc_chan_result->measurement is in the unit of
+	 * adc_properties.adc_reference. For generic channel processing,
+	 * channel measurement is a scale/ratio relative to the adc
+	 * reference input
+	 */
+	adc_chan_result->physical = adc_chan_result->measurement;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_scale_default);
+
+int32_t qpnp_vadc_check_result(int32_t *data)
+{
+	if (*data < QPNP_VADC_MIN_ADC_CODE)
+		*data = QPNP_VADC_MIN_ADC_CODE;
+	else if (*data > QPNP_VADC_MAX_ADC_CODE)
+		*data = QPNP_VADC_MAX_ADC_CODE;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_vadc_check_result);
+
+int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
+			struct qpnp_adc_drv *adc_qpnp)
+{
+	struct device_node *node = spmi->dev.of_node;
+	struct resource *res;
+	struct device_node *child;
+	struct qpnp_vadc_amux *adc_channel_list;
+	struct qpnp_adc_properties *adc_prop;
+	struct qpnp_vadc_amux_properties *amux_prop;
+	int count_adc_channel_list = 0, decimation, rc = 0;
+
+	if (!node)
+		return -EINVAL;
+
+	for_each_child_of_node(node, child)
+		count_adc_channel_list++;
+
+	if (!count_adc_channel_list) {
+		pr_err("No channel listing\n");
+		return -EINVAL;
+	}
+
+	adc_qpnp->spmi = spmi;
+
+	adc_prop = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_properties),
+					GFP_KERNEL);
+	if (!adc_prop) {
+		dev_err(&spmi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+	adc_channel_list = devm_kzalloc(&spmi->dev,
+		(sizeof(struct qpnp_vadc_amux) * count_adc_channel_list),
+				GFP_KERNEL);
+	if (!adc_channel_list) {
+		dev_err(&spmi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	amux_prop = devm_kzalloc(&spmi->dev,
+		sizeof(struct qpnp_vadc_amux_properties) +
+		sizeof(struct qpnp_vadc_chan_properties), GFP_KERNEL);
+	if (!amux_prop) {
+		dev_err(&spmi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	for_each_child_of_node(node, child) {
+		int channel_num, scaling, post_scaling, hw_settle_time;
+		int fast_avg_setup, calib_type, i = 0, rc;
+		const char *calibration_param, *channel_name;
+
+		channel_name = of_get_property(child,
+				"label", NULL) ? : child->name;
+		if (!channel_name) {
+			pr_err("Invalid channel name\n");
+			return -EINVAL;
+		}
+
+		rc = of_property_read_u32(child, "qcom,channel-num",
+								&channel_num);
+		if (rc) {
+			pr_err("Invalid channel num\n");
+			return -EINVAL;
+		}
+		rc = of_property_read_u32(child, "qcom,decimation",
+								&decimation);
+		if (rc) {
+			pr_err("Invalid channel decimation property\n");
+			return -EINVAL;
+		}
+		rc = of_property_read_u32(child,
+				"qcom,pre-div-channel-scaling", &scaling);
+		if (rc) {
+			pr_err("Invalid channel scaling property\n");
+			return -EINVAL;
+		}
+		rc = of_property_read_u32(child,
+				"qcom,scale-function", &post_scaling);
+		if (rc) {
+			pr_err("Invalid channel post scaling property\n");
+			return -EINVAL;
+		}
+		rc = of_property_read_u32(child,
+				"qcom,hw-settle-time", &hw_settle_time);
+		if (rc) {
+			pr_err("Invalid channel hw settle time property\n");
+			return -EINVAL;
+		}
+		rc = of_property_read_u32(child,
+				"qcom,fast-avg-setup", &fast_avg_setup);
+		if (rc) {
+			pr_err("Invalid channel fast average setup\n");
+			return -EINVAL;
+		}
+		calibration_param = of_get_property(child,
+				"qcom,calibration-type", NULL);
+		if (!strncmp(calibration_param, "absolute", 8))
+			calib_type = CALIB_ABSOLUTE;
+		else if (!strncmp(calibration_param, "historical", 9))
+			calib_type = CALIB_RATIOMETRIC;
+		else {
+			pr_err("%s: Invalid calibration property\n", __func__);
+			return -EINVAL;
+		}
+		/* Individual channel properties */
+		adc_channel_list[i].name = (char *)channel_name;
+		adc_channel_list[i].channel_num = channel_num;
+		adc_channel_list[i].chan_path_prescaling = scaling;
+		adc_channel_list[i].adc_decimation = decimation;
+		adc_channel_list[i].adc_scale_fn = post_scaling;
+		adc_channel_list[i].hw_settle_time = hw_settle_time;
+		adc_channel_list[i].fast_avg_setup = fast_avg_setup;
+		i++;
+	}
+	adc_qpnp->adc_channels = adc_channel_list;
+	adc_qpnp->amux_prop = amux_prop;
+
+	/* Get the ADC VDD reference voltage and ADC bit resolution */
+	rc = of_property_read_u32(node, "qcom,adc-vdd-reference",
+			&adc_prop->adc_vdd_reference);
+	if (rc) {
+		pr_err("Invalid adc vdd reference property\n");
+		return -EINVAL;
+	}
+	rc = of_property_read_u32(node, "qcom,adc-bit-resolution",
+			&adc_prop->bitresolution);
+	if (rc) {
+		pr_err("Invalid adc bit resolution property\n");
+		return -EINVAL;
+	}
+	adc_qpnp->adc_prop = adc_prop;
+
+	/* Get the peripheral address */
+	res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 0);
+	if (!res) {
+		pr_err("No base address definition\n");
+		return -EINVAL;
+	}
+
+	adc_qpnp->slave = spmi->sid;
+	adc_qpnp->offset = res->start;
+
+	/* Register the ADC peripheral interrupt */
+	adc_qpnp->adc_irq = spmi_get_irq(spmi, 0, 0);
+	if (adc_qpnp->adc_irq < 0) {
+		pr_err("Invalid irq\n");
+		return -ENXIO;
+	}
+
+	mutex_init(&adc_qpnp->adc_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_get_devicetree_data);
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
new file mode 100644
index 0000000..8b2cb97
--- /dev/null
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -0,0 +1,784 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/hwmon.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/spmi.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/qpnp/qpnp-adc.h>
+#include <linux/platform_device.h>
+
+/* QPNP VADC register definition */
+#define QPNP_VADC_STATUS1					0x8
+#define QPNP_VADC_STATUS1_OP_MODE				4
+#define QPNP_VADC_STATUS1_MEAS_INTERVAL_EN_STS			BIT(2)
+#define QPNP_VADC_STATUS1_REQ_STS				BIT(1)
+#define QPNP_VADC_STATUS1_EOC					BIT(0)
+#define QPNP_VADC_STATUS2					0x9
+#define QPNP_VADC_STATUS2_CONV_SEQ_STATE				6
+#define QPNP_VADC_STATUS2_FIFO_NOT_EMPTY_FLAG			BIT(1)
+#define QPNP_VADC_STATUS2_CONV_SEQ_TIMEOUT_STS			BIT(0)
+#define QPNP_VADC_STATUS2_CONV_SEQ_STATE_SHIFT			4
+#define QPNP_VADC_CONV_TIMEOUT_ERR				2
+
+#define QPNP_VADC_INT_SET_TYPE					0x11
+#define QPNP_VADC_INT_POLARITY_HIGH				0x12
+#define QPNP_VADC_INT_POLARITY_LOW				0x13
+#define QPNP_VADC_INT_LATCHED_CLR				0x14
+#define QPNP_VADC_INT_EN_SET					0x15
+#define QPNP_VADC_INT_CLR					0x16
+#define QPNP_VADC_INT_LOW_THR_BIT				BIT(4)
+#define QPNP_VADC_INT_HIGH_THR_BIT				BIT(3)
+#define QPNP_VADC_INT_CONV_SEQ_TIMEOUT_BIT			BIT(2)
+#define QPNP_VADC_INT_FIFO_NOT_EMPTY_BIT			BIT(1)
+#define QPNP_VADC_INT_EOC_BIT					BIT(0)
+#define QPNP_VADC_INT_CLR_MASK					0x1f
+#define QPNP_VADC_MODE_CTL					0x40
+#define QPNP_VADC_OP_MODE_SHIFT					4
+#define QPNP_VADC_VREF_XO_THM_FORCE				BIT(2)
+#define QPNP_VADC_AMUX_TRIM_EN					BIT(1)
+#define QPNP_VADC_ADC_TRIM_EN					BIT(0)
+#define QPNP_VADC_EN_CTL1					0x46
+#define QPNP_VADC_ADC_EN					BIT(7)
+#define QPNP_VADC_ADC_CH_SEL_CTL					0x48
+#define QPNP_VADC_ADC_DIG_PARAM					0x50
+#define QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT			3
+#define QPNP_VADC_HW_SETTLE_DELAY				0x51
+#define QPNP_VADC_CONV_REQ					0x52
+#define QPNP_VADC_CONV_REQ_SET					BIT(7)
+#define QPNP_VADC_CONV_SEQ_CTL					0x54
+#define QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT				4
+#define QPNP_VADC_CONV_SEQ_TRIG_CTL				0x55
+#define QPNP_VADC_CONV_SEQ_FALLING_EDGE				0x0
+#define QPNP_VADC_CONV_SEQ_RISING_EDGE				0x1
+#define QPNP_VADC_CONV_SEQ_EDGE_SHIFT				7
+#define QPNP_VADC_FAST_AVG_CTL					0x5a
+
+#define QPNP_VADC_M0_LOW_THR_LSB					0x5c
+#define QPNP_VADC_M0_LOW_THR_MSB					0x5d
+#define QPNP_VADC_M0_HIGH_THR_LSB				0x5e
+#define QPNP_VADC_M0_HIGH_THR_MSB				0x5f
+#define QPNP_VADC_M1_LOW_THR_LSB					0x69
+#define QPNP_VADC_M1_LOW_THR_MSB					0x6a
+#define QPNP_VADC_M1_HIGH_THR_LSB				0x6b
+#define QPNP_VADC_M1_HIGH_THR_MSB				0x6c
+
+#define QPNP_VADC_DATA0						0x60
+#define QPNP_VADC_DATA1						0x61
+#define QPNP_VADC_CONV_TIMEOUT_ERR				2
+#define QPNP_VADC_CONV_TIME_MIN					2000
+#define QPNP_VADC_CONV_TIME_MAX					2100
+
+#define QPNP_ADC_HWMON_NAME_LENGTH				16
+
+struct qpnp_vadc_drv {
+	struct qpnp_adc_drv		*adc;
+	struct dentry			*dent;
+	struct device			*vadc_hwmon;
+	bool				vadc_init_calib;
+	struct sensor_device_attribute		sens_attr[0];
+};
+
+struct qpnp_vadc_drv *qpnp_vadc;
+
+static struct qpnp_vadc_scale_fn vadc_scale_fn[] = {
+	[SCALE_DEFAULT] = {qpnp_adc_scale_default},
+};
+
+static int32_t qpnp_vadc_read_reg(int16_t reg, u8 *data)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+	int rc;
+
+	rc = spmi_ext_register_readl(vadc->adc->spmi->ctrl, vadc->adc->slave,
+		reg, data, 1);
+	if (rc < 0) {
+		pr_err("qpnp adc read reg %d failed with %d\n", reg, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int32_t qpnp_vadc_write_reg(int16_t reg, u8 data)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+	int rc;
+	u8 *buf;
+
+	buf = &data;
+
+	rc = spmi_ext_register_writel(vadc->adc->spmi->ctrl, vadc->adc->slave,
+		reg, buf, 1);
+	if (rc < 0) {
+		pr_err("qpnp adc write reg %d failed with %d\n", reg, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int32_t qpnp_vadc_configure_interrupt(void)
+{
+	int rc = 0;
+	u8 data = 0;
+
+	/* Configure interrupt as an Edge trigger */
+	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_SET_TYPE,
+					QPNP_VADC_INT_CLR_MASK);
+	if (rc < 0) {
+		pr_err("%s Interrupt configure failed\n", __func__);
+		return rc;
+	}
+
+	/* Configure interrupt for rising edge trigger */
+	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_POLARITY_HIGH,
+					QPNP_VADC_INT_CLR_MASK);
+	if (rc < 0) {
+		pr_err("%s Rising edge trigger configure failed\n", __func__);
+		return rc;
+	}
+
+	/* Disable low level interrupt triggering */
+	data = QPNP_VADC_INT_CLR_MASK;
+	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_POLARITY_LOW,
+					(~data & QPNP_VADC_INT_CLR_MASK));
+	if (rc < 0) {
+		pr_err("%s Setting level low to disable failed\n", __func__);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int32_t qpnp_vadc_enable(bool state)
+{
+	int rc = 0;
+	u8 data = 0;
+
+	data = QPNP_VADC_ADC_EN;
+	if (state) {
+		rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
+					data);
+		if (rc < 0) {
+			pr_err("VADC enable failed\n");
+			return rc;
+		}
+	} else {
+		rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
+					(~data & QPNP_VADC_ADC_EN));
+		if (rc < 0) {
+			pr_err("VADC disable failed\n");
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+int32_t qpnp_vadc_configure(
+			struct qpnp_vadc_amux_properties *chan_prop)
+{
+	u8 decimation = 0, conv_sequence = 0, conv_sequence_trig = 0;
+	int rc = 0;
+
+	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_EN_SET,
+				QPNP_VADC_INT_EOC_BIT);
+	if (rc < 0) {
+		pr_err("qpnp adc configure error for interrupt setup\n");
+		return rc;
+	}
+
+	rc = qpnp_vadc_write_reg(QPNP_VADC_MODE_CTL, chan_prop->mode_sel);
+	if (rc < 0) {
+		pr_err("qpnp adc configure error for mode selection\n");
+		return rc;
+	}
+
+	rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_CH_SEL_CTL,
+						chan_prop->amux_channel);
+	if (rc < 0) {
+		pr_err("qpnp adc configure error for channel selection\n");
+		return rc;
+	}
+
+	decimation |= chan_prop->decimation <<
+				QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
+	rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_DIG_PARAM, decimation);
+	if (rc < 0) {
+		pr_err("qpnp adc configure error for digital parameter setup\n");
+		return rc;
+	}
+
+	rc = qpnp_vadc_write_reg(QPNP_VADC_HW_SETTLE_DELAY,
+						chan_prop->hw_settle_time);
+	if (rc < 0) {
+		pr_err("qpnp adc configure error for hw settling time setup\n");
+		return rc;
+	}
+
+	if (chan_prop->mode_sel == (ADC_OP_NORMAL_MODE <<
+					QPNP_VADC_OP_MODE_SHIFT)) {
+		rc = qpnp_vadc_write_reg(QPNP_VADC_FAST_AVG_CTL,
+						chan_prop->fast_avg_setup);
+		if (rc < 0) {
+			pr_err("qpnp adc fast averaging configure error\n");
+			return rc;
+		}
+	} else if (chan_prop->mode_sel == (ADC_OP_CONVERSION_SEQUENCER <<
+					QPNP_VADC_OP_MODE_SHIFT)) {
+		conv_sequence = ((ADC_SEQ_HOLD_100US <<
+				QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT) |
+				ADC_CONV_SEQ_TIMEOUT_5MS);
+		rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_CTL,
+							conv_sequence);
+		if (rc < 0) {
+			pr_err("qpnp adc conversion sequence error\n");
+			return rc;
+		}
+
+		conv_sequence_trig = ((QPNP_VADC_CONV_SEQ_RISING_EDGE <<
+				QPNP_VADC_CONV_SEQ_EDGE_SHIFT) |
+				chan_prop->trigger_channel);
+		rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_TRIG_CTL,
+							conv_sequence_trig);
+		if (rc < 0) {
+			pr_err("qpnp adc conversion trigger error\n");
+			return rc;
+		}
+	}
+
+	rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_REQ, QPNP_VADC_CONV_REQ_SET);
+	if (rc < 0) {
+		pr_err("qpnp adc request conversion failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(qpnp_vadc_configure);
+
+static int32_t qpnp_vadc_read_conversion_result(int32_t *data)
+{
+	uint8_t rslt_lsb, rslt_msb;
+	int rc = 0;
+
+	rc = qpnp_vadc_read_reg(QPNP_VADC_DATA0, &rslt_lsb);
+	if (rc < 0) {
+		pr_err("qpnp adc result read failed for data0 with %d\n", rc);
+		return rc;
+	}
+
+	rc = qpnp_vadc_read_reg(QPNP_VADC_DATA1, &rslt_msb);
+	if (rc < 0) {
+		pr_err("qpnp adc result read failed for data1 with %d\n", rc);
+		return rc;
+	}
+
+	*data = (rslt_msb << 8) | rslt_lsb;
+
+	rc = qpnp_vadc_check_result(data);
+	if (rc < 0) {
+		pr_err("VADC data check failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+static int32_t qpnp_vadc_read_status(int mode_sel)
+{
+	u8 status1, status2, status2_conv_seq_state;
+	u8 status_err = QPNP_VADC_CONV_TIMEOUT_ERR;
+	int rc;
+
+	switch (mode_sel) {
+	case (ADC_OP_CONVERSION_SEQUENCER << QPNP_VADC_OP_MODE_SHIFT):
+		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+		if (rc) {
+			pr_err("qpnp_vadc read mask interrupt failed\n");
+			return rc;
+		}
+
+		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS2, &status2);
+		if (rc) {
+			pr_err("qpnp_vadc read mask interrupt failed\n");
+			return rc;
+		}
+
+		if (!(status2 & ~QPNP_VADC_STATUS2_CONV_SEQ_TIMEOUT_STS) &&
+			(status1 & (~QPNP_VADC_STATUS1_REQ_STS |
+						QPNP_VADC_STATUS1_EOC))) {
+			rc = status_err;
+			return rc;
+		}
+
+		status2_conv_seq_state = status2 >>
+					QPNP_VADC_STATUS2_CONV_SEQ_STATE_SHIFT;
+		if (status2_conv_seq_state != ADC_CONV_SEQ_IDLE) {
+			pr_err("qpnp vadc seq error with status %d\n",
+						status2);
+			rc = -EINVAL;
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static void qpnp_vadc_work(struct work_struct *work)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+	int rc;
+
+	rc = qpnp_vadc_write_reg(QPNP_VADC_INT_CLR, QPNP_VADC_INT_EOC_BIT);
+	if (rc)
+		pr_err("qpnp_vadc clear mask interrupt failed with %d\n", rc);
+
+	complete(&vadc->adc->adc_rslt_completion);
+
+	return;
+}
+DECLARE_WORK(trigger_completion_work, qpnp_vadc_work);
+
+static irqreturn_t qpnp_vadc_isr(int irq, void *dev_id)
+{
+	schedule_work(&trigger_completion_work);
+
+	return IRQ_HANDLED;
+}
+
+static uint32_t qpnp_vadc_calib_device(void)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+	struct qpnp_vadc_amux_properties conv;
+	int rc, calib_read_1, calib_read_2;
+	u8 status1 = 0;
+
+	conv.amux_channel = REF_125V;
+	conv.decimation = DECIMATION_TYPE2;
+	conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
+	conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
+	conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
+
+	rc = qpnp_vadc_configure(&conv);
+	if (rc) {
+		pr_err("qpnp_vadc configure failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
+					QPNP_VADC_STATUS1_EOC)) {
+		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+		if (rc < 0)
+			return rc;
+		usleep_range(QPNP_VADC_CONV_TIME_MIN,
+					QPNP_VADC_CONV_TIME_MAX);
+	}
+
+	rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+	if (rc) {
+		pr_err("qpnp adc read adc failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	conv.amux_channel = REF_625MV;
+	conv.decimation = DECIMATION_TYPE2;
+	conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
+	conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
+	conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
+	rc = qpnp_vadc_configure(&conv);
+	if (rc) {
+		pr_err("qpnp adc configure failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
+					QPNP_VADC_STATUS1_EOC)) {
+		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+		if (rc < 0)
+			return rc;
+		usleep_range(QPNP_VADC_CONV_TIME_MIN,
+					QPNP_VADC_CONV_TIME_MAX);
+	}
+
+	rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+	if (rc) {
+		pr_err("qpnp adc read adc failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
+					(calib_read_1 - calib_read_2);
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx
+						= QPNP_ADC_625_UV;
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_vref =
+					calib_read_1;
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd =
+					calib_read_2;
+	/* Ratiometric Calibration */
+	conv.amux_channel = VDD_VADC;
+	conv.decimation = DECIMATION_TYPE2;
+	conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
+	conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
+	conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
+	rc = qpnp_vadc_configure(&conv);
+	if (rc) {
+		pr_err("qpnp adc configure failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
+					QPNP_VADC_STATUS1_EOC)) {
+		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+		if (rc < 0)
+			return rc;
+		usleep_range(QPNP_VADC_CONV_TIME_MIN,
+					QPNP_VADC_CONV_TIME_MAX);
+	}
+
+	rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+	if (rc) {
+		pr_err("qpnp adc read adc failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	conv.amux_channel = VDD_VADC;
+	conv.decimation = DECIMATION_TYPE2;
+	conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
+	conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
+	conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
+	rc = qpnp_vadc_configure(&conv);
+	if (rc) {
+		pr_err("qpnp adc configure failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	while (status1 != (~QPNP_VADC_STATUS1_REQ_STS |
+					QPNP_VADC_STATUS1_EOC)) {
+		rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
+		if (rc < 0)
+			return rc;
+		usleep_range(QPNP_VADC_CONV_TIME_MIN,
+					QPNP_VADC_CONV_TIME_MAX);
+	}
+
+	rc = qpnp_vadc_read_conversion_result(&calib_read_1);
+	if (rc) {
+		pr_err("qpnp adc read adc failed with %d\n", rc);
+		goto calib_fail;
+	}
+
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy =
+					(calib_read_1 - calib_read_2);
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx =
+					vadc->adc->adc_prop->adc_vdd_reference;
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_vref =
+					calib_read_1;
+	vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd =
+					calib_read_2;
+
+calib_fail:
+	return rc;
+}
+
+int32_t qpnp_vadc_conv_seq_request(enum qpnp_vadc_trigger trigger_channel,
+					enum qpnp_vadc_channels channel,
+					struct qpnp_vadc_result *result)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+	int rc, scale_type, amux_prescaling;
+
+	if (!vadc->vadc_init_calib) {
+		rc = qpnp_vadc_calib_device();
+		if (rc) {
+			pr_err("Calibration failed\n");
+			return rc;
+		} else
+			vadc->vadc_init_calib = true;
+	}
+
+	mutex_lock(&vadc->adc->adc_lock);
+
+	rc = qpnp_vadc_enable(true);
+	if (rc)
+		goto fail_unlock;
+
+	vadc->adc->amux_prop->amux_channel = channel;
+	vadc->adc->amux_prop->decimation =
+			vadc->adc->adc_channels[channel].adc_decimation;
+	vadc->adc->amux_prop->hw_settle_time =
+			vadc->adc->adc_channels[channel].hw_settle_time;
+	vadc->adc->amux_prop->fast_avg_setup =
+			vadc->adc->adc_channels[channel].fast_avg_setup;
+
+	if (trigger_channel < ADC_SEQ_NONE)
+		vadc->adc->amux_prop->mode_sel = (ADC_OP_CONVERSION_SEQUENCER
+						<< QPNP_VADC_OP_MODE_SHIFT);
+	else if (trigger_channel == ADC_SEQ_NONE)
+		vadc->adc->amux_prop->mode_sel = (ADC_OP_NORMAL_MODE
+						<< QPNP_VADC_OP_MODE_SHIFT);
+	else {
+		pr_err("Invalid trigger channel:%d\n", trigger_channel);
+		goto fail;
+	}
+
+	vadc->adc->amux_prop->trigger_channel = trigger_channel;
+
+	rc = qpnp_vadc_configure(vadc->adc->amux_prop);
+	if (rc) {
+		pr_info("qpnp vadc configure failed with %d\n", rc);
+		goto fail;
+	}
+
+	wait_for_completion(&vadc->adc->adc_rslt_completion);
+
+	if (trigger_channel < ADC_SEQ_NONE) {
+		rc = qpnp_vadc_read_status(vadc->adc->amux_prop->mode_sel);
+		if (rc)
+			pr_info("Conversion sequence timed out - %d\n", rc);
+	}
+
+	rc = qpnp_vadc_read_conversion_result(&result->adc_code);
+	if (rc) {
+		pr_info("qpnp vadc read adc code failed with %d\n", rc);
+		goto fail;
+	}
+
+	amux_prescaling = vadc->adc->adc_channels[channel].chan_path_prescaling;
+
+	vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
+		qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
+	vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
+		 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
+
+	scale_type = vadc->adc->adc_channels[channel].adc_scale_fn;
+	if (scale_type >= SCALE_NONE) {
+		rc = -EBADF;
+		goto fail;
+	}
+
+	vadc_scale_fn[scale_type].chan(result->adc_code,
+		vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
+
+fail:
+	rc = qpnp_vadc_enable(false);
+	if (rc)
+		pr_err("Disable ADC failed during configuration\n");
+
+fail_unlock:
+	mutex_unlock(&vadc->adc->adc_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(qpnp_vadc_conv_seq_request);
+
+int32_t qpnp_vadc_read(enum qpnp_vadc_channels channel,
+				struct qpnp_vadc_result *result)
+{
+	return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
+				channel, result);
+}
+EXPORT_SYMBOL_GPL(qpnp_vadc_read);
+
+static ssize_t qpnp_adc_show(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct qpnp_vadc_result result;
+	int rc = -1;
+
+	rc = qpnp_vadc_read(attr->index, &result);
+
+	if (rc)
+		return 0;
+
+	return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
+		"Result:%lld Raw:%d\n", result.physical, result.adc_code);
+}
+
+static struct sensor_device_attribute qpnp_adc_attr =
+	SENSOR_ATTR(NULL, S_IRUGO, qpnp_adc_show, NULL, 0);
+
+static int32_t qpnp_vadc_init_hwmon(struct spmi_device *spmi)
+{
+	struct qpnp_vadc_drv *vadc = qpnp_vadc;
+	struct device_node *child;
+	struct device_node *node = spmi->dev.of_node;
+	int rc = 0, i = 0, channel;
+
+	for_each_child_of_node(node, child) {
+		channel = vadc->adc->adc_channels[i].channel_num;
+		qpnp_adc_attr.index = vadc->adc->adc_channels[i].channel_num;
+		qpnp_adc_attr.dev_attr.attr.name =
+						vadc->adc->adc_channels[i].name;
+		sysfs_attr_init(&vadc->sens_attr[i].dev_attr.attr);
+		memcpy(&vadc->sens_attr[i], &qpnp_adc_attr,
+						sizeof(qpnp_adc_attr));
+		rc = device_create_file(&spmi->dev,
+				&vadc->sens_attr[i].dev_attr);
+		if (rc) {
+			dev_err(&spmi->dev,
+				"device_create_file failed for dev %s\n",
+				vadc->adc->adc_channels[i].name);
+			goto hwmon_err_sens;
+		}
+		i++;
+	}
+
+	return 0;
+hwmon_err_sens:
+	pr_info("Init HWMON failed for qpnp_adc with %d\n", rc);
+	return rc;
+}
+
+static int __devinit qpnp_vadc_probe(struct spmi_device *spmi)
+{
+	struct qpnp_vadc_drv *vadc;
+	struct qpnp_adc_drv *adc_qpnp;
+	struct device_node *node = spmi->dev.of_node;
+	struct device_node *child;
+	int rc, count_adc_channel_list = 0;
+
+	if (!node)
+		return -EINVAL;
+
+	if (qpnp_vadc) {
+		pr_err("VADC already in use\n");
+		return -EBUSY;
+	}
+
+	for_each_child_of_node(node, child)
+		count_adc_channel_list++;
+
+	if (!count_adc_channel_list) {
+		pr_err("No channel listing\n");
+		return -EINVAL;
+	}
+
+	vadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_vadc_drv) +
+		(sizeof(struct sensor_device_attribute) *
+				count_adc_channel_list), GFP_KERNEL);
+	if (!vadc) {
+		dev_err(&spmi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
+			GFP_KERNEL);
+	if (!adc_qpnp) {
+		dev_err(&spmi->dev, "Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	vadc->adc = adc_qpnp;
+
+	rc = qpnp_adc_get_devicetree_data(spmi, vadc->adc);
+	if (rc) {
+		dev_err(&spmi->dev, "failed to read device tree\n");
+		return rc;
+	}
+
+	rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq,
+				qpnp_vadc_isr, IRQF_TRIGGER_RISING,
+				"qpnp_vadc_interrupt", vadc);
+	if (rc) {
+		dev_err(&spmi->dev,
+			"failed to request adc irq with error %d\n", rc);
+		return rc;
+	}
+
+	qpnp_vadc = vadc;
+	dev_set_drvdata(&spmi->dev, vadc);
+	rc = qpnp_vadc_init_hwmon(spmi);
+	if (rc) {
+		dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
+		goto fail_free_irq;
+	}
+	vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
+	vadc->vadc_init_calib = false;
+
+	rc = qpnp_vadc_configure_interrupt();
+	if (rc) {
+		dev_err(&spmi->dev, "failed to configure interrupt");
+		goto fail_free_irq;
+	}
+
+	return 0;
+
+fail_free_irq:
+	free_irq(vadc->adc->adc_irq, vadc);
+
+	return rc;
+}
+
+static int __devexit qpnp_vadc_remove(struct spmi_device *spmi)
+{
+	struct qpnp_vadc_drv *vadc = dev_get_drvdata(&spmi->dev);
+	struct device_node *node = spmi->dev.of_node;
+	struct device_node *child;
+	int i = 0;
+
+	for_each_child_of_node(node, child) {
+		device_remove_file(&spmi->dev,
+			&vadc->sens_attr[i].dev_attr);
+		i++;
+	}
+	free_irq(vadc->adc->adc_irq, vadc);
+	dev_set_drvdata(&spmi->dev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id qpnp_vadc_match_table[] = {
+	{	.compatible = "qcom,qpnp-vadc",
+	},
+	{}
+};
+
+static struct spmi_driver qpnp_vadc_driver = {
+	.driver		= {
+		.name	= "qcom,qpnp-vadc",
+		.of_match_table = qpnp_vadc_match_table,
+	},
+	.probe		= qpnp_vadc_probe,
+	.remove		= qpnp_vadc_remove,
+};
+
+static int __init qpnp_vadc_init(void)
+{
+	return spmi_driver_register(&qpnp_vadc_driver);
+}
+module_init(qpnp_vadc_init);
+
+static void __exit qpnp_vadc_exit(void)
+{
+	spmi_driver_unregister(&qpnp_vadc_driver);
+}
+module_exit(qpnp_vadc_exit);
+
+MODULE_DESCRIPTION("QPNP PMIC Voltage ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
new file mode 100644
index 0000000..33559dd
--- /dev/null
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -0,0 +1,689 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+/*
+ * Qualcomm PMIC QPNP ADC driver header file
+ *
+ */
+
+#ifndef __QPNP_ADC_H
+#define __QPNP_ADC_H
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+/**
+ * enum qpnp_vadc_channels - QPNP AMUX arbiter channels
+ */
+enum qpnp_vadc_channels {
+	USBIN = 0,
+	DCIN,
+	VCHG_SNS,
+	SPARE1_03,
+	SPARE2_03,
+	VCOIN,
+	VBAT_SNS,
+	VSYS,
+	DIE_TEMP,
+	REF_625MV,
+	REF_125V,
+	CHG_TEMP,
+	SPARE1,
+	SPARE2,
+	GND_REF,
+	VDD_VADC,
+	P_MUX1_1_1,
+	P_MUX2_1_1,
+	P_MUX3_1_1,
+	P_MUX4_1_1,
+	P_MUX5_1_1,
+	P_MUX6_1_1,
+	P_MUX7_1_1,
+	P_MUX8_1_1,
+	P_MUX9_1_1,
+	P_MUX10_1_1,
+	P_MUX11_1_1,
+	P_MUX12_1_1,
+	P_MUX13_1_1,
+	P_MUX14_1_1,
+	P_MUX15_1_1,
+	P_MUX16_1_1,
+	P_MUX1_1_3,
+	P_MUX2_1_3,
+	P_MUX3_1_3,
+	P_MUX4_1_3,
+	P_MUX5_1_3,
+	P_MUX6_1_3,
+	P_MUX7_1_3,
+	P_MUX8_1_3,
+	P_MUX9_1_3,
+	P_MUX10_1_3,
+	P_MUX11_1_3,
+	P_MUX12_1_3,
+	P_MUX13_1_3,
+	P_MUX14_1_3,
+	P_MUX15_1_3,
+	P_MUX16_1_3,
+	LR_MUX1_BATT_THERM,
+	LR_MUX2_BAT_ID,
+	LR_MUX3_XO_THERM,
+	LR_MUX4_AMUX_THM1,
+	LR_MUX5_AMUX_THM2,
+	LR_MUX6_AMUX_THM3,
+	LR_MUX7_HW_ID,
+	LR_MUX8_AMUX_THM4,
+	LR_MUX9_AMUX_THM5,
+	LR_MUX10_USB_ID,
+	AMUX_PU1,
+	AMUX_PU2,
+	LR_MUX3_BUF_XO_THERM_BUF,
+	LR_MUX1_PU1_BAT_THERM,
+	LR_MUX2_PU1_BAT_ID,
+	LR_MUX3_PU1_XO_THERM,
+	LR_MUX4_PU1_AMUX_THM1,
+	LR_MUX5_PU1_AMUX_THM2,
+	LR_MUX6_PU1_AMUX_THM3,
+	LR_MUX7_PU1_AMUX_HW_ID,
+	LR_MUX8_PU1_AMUX_THM4,
+	LR_MUX9_PU1_AMUX_THM5,
+	LR_MUX10_PU1_AMUX_USB_ID,
+	LR_MUX3_BUF_PU1_XO_THERM_BUF,
+	LR_MUX1_PU2_BAT_THERM,
+	LR_MUX2_PU2_BAT_ID,
+	LR_MUX3_PU2_XO_THERM,
+	LR_MUX4_PU2_AMUX_THM1,
+	LR_MUX5_PU2_AMUX_THM2,
+	LR_MUX6_PU2_AMUX_THM3,
+	LR_MUX7_PU2_AMUX_HW_ID,
+	LR_MUX8_PU2_AMUX_THM4,
+	LR_MUX9_PU2_AMUX_THM5,
+	LR_MUX10_PU2_AMUX_USB_ID,
+	LR_MUX3_BUF_PU2_XO_THERM_BUF,
+	LR_MUX1_PU1_PU2_BAT_THERM,
+	LR_MUX2_PU1_PU2_BAT_ID,
+	LR_MUX3_PU1_PU2_XO_THERM,
+	LR_MUX4_PU1_PU2_AMUX_THM1,
+	LR_MUX5_PU1_PU2_AMUX_THM2,
+	LR_MUX6_PU1_PU2_AMUX_THM3,
+	LR_MUX7_PU1_PU2_AMUX_HW_ID,
+	LR_MUX8_PU1_PU2_AMUX_THM4,
+	LR_MUX9_PU1_PU2_AMUX_THM5,
+	LR_MUX10_PU1_PU2_AMUX_USB_ID,
+	LR_MUX3_BUF_PU1_PU2_XO_THERM_BUF,
+	ALL_OFF,
+	ADC_MAX_NUM,
+};
+
+#define QPNP_ADC_625_UV	625000
+
+/**
+ * enum qpnp_adc_decimation_type - Sampling rate supported.
+ * %DECIMATION_TYPE1: 512
+ * %DECIMATION_TYPE2: 1K
+ * %DECIMATION_TYPE3: 2K
+ * %DECIMATION_TYPE4: 4k
+ * %DECIMATION_NONE: Do not use this Sampling type.
+ *
+ * The Sampling rate is specific to each channel of the QPNP ADC arbiter.
+ */
+enum qpnp_adc_decimation_type {
+	DECIMATION_TYPE1 = 0,
+	DECIMATION_TYPE2,
+	DECIMATION_TYPE3,
+	DECIMATION_TYPE4,
+	DECIMATION_NONE,
+};
+
+/**
+ * enum qpnp_adc_calib_type - QPNP ADC Calibration type.
+ * %ADC_CALIB_ABSOLUTE: Use 625mV and 1.25V reference channels.
+ * %ADC_CALIB_RATIOMETRIC: Use reference Voltage/GND.
+ * %ADC_CALIB_CONFIG_NONE: Do not use this calibration type.
+ *
+ * Use the input reference voltage depending on the calibration type
+ * to calcluate the offset and gain parameters. The calibration is
+ * specific to each channel of the QPNP ADC.
+ */
+enum qpnp_adc_calib_type {
+	CALIB_ABSOLUTE = 0,
+	CALIB_RATIOMETRIC,
+	CALIB_NONE,
+};
+
+/**
+ * enum qpnp_adc_channel_scaling_param - pre-scaling AMUX ratio.
+ * %CHAN_PATH_SCALING1: ratio of {1, 1}
+ * %CHAN_PATH_SCALING2: ratio of {1, 3}
+ * %CHAN_PATH_SCALING3: ratio of {1, 4}
+ * %CHAN_PATH_SCALING4: ratio of {1, 6}
+ * %CHAN_PATH_NONE: Do not use this pre-scaling ratio type.
+ *
+ * The pre-scaling is applied for signals to be within the voltage range
+ * of the ADC.
+ */
+enum qpnp_adc_channel_scaling_param {
+	PATH_SCALING1 = 0,
+	PATH_SCALING2,
+	PATH_SCALING3,
+	PATH_SCALING4,
+	PATH_SCALING_NONE,
+};
+
+/**
+ * enum qpnp_adc_scale_fn_type - Scaling function for pm8921 pre calibrated
+ *				   digital data relative to ADC reference.
+ * %ADC_SCALE_DEFAULT: Default scaling to convert raw adc code to voltage.
+ * %ADC_SCALE_BATT_THERM: Conversion to temperature based on btm parameters.
+ * %ADC_SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
+ * %ADC_SCALE_XTERN_CHGR_CUR: Returns current across 0.1 ohm resistor.
+ * %ADC_SCALE_XOTHERM: Returns XO thermistor voltage in degree's Centigrade.
+ * %ADC_SCALE_NONE: Do not use this scaling type.
+ */
+enum qpnp_adc_scale_fn_type {
+	SCALE_DEFAULT = 0,
+	SCALE_BATT_THERM,
+	SCALE_PA_THERM,
+	SCALE_PMIC_THERM,
+	SCALE_XOTHERM,
+	SCALE_NONE,
+};
+
+/**
+ * enum qpnp_adc_fast_avg_ctl - Provides ability to obtain single result
+ *		from the ADC that is an average of multiple measurement
+ *		samples. Select number of samples for use in fast
+ *		average mode (i.e. 2 ^ value).
+ * %ADC_FAST_AVG_SAMPLE_1:   0x0 = 1
+ * %ADC_FAST_AVG_SAMPLE_2:   0x1 = 2
+ * %ADC_FAST_AVG_SAMPLE_4:   0x2 = 4
+ * %ADC_FAST_AVG_SAMPLE_8:   0x3 = 8
+ * %ADC_FAST_AVG_SAMPLE_16:  0x4 = 16
+ * %ADC_FAST_AVG_SAMPLE_32:  0x5 = 32
+ * %ADC_FAST_AVG_SAMPLE_64:  0x6 = 64
+ * %ADC_FAST_AVG_SAMPLE_128: 0x7 = 128
+ * %ADC_FAST_AVG_SAMPLE_256: 0x8 = 256
+ * %ADC_FAST_AVG_SAMPLE_512: 0x9 = 512
+ */
+enum qpnp_adc_fast_avg_ctl {
+	ADC_FAST_AVG_SAMPLE_1 = 0,
+	ADC_FAST_AVG_SAMPLE_2,
+	ADC_FAST_AVG_SAMPLE_4,
+	ADC_FAST_AVG_SAMPLE_8,
+	ADC_FAST_AVG_SAMPLE_16,
+	ADC_FAST_AVG_SAMPLE_32,
+	ADC_FAST_AVG_SAMPLE_64,
+	ADC_FAST_AVG_SAMPLE_128,
+	ADC_FAST_AVG_SAMPLE_256,
+	ADC_FAST_AVG_SAMPLE_512,
+	ADC_FAST_AVG_SAMPLE_NONE,
+};
+
+/**
+ * enum qpnp_adc_hw_settle_time - Time between AMUX getting configured and
+ *		the ADC starting conversion. Delay = 100us * value for
+ *		value < 11 and 2ms * (value - 10) otherwise.
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_0US:   0us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_100US: 100us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_200US: 200us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_300US: 300us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_400US: 400us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_500US: 500us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_600US: 600us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_700US: 700us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_800US: 800us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_900US: 900us
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_1MS:   1ms
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_2MS:   2ms
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_4MS:   4ms
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_6MS:   6ms
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_8MS:   8ms
+ * %ADC_CHANNEL_HW_SETTLE_DELAY_10MS:  10ms
+ * %ADC_CHANNEL_HW_SETTLE_NONE
+ */
+enum qpnp_adc_hw_settle_time {
+	ADC_CHANNEL_HW_SETTLE_DELAY_0US = 0,
+	ADC_CHANNEL_HW_SETTLE_DELAY_100US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_2000US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_300US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_400US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_500US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_600US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_700US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_800US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_900US,
+	ADC_CHANNEL_HW_SETTLE_DELAY_1MS,
+	ADC_CHANNEL_HW_SETTLE_DELAY_2MS,
+	ADC_CHANNEL_HW_SETTLE_DELAY_4MS,
+	ADC_CHANNEL_HW_SETTLE_DELAY_6MS,
+	ADC_CHANNEL_HW_SETTLE_DELAY_8MS,
+	ADC_CHANNEL_HW_SETTLE_DELAY_10MS,
+	ADC_CHANNEL_HW_SETTLE_NONE,
+};
+
+/**
+ * enum qpnp_vadc_mode_sel - Selects the basic mode of operation.
+ *		- The normal mode is used for single measurement.
+ *		- The Conversion sequencer is used to trigger an
+ *		  ADC read when a HW trigger is selected.
+ *		- The measurement interval performs a single or
+ *		  continous measurement at a specified interval/delay.
+ * %ADC_OP_NORMAL_MODE : Normal mode used for single measurement.
+ * %ADC_OP_CONVERSION_SEQUENCER : Conversion sequencer used to trigger
+ *		  an ADC read on a HW supported trigger.
+ *		  Refer to enum qpnp_vadc_trigger for
+ *		  supported HW triggers.
+ * %ADC_OP_MEASUREMENT_INTERVAL : The measurement interval performs a
+ *		  single or continous measurement after a specified delay.
+ *		  For delay look at qpnp_adc_meas_timer.
+ */
+enum qpnp_vadc_mode_sel {
+	ADC_OP_NORMAL_MODE = 0,
+	ADC_OP_CONVERSION_SEQUENCER,
+	ADC_OP_MEASUREMENT_INTERVAL,
+	ADC_OP_MODE_NONE,
+};
+
+/**
+ * enum qpnp_vadc_trigger - Select the HW trigger to be used while
+ *		measuring the ADC reading.
+ * %ADC_GSM_PA_ON : GSM power amplifier on.
+ * %ADC_TX_GTR_THRES : Transmit power greater than threshold.
+ * %ADC_CAMERA_FLASH_RAMP : Flash ramp up done.
+ * %ADC_DTEST : DTEST.
+ */
+enum qpnp_vadc_trigger {
+	ADC_GSM_PA_ON = 0,
+	ADC_TX_GTR_THRES,
+	ADC_CAMERA_FLASH_RAMP,
+	ADC_DTEST,
+	ADC_SEQ_NONE,
+};
+
+/**
+ * enum qpnp_vadc_conv_seq_timeout - Select delay (0 to 15ms) from
+ *		conversion request to triggering conversion sequencer
+ *		hold off time.
+ */
+enum qpnp_vadc_conv_seq_timeout {
+	ADC_CONV_SEQ_TIMEOUT_0MS = 0,
+	ADC_CONV_SEQ_TIMEOUT_1MS,
+	ADC_CONV_SEQ_TIMEOUT_2MS,
+	ADC_CONV_SEQ_TIMEOUT_3MS,
+	ADC_CONV_SEQ_TIMEOUT_4MS,
+	ADC_CONV_SEQ_TIMEOUT_5MS,
+	ADC_CONV_SEQ_TIMEOUT_6MS,
+	ADC_CONV_SEQ_TIMEOUT_7MS,
+	ADC_CONV_SEQ_TIMEOUT_8MS,
+	ADC_CONV_SEQ_TIMEOUT_9MS,
+	ADC_CONV_SEQ_TIMEOUT_10MS,
+	ADC_CONV_SEQ_TIMEOUT_11MS,
+	ADC_CONV_SEQ_TIMEOUT_12MS,
+	ADC_CONV_SEQ_TIMEOUT_13MS,
+	ADC_CONV_SEQ_TIMEOUT_14MS,
+	ADC_CONV_SEQ_TIMEOUT_15MS,
+	ADC_CONV_SEQ_TIMEOUT_NONE,
+};
+
+/**
+ * enum qpnp_adc_conv_seq_holdoff - Select delay from conversion
+ *		trigger signal (i.e. adc_conv_seq_trig) transition
+ *		to ADC enable. Delay = 25us * (value + 1).
+ */
+enum qpnp_adc_conv_seq_holdoff {
+	ADC_SEQ_HOLD_25US = 0,
+	ADC_SEQ_HOLD_50US,
+	ADC_SEQ_HOLD_75US,
+	ADC_SEQ_HOLD_100US,
+	ADC_SEQ_HOLD_125US,
+	ADC_SEQ_HOLD_150US,
+	ADC_SEQ_HOLD_175US,
+	ADC_SEQ_HOLD_200US,
+	ADC_SEQ_HOLD_225US,
+	ADC_SEQ_HOLD_250US,
+	ADC_SEQ_HOLD_275US,
+	ADC_SEQ_HOLD_300US,
+	ADC_SEQ_HOLD_325US,
+	ADC_SEQ_HOLD_350US,
+	ADC_SEQ_HOLD_375US,
+	ADC_SEQ_HOLD_400US,
+	ADC_SEQ_HOLD_NONE,
+};
+
+/**
+ * enum qpnp_adc_conv_seq_state - Conversion sequencer operating state
+ * %ADC_CONV_SEQ_IDLE : Sequencer is in idle.
+ * %ADC_CONV_TRIG_RISE : Waiting for rising edge trigger.
+ * %ADC_CONV_TRIG_HOLDOFF : Waiting for rising trigger hold off time.
+ * %ADC_CONV_MEAS_RISE : Measuring selected ADC signal.
+ * %ADC_CONV_TRIG_FALL : Waiting for falling trigger edge.
+ * %ADC_CONV_FALL_HOLDOFF : Waiting for falling trigger hold off time.
+ * %ADC_CONV_MEAS_FALL : Measuring selected ADC signal.
+ * %ADC_CONV_ERROR : Aberrant Hardware problem.
+ */
+enum qpnp_adc_conv_seq_state {
+	ADC_CONV_SEQ_IDLE = 0,
+	ADC_CONV_TRIG_RISE,
+	ADC_CONV_TRIG_HOLDOFF,
+	ADC_CONV_MEAS_RISE,
+	ADC_CONV_TRIG_FALL,
+	ADC_CONV_FALL_HOLDOFF,
+	ADC_CONV_MEAS_FALL,
+	ADC_CONV_ERROR,
+	ADC_CONV_NONE,
+};
+
+/**
+ * enum qpnp_adc_meas_timer - Selects the measurement interval time.
+ *		If value = 0, use 0ms else use 2^(value + 4)/ 32768).
+ * %ADC_MEAS_INTERVAL_0MS : 0ms
+ * %ADC_MEAS_INTERVAL_1P0MS : 1ms
+ * %ADC_MEAS_INTERVAL_2P0MS : 2ms
+ * %ADC_MEAS_INTERVAL_3P9MS : 3.9ms
+ * %ADC_MEAS_INTERVAL_7P8MS : 7.8ms
+ * %ADC_MEAS_INTERVAL_15P6MS : 15.6ms
+ * %ADC_MEAS_INTERVAL_31P3MS : 31.3ms
+ * %ADC_MEAS_INTERVAL_62P5MS : 62.5ms
+ * %ADC_MEAS_INTERVAL_125MS : 125ms
+ * %ADC_MEAS_INTERVAL_250MS : 250ms
+ * %ADC_MEAS_INTERVAL_500MS : 500ms
+ * %ADC_MEAS_INTERVAL_1S : 1seconds
+ * %ADC_MEAS_INTERVAL_2S : 2seconds
+ * %ADC_MEAS_INTERVAL_4S : 4seconds
+ * %ADC_MEAS_INTERVAL_8S : 8seconds
+ * %ADC_MEAS_INTERVAL_16S: 16seconds
+ */
+enum qpnp_adc_meas_timer {
+	ADC_MEAS_INTERVAL_0MS = 0,
+	ADC_MEAS_INTERVAL_1P0MS,
+	ADC_MEAS_INTERVAL_2P0MS,
+	ADC_MEAS_INTERVAL_3P9MS,
+	ADC_MEAS_INTERVAL_7P8MS,
+	ADC_MEAS_INTERVAL_15P6MS,
+	ADC_MEAS_INTERVAL_31P3MS,
+	ADC_MEAS_INTERVAL_62P5MS,
+	ADC_MEAS_INTERVAL_125MS,
+	ADC_MEAS_INTERVAL_250MS,
+	ADC_MEAS_INTERVAL_500MS,
+	ADC_MEAS_INTERVAL_1S,
+	ADC_MEAS_INTERVAL_2S,
+	ADC_MEAS_INTERVAL_4S,
+	ADC_MEAS_INTERVAL_8S,
+	ADC_MEAS_INTERVAL_16S,
+	ADC_MEAS_INTERVAL_NONE,
+};
+
+/**
+ * enum qpnp_adc_meas_interval_op_ctl - Select operating mode.
+ * %ADC_MEAS_INTERVAL_OP_SINGLE : Conduct single measurement at specified time
+ *			delay.
+ * %ADC_MEAS_INTERVAL_OP_CONTINUOUS : Make measurements at measurement interval
+ *			times.
+ */
+enum qpnp_adc_meas_interval_op_ctl {
+	ADC_MEAS_INTERVAL_OP_SINGLE = 0,
+	ADC_MEAS_INTERVAL_OP_CONTINUOUS,
+	ADC_MEAS_INTERVAL_OP_NONE,
+};
+
+/**
+ * struct qpnp_vadc_linear_graph - Represent ADC characteristics.
+ * @dy: Numerator slope to calculate the gain.
+ * @dx: Denominator slope to calculate the gain.
+ * @adc_vref: A/D word of the voltage reference used for the channel.
+ * @adc_gnd: A/D word of the ground reference used for the channel.
+ *
+ * Each ADC device has different offset and gain parameters which are computed
+ * to calibrate the device.
+ */
+struct qpnp_vadc_linear_graph {
+	int64_t dy;
+	int64_t dx;
+	int64_t adc_vref;
+	int64_t adc_gnd;
+};
+
+/**
+ * struct qpnp_vadc_map_pt - Map the graph representation for ADC channel
+ * @x: Represent the ADC digitized code.
+ * @y: Represent the physical data which can be temperature, voltage,
+ *     resistance.
+ */
+struct qpnp_vadc_map_pt {
+	int32_t x;
+	int32_t y;
+};
+
+/**
+ * struct qpnp_vadc_scaling_ratio - Represent scaling ratio for adc input.
+ * @num: Numerator scaling parameter.
+ * @den: Denominator scaling parameter.
+ */
+struct qpnp_vadc_scaling_ratio {
+	int32_t num;
+	int32_t den;
+};
+
+/**
+ * struct qpnp_adc_properties - Represent the ADC properties.
+ * @adc_reference: Reference voltage for QPNP ADC.
+ * @bitresolution: ADC bit resolution for QPNP ADC.
+ * @biploar: Polarity for QPNP ADC.
+ */
+struct qpnp_adc_properties {
+	uint32_t	adc_vdd_reference;
+	uint32_t	bitresolution;
+	bool		bipolar;
+};
+
+/**
+ * struct qpnp_vadc_chan_properties - Represent channel properties of the ADC.
+ * @offset_gain_numerator: The inverse numerator of the gain applied to the
+ *			   input channel.
+ * @offset_gain_denominator: The inverse denominator of the gain applied to the
+ *			     input channel.
+ * @adc_graph: ADC graph for the channel of struct type qpnp_adc_linear_graph.
+ */
+struct qpnp_vadc_chan_properties {
+	uint32_t			offset_gain_numerator;
+	uint32_t			offset_gain_denominator;
+	struct qpnp_vadc_linear_graph	adc_graph[2];
+};
+
+/**
+ * struct qpnp_adc_result - Represent the result of the QPNP ADC.
+ * @chan: The channel number of the requested conversion.
+ * @adc_code: The pre-calibrated digital output of a given ADC relative to the
+ *	      the ADC reference.
+ * @measurement: In units specific for a given ADC; most ADC uses reference
+ *		 voltage but some ADC uses reference current. This measurement
+ *		 here is a number relative to a reference of a given ADC.
+ * @physical: The data meaningful for each individual channel whether it is
+ *	      voltage, current, temperature, etc.
+ *	      All voltage units are represented in micro - volts.
+ *	      -Battery temperature units are represented as 0.1 DegC.
+ *	      -PA Therm temperature units are represented as DegC.
+ *	      -PMIC Die temperature units are represented as 0.001 DegC.
+ */
+struct qpnp_vadc_result {
+	uint32_t	chan;
+	int32_t		adc_code;
+	int64_t		measurement;
+	int64_t		physical;
+};
+
+/**
+ * struct qpnp_adc_amux - AMUX properties for individual channel
+ * @name: Channel string name.
+ * @channel_num: Channel in integer used from qpnp_adc_channels.
+ * @chan_path_prescaling: Channel scaling performed on the input signal.
+ * @adc_decimation: Sampling rate desired for the channel.
+ * adc_scale_fn: Scaling function to convert to the data meaningful for
+ *		 each individual channel whether it is voltage, current,
+ *		 temperature, etc and compensates the channel properties.
+ */
+struct qpnp_vadc_amux {
+	char					*name;
+	enum qpnp_vadc_channels			channel_num;
+	enum qpnp_adc_channel_scaling_param	chan_path_prescaling;
+	enum qpnp_adc_decimation_type		adc_decimation;
+	enum qpnp_adc_scale_fn_type		adc_scale_fn;
+	enum qpnp_adc_fast_avg_ctl		fast_avg_setup;
+	enum qpnp_adc_hw_settle_time		hw_settle_time;
+};
+
+/**
+ * struct qpnp_vadc_scaling_ratio
+ *
+ */
+static const struct qpnp_vadc_scaling_ratio qpnp_vadc_amux_scaling_ratio[] = {
+	{1, 1},
+	{1, 3},
+	{1, 4},
+	{1, 6},
+	{1, 20}
+};
+
+/**
+ * struct qpnp_vadc_scale_fn - Scaling function prototype
+ * @chan: Function pointer to one of the scaling functions
+ *	which takes the adc properties, channel properties,
+ *	and returns the physical result
+ */
+struct qpnp_vadc_scale_fn {
+	int32_t (*chan) (int32_t,
+		const struct qpnp_adc_properties *,
+		const struct qpnp_vadc_chan_properties *,
+		struct qpnp_vadc_result *);
+};
+
+/**
+ * struct qpnp_adc_drv - QPNP ADC device structure.
+ * @spmi - spmi device for ADC peripheral.
+ * @offset - base offset for the ADC peripheral.
+ * @adc_prop - ADC properties specific to the ADC peripheral.
+ * @amux_prop - AMUX properties representing the ADC peripheral.
+ * @adc_channels - ADC channel properties for the ADC peripheral.
+ * @adc_irq - IRQ number that is mapped to the ADC peripheral.
+ * @adc_lock - ADC lock for access to the peripheral.
+ * @adc_rslt_completion - ADC result notification after interrupt
+ *			  is received.
+ */
+struct qpnp_adc_drv {
+	struct spmi_device		*spmi;
+	uint8_t				slave;
+	uint16_t			offset;
+	struct qpnp_adc_properties	*adc_prop;
+	struct qpnp_vadc_amux_properties	*amux_prop;
+	struct qpnp_vadc_amux		*adc_channels;
+	int				adc_irq;
+	struct mutex			adc_lock;
+	struct completion		adc_rslt_completion;
+};
+
+/**
+ * struct qpnp_vadc_amux_properties - QPNP VADC amux channel property.
+ * @amux_channel - Refer to the qpnp_vadc_channel list.
+ * @decimation - Sampling rate supported for the channel.
+ * @mode_sel - The basic mode of operation.
+ * @hw_settle_time - The time between AMUX being configured and the
+ *			start of conversion.
+ * @fast_avg_setup - Ability to provide single result from the ADC
+ *			that is an average of multiple measurements.
+ * @trigger_channel - HW trigger channel for conversion sequencer.
+ * @chan_prop - Represent the channel properties of the ADC.
+ */
+struct qpnp_vadc_amux_properties {
+	uint32_t			amux_channel;
+	uint32_t			decimation;
+	uint32_t			mode_sel;
+	uint32_t			hw_settle_time;
+	uint32_t			fast_avg_setup;
+	enum qpnp_vadc_trigger		trigger_channel;
+	struct qpnp_vadc_chan_properties	chan_prop[0];
+};
+
+/* Public API */
+#if defined(CONFIG_SENSORS_QPNP_ADC_VOLTAGE)				\
+			|| defined(CONFIG_SENSORS_QPNP_ADC_VOLTAGE_MODULE)
+/**
+ * qpnp_vadc_read() - Performs ADC read on the channel.
+ * @channel:	Input channel to perform the ADC read.
+ * @result:	Structure pointer of type adc_chan_result
+ *		in which the ADC read results are stored.
+ */
+int32_t qpnp_vadc_read(enum qpnp_vadc_channels channel,
+				struct qpnp_vadc_result *result);
+
+/**
+ * qpnp_vadc_conv_seq_request() - Performs ADC read on the conversion
+ *				sequencer channel.
+ * @channel:	Input channel to perform the ADC read.
+ * @result:	Structure pointer of type adc_chan_result
+ *		in which the ADC read results are stored.
+ */
+int32_t qpnp_vadc_conv_seq_request(
+			enum qpnp_vadc_trigger trigger_channel,
+			enum qpnp_vadc_channels channel,
+			struct qpnp_vadc_result *result);
+
+/**
+ * qpnp_vadc_check_result() - Performs check on the ADC raw code.
+ * @data:	Data used for verifying the range of the ADC code.
+ */
+int32_t qpnp_vadc_check_result(int32_t *data);
+
+/**
+ * qpnp_adc_get_devicetree_data() - Abstracts the ADC devicetree data.
+ * @spmi:	spmi ADC device.
+ * @adc_qpnp:	spmi device tree node structure
+ */
+int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
+					struct qpnp_adc_drv *adc_qpnp);
+
+/**
+ * qpnp_vadc_configure() - Configure ADC device to start conversion.
+ * @chan_prop:	Individual channel properties for the AMUX channel.
+ */
+int32_t qpnp_vadc_configure(
+			struct qpnp_vadc_amux_properties *chan_prop);
+
+/**
+ * qpnp_adc_scale_default() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset.
+ * @adc_code:	pre-calibrated digital ouput of the ADC.
+ * @adc_prop:	adc properties of the qpnp adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	Individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	Physical result to be stored.
+ */
+int32_t qpnp_adc_scale_default(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+#else
+static inline int32_t qpnp_vadc_read(uint32_t channel,
+				struct qpnp_vadc_result *result)
+{ return -ENXIO; }
+static inline int32_t qpnp_vadc_conv_seq_request(
+			enum qpnp_vadc_trigger trigger_channel,
+			enum qpnp_vadc_channels channel,
+			struct qpnp_vadc_result *result)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_default(int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_adc_chan_properties *chan_prop,
+			struct qpnp_adc_chan_result *chan_rslt)
+{ return -ENXIO; }
+#endif
+
+#endif