Re: [PATCH V3 3/4] iio: adc: Add support for PMIC7 ADC

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux