All of lore.kernel.org
 help / color / mirror / Atom feed
From: Joel Stanley <joel@jms.id.au>
To: Tomer Maimon <tmaimon77@gmail.com>
Cc: Andrew Jeffery <andrew@aj.id.au>,
	OpenBMC Maillist <openbmc@lists.ozlabs.org>,
	Benjamin Fair <benjaminfair@google.com>
Subject: Re: [PATCH linux dev-5.8 v3 03/12] iio: adc: add calibration support to npcm ADC
Date: Fri, 15 Jan 2021 06:25:35 +0000	[thread overview]
Message-ID: <CACPK8Xc44fMUy9NKCYLi2eVU681p4A2F6r7F8OZPG+HmeYa69A@mail.gmail.com> (raw)
In-Reply-To: <20210113200010.71845-4-tmaimon77@gmail.com>

On Wed, 13 Jan 2021 at 20:00, Tomer Maimon <tmaimon77@gmail.com> wrote:
>
> Add calibration to improve accuracy measurement when using
> internal reference voltage.
>
> the calibration values taken from the FUSE module.
>
> Signed-off-by: Tomer Maimon <tmaimon77@gmail.com>

Reviewed-by: Joel Stanley <joel@jms.id.au>

When submitting this to mainline you should consider putting the fuse
reading code in it's own driver if it is to be used by other
components in your system.

> ---
>  drivers/iio/adc/npcm_adc.c | 178 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 178 insertions(+)
>
> diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c
> index 83bad2d5575d..081378b98fa9 100644
> --- a/drivers/iio/adc/npcm_adc.c
> +++ b/drivers/iio/adc/npcm_adc.c
> @@ -17,6 +17,8 @@
>  #include <linux/reset.h>
>
>  struct npcm_adc {
> +       u32 R05;
> +       u32 R15;
>         bool int_status;
>         u32 adc_sample_hz;
>         struct device *dev;
> @@ -51,6 +53,41 @@ struct npcm_adc {
>  #define NPCM_RESOLUTION_BITS           10
>  #define NPCM_INT_VREF_MV               2000
>
> +/* FUSE registers */
> +#define NPCM7XX_FST            0x00
> +#define NPCM7XX_FADDR          0x04
> +#define NPCM7XX_FDATA          0x08
> +#define NPCM7XX_FCFG           0x0C
> +#define NPCM7XX_FCTL           0x14
> +
> +/* FST Register Bits */
> +#define NPCM7XX_FST_RDY                BIT(0)
> +#define NPCM7XX_FST_RDST       BIT(1)
> +
> +/* FADDR Register Bits */
> +#define NPCM7XX_FADDR_BYTEADDR         BIT(0)
> +#define NPCM7XX_FADDR_BYTEADDR_MASK    GENMASK(9, 0)
> +
> +/* FADDR Register Bits */
> +#define NPCM7XX_FDATA_DATA             BIT(0)
> +#define NPCM7XX_FDATA_CLEAN_VALUE      BIT(1)
> +#define NPCM7XX_FDATA_DATA_MASK                GENMASK(7, 0)
> +
> +/* FCTL Register Bits */
> +#define NPCM7XX_FCTL_RDST              BIT(1)
> +
> +/* ADC Calibration Definition */
> +#define NPCM_INT_1500MV                768
> +#define NPCM_INT_1000MV                512
> +#define NPCM_ADC_MIN_VAL       0
> +#define NPCM_ADC_MAX_VAL       1023
> +
> +#define FUSE_CALIB_ADDR                24
> +#define FUSE_CALIB_SIZE                8
> +#define DATA_CALIB_SIZE                4
> +#define FUSE_READ_SLEEP                500
> +#define FUSE_READ_TIMEOUT      1000000
> +
>  #define NPCM_ADC_CHAN(ch) {                                    \
>         .type = IIO_VOLTAGE,                                    \
>         .indexed = 1,                                           \
> @@ -71,6 +108,119 @@ static const struct iio_chan_spec npcm_adc_iio_channels[] = {
>         NPCM_ADC_CHAN(7),
>  };
>
> +static void npcm750_fuse_read(struct regmap *fuse_regmap, u32 addr, u8 *data)
> +{
> +       u32 val;
> +       u32 fstreg;
> +
> +       regmap_read_poll_timeout(fuse_regmap, NPCM7XX_FST, fstreg,
> +                                fstreg & NPCM7XX_FST_RDY, FUSE_READ_SLEEP,
> +                                FUSE_READ_TIMEOUT);
> +       regmap_write_bits(fuse_regmap, NPCM7XX_FST,
> +                         NPCM7XX_FST_RDST, NPCM7XX_FST_RDST);
> +
> +       regmap_write_bits(fuse_regmap, NPCM7XX_FADDR,
> +                         NPCM7XX_FADDR_BYTEADDR_MASK, addr);
> +       regmap_read(fuse_regmap, NPCM7XX_FADDR, &val);
> +       regmap_write(fuse_regmap, NPCM7XX_FCTL, NPCM7XX_FCTL_RDST);
> +
> +       regmap_read_poll_timeout(fuse_regmap, NPCM7XX_FST, fstreg,
> +                                fstreg & NPCM7XX_FST_RDY, FUSE_READ_SLEEP,
> +                                FUSE_READ_TIMEOUT);
> +       regmap_write_bits(fuse_regmap, NPCM7XX_FST,
> +                         NPCM7XX_FST_RDST, NPCM7XX_FST_RDST);
> +
> +       regmap_read(fuse_regmap, NPCM7XX_FDATA, &val);
> +       *data = (u8)val;
> +
> +       regmap_write_bits(fuse_regmap, NPCM7XX_FDATA, NPCM7XX_FDATA_DATA_MASK,
> +                         NPCM7XX_FDATA_CLEAN_VALUE);
> +}
> +
> +static int npcm750_ECC_to_nibble(u8 ECC, u8 nibble)
> +{
> +       u8 nibble_b0 = (nibble >> 0) & BIT(0);
> +       u8 nibble_b1 = (nibble >> 1) & BIT(0);
> +       u8 nibble_b2 = (nibble >> 2) & BIT(0);
> +       u8 nibble_b3 = (nibble >> 3) & BIT(0);
> +       u8 tmp_ECC = nibble;
> +
> +       tmp_ECC |= (nibble_b0 ^ nibble_b1) << 4 | (nibble_b2 ^ nibble_b3) << 5 |
> +               (nibble_b0 ^ nibble_b2) << 6  | (nibble_b1 ^ nibble_b3) << 7;
> +
> +       if (tmp_ECC != ECC)
> +               return -EINVAL;
> +
> +       return 0;
> +}
> +
> +static int npcm750_ECC_to_byte(u16 ECC, u8 *Byte)
> +{
> +       u8 nibble_L, nibble_H;
> +       u8 ECC_L, ECC_H;
> +
> +       ECC_H = ECC >> 8;
> +       nibble_H = ECC_H & 0x0F;
> +       ECC_L = ECC >> 0;
> +       nibble_L = ECC_L & 0x0F;
> +
> +       if (npcm750_ECC_to_nibble(ECC_H, nibble_H) != 0 ||
> +           npcm750_ECC_to_nibble(ECC_L, nibble_L) != 0)
> +               return -EINVAL;
> +
> +       *Byte = nibble_H << 4 | nibble_L << 0;
> +
> +       return 0;
> +}
> +
> +static int npcm750_read_nibble_parity(u8 *block_ECC, u8 *ADC_calib)
> +{
> +       int i;
> +       u16 ECC;
> +
> +       for (i = 0; i < DATA_CALIB_SIZE; i++) {
> +               memcpy(&ECC, block_ECC + (i * 2), 2);
> +               if (npcm750_ECC_to_byte(ECC, &ADC_calib[i]) != 0)
> +                       return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static int npcm750_fuse_calibration_read(struct platform_device *pdev,
> +                                        struct npcm_adc *info)
> +{
> +       struct device_node *np = pdev->dev.of_node;
> +       struct regmap *fuse_regmap;
> +       ssize_t bytes_read = 0;
> +       u8 read_buf[8];
> +       u32 ADC_calib;
> +       u32 addr = FUSE_CALIB_ADDR;
> +
> +       fuse_regmap = syscon_regmap_lookup_by_phandle(np, "syscon");
> +       if (IS_ERR(fuse_regmap)) {
> +               dev_warn(&pdev->dev, "Failed to find syscon\n");
> +               return PTR_ERR(fuse_regmap);
> +       }
> +
> +       while (bytes_read < FUSE_CALIB_SIZE) {
> +               npcm750_fuse_read(fuse_regmap, addr,
> +                                 &read_buf[bytes_read]);
> +               bytes_read++;
> +               addr++;
> +       }
> +
> +       if (npcm750_read_nibble_parity(read_buf, (u8 *)&ADC_calib)) {
> +               dev_warn(info->dev, "FUSE Calibration read failed\n");
> +               return -EINVAL;
> +       }
> +
> +       info->R05 = ADC_calib & 0xFFFF;
> +       info->R15 = ADC_calib >> 16;
> +
> +       return 0;
> +}
> +
>  static irqreturn_t npcm_adc_isr(int irq, void *data)
>  {
>         u32 regtemp;
> @@ -125,6 +275,29 @@ static int npcm_adc_read(struct npcm_adc *info, int *val, u8 channel)
>         return 0;
>  }
>
> +static void npcm_adc_calibration(int *val, struct npcm_adc *info)
> +{
> +       int mul_val;
> +       int offset_val;
> +
> +       mul_val = NPCM_INT_1000MV * (*val - info->R15);
> +       if (mul_val < 0) {
> +               mul_val = mul_val * -1;
> +               offset_val = DIV_ROUND_CLOSEST(mul_val,
> +                                              (info->R15 - info->R05));
> +               *val = NPCM_INT_1500MV - offset_val;
> +       } else {
> +               offset_val = DIV_ROUND_CLOSEST(mul_val,
> +                                              (info->R15 - info->R05));
> +               *val = NPCM_INT_1500MV + offset_val;
> +       }
> +
> +       if (*val < NPCM_ADC_MIN_VAL)
> +               *val = NPCM_ADC_MIN_VAL;
> +       if (*val > NPCM_ADC_MAX_VAL)
> +               *val = NPCM_ADC_MAX_VAL;
> +}
> +
>  static int npcm_adc_read_raw(struct iio_dev *indio_dev,
>                              struct iio_chan_spec const *chan, int *val,
>                              int *val2, long mask)
> @@ -142,6 +315,10 @@ static int npcm_adc_read_raw(struct iio_dev *indio_dev,
>                         dev_err(info->dev, "NPCM ADC read failed\n");
>                         return ret;
>                 }
> +
> +               if ((info->R05 || info->R15) && IS_ERR(info->vref))
> +                       npcm_adc_calibration(val, info);
> +
>                 return IIO_VAL_INT;
>         case IIO_CHAN_INFO_SCALE:
>                 if (!IS_ERR(info->vref)) {
> @@ -248,6 +425,7 @@ static int npcm_adc_probe(struct platform_device *pdev)
>                           info->regs + NPCM_ADCCON);
>         }
>
> +       npcm750_fuse_calibration_read(pdev, info);
>         init_waitqueue_head(&info->wq);
>
>         reg_con = ioread32(info->regs + NPCM_ADCCON);
> --
> 2.22.0
>

  reply	other threads:[~2021-01-15  6:27 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-13 19:59 [PATCH linux dev-5.8 v3 00/12] Add NPCM7xx patches to dev-5.8 Tomer Maimon
2021-01-13 19:59 ` [PATCH linux dev-5.8 v3 01/12] clk: npcm7xx: add read only flag to divider clocks Tomer Maimon
2021-01-15  6:22   ` Joel Stanley
2021-01-13 20:00 ` [PATCH linux dev-5.8 v3 02/12] dt-binding: iio: add syscon property to NPCM ADC Tomer Maimon
2021-01-15  6:27   ` Joel Stanley
2021-01-13 20:00 ` [PATCH linux dev-5.8 v3 03/12] iio: adc: add calibration support to npcm ADC Tomer Maimon
2021-01-15  6:25   ` Joel Stanley [this message]
2021-01-13 20:00 ` [PATCH linux dev-5.8 v3 04/12] dts: npcm750: add fuse regmap support node Tomer Maimon
2021-01-15  6:27   ` Joel Stanley
2021-01-13 20:00 ` [PATCH linux dev-5.8 v3 05/12] dt-binding: watchdog: Add DT restart priority and reset type Tomer Maimon
2021-01-13 20:00 ` [PATCH linux dev-5.8 v3 06/12] watchdog: npcm: Add DT restart priority and reset type support Tomer Maimon
2021-01-13 20:00 ` [PATCH linux dev-5.8 v3 07/12] pinctrl: npcm7xx: Add HGPIO pin support to NPCM7xx pinctrl driver Tomer Maimon
2021-01-14  6:21   ` Tomer Maimon
2021-01-13 20:00 ` [PATCH linux dev-5.8 v3 08/12] pinctrl: pinconf: add pin persist configuration Tomer Maimon
2021-01-13 20:00 ` [PATCH linux dev-5.8 v3 09/12] pinctrl: npcm7xx: Add pin persist configuration support Tomer Maimon
2021-01-13 20:00 ` [PATCH linux dev-5.8 v3 10/12] spi: npcm-pspi: Add full duplex support Tomer Maimon
2021-01-13 20:00 ` [PATCH linux dev-5.8 v3 11/12] dt-binding: bmc: add NPCM7XX JTAG master documentation Tomer Maimon
2021-01-13 20:00 ` [PATCH linux dev-5.8 v3 12/12] misc: npcm7xx-jtag-master: add NPCM7xx JTAG master driver Tomer Maimon
2021-01-15  6:45 ` [PATCH linux dev-5.8 v3 00/12] Add NPCM7xx patches to dev-5.8 Joel Stanley

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CACPK8Xc44fMUy9NKCYLi2eVU681p4A2F6r7F8OZPG+HmeYa69A@mail.gmail.com \
    --to=joel@jms.id.au \
    --cc=andrew@aj.id.au \
    --cc=benjaminfair@google.com \
    --cc=openbmc@lists.ozlabs.org \
    --cc=tmaimon77@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.