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
next prev 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.