On 04/04/17 13:08, Linus Walleij wrote: > 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@xxxxxxxxxxxxxxxxxxx > Cc: linux-arm-msm@xxxxxxxxxxxxxxx > Cc: Ivan T. Ivanov <iivanov.xz@xxxxxxxxx> > Cc: Andy Gross <andy.gross@xxxxxxxxxx> > Cc: Bjorn Andersson <bjorn.andersson@xxxxxxxxxx> > Cc: Stephen Boyd <sboyd@xxxxxxxxxxxxxx> > Cc: Srinivas Kandagatla <srinivas.kandagatla@xxxxxxxxxx> > Cc: Rama Krishna Phani A <rphani@xxxxxxxxxxxxxx> > Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx> Applied to the togreg branhc of iio.git and pushed out as testing for the autobuilders to play with it. Thanks, Jonathan > --- > ChangeLog v4->v5: > - Fix kernel build again. Give up and create a helper module > with EXPORT_SYMBOL() functions. It works for allyes and allmod, > finally. YES I TESTED IT THOROUGHLY: > > x86_64 allmodconfig: > CC [M] kernel/configs.o > CC [M] drivers/iio/adc/qcom-vadc-common.o > CC [M] drivers/iio/adc/qcom-spmi-vadc.o > CC [M] drivers/iio/adc/qcom-pm8xxx-xoadc.o > Building modules, stage 2. > MODPOST 6247 modules > CC drivers/iio/adc/qcom-pm8xxx-xoadc.mod.o > CC drivers/iio/adc/qcom-vadc-common.mod.o > CC drivers/iio/adc/qcom-spmi-vadc.mod.o > CC kernel/configs.mod.o > LD [M] drivers/iio/adc/qcom-pm8xxx-xoadc.ko > LD [M] drivers/iio/adc/qcom-spmi-vadc.ko > LD [M] drivers/iio/adc/qcom-vadc-common.ko > LD [M] kernel/configs.ko > > x86_64 allyesconfig: > CC drivers/iio/adc/qcom-vadc-common.o > CC drivers/iio/adc/qcom-spmi-vadc.o > CC drivers/iio/adc/qcom-pm8xxx-xoadc.o > LD drivers/iio/adc/built-in.o > LD drivers/iio/built-in.o > LD vmlinux.o > MODPOST vmlinux.o > KSYM .tmp_kallsyms1.o > KSYM .tmp_kallsyms2.o > LD vmlinux > > So help me God. And sorry for wasting so much of your time with > these build issues. :( :( :( > > - Missing inclusion guard in the .h file. > ChangeLog v3->v4: > - Fix up the kernel build, tested with allyes and allmod. > ChangeLog v2->v3: > - Rewrite on top of Rama Krishna's changes. Now we use the > generic channel properties, calibration graph and prescale > settings in all VADC drivers. I did away with the vtable > indirection which I just don't see the point of, it's > better to just pass the type of conversion function around > and have a switch case select the conversion. It was done like > that in the vendor tree but it's not a good idea. > ChangeLog v1->v2: > - No changes just reposting > --- > drivers/iio/adc/Kconfig | 4 + > drivers/iio/adc/Makefile | 1 + > drivers/iio/adc/qcom-spmi-vadc.c | 325 ++----------------------------------- > drivers/iio/adc/qcom-vadc-common.c | 230 ++++++++++++++++++++++++++ > drivers/iio/adc/qcom-vadc-common.h | 108 ++++++++++++ > 5 files changed, 358 insertions(+), 310 deletions(-) > create mode 100644 drivers/iio/adc/qcom-vadc-common.c > create mode 100644 drivers/iio/adc/qcom-vadc-common.h > > diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig > index dedae7adbce9..8720e1c706fe 100644 > --- a/drivers/iio/adc/Kconfig > +++ b/drivers/iio/adc/Kconfig > @@ -442,6 +442,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 > @@ -460,6 +463,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. > > diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile > index d0012620cd1c..8c2e294042ae 100644 > --- a/drivers/iio/adc/Makefile > +++ b/drivers/iio/adc/Makefile > @@ -43,6 +43,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 > diff --git a/drivers/iio/adc/qcom-spmi-vadc.c b/drivers/iio/adc/qcom-spmi-vadc.c > index 0a19761d656c..9e600bfd1765 100644 > --- a/drivers/iio/adc/qcom-spmi-vadc.c > +++ b/drivers/iio/adc/qcom-spmi-vadc.c > @@ -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,84 +77,10 @@ > > #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. > * @calibration: calibration type. > @@ -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 @@ static int vadc_measure_ref_points(struct vadc_priv *vadc) > 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]; > diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c > new file mode 100644 > index 000000000000..102fc51b10aa > --- /dev/null > +++ b/drivers/iio/adc/qcom-vadc-common.c > @@ -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); > diff --git a/drivers/iio/adc/qcom-vadc-common.h b/drivers/iio/adc/qcom-vadc-common.h > new file mode 100644 > index 000000000000..63c872a70adc > --- /dev/null > +++ b/drivers/iio/adc/qcom-vadc-common.h > @@ -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 */ > -- To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html