iio: adc: break out common code from SPMI VADC
The SPMI VADC and the earlier XOADC share a subset of common code, so to be able to use the same code in both drivers, we break out a separate file with the common code, prefix exported functions that are no longer static with qcom_* and bake an object qcom-spmi-vadc.o that contains both files: qcom-vadc-common.o and qcom-spmi-vadc-core.o. As we need to follow the procedure for making a kernel module or compiled in object from several files, but still want to produce the same module name, rename the qcom-spmi-vadc.c file to qcom-spmi-vadc-core.c so we can bake the two objects into qcom-spmi-vadc.o Cc: linux-arm-kernel@lists.infradead.org Cc: linux-arm-msm@vger.kernel.org Cc: Ivan T. Ivanov <iivanov.xz@gmail.com> Cc: Andy Gross <andy.gross@linaro.org> Cc: Bjorn Andersson <bjorn.andersson@linaro.org> Cc: Stephen Boyd <sboyd@codeaurora.org> Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Cc: Rama Krishna Phani A <rphani@codeaurora.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
This commit is contained in:
parent
96b3c83303
commit
e932d4f041
|
@ -496,6 +496,9 @@ config PALMAS_GPADC
|
|||
is used in smartphones and tablets and supports a 16 channel
|
||||
general purpose ADC.
|
||||
|
||||
config QCOM_VADC_COMMON
|
||||
tristate
|
||||
|
||||
config QCOM_SPMI_IADC
|
||||
tristate "Qualcomm SPMI PMIC current ADC"
|
||||
depends on SPMI
|
||||
|
@ -514,6 +517,7 @@ config QCOM_SPMI_VADC
|
|||
tristate "Qualcomm SPMI PMIC voltage ADC"
|
||||
depends on SPMI
|
||||
select REGMAP_SPMI
|
||||
select QCOM_VADC_COMMON
|
||||
help
|
||||
This is the IIO Voltage ADC driver for Qualcomm QPNP VADC Chip.
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
|
|||
obj-$(CONFIG_NAU7802) += nau7802.o
|
||||
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
|
||||
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
|
||||
obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o
|
||||
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
|
||||
obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
|
||||
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
#include <dt-bindings/iio/qcom,spmi-vadc.h>
|
||||
|
||||
#include "qcom-vadc-common.h"
|
||||
|
||||
/* VADC register and bit definitions */
|
||||
#define VADC_REVISION2 0x1
|
||||
#define VADC_REVISION2_SUPPORTED_VADC 1
|
||||
|
@ -75,83 +77,9 @@
|
|||
|
||||
#define VADC_DATA 0x60 /* 16 bits */
|
||||
|
||||
#define VADC_CONV_TIME_MIN_US 2000
|
||||
#define VADC_CONV_TIME_MAX_US 2100
|
||||
|
||||
/* Min ADC code represents 0V */
|
||||
#define VADC_MIN_ADC_CODE 0x6000
|
||||
/* Max ADC code represents full-scale range of 1.8V */
|
||||
#define VADC_MAX_ADC_CODE 0xa800
|
||||
|
||||
#define VADC_ABSOLUTE_RANGE_UV 625000
|
||||
#define VADC_RATIOMETRIC_RANGE 1800
|
||||
|
||||
#define VADC_DEF_PRESCALING 0 /* 1:1 */
|
||||
#define VADC_DEF_DECIMATION 0 /* 512 */
|
||||
#define VADC_DEF_HW_SETTLE_TIME 0 /* 0 us */
|
||||
#define VADC_DEF_AVG_SAMPLES 0 /* 1 sample */
|
||||
#define VADC_DEF_CALIB_TYPE VADC_CALIB_ABSOLUTE
|
||||
|
||||
#define VADC_DECIMATION_MIN 512
|
||||
#define VADC_DECIMATION_MAX 4096
|
||||
|
||||
#define VADC_HW_SETTLE_DELAY_MAX 10000
|
||||
#define VADC_AVG_SAMPLES_MAX 512
|
||||
|
||||
#define KELVINMIL_CELSIUSMIL 273150
|
||||
|
||||
#define PMI_CHG_SCALE_1 -138890
|
||||
#define PMI_CHG_SCALE_2 391750000000LL
|
||||
|
||||
#define VADC_CHAN_MIN VADC_USBIN
|
||||
#define VADC_CHAN_MAX VADC_LR_MUX3_BUF_PU1_PU2_XO_THERM
|
||||
|
||||
/**
|
||||
* struct 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 vadc_map_pt {
|
||||
s32 x;
|
||||
s32 y;
|
||||
};
|
||||
|
||||
/*
|
||||
* VADC_CALIB_ABSOLUTE: uses the 625mV and 1.25V as reference channels.
|
||||
* VADC_CALIB_RATIOMETRIC: uses the reference voltage (1.8V) and GND for
|
||||
* calibration.
|
||||
*/
|
||||
enum vadc_calibration {
|
||||
VADC_CALIB_ABSOLUTE = 0,
|
||||
VADC_CALIB_RATIOMETRIC
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vadc_linear_graph - Represent ADC characteristics.
|
||||
* @dy: numerator slope to calculate the gain.
|
||||
* @dx: denominator slope to calculate the gain.
|
||||
* @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 vadc_linear_graph {
|
||||
s32 dy;
|
||||
s32 dx;
|
||||
s32 gnd;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vadc_prescale_ratio - Represent scaling ratio for ADC input.
|
||||
* @num: the inverse numerator of the gain applied to the input channel.
|
||||
* @den: the inverse denominator of the gain applied to the input channel.
|
||||
*/
|
||||
struct vadc_prescale_ratio {
|
||||
u32 num;
|
||||
u32 den;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vadc_channel_prop - VADC channel property.
|
||||
* @channel: channel number, refer to the channel list.
|
||||
|
@ -162,9 +90,8 @@ struct vadc_prescale_ratio {
|
|||
* start of conversion.
|
||||
* @avg_samples: ability to provide single result from the ADC
|
||||
* that is an average of multiple measurements.
|
||||
* @scale_fn: Represents the scaling function to convert voltage
|
||||
* @scale_fn_type: Represents the scaling function to convert voltage
|
||||
* physical units desired by the client for the channel.
|
||||
* Referenced from enum vadc_scale_fn_type.
|
||||
*/
|
||||
struct vadc_channel_prop {
|
||||
unsigned int channel;
|
||||
|
@ -173,7 +100,7 @@ struct vadc_channel_prop {
|
|||
unsigned int prescale;
|
||||
unsigned int hw_settle_time;
|
||||
unsigned int avg_samples;
|
||||
unsigned int scale_fn;
|
||||
enum vadc_scale_fn_type scale_fn_type;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -204,35 +131,6 @@ struct vadc_priv {
|
|||
struct mutex lock;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vadc_scale_fn - Scaling function prototype
|
||||
* @scale: Function pointer to one of the scaling functions
|
||||
* which takes the adc properties, channel properties,
|
||||
* and returns the physical result.
|
||||
*/
|
||||
struct vadc_scale_fn {
|
||||
int (*scale)(struct vadc_priv *, const struct vadc_channel_prop *,
|
||||
u16, int *);
|
||||
};
|
||||
|
||||
/**
|
||||
* enum vadc_scale_fn_type - Scaling function to convert ADC code to
|
||||
* physical scaled units for the channel.
|
||||
* SCALE_DEFAULT: Default scaling to convert raw adc code to voltage (uV).
|
||||
* SCALE_THERM_100K_PULLUP: Returns temperature in millidegC.
|
||||
* Uses a mapping table with 100K pullup.
|
||||
* SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
|
||||
* SCALE_XOTHERM: Returns XO thermistor voltage in millidegC.
|
||||
* SCALE_PMI_CHG_TEMP: Conversion for PMI CHG temp
|
||||
*/
|
||||
enum vadc_scale_fn_type {
|
||||
SCALE_DEFAULT = 0,
|
||||
SCALE_THERM_100K_PULLUP,
|
||||
SCALE_PMIC_THERM,
|
||||
SCALE_XOTHERM,
|
||||
SCALE_PMI_CHG_TEMP,
|
||||
};
|
||||
|
||||
static const struct vadc_prescale_ratio vadc_prescale_ratios[] = {
|
||||
{.num = 1, .den = 1},
|
||||
{.num = 1, .den = 3},
|
||||
|
@ -244,44 +142,6 @@ static const struct vadc_prescale_ratio vadc_prescale_ratios[] = {
|
|||
{.num = 1, .den = 10}
|
||||
};
|
||||
|
||||
/* Voltage to temperature */
|
||||
static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = {
|
||||
{1758, -40},
|
||||
{1742, -35},
|
||||
{1719, -30},
|
||||
{1691, -25},
|
||||
{1654, -20},
|
||||
{1608, -15},
|
||||
{1551, -10},
|
||||
{1483, -5},
|
||||
{1404, 0},
|
||||
{1315, 5},
|
||||
{1218, 10},
|
||||
{1114, 15},
|
||||
{1007, 20},
|
||||
{900, 25},
|
||||
{795, 30},
|
||||
{696, 35},
|
||||
{605, 40},
|
||||
{522, 45},
|
||||
{448, 50},
|
||||
{383, 55},
|
||||
{327, 60},
|
||||
{278, 65},
|
||||
{237, 70},
|
||||
{202, 75},
|
||||
{172, 80},
|
||||
{146, 85},
|
||||
{125, 90},
|
||||
{107, 95},
|
||||
{92, 100},
|
||||
{79, 105},
|
||||
{68, 110},
|
||||
{59, 115},
|
||||
{51, 120},
|
||||
{44, 125}
|
||||
};
|
||||
|
||||
static int vadc_read(struct vadc_priv *vadc, u16 offset, u8 *data)
|
||||
{
|
||||
return regmap_bulk_read(vadc->regmap, vadc->base + offset, data, 1);
|
||||
|
@ -553,159 +413,6 @@ err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int vadc_map_voltage_temp(const struct vadc_map_pt *pts,
|
||||
u32 tablesize, s32 input, s64 *output)
|
||||
{
|
||||
bool descending = 1;
|
||||
u32 i = 0;
|
||||
|
||||
if (!pts)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check if table is descending or ascending */
|
||||
if (tablesize > 1) {
|
||||
if (pts[0].x < pts[1].x)
|
||||
descending = 0;
|
||||
}
|
||||
|
||||
while (i < tablesize) {
|
||||
if ((descending) && (pts[i].x < input)) {
|
||||
/* table entry is less than measured*/
|
||||
/* value and table is descending, stop */
|
||||
break;
|
||||
} else if ((!descending) &&
|
||||
(pts[i].x > input)) {
|
||||
/* table entry is greater than measured*/
|
||||
/*value and table is ascending, stop */
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
*output = pts[0].y;
|
||||
} else if (i == tablesize) {
|
||||
*output = pts[tablesize - 1].y;
|
||||
} else {
|
||||
/* result is between search_index and search_index-1 */
|
||||
/* interpolate linearly */
|
||||
*output = (((s32)((pts[i].y - pts[i - 1].y) *
|
||||
(input - pts[i - 1].x)) /
|
||||
(pts[i].x - pts[i - 1].x)) +
|
||||
pts[i - 1].y);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vadc_scale_calib(struct vadc_priv *vadc, u16 adc_code,
|
||||
const struct vadc_channel_prop *prop,
|
||||
s64 *scale_voltage)
|
||||
{
|
||||
*scale_voltage = (adc_code -
|
||||
vadc->graph[prop->calibration].gnd);
|
||||
*scale_voltage *= vadc->graph[prop->calibration].dx;
|
||||
*scale_voltage = div64_s64(*scale_voltage,
|
||||
vadc->graph[prop->calibration].dy);
|
||||
if (prop->calibration == VADC_CALIB_ABSOLUTE)
|
||||
*scale_voltage +=
|
||||
vadc->graph[prop->calibration].dx;
|
||||
|
||||
if (*scale_voltage < 0)
|
||||
*scale_voltage = 0;
|
||||
}
|
||||
|
||||
static int vadc_scale_volt(struct vadc_priv *vadc,
|
||||
const struct vadc_channel_prop *prop, u16 adc_code,
|
||||
int *result_uv)
|
||||
{
|
||||
const struct vadc_prescale_ratio *prescale;
|
||||
s64 voltage = 0, result = 0;
|
||||
|
||||
vadc_scale_calib(vadc, adc_code, prop, &voltage);
|
||||
|
||||
prescale = &vadc_prescale_ratios[prop->prescale];
|
||||
voltage = voltage * prescale->den;
|
||||
result = div64_s64(voltage, prescale->num);
|
||||
*result_uv = result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vadc_scale_therm(struct vadc_priv *vadc,
|
||||
const struct vadc_channel_prop *prop, u16 adc_code,
|
||||
int *result_mdec)
|
||||
{
|
||||
s64 voltage = 0, result = 0;
|
||||
|
||||
vadc_scale_calib(vadc, adc_code, prop, &voltage);
|
||||
|
||||
if (prop->calibration == VADC_CALIB_ABSOLUTE)
|
||||
voltage = div64_s64(voltage, 1000);
|
||||
|
||||
vadc_map_voltage_temp(adcmap_100k_104ef_104fb,
|
||||
ARRAY_SIZE(adcmap_100k_104ef_104fb),
|
||||
voltage, &result);
|
||||
result *= 1000;
|
||||
*result_mdec = result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vadc_scale_die_temp(struct vadc_priv *vadc,
|
||||
const struct vadc_channel_prop *prop,
|
||||
u16 adc_code, int *result_mdec)
|
||||
{
|
||||
const struct vadc_prescale_ratio *prescale;
|
||||
s64 voltage = 0;
|
||||
u64 temp; /* Temporary variable for do_div */
|
||||
|
||||
vadc_scale_calib(vadc, adc_code, prop, &voltage);
|
||||
|
||||
if (voltage > 0) {
|
||||
prescale = &vadc_prescale_ratios[prop->prescale];
|
||||
temp = voltage * prescale->den;
|
||||
do_div(temp, prescale->num * 2);
|
||||
voltage = temp;
|
||||
} else {
|
||||
voltage = 0;
|
||||
}
|
||||
|
||||
voltage -= KELVINMIL_CELSIUSMIL;
|
||||
*result_mdec = voltage;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vadc_scale_chg_temp(struct vadc_priv *vadc,
|
||||
const struct vadc_channel_prop *prop,
|
||||
u16 adc_code, int *result_mdec)
|
||||
{
|
||||
const struct vadc_prescale_ratio *prescale;
|
||||
s64 voltage = 0, result = 0;
|
||||
|
||||
vadc_scale_calib(vadc, adc_code, prop, &voltage);
|
||||
|
||||
prescale = &vadc_prescale_ratios[prop->prescale];
|
||||
voltage = voltage * prescale->den;
|
||||
voltage = div64_s64(voltage, prescale->num);
|
||||
voltage = ((PMI_CHG_SCALE_1) * (voltage * 2));
|
||||
voltage = (voltage + PMI_CHG_SCALE_2);
|
||||
result = div64_s64(voltage, 1000000);
|
||||
*result_mdec = result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vadc_decimation_from_dt(u32 value)
|
||||
{
|
||||
if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
|
||||
value > VADC_DECIMATION_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
return __ffs64(value / VADC_DECIMATION_MIN);
|
||||
}
|
||||
|
||||
static int vadc_prescaling_from_dt(u32 num, u32 den)
|
||||
{
|
||||
unsigned int pre;
|
||||
|
@ -742,14 +449,6 @@ static int vadc_avg_samples_from_dt(u32 value)
|
|||
return __ffs64(value);
|
||||
}
|
||||
|
||||
static struct vadc_scale_fn scale_fn[] = {
|
||||
[SCALE_DEFAULT] = {vadc_scale_volt},
|
||||
[SCALE_THERM_100K_PULLUP] = {vadc_scale_therm},
|
||||
[SCALE_PMIC_THERM] = {vadc_scale_die_temp},
|
||||
[SCALE_XOTHERM] = {vadc_scale_therm},
|
||||
[SCALE_PMI_CHG_TEMP] = {vadc_scale_chg_temp},
|
||||
};
|
||||
|
||||
static int vadc_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val, int *val2,
|
||||
long mask)
|
||||
|
@ -766,7 +465,13 @@ static int vadc_read_raw(struct iio_dev *indio_dev,
|
|||
if (ret)
|
||||
break;
|
||||
|
||||
scale_fn[prop->scale_fn].scale(vadc, prop, adc_code, val);
|
||||
ret = qcom_vadc_scale(prop->scale_fn_type,
|
||||
&vadc->graph[prop->calibration],
|
||||
&vadc_prescale_ratios[prop->prescale],
|
||||
(prop->calibration == VADC_CALIB_ABSOLUTE),
|
||||
adc_code, val);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
|
@ -809,7 +514,7 @@ struct vadc_channels {
|
|||
unsigned int prescale_index;
|
||||
enum iio_chan_type type;
|
||||
long info_mask;
|
||||
unsigned int scale_fn;
|
||||
enum vadc_scale_fn_type scale_fn_type;
|
||||
};
|
||||
|
||||
#define VADC_CHAN(_dname, _type, _mask, _pre, _scale) \
|
||||
|
@ -818,7 +523,7 @@ struct vadc_channels {
|
|||
.prescale_index = _pre, \
|
||||
.type = _type, \
|
||||
.info_mask = _mask, \
|
||||
.scale_fn = _scale \
|
||||
.scale_fn_type = _scale \
|
||||
}, \
|
||||
|
||||
#define VADC_NO_CHAN(_dname, _type, _mask, _pre) \
|
||||
|
@ -976,7 +681,7 @@ static int vadc_get_dt_channel_data(struct device *dev,
|
|||
|
||||
ret = of_property_read_u32(node, "qcom,decimation", &value);
|
||||
if (!ret) {
|
||||
ret = vadc_decimation_from_dt(value);
|
||||
ret = qcom_vadc_decimation_from_dt(value);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%02x invalid decimation %d\n",
|
||||
chan, value);
|
||||
|
@ -1068,7 +773,7 @@ static int vadc_get_dt_data(struct vadc_priv *vadc, struct device_node *node)
|
|||
return ret;
|
||||
}
|
||||
|
||||
prop.scale_fn = vadc_chans[prop.channel].scale_fn;
|
||||
prop.scale_fn_type = vadc_chans[prop.channel].scale_fn_type;
|
||||
vadc->chan_props[index] = prop;
|
||||
|
||||
vadc_chan = &vadc_chans[prop.channel];
|
||||
|
|
|
@ -0,0 +1,230 @@
|
|||
#include <linux/bug.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "qcom-vadc-common.h"
|
||||
|
||||
/* Voltage to temperature */
|
||||
static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = {
|
||||
{1758, -40},
|
||||
{1742, -35},
|
||||
{1719, -30},
|
||||
{1691, -25},
|
||||
{1654, -20},
|
||||
{1608, -15},
|
||||
{1551, -10},
|
||||
{1483, -5},
|
||||
{1404, 0},
|
||||
{1315, 5},
|
||||
{1218, 10},
|
||||
{1114, 15},
|
||||
{1007, 20},
|
||||
{900, 25},
|
||||
{795, 30},
|
||||
{696, 35},
|
||||
{605, 40},
|
||||
{522, 45},
|
||||
{448, 50},
|
||||
{383, 55},
|
||||
{327, 60},
|
||||
{278, 65},
|
||||
{237, 70},
|
||||
{202, 75},
|
||||
{172, 80},
|
||||
{146, 85},
|
||||
{125, 90},
|
||||
{107, 95},
|
||||
{92, 100},
|
||||
{79, 105},
|
||||
{68, 110},
|
||||
{59, 115},
|
||||
{51, 120},
|
||||
{44, 125}
|
||||
};
|
||||
|
||||
static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts,
|
||||
u32 tablesize, s32 input, s64 *output)
|
||||
{
|
||||
bool descending = 1;
|
||||
u32 i = 0;
|
||||
|
||||
if (!pts)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check if table is descending or ascending */
|
||||
if (tablesize > 1) {
|
||||
if (pts[0].x < pts[1].x)
|
||||
descending = 0;
|
||||
}
|
||||
|
||||
while (i < tablesize) {
|
||||
if ((descending) && (pts[i].x < input)) {
|
||||
/* table entry is less than measured*/
|
||||
/* value and table is descending, stop */
|
||||
break;
|
||||
} else if ((!descending) &&
|
||||
(pts[i].x > input)) {
|
||||
/* table entry is greater than measured*/
|
||||
/*value and table is ascending, stop */
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
*output = pts[0].y;
|
||||
} else if (i == tablesize) {
|
||||
*output = pts[tablesize - 1].y;
|
||||
} else {
|
||||
/* result is between search_index and search_index-1 */
|
||||
/* interpolate linearly */
|
||||
*output = (((s32)((pts[i].y - pts[i - 1].y) *
|
||||
(input - pts[i - 1].x)) /
|
||||
(pts[i].x - pts[i - 1].x)) +
|
||||
pts[i - 1].y);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcom_vadc_scale_calib(const struct vadc_linear_graph *calib_graph,
|
||||
u16 adc_code,
|
||||
bool absolute,
|
||||
s64 *scale_voltage)
|
||||
{
|
||||
*scale_voltage = (adc_code - calib_graph->gnd);
|
||||
*scale_voltage *= calib_graph->dx;
|
||||
*scale_voltage = div64_s64(*scale_voltage, calib_graph->dy);
|
||||
if (absolute)
|
||||
*scale_voltage += calib_graph->dx;
|
||||
|
||||
if (*scale_voltage < 0)
|
||||
*scale_voltage = 0;
|
||||
}
|
||||
|
||||
static int qcom_vadc_scale_volt(const struct vadc_linear_graph *calib_graph,
|
||||
const struct vadc_prescale_ratio *prescale,
|
||||
bool absolute, u16 adc_code,
|
||||
int *result_uv)
|
||||
{
|
||||
s64 voltage = 0, result = 0;
|
||||
|
||||
qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
|
||||
|
||||
voltage = voltage * prescale->den;
|
||||
result = div64_s64(voltage, prescale->num);
|
||||
*result_uv = result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
|
||||
const struct vadc_prescale_ratio *prescale,
|
||||
bool absolute, u16 adc_code,
|
||||
int *result_mdec)
|
||||
{
|
||||
s64 voltage = 0, result = 0;
|
||||
int ret;
|
||||
|
||||
qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
|
||||
|
||||
if (absolute)
|
||||
voltage = div64_s64(voltage, 1000);
|
||||
|
||||
ret = qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb,
|
||||
ARRAY_SIZE(adcmap_100k_104ef_104fb),
|
||||
voltage, &result);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
result *= 1000;
|
||||
*result_mdec = result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph *calib_graph,
|
||||
const struct vadc_prescale_ratio *prescale,
|
||||
bool absolute,
|
||||
u16 adc_code, int *result_mdec)
|
||||
{
|
||||
s64 voltage = 0;
|
||||
u64 temp; /* Temporary variable for do_div */
|
||||
|
||||
qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
|
||||
|
||||
if (voltage > 0) {
|
||||
temp = voltage * prescale->den;
|
||||
do_div(temp, prescale->num * 2);
|
||||
voltage = temp;
|
||||
} else {
|
||||
voltage = 0;
|
||||
}
|
||||
|
||||
voltage -= KELVINMIL_CELSIUSMIL;
|
||||
*result_mdec = voltage;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph,
|
||||
const struct vadc_prescale_ratio *prescale,
|
||||
bool absolute,
|
||||
u16 adc_code, int *result_mdec)
|
||||
{
|
||||
s64 voltage = 0, result = 0;
|
||||
|
||||
qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
|
||||
|
||||
voltage = voltage * prescale->den;
|
||||
voltage = div64_s64(voltage, prescale->num);
|
||||
voltage = ((PMI_CHG_SCALE_1) * (voltage * 2));
|
||||
voltage = (voltage + PMI_CHG_SCALE_2);
|
||||
result = div64_s64(voltage, 1000000);
|
||||
*result_mdec = result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
|
||||
const struct vadc_linear_graph *calib_graph,
|
||||
const struct vadc_prescale_ratio *prescale,
|
||||
bool absolute,
|
||||
u16 adc_code, int *result)
|
||||
{
|
||||
switch (scaletype) {
|
||||
case SCALE_DEFAULT:
|
||||
return qcom_vadc_scale_volt(calib_graph, prescale,
|
||||
absolute, adc_code,
|
||||
result);
|
||||
case SCALE_THERM_100K_PULLUP:
|
||||
case SCALE_XOTHERM:
|
||||
return qcom_vadc_scale_therm(calib_graph, prescale,
|
||||
absolute, adc_code,
|
||||
result);
|
||||
case SCALE_PMIC_THERM:
|
||||
return qcom_vadc_scale_die_temp(calib_graph, prescale,
|
||||
absolute, adc_code,
|
||||
result);
|
||||
case SCALE_PMI_CHG_TEMP:
|
||||
return qcom_vadc_scale_chg_temp(calib_graph, prescale,
|
||||
absolute, adc_code,
|
||||
result);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_vadc_scale);
|
||||
|
||||
int qcom_vadc_decimation_from_dt(u32 value)
|
||||
{
|
||||
if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
|
||||
value > VADC_DECIMATION_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
return __ffs64(value / VADC_DECIMATION_MIN);
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_vadc_decimation_from_dt);
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Code shared between the different Qualcomm PMIC voltage ADCs
|
||||
*/
|
||||
|
||||
#ifndef QCOM_VADC_COMMON_H
|
||||
#define QCOM_VADC_COMMON_H
|
||||
|
||||
#define VADC_CONV_TIME_MIN_US 2000
|
||||
#define VADC_CONV_TIME_MAX_US 2100
|
||||
|
||||
/* Min ADC code represents 0V */
|
||||
#define VADC_MIN_ADC_CODE 0x6000
|
||||
/* Max ADC code represents full-scale range of 1.8V */
|
||||
#define VADC_MAX_ADC_CODE 0xa800
|
||||
|
||||
#define VADC_ABSOLUTE_RANGE_UV 625000
|
||||
#define VADC_RATIOMETRIC_RANGE 1800
|
||||
|
||||
#define VADC_DEF_PRESCALING 0 /* 1:1 */
|
||||
#define VADC_DEF_DECIMATION 0 /* 512 */
|
||||
#define VADC_DEF_HW_SETTLE_TIME 0 /* 0 us */
|
||||
#define VADC_DEF_AVG_SAMPLES 0 /* 1 sample */
|
||||
#define VADC_DEF_CALIB_TYPE VADC_CALIB_ABSOLUTE
|
||||
|
||||
#define VADC_DECIMATION_MIN 512
|
||||
#define VADC_DECIMATION_MAX 4096
|
||||
|
||||
#define VADC_HW_SETTLE_DELAY_MAX 10000
|
||||
#define VADC_AVG_SAMPLES_MAX 512
|
||||
|
||||
#define KELVINMIL_CELSIUSMIL 273150
|
||||
|
||||
#define PMI_CHG_SCALE_1 -138890
|
||||
#define PMI_CHG_SCALE_2 391750000000LL
|
||||
|
||||
/**
|
||||
* struct 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 vadc_map_pt {
|
||||
s32 x;
|
||||
s32 y;
|
||||
};
|
||||
|
||||
/*
|
||||
* VADC_CALIB_ABSOLUTE: uses the 625mV and 1.25V as reference channels.
|
||||
* VADC_CALIB_RATIOMETRIC: uses the reference voltage (1.8V) and GND for
|
||||
* calibration.
|
||||
*/
|
||||
enum vadc_calibration {
|
||||
VADC_CALIB_ABSOLUTE = 0,
|
||||
VADC_CALIB_RATIOMETRIC
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vadc_linear_graph - Represent ADC characteristics.
|
||||
* @dy: numerator slope to calculate the gain.
|
||||
* @dx: denominator slope to calculate the gain.
|
||||
* @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 vadc_linear_graph {
|
||||
s32 dy;
|
||||
s32 dx;
|
||||
s32 gnd;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct vadc_prescale_ratio - Represent scaling ratio for ADC input.
|
||||
* @num: the inverse numerator of the gain applied to the input channel.
|
||||
* @den: the inverse denominator of the gain applied to the input channel.
|
||||
*/
|
||||
struct vadc_prescale_ratio {
|
||||
u32 num;
|
||||
u32 den;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum vadc_scale_fn_type - Scaling function to convert ADC code to
|
||||
* physical scaled units for the channel.
|
||||
* SCALE_DEFAULT: Default scaling to convert raw adc code to voltage (uV).
|
||||
* SCALE_THERM_100K_PULLUP: Returns temperature in millidegC.
|
||||
* Uses a mapping table with 100K pullup.
|
||||
* SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
|
||||
* SCALE_XOTHERM: Returns XO thermistor voltage in millidegC.
|
||||
* SCALE_PMI_CHG_TEMP: Conversion for PMI CHG temp
|
||||
*/
|
||||
enum vadc_scale_fn_type {
|
||||
SCALE_DEFAULT = 0,
|
||||
SCALE_THERM_100K_PULLUP,
|
||||
SCALE_PMIC_THERM,
|
||||
SCALE_XOTHERM,
|
||||
SCALE_PMI_CHG_TEMP,
|
||||
};
|
||||
|
||||
int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
|
||||
const struct vadc_linear_graph *calib_graph,
|
||||
const struct vadc_prescale_ratio *prescale,
|
||||
bool absolute,
|
||||
u16 adc_code, int *result_mdec);
|
||||
|
||||
int qcom_vadc_decimation_from_dt(u32 value);
|
||||
|
||||
#endif /* QCOM_VADC_COMMON_H */
|
Loading…
Reference in New Issue