All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tomer Maimon <tmaimon77@gmail.com>
To: openbmc@lists.ozlabs.org
Cc: Andrew Jeffery <andrew@aj.id.au>,
	Tomer Maimon <tmaimon77@gmail.com>,
	benjaminfair@google.com
Subject: [PATCH linux dev-5.8 v2 02/11] iio: adc: add calibration support to npcm ADC
Date: Tue,  5 Jan 2021 15:44:59 +0200	[thread overview]
Message-ID: <20210105134508.225702-3-tmaimon77@gmail.com> (raw)
In-Reply-To: <20210105134508.225702-1-tmaimon77@gmail.com>

Add calibration to improve accuracy measurement when using
internal referance voltage.

the calibration values taken from the FUSE module.

Signed-off-by: Tomer Maimon <tmaimon77@gmail.com>
---
 drivers/iio/adc/npcm_adc.c | 191 +++++++++++++++++++++++++++++++++++++
 1 file changed, 191 insertions(+)

diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c
index 83bad2d5575d..02628b7eaca1 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,40 @@ 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_TIMEOUT	0xDEADBEEF
+
 #define NPCM_ADC_CHAN(ch) {					\
 	.type = IIO_VOLTAGE,					\
 	.indexed = 1,						\
@@ -71,6 +107,133 @@ static const struct iio_chan_spec npcm_adc_iio_channels[] = {
 	NPCM_ADC_CHAN(7),
 };
 
+static int npcm750_fuse_wait_for_ready(struct regmap *fuse_regmap, u32 timeout)
+{
+	u32 time = timeout;
+	u32 fstreg;
+
+	while (--time > 1) {
+		regmap_read(fuse_regmap, NPCM7XX_FST, &fstreg);
+		if (fstreg & NPCM7XX_FST_RDY) {
+			regmap_write_bits(fuse_regmap, NPCM7XX_FST,
+					  NPCM7XX_FST_RDST, NPCM7XX_FST_RDST);
+			return 0;
+		}
+	}
+
+	/* try to clear the status in case it was set */
+	regmap_write_bits(fuse_regmap, NPCM7XX_FST, NPCM7XX_FST_RDST,
+			  NPCM7XX_FST_RDST);
+
+	return -EINVAL;
+}
+
+static void npcm750_fuse_read(struct regmap *fuse_regmap, u32 addr, u8 *data)
+{
+	u32 val;
+
+	npcm750_fuse_wait_for_ready(fuse_regmap, FUSE_READ_TIMEOUT);
+
+	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);
+
+	npcm750_fuse_wait_for_ready(fuse_regmap, FUSE_READ_TIMEOUT);
+	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;
+
+	if (of_device_is_compatible(np, "nuvoton,npcm750-adc")) {
+		fuse_regmap = syscon_regmap_lookup_by_compatible
+			("nuvoton,npcm750-fuse");
+		if (IS_ERR(fuse_regmap)) {
+			dev_warn(&pdev->dev, "Failed to find nuvoton,npcm750-fuse\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 Clibration 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 +288,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 +328,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 +438,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


  parent reply	other threads:[~2021-01-05 13:53 UTC|newest]

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

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=20210105134508.225702-3-tmaimon77@gmail.com \
    --to=tmaimon77@gmail.com \
    --cc=andrew@aj.id.au \
    --cc=benjaminfair@google.com \
    --cc=openbmc@lists.ozlabs.org \
    /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.