From patchwork Wed Sep 8 15:54:51 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Olivier Moysan X-Patchwork-Id: 12481433 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.1 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 66C5AC433F5 for ; Wed, 8 Sep 2021 15:58:11 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 354EB61154 for ; Wed, 8 Sep 2021 15:58:11 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 354EB61154 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=foss.st.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=6ZVO3/51a2HxAD/gQMrEMGX3qZKp4GPTvH44NLjAIOc=; b=fN/tH9cOcI3KqJ vIydEzI9OReyZXf+scv8WB+1OIQ1DGcS2swmn5a8rSu3u/C6hl0P2KPpSxNcMBEJP8kJuT0TsXtt9 BO2HuuKptb7AtHCFN9voVPeEKlnWXUbK4lHSgM2iPq7fHjZL3k0GlFboRJz9l7wcBUCof1DzOK8KO paq/l9G+jJmC6Wm9D4CeAtrGd6vSz1Csi1ZgR91VnzgswyFrsX+8CiTRv6H4I2MEPuCgf7tSI+3G0 1a9cRHMqi6/xgqT1NUVmRo3MPPLaBW9Yj3A3rGt8J0h9UR++4h+iAv9lpREErZhdAGu8NA+M4Af/3 xqv5ipgX+5WN0/PZbXLw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mNzwA-0076Ek-Cu; Wed, 08 Sep 2021 15:56:34 +0000 Received: from mx08-00178001.pphosted.com ([91.207.212.93] helo=mx07-00178001.pphosted.com) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mNzvA-0075wF-D4 for linux-arm-kernel@lists.infradead.org; Wed, 08 Sep 2021 15:55:34 +0000 Received: from pps.filterd (m0046660.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.1.2/8.16.0.43) with SMTP id 188FpQ8Z005816; Wed, 8 Sep 2021 17:55:26 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=selector1; bh=BG/Ki6ZeekgfBPE/MfIcKhxRwcZEyXIAfl11Ncp86lk=; b=3+k4l0ktw1rfzTwgPPsVvtPLqfxnRWsjdSVy/exxCsaJE9YXbj7Yx2ajm2GbWjfmoXeP q9y6JCzTfZJrnTY4++eY+g/szFU93Xp4zHb3RSnyHHXTLRxPMt9UvMrBoO3qlLOrPOzW ctSgnchZ3IjE8gPoX11L6LFZ0bhndxw59aVBYKh+nF56vwfV8KjGzqJpELF6OcPjr2gm SCli++QlCGWpxZNuXwM21SJ7XZrT65IUfZKSchIB7t9i9WmaLWfKu06oWy76fXbSazSu 3VpuXcHvOOK1nYfCJU/jxey4LUUrrVZK1McynXaaWru3qs/dl5j1fQvXE7f2vOcGUYhK Zw== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com with ESMTP id 3axtha2b9f-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 08 Sep 2021 17:55:26 +0200 Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 43692100034; Wed, 8 Sep 2021 17:55:25 +0200 (CEST) Received: from Webmail-eu.st.com (sfhdag1node3.st.com [10.75.127.3]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 32E562203DE; Wed, 8 Sep 2021 17:55:25 +0200 (CEST) Received: from localhost (10.75.127.48) by SFHDAG1NODE3.st.com (10.75.127.3) with Microsoft SMTP Server (TLS) id 15.0.1497.18; Wed, 8 Sep 2021 17:55:24 +0200 From: Olivier Moysan To: Alexandre Torgue , Arnaud Pouliquen , Fabrice Gasnier , Jonathan Cameron , Lars-Peter Clausen , Maxime Coquelin , Olivier Moysan , Rob Herring CC: , , , , , Subject: [PATCH 6/7] iio: adc: stm32-adc: add vrefint calibration support Date: Wed, 8 Sep 2021 17:54:51 +0200 Message-ID: <20210908155452.25458-7-olivier.moysan@foss.st.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210908155452.25458-1-olivier.moysan@foss.st.com> References: <20210908155452.25458-1-olivier.moysan@foss.st.com> MIME-Version: 1.0 X-Originating-IP: [10.75.127.48] X-ClientProxiedBy: SFHDAG2NODE1.st.com (10.75.127.4) To SFHDAG1NODE3.st.com (10.75.127.3) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.182.1,Aquarius:18.0.790,Hydra:6.0.391,FMLib:17.0.607.475 definitions=2021-09-08_06,2021-09-07_02,2020-04-07_01 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210908_085532_784615_B0DE48B4 X-CRM114-Status: GOOD ( 25.86 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add support of vrefint calibration. If a channel is labeled as vrefint, get vrefint calibration from non volatile memory for this channel. A conversion on vrefint channel allows to update scale factor according to vrefint deviation, compared to vrefint calibration value. Signed-off-by: Olivier Moysan --- drivers/iio/adc/stm32-adc.c | 88 ++++++++++++++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index ef3d2af98025..9e52a7de9b16 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #define STM32_ADC_TIMEOUT (msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000)) #define STM32_ADC_HW_STOP_DELAY_MS 100 #define STM32_ADC_CHAN_NONE -1 +#define STM32_ADC_VREFINT_VOLTAGE 3300 #define STM32_DMA_BUFFER_SIZE PAGE_SIZE @@ -79,6 +81,7 @@ enum stm32_adc_extsel { }; enum stm32_adc_int_ch { + STM32_ADC_INT_CH_NONE = -1, STM32_ADC_INT_CH_VDDCORE, STM32_ADC_INT_CH_VREFINT, STM32_ADC_INT_CH_VBAT, @@ -137,6 +140,16 @@ struct stm32_adc_regs { int shift; }; +/** + * struct stm32_adc_vrefint - stm32 ADC internal reference voltage data + * @vrefint_cal: vrefint calibration value from nvmem + * @vrefint_data: vrefint actual value + */ +struct stm32_adc_vrefint { + u32 vrefint_cal; + u32 vrefint_data; +}; + /** * struct stm32_adc_regspec - stm32 registers definition * @dr: data register offset @@ -186,6 +199,7 @@ struct stm32_adc; * @unprepare: optional unprepare routine (disable, power-down) * @irq_clear: routine to clear irqs * @smp_cycles: programmable sampling time (ADC clock cycles) + * @ts_vrefint_ns: vrefint minimum sampling time in ns */ struct stm32_adc_cfg { const struct stm32_adc_regspec *regs; @@ -199,6 +213,7 @@ struct stm32_adc_cfg { void (*unprepare)(struct iio_dev *); void (*irq_clear)(struct iio_dev *indio_dev, u32 msk); const unsigned int *smp_cycles; + const unsigned int ts_vrefint_ns; }; /** @@ -223,6 +238,7 @@ struct stm32_adc_cfg { * @pcsel: bitmask to preselect channels on some devices * @smpr_val: sampling time settings (e.g. smpr1 / smpr2) * @cal: optional calibration data on some devices + * @vrefint: internal reference voltage data * @chan_name: channel name array * @num_diff: number of differential channels * @int_ch: internal channel indexes array @@ -248,6 +264,7 @@ struct stm32_adc { u32 pcsel; u32 smpr_val[2]; struct stm32_adc_calib cal; + struct stm32_adc_vrefint vrefint; char chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ]; u32 num_diff; int int_ch[STM32_ADC_INT_CH_NB]; @@ -1331,15 +1348,35 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, ret = stm32_adc_single_conv(indio_dev, chan, val); else ret = -EINVAL; + + /* If channel mask corresponds to vrefint, store data */ + if (adc->int_ch[STM32_ADC_INT_CH_VREFINT] == chan->channel) + adc->vrefint.vrefint_data = *val; + iio_device_release_direct_mode(indio_dev); return ret; case IIO_CHAN_INFO_SCALE: if (chan->differential) { - *val = adc->common->vref_mv * 2; + if (adc->vrefint.vrefint_data && + adc->vrefint.vrefint_cal) { + *val = STM32_ADC_VREFINT_VOLTAGE * 2 * + adc->vrefint.vrefint_cal / + adc->vrefint.vrefint_data; + } else { + *val = adc->common->vref_mv * 2; + } *val2 = chan->scan_type.realbits; } else { - *val = adc->common->vref_mv; + /* Use vrefint data if available */ + if (adc->vrefint.vrefint_data && + adc->vrefint.vrefint_cal) { + *val = STM32_ADC_VREFINT_VOLTAGE * + adc->vrefint.vrefint_cal / + adc->vrefint.vrefint_data; + } else { + *val = adc->common->vref_mv; + } *val2 = chan->scan_type.realbits; } return IIO_VAL_FRACTIONAL_LOG2; @@ -1907,6 +1944,35 @@ static int stm32_adc_legacy_chan_init(struct iio_dev *indio_dev, return scan_index; } +static int stm32_adc_get_int_ch(struct iio_dev *indio_dev, const char *ch_name, + int chan) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + u16 vrefint; + int i, ret; + + for (i = 0; i < STM32_ADC_INT_CH_NB; i++) { + if (!strncmp(stm32_adc_ic[i].name, ch_name, STM32_ADC_CH_SZ)) { + adc->int_ch[i] = chan; + /* If channel is vrefint get calibration data. */ + if (stm32_adc_ic[i].idx == STM32_ADC_INT_CH_VREFINT) { + ret = nvmem_cell_read_u16(&indio_dev->dev, "vrefint", &vrefint); + if (ret && ret != -ENOENT && ret != -EOPNOTSUPP) { + dev_err(&indio_dev->dev, "nvmem access error %d\n", ret); + return ret; + } + if (ret == -ENOENT) + dev_dbg(&indio_dev->dev, + "vrefint calibration not found\n"); + else + adc->vrefint.vrefint_cal = vrefint; + } + } + } + + return 0; +} + static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev, struct stm32_adc *adc, struct iio_chan_spec *channels) @@ -1938,10 +2004,9 @@ static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev, return -EINVAL; } strncpy(adc->chan_name[val], name, STM32_ADC_CH_SZ); - for (i = 0; i < STM32_ADC_INT_CH_NB; i++) { - if (!strncmp(stm32_adc_ic[i].name, name, STM32_ADC_CH_SZ)) - adc->int_ch[i] = val; - } + ret = stm32_adc_get_int_ch(indio_dev, name, val); + if (ret) + goto err; } else if (ret != -EINVAL) { dev_err(&indio_dev->dev, "Invalid label %d\n", ret); goto err; @@ -2044,6 +2109,16 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping) */ of_property_read_u32_index(node, "st,min-sample-time-nsecs", i, &smp); + + /* + * For vrefint channel, ensure that the sampling time cannot + * be lower than the one specified in the datasheet + */ + if (channels[i].channel == adc->int_ch[STM32_ADC_INT_CH_VREFINT] && + smp < adc->cfg->ts_vrefint_ns) { + smp = adc->cfg->ts_vrefint_ns; + } + /* Prepare sampling time settings */ stm32_adc_smpr_init(adc, channels[i].channel, smp); } @@ -2350,6 +2425,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = { .unprepare = stm32h7_adc_unprepare, .smp_cycles = stm32h7_adc_smp_cycles, .irq_clear = stm32h7_adc_irq_clear, + .ts_vrefint_ns = 4300, }; static const struct of_device_id stm32_adc_of_match[] = {