|
@@ -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];
|