Hi Jishnu, It is nice to cc a reviewer from a previous version. Just saw this. On Mon, Apr 27, 2020 at 6:55 PM Jishnu Prakash <jprakash@xxxxxxxxxxxxxx> wrote: > > The ADC architecture on PMIC7 is changed as compared to PMIC5. The > major change from PMIC5 is that all SW communication to ADC goes through > PMK8350, which communicates with other PMICs through PBS when the ADC > on PMK8350 works in master mode. The SID register is used to identify the > PMICs with which the PBS needs to communicate. Add support for the same. > > Signed-off-by: Jishnu Prakash <jprakash@xxxxxxxxxxxxxx> > --- > drivers/iio/adc/qcom-spmi-adc5.c | 239 +++++++++++++++++++++++++++++++++- > drivers/iio/adc/qcom-vadc-common.c | 260 +++++++++++++++++++++++++++++++++++++ > drivers/iio/adc/qcom-vadc-common.h | 15 +++ > 3 files changed, 510 insertions(+), 4 deletions(-) > > diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c > index 21fdcde..a66eeb7 100644 > --- a/drivers/iio/adc/qcom-spmi-adc5.c > +++ b/drivers/iio/adc/qcom-spmi-adc5.c > @@ -1,6 +1,6 @@ > // SPDX-License-Identifier: GPL-2.0 > /* > - * Copyright (c) 2018, The Linux Foundation. All rights reserved. > + * Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved. > */ > > #include <linux/bitops.h> > @@ -23,6 +23,7 @@ > > #define ADC5_USR_REVISION1 0x0 > #define ADC5_USR_STATUS1 0x8 > +#define ADC5_USR_STATUS1_CONV_FAULT BIT(7) > #define ADC5_USR_STATUS1_REQ_STS BIT(1) > #define ADC5_USR_STATUS1_EOC BIT(0) > #define ADC5_USR_STATUS1_REQ_STS_EOC_MASK 0x3 > @@ -65,6 +66,9 @@ > > #define ADC5_USR_IBAT_DATA1 0x53 > > +#define ADC_CHANNEL_OFFSET 0x8 > +#define ADC_CHANNEL_MASK GENMASK(7, 0) > + > /* > * Conversion time varies based on the decimation, clock rate, fast average > * samples and measurements queued across different VADC peripherals. > @@ -79,6 +83,11 @@ > #define ADC5_HW_SETTLE_DIFF_MINOR 3 > #define ADC5_HW_SETTLE_DIFF_MAJOR 5 > > +/* For PMIC7 */ > +#define ADC_APP_SID 0x40 > +#define ADC_APP_SID_MASK GENMASK(3, 0) > +#define ADC7_CONV_TIMEOUT msecs_to_jiffies(10) > + > enum adc5_cal_method { > ADC5_NO_CAL = 0, > ADC5_RATIOMETRIC_CAL, > @@ -96,6 +105,7 @@ enum adc5_cal_val { > * @cal_method: calibration method. > * @cal_val: calibration value > * @decimation: sampling rate supported for the channel. > + * @sid: slave id of PMIC owning the channel, for PMIC7. > * @prescale: channel scaling performed on the input signal. > * @hw_settle_time: the time between AMUX being configured and the > * start of conversion. > @@ -110,6 +120,7 @@ struct adc5_channel_prop { > enum adc5_cal_method cal_method; > enum adc5_cal_val cal_val; > unsigned int decimation; > + unsigned int sid; > unsigned int prescale; > unsigned int hw_settle_time; > unsigned int avg_samples; > @@ -140,6 +151,7 @@ struct adc5_chip { > bool poll_eoc; > struct completion complete; > struct mutex lock; > + int irq_eoc; > const struct adc5_data *data; > }; > > @@ -155,6 +167,8 @@ static const struct vadc_prescale_ratio adc5_prescale_ratios[] = { > {.num = 1, .den = 16} > }; > > +static const struct adc5_data adc7_data_pmic; > + > static int adc5_read(struct adc5_chip *adc, u16 offset, u8 *data, int len) > { > return regmap_bulk_read(adc->regmap, adc->base + offset, data, len); > @@ -165,6 +179,11 @@ static int adc5_write(struct adc5_chip *adc, u16 offset, u8 *data, int len) > return regmap_bulk_write(adc->regmap, adc->base + offset, data, len); > } > > +static int adc5_masked_write(struct adc5_chip *adc, u16 offset, u8 mask, u8 val) > +{ > + return regmap_update_bits(adc->regmap, adc->base + offset, mask, val); > +} > + > static int adc5_prescaling_from_dt(u32 num, u32 den) > { > unsigned int pre; > @@ -314,6 +333,47 @@ static int adc5_configure(struct adc5_chip *adc, > return adc5_write(adc, ADC5_USR_DIG_PARAM, buf, sizeof(buf)); > } > > +static int adc7_configure(struct adc5_chip *adc, > + struct adc5_channel_prop *prop) > +{ > + int ret; > + u8 conv_req = 0, buf[4]; > + > + ret = adc5_masked_write(adc, ADC_APP_SID, ADC_APP_SID_MASK, prop->sid); > + if (ret) > + return ret; > + > + ret = adc5_read(adc, ADC5_USR_DIG_PARAM, buf, sizeof(buf)); > + if (ret < 0) > + return ret; > + > + /* Digital param selection */ > + adc5_update_dig_param(adc, prop, &buf[0]); > + > + /* Update fast average sample value */ > + buf[1] &= 0xff & ~ADC5_USR_FAST_AVG_CTL_SAMPLES_MASK; Did you answer Andy's query about this in v2? I couldn't find it. > + buf[1] |= prop->avg_samples; > + > + /* Select ADC channel */ > + buf[2] = prop->channel; > + > + /* Select HW settle delay for channel */ > + buf[3] &= 0xff & ~ADC5_USR_HW_SETTLE_DELAY_MASK; Same here. > + buf[3] |= prop->hw_settle_time; > + > + /* Select CONV request */ > + conv_req = ADC5_USR_CONV_REQ_REQ; > + > + if (!adc->poll_eoc) > + reinit_completion(&adc->complete); > + > + ret = adc5_write(adc, ADC5_USR_DIG_PARAM, buf, sizeof(buf)); > + if (ret) > + return ret; > + > + return adc5_write(adc, ADC5_USR_CONV_REQ, &conv_req, 1); Is it required to call adc5_write() twice here in sequence on the adc7? adc5_configure() above manages just fine by having an extra element in buf and one call. > +} > + > static int adc5_do_conversion(struct adc5_chip *adc, > struct adc5_channel_prop *prop, > struct iio_chan_spec const *chan, > @@ -355,6 +415,43 @@ static int adc5_do_conversion(struct adc5_chip *adc, > return ret; > } > > +static int adc7_do_conversion(struct adc5_chip *adc, > + struct adc5_channel_prop *prop, > + struct iio_chan_spec const *chan, > + u16 *data_volt, u16 *data_cur) > +{ > + int ret; > + u8 status; > + > + mutex_lock(&adc->lock); > + > + ret = adc7_configure(adc, prop); > + if (ret) { > + dev_err(adc->dev, "ADC configure failed with %d\n", ret); > + goto unlock; > + } > + > + /* No support for polling mode at present */ > + wait_for_completion_timeout(&adc->complete, ADC7_CONV_TIMEOUT); > + > + ret = adc5_read(adc, ADC5_USR_STATUS1, &status, 1); > + if (ret < 0) > + goto unlock; > + > + if (status & ADC5_USR_STATUS1_CONV_FAULT) { > + dev_err(adc->dev, "Unexpected conversion fault\n"); > + ret = -EIO; > + goto unlock; > + } > + > + ret = adc5_read_voltage_data(adc, data_volt); > + > +unlock: > + mutex_unlock(&adc->lock); > + > + return ret; > +} > + > static irqreturn_t adc5_isr(int irq, void *dev_id) > { > struct adc5_chip *adc = dev_id; > @@ -377,6 +474,56 @@ static int adc5_of_xlate(struct iio_dev *indio_dev, > return -EINVAL; > } > > +static int adc7_of_xlate(struct iio_dev *indio_dev, > + const struct of_phandle_args *iiospec) > +{ > + struct adc5_chip *adc = iio_priv(indio_dev); > + int i, v_channel; > + > + for (i = 0; i < adc->nchannels; i++) { > + v_channel = (adc->chan_props[i].sid << ADC_CHANNEL_OFFSET | > + adc->chan_props[i].channel); > + if (v_channel == iiospec->args[0]) > + return i; > + } > + > + return -EINVAL; > +} > + > +static int adc7_read_raw(struct iio_dev *indio_dev, > + struct iio_chan_spec const *chan, int *val, int *val2, > + long mask) Just a nit. Since all your adc7 functions follow your adc5 functions, please move this below adc5_read_raw for consistency. > +{ > + struct adc5_chip *adc = iio_priv(indio_dev); > + struct adc5_channel_prop *prop; > + u16 adc_code_volt, adc_code_cur; > + int ret; > + > + prop = &adc->chan_props[chan->address]; > + > + switch (mask) { > + case IIO_CHAN_INFO_PROCESSED: > + ret = adc7_do_conversion(adc, prop, chan, Except for this bit (call to adc7_do_conversion instead of adc5_do_conversion), this function is identical to adc5_read_raw. How about making adc5_read_raw and adc7_read_raw a shim around a function adc_read_raw_common() that takes a function pointer? > + &adc_code_volt, &adc_code_cur); > + if (ret) > + return ret; > + > + ret = qcom_adc5_hw_scale(prop->scale_fn_type, > + &adc5_prescale_ratios[prop->prescale], > + adc->data, > + adc_code_volt, val); > + > + if (ret) > + return ret; > + > + return IIO_VAL_INT; > + default: > + return -EINVAL; > + } > + > + return 0; > +} > + > static int adc5_read_raw(struct iio_dev *indio_dev, > struct iio_chan_spec const *chan, int *val, int *val2, > long mask) > @@ -415,6 +562,11 @@ static const struct iio_info adc5_info = { > .of_xlate = adc5_of_xlate, > }; > > +static const struct iio_info adc7_info = { > + .read_raw = adc7_read_raw, > + .of_xlate = adc7_of_xlate, > +}; > + > struct adc5_channels { > const char *datasheet_name; > unsigned int prescale_index; > @@ -477,6 +629,39 @@ static const struct adc5_channels adc5_chans_pmic[ADC5_MAX_CHANNEL] = { > SCALE_HW_CALIB_PM5_SMB_TEMP) > }; > > +static const struct adc5_channels adc7_chans_pmic[ADC5_MAX_CHANNEL] = { > + [ADC7_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 0, > + SCALE_HW_CALIB_DEFAULT) > + [ADC7_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 0, > + SCALE_HW_CALIB_DEFAULT) > + [ADC7_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 1, > + SCALE_HW_CALIB_DEFAULT) > + [ADC7_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 3, > + SCALE_HW_CALIB_DEFAULT) > + [ADC7_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 0, > + SCALE_HW_CALIB_PMIC_THERM_PM7) > + [ADC7_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_pu2", 0, > + SCALE_HW_CALIB_THERM_100K_PU_PM7) > + [ADC7_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_pu2", 0, > + SCALE_HW_CALIB_THERM_100K_PU_PM7) > + [ADC7_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_pu2", 0, > + SCALE_HW_CALIB_THERM_100K_PU_PM7) > + [ADC7_AMUX_THM4_100K_PU] = ADC5_CHAN_TEMP("amux_thm4_pu2", 0, > + SCALE_HW_CALIB_THERM_100K_PU_PM7) > + [ADC7_AMUX_THM5_100K_PU] = ADC5_CHAN_TEMP("amux_thm5_pu2", 0, > + SCALE_HW_CALIB_THERM_100K_PU_PM7) > + [ADC7_AMUX_THM6_100K_PU] = ADC5_CHAN_TEMP("amux_thm6_pu2", 0, Use space instead of tab for indentation in all the THMx channels to make it look more in line. > + SCALE_HW_CALIB_THERM_100K_PU_PM7) > + [ADC7_GPIO1_100K_PU] = ADC5_CHAN_TEMP("gpio1_pu2", 0, > + SCALE_HW_CALIB_THERM_100K_PU_PM7) > + [ADC7_GPIO2_100K_PU] = ADC5_CHAN_TEMP("gpio2_pu2", 0, > + SCALE_HW_CALIB_THERM_100K_PU_PM7) > + [ADC7_GPIO3_100K_PU] = ADC5_CHAN_TEMP("gpio3_pu2", 0, > + SCALE_HW_CALIB_THERM_100K_PU_PM7) > + [ADC7_GPIO4_100K_PU] = ADC5_CHAN_TEMP("gpio4_pu2", 0, > + SCALE_HW_CALIB_THERM_100K_PU_PM7) > +}; > + > static const struct adc5_channels adc5_chans_rev2[ADC5_MAX_CHANNEL] = { > [ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 0, > SCALE_HW_CALIB_DEFAULT) > @@ -511,6 +696,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc, > { > const char *name = node->name, *channel_name; > u32 chan, value, varr[2]; > + u32 sid = 0; > int ret; > struct device *dev = adc->dev; > > @@ -520,6 +706,15 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc, > return ret; > } > > + /* Value read from "reg" is virtual channel number */ > + > + /* virtual channel number = sid << 8 | channel number */ > + > + if (adc->data == &adc7_data_pmic) { > + sid = chan >> ADC_CHANNEL_OFFSET; > + chan = chan & ADC_CHANNEL_MASK; > + } > + > if (chan > ADC5_PARALLEL_ISENSE_VBAT_IDATA || > !data->adc_chans[chan].datasheet_name) { > dev_err(dev, "%s invalid channel number %d\n", name, chan); > @@ -528,6 +723,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc, > > /* the channel has DT description */ > prop->channel = chan; > + prop->sid = sid; > > channel_name = of_get_property(node, > "label", NULL) ? : node->name; > @@ -578,8 +774,9 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc, > pr_debug("dig_ver:minor:%d, major:%d\n", dig_version[0], > dig_version[1]); > /* Digital controller >= 5.3 have hw_settle_2 option */ > - if (dig_version[0] >= ADC5_HW_SETTLE_DIFF_MINOR && > - dig_version[1] >= ADC5_HW_SETTLE_DIFF_MAJOR) > + if ((dig_version[0] >= ADC5_HW_SETTLE_DIFF_MINOR && > + dig_version[1] >= ADC5_HW_SETTLE_DIFF_MAJOR) || > + adc->data == &adc7_data_pmic) > ret = adc5_hw_settle_time_from_dt(value, > data->hw_settle_2); > else > @@ -629,6 +826,7 @@ static const struct adc5_data adc5_data_pmic = { > .full_scale_code_volt = 0x70e4, > .full_scale_code_cur = 0x2710, > .adc_chans = adc5_chans_pmic, > + .info = &adc5_info, This belongs in a separate patch along with the change in adc5_data_pmic_rev2 below > .decimation = (unsigned int [ADC5_DECIMATION_SAMPLES_MAX]) > {250, 420, 840}, > .hw_settle_1 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX]) > @@ -639,10 +837,23 @@ static const struct adc5_data adc5_data_pmic = { > 1, 2, 4, 8, 16, 32, 64, 128}, > }; > > +static const struct adc5_data adc7_data_pmic = { > + .full_scale_code_volt = 0x70e4, > + .adc_chans = adc7_chans_pmic, > + .info = &adc7_info, > + .decimation = (unsigned int [ADC5_DECIMATION_SAMPLES_MAX]) > + {85, 340, 1360}, > + .hw_settle_2 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX]) > + {15, 100, 200, 300, 400, 500, 600, 700, > + 1000, 2000, 4000, 8000, 16000, 32000, > + 64000, 128000}, > +}; > + > static const struct adc5_data adc5_data_pmic_rev2 = { > .full_scale_code_volt = 0x4000, > .full_scale_code_cur = 0x1800, > .adc_chans = adc5_chans_rev2, > + .info = &adc5_info, Separate patch. > .decimation = (unsigned int [ADC5_DECIMATION_SAMPLES_MAX]) > {256, 512, 1024}, > .hw_settle_1 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX]) > @@ -659,6 +870,10 @@ static const struct of_device_id adc5_match_table[] = { > .data = &adc5_data_pmic, > }, > { > + .compatible = "qcom,spmi-adc7", > + .data = &adc7_data_pmic, > + }, > + { > .compatible = "qcom,spmi-adc-rev2", > .data = &adc5_data_pmic_rev2, > }, > @@ -752,6 +967,9 @@ static int adc5_probe(struct platform_device *pdev) > adc->regmap = regmap; > adc->dev = dev; > adc->base = reg; > + > + platform_set_drvdata(pdev, adc); > + > init_completion(&adc->complete); > mutex_init(&adc->lock); > > @@ -761,6 +979,8 @@ static int adc5_probe(struct platform_device *pdev) > return ret; > } > > + indio_dev->info = adc->data->info; > + > irq_eoc = platform_get_irq(pdev, 0); > if (irq_eoc < 0) { > if (irq_eoc == -EPROBE_DEFER || irq_eoc == -EINVAL) > @@ -773,23 +993,34 @@ static int adc5_probe(struct platform_device *pdev) > return ret; > } > > + adc->irq_eoc = irq_eoc; > + I think this belongs in a separate patch along with the adc5_exit function below. > indio_dev->dev.parent = dev; > indio_dev->dev.of_node = node; > indio_dev->name = pdev->name; > indio_dev->modes = INDIO_DIRECT_MODE; > - indio_dev->info = &adc5_info; > indio_dev->channels = adc->iio_chans; > indio_dev->num_channels = adc->nchannels; > > return devm_iio_device_register(dev, indio_dev); > } > > +static int adc5_exit(struct platform_device *pdev) > +{ > + struct adc5_chip *adc = platform_get_drvdata(pdev); > + > + if (adc->irq_eoc >= 0) > + disable_irq(adc->irq_eoc); > + return 0; > +} > + > static struct platform_driver adc5_driver = { > .driver = { > .name = "qcom-spmi-adc5.c", > .of_match_table = adc5_match_table, > }, > .probe = adc5_probe, > + .remove = adc5_exit, This really belongs in a separate patch > }; > module_platform_driver(adc5_driver); > > diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c > index 2bb78d1..b6915c2 100644 > --- a/drivers/iio/adc/qcom-vadc-common.c > +++ b/drivers/iio/adc/qcom-vadc-common.c > @@ -89,6 +89,195 @@ static const struct vadc_map_pt adcmap_100k_104ef_104fb_1875_vref[] = { > { 46, 125000 }, > }; > > +static const struct vadc_map_pt adcmap7_die_temp[] = { > + { 433700, 1967}, > + { 473100, 1964}, > + { 512400, 1957}, > + { 551500, 1949}, > + { 590500, 1940}, > + { 629300, 1930}, > + { 667900, 1921}, > + { 706400, 1910}, > + { 744600, 1896}, > + { 782500, 1878}, > + { 820100, 1859}, > + { 857300, 0}, > +}; > + > +/* > + * Resistance to temperature table for 100k pull up for NTCG104EF104. > + */ > +static const struct vadc_map_pt adcmap7_100k[] = { > + { 4250657, -40960 }, > + { 3962085, -39936 }, > + { 3694875, -38912 }, > + { 3447322, -37888 }, > + { 3217867, -36864 }, > + { 3005082, -35840 }, > + { 2807660, -34816 }, > + { 2624405, -33792 }, > + { 2454218, -32768 }, > + { 2296094, -31744 }, > + { 2149108, -30720 }, > + { 2012414, -29696 }, > + { 1885232, -28672 }, > + { 1766846, -27648 }, > + { 1656598, -26624 }, > + { 1553884, -25600 }, > + { 1458147, -24576 }, > + { 1368873, -23552 }, > + { 1285590, -22528 }, > + { 1207863, -21504 }, > + { 1135290, -20480 }, > + { 1067501, -19456 }, > + { 1004155, -18432 }, > + { 944935, -17408 }, > + { 889550, -16384 }, > + { 837731, -15360 }, > + { 789229, -14336 }, > + { 743813, -13312 }, > + { 701271, -12288 }, > + { 661405, -11264 }, > + { 624032, -10240 }, > + { 588982, -9216 }, > + { 556100, -8192 }, > + { 525239, -7168 }, > + { 496264, -6144 }, > + { 469050, -5120 }, > + { 443480, -4096 }, > + { 419448, -3072 }, > + { 396851, -2048 }, > + { 375597, -1024 }, > + { 355598, 0 }, > + { 336775, 1024 }, > + { 319052, 2048 }, > + { 302359, 3072 }, > + { 286630, 4096 }, > + { 271806, 5120 }, > + { 257829, 6144 }, > + { 244646, 7168 }, > + { 232209, 8192 }, > + { 220471, 9216 }, > + { 209390, 10240 }, > + { 198926, 11264 }, > + { 189040, 12288 }, > + { 179698, 13312 }, > + { 170868, 14336 }, > + { 162519, 15360 }, > + { 154622, 16384 }, > + { 147150, 17408 }, > + { 140079, 18432 }, > + { 133385, 19456 }, > + { 127046, 20480 }, > + { 121042, 21504 }, > + { 115352, 22528 }, > + { 109960, 23552 }, > + { 104848, 24576 }, > + { 100000, 25600 }, > + { 95402, 26624 }, > + { 91038, 27648 }, > + { 86897, 28672 }, > + { 82965, 29696 }, > + { 79232, 30720 }, > + { 75686, 31744 }, > + { 72316, 32768 }, > + { 69114, 33792 }, > + { 66070, 34816 }, > + { 63176, 35840 }, > + { 60423, 36864 }, > + { 57804, 37888 }, > + { 55312, 38912 }, > + { 52940, 39936 }, > + { 50681, 40960 }, > + { 48531, 41984 }, > + { 46482, 43008 }, > + { 44530, 44032 }, > + { 42670, 45056 }, > + { 40897, 46080 }, > + { 39207, 47104 }, > + { 37595, 48128 }, > + { 36057, 49152 }, > + { 34590, 50176 }, > + { 33190, 51200 }, > + { 31853, 52224 }, > + { 30577, 53248 }, > + { 29358, 54272 }, > + { 28194, 55296 }, > + { 27082, 56320 }, > + { 26020, 57344 }, > + { 25004, 58368 }, > + { 24033, 59392 }, > + { 23104, 60416 }, > + { 22216, 61440 }, > + { 21367, 62464 }, > + { 20554, 63488 }, > + { 19776, 64512 }, > + { 19031, 65536 }, > + { 18318, 66560 }, > + { 17636, 67584 }, > + { 16982, 68608 }, > + { 16355, 69632 }, > + { 15755, 70656 }, > + { 15180, 71680 }, > + { 14628, 72704 }, > + { 14099, 73728 }, > + { 13592, 74752 }, > + { 13106, 75776 }, > + { 12640, 76800 }, > + { 12192, 77824 }, > + { 11762, 78848 }, > + { 11350, 79872 }, > + { 10954, 80896 }, > + { 10574, 81920 }, > + { 10209, 82944 }, > + { 9858, 83968 }, > + { 9521, 84992 }, > + { 9197, 86016 }, > + { 8886, 87040 }, > + { 8587, 88064 }, > + { 8299, 89088 }, > + { 8023, 90112 }, > + { 7757, 91136 }, > + { 7501, 92160 }, > + { 7254, 93184 }, > + { 7017, 94208 }, > + { 6789, 95232 }, > + { 6570, 96256 }, > + { 6358, 97280 }, > + { 6155, 98304 }, > + { 5959, 99328 }, > + { 5770, 100352 }, > + { 5588, 101376 }, > + { 5412, 102400 }, > + { 5243, 103424 }, > + { 5080, 104448 }, > + { 4923, 105472 }, > + { 4771, 106496 }, > + { 4625, 107520 }, > + { 4484, 108544 }, > + { 4348, 109568 }, > + { 4217, 110592 }, > + { 4090, 111616 }, > + { 3968, 112640 }, > + { 3850, 113664 }, > + { 3736, 114688 }, > + { 3626, 115712 }, > + { 3519, 116736 }, > + { 3417, 117760 }, > + { 3317, 118784 }, > + { 3221, 119808 }, > + { 3129, 120832 }, > + { 3039, 121856 }, > + { 2952, 122880 }, > + { 2868, 123904 }, > + { 2787, 124928 }, > + { 2709, 125952 }, > + { 2633, 126976 }, > + { 2560, 128000 }, > + { 2489, 129024 }, > + { 2420, 130048 } > +}; > + > static int qcom_vadc_scale_hw_calib_volt( > const struct vadc_prescale_ratio *prescale, > const struct adc5_data *data, > @@ -97,6 +286,10 @@ static int qcom_vadc_scale_hw_calib_therm( > const struct vadc_prescale_ratio *prescale, > const struct adc5_data *data, > u16 adc_code, int *result_mdec); > +static int qcom_vadc7_scale_hw_calib_therm( > + const struct vadc_prescale_ratio *prescale, > + const struct adc5_data *data, > + u16 adc_code, int *result_mdec); > static int qcom_vadc_scale_hw_smb_temp( > const struct vadc_prescale_ratio *prescale, > const struct adc5_data *data, > @@ -109,12 +302,20 @@ static int qcom_vadc_scale_hw_calib_die_temp( > const struct vadc_prescale_ratio *prescale, > const struct adc5_data *data, > u16 adc_code, int *result_mdec); > +static int qcom_vadc7_scale_hw_calib_die_temp( > + const struct vadc_prescale_ratio *prescale, > + const struct adc5_data *data, > + u16 adc_code, int *result_mdec); > > static struct qcom_adc5_scale_type scale_adc5_fn[] = { > [SCALE_HW_CALIB_DEFAULT] = {qcom_vadc_scale_hw_calib_volt}, > [SCALE_HW_CALIB_THERM_100K_PULLUP] = {qcom_vadc_scale_hw_calib_therm}, > [SCALE_HW_CALIB_XOTHERM] = {qcom_vadc_scale_hw_calib_therm}, > + [SCALE_HW_CALIB_THERM_100K_PU_PM7] = { > + qcom_vadc7_scale_hw_calib_therm}, > [SCALE_HW_CALIB_PMIC_THERM] = {qcom_vadc_scale_hw_calib_die_temp}, > + [SCALE_HW_CALIB_PMIC_THERM_PM7] = { > + qcom_vadc7_scale_hw_calib_die_temp}, > [SCALE_HW_CALIB_PM5_CHG_TEMP] = {qcom_vadc_scale_hw_chg5_temp}, > [SCALE_HW_CALIB_PM5_SMB_TEMP] = {qcom_vadc_scale_hw_smb_temp}, > }; > @@ -291,6 +492,32 @@ static int qcom_vadc_scale_code_voltage_factor(u16 adc_code, > return (int) voltage; > } > > +static int qcom_vadc7_scale_hw_calib_therm( > + const struct vadc_prescale_ratio *prescale, > + const struct adc5_data *data, > + u16 adc_code, int *result_mdec) > +{ > + s64 resistance = adc_code; > + int ret, result; > + > + if (adc_code >= RATIO_MAX_ADC7) > + return -EINVAL; > + > + /* (ADC code * R_PULLUP (100Kohm)) / (full_scale_code - ADC code)*/ > + resistance *= R_PU_100K; > + resistance = div64_s64(resistance, RATIO_MAX_ADC7 - adc_code); > + > + ret = qcom_vadc_map_voltage_temp(adcmap7_100k, > + ARRAY_SIZE(adcmap7_100k), > + resistance, &result); > + if (ret) > + return ret; > + > + *result_mdec = result; > + > + return 0; > +} > + > static int qcom_vadc_scale_hw_calib_volt( > const struct vadc_prescale_ratio *prescale, > const struct adc5_data *data, > @@ -330,6 +557,39 @@ static int qcom_vadc_scale_hw_calib_die_temp( > return 0; > } > > +static int qcom_vadc7_scale_hw_calib_die_temp( > + const struct vadc_prescale_ratio *prescale, > + const struct adc5_data *data, > + u16 adc_code, int *result_mdec) > +{ > + > + int voltage, vtemp0, temp, i = ARRAY_SIZE(adcmap7_die_temp) - 1; > + > + voltage = qcom_vadc_scale_code_voltage_factor(adc_code, > + prescale, data, 1); > + > + if (adcmap7_die_temp[0].x > voltage) { > + *result_mdec = DIE_TEMP_ADC7_SCALE_1; > + return 0; > + } else if (adcmap7_die_temp[i].x <= voltage) { > + *result_mdec = DIE_TEMP_ADC7_MAX; > + return 0; > + } > + > + for (i = 0; i < ARRAY_SIZE(adcmap7_die_temp); i++) > + if (adcmap7_die_temp[i].x > voltage) > + break; > + > + vtemp0 = adcmap7_die_temp[i - 1].x; > + voltage = voltage - vtemp0; > + temp = div64_s64(voltage * DIE_TEMP_ADC7_SCALE_FACTOR, > + adcmap7_die_temp[i - 1].y); > + temp += DIE_TEMP_ADC7_SCALE_1 + (DIE_TEMP_ADC7_SCALE_2 * (i - 1)); > + *result_mdec = temp; > + > + return 0; > +} > + > static int qcom_vadc_scale_hw_smb_temp( > const struct vadc_prescale_ratio *prescale, > const struct adc5_data *data, > diff --git a/drivers/iio/adc/qcom-vadc-common.h b/drivers/iio/adc/qcom-vadc-common.h > index e074902a..d195e83 100644 > --- a/drivers/iio/adc/qcom-vadc-common.h > +++ b/drivers/iio/adc/qcom-vadc-common.h > @@ -49,6 +49,14 @@ > #define ADC5_FULL_SCALE_CODE 0x70e4 > #define ADC5_USR_DATA_CHECK 0x8000 > > +#define R_PU_100K 100000 > +#define RATIO_MAX_ADC7 0x4000 > + > +#define DIE_TEMP_ADC7_SCALE_1 -60000 > +#define DIE_TEMP_ADC7_SCALE_2 20000 > +#define DIE_TEMP_ADC7_SCALE_FACTOR 1000 > +#define DIE_TEMP_ADC7_MAX 160000 > + > /** > * struct vadc_map_pt - Map the graph representation for ADC channel > * @x: Represent the ADC digitized code. > @@ -110,8 +118,12 @@ struct vadc_prescale_ratio { > * lookup table. The hardware applies offset/slope to adc code. > * SCALE_HW_CALIB_XOTHERM: Returns XO thermistor voltage in millidegC using > * 100k pullup. The hardware applies offset/slope to adc code. > + * SCALE_HW_CALIB_THERM_100K_PU_PM7: Returns temperature in millidegC using > + * lookup table for PMIC7. The hardware applies offset/slope to adc code. > * SCALE_HW_CALIB_PMIC_THERM: Returns result in milli degree's Centigrade. > * The hardware applies offset/slope to adc code. > + * SCALE_HW_CALIB_PMIC_THERM: Returns result in milli degree's Centigrade. > + * The hardware applies offset/slope to adc code. This is for PMIC7. > * SCALE_HW_CALIB_PM5_CHG_TEMP: Returns result in millidegrees for PMIC5 > * charger temperature. > * SCALE_HW_CALIB_PM5_SMB_TEMP: Returns result in millidegrees for PMIC5 > @@ -126,7 +138,9 @@ enum vadc_scale_fn_type { > SCALE_HW_CALIB_DEFAULT, > SCALE_HW_CALIB_THERM_100K_PULLUP, > SCALE_HW_CALIB_XOTHERM, > + SCALE_HW_CALIB_THERM_100K_PU_PM7, > SCALE_HW_CALIB_PMIC_THERM, > + SCALE_HW_CALIB_PMIC_THERM_PM7, > SCALE_HW_CALIB_PM5_CHG_TEMP, > SCALE_HW_CALIB_PM5_SMB_TEMP, > SCALE_HW_CALIB_INVALID, > @@ -136,6 +150,7 @@ struct adc5_data { > const u32 full_scale_code_volt; > const u32 full_scale_code_cur; > const struct adc5_channels *adc_chans; > + const struct iio_info *info; > unsigned int *decimation; > unsigned int *hw_settle_1; > unsigned int *hw_settle_2; > -- > The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, > a Linux Foundation Collaborative Project