Received: by 2002:a05:6a11:4021:0:0:0:0 with SMTP id ky33csp789417pxb; Tue, 14 Sep 2021 08:46:28 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzsRvqHMmPG22hkMLc1EkDR0ftdN1aG52a+Oqg+vGZ+Otwo8mQt0AN+30cyswoNuod/IDYT X-Received: by 2002:ac2:46d3:: with SMTP id p19mr13616049lfo.689.1631634388320; Tue, 14 Sep 2021 08:46:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1631634388; cv=none; d=google.com; s=arc-20160816; b=TbNnfF7dJLz9SLza2z6I3gMkif1GL8v2jSIXdgCAd3Xxsw69V9sadenbL8K1uWIq5u NDEH7Z4f8i5tX65mn0TiuN0930ByBdSso9nzVOGIttBeObpcGMhh5K31mFkPExXoSWOU yn+Ven/ptLYC3b98kPKZYLHRg0PJF/lLfn635LVSM414/CYVJxA6f04h9K3lfv2Ojj+r 5omfjqJjMK9V3jL/dr62J677UnYI6etFhi3T5x+bLWNnZ2XzJXaYPJBb+9qPkO598eaz d1uKgH7efSR/iFAyz6Y13CjrtxbIkBxiwI6glTZB7iMGclpA+NaVCYG68yNm2gPG08K5 4M7A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:content-language :in-reply-to:mime-version:user-agent:date:message-id:from:references :cc:to:subject:dkim-signature; bh=A8LADHphWjjLt84Bir09Xe1QHp8f+yYPjzgWKfVFsHw=; b=TLhoShv0beCImhzJAIdaKaE4ZmmF3U/kY2m63wll8G5xwVHpzD70VQZk4C3FhOzaPa W4ncwfhQ3dPb42i5yk7p99b8QJQCk++ElbJCzlCTTM4tHtKXS+iX+eVzUQUTgy/T8lMM qblZfz3GZvk0T2zpHV22km/hXuPfQ2kS167NlIxYz3xE5AVPTAhwo5MiRqz+26uVGuc7 jSjunD9zG3CdLgxn+TBEW7WehsAV9wwkNn+9v25gsnbSBfb/shrpm8a0e7ZHdh2YQ76T QVSch/vrZR5ScacGyJWgletKKY+wYfp0w17/xQjKj0PNOWJw+tMuBoZ6hlKRTt9Ob4AB xh/Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@foss.st.com header.s=selector1 header.b=DS66DihZ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=foss.st.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id bp20si14602693lfb.242.2021.09.14.08.46.00; Tue, 14 Sep 2021 08:46:28 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@foss.st.com header.s=selector1 header.b=DS66DihZ; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=foss.st.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234886AbhINPpF (ORCPT + 99 others); Tue, 14 Sep 2021 11:45:05 -0400 Received: from mx07-00178001.pphosted.com ([185.132.182.106]:57386 "EHLO mx07-00178001.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234457AbhINPpF (ORCPT ); Tue, 14 Sep 2021 11:45:05 -0400 Received: from pps.filterd (m0046668.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.1.2/8.16.1.2) with SMTP id 18EDNHlw026831; Tue, 14 Sep 2021 17:43:18 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h=subject : to : cc : references : from : message-id : date : mime-version : in-reply-to : content-type : content-transfer-encoding; s=selector1; bh=A8LADHphWjjLt84Bir09Xe1QHp8f+yYPjzgWKfVFsHw=; b=DS66DihZXyBSbUlyRb5ENSmSBzZj9zAigdPcGw0UzasbNZK9yN2ludCw1+hZb6o37nvi 6blpaNC+Vs9ltAQoaL7r03kZGEfcI07PpAhhU9YOOlxLatX6ejtri1AB4vXpEjn20+tX WUMyAqgrf6QkCQmoFILOoNE8PAX+wXMTFfj70vZP7kl2kqVjQL2DpJBq0Jq76VRYga+h QDbgyC946/ZX3eJy3e/hDPDTFOub42K4aIxfh77+90qKYYWozr3S8lhU9jP8a+NXbqWx GFJP9mvDUhx37kI1JE+Hx7eYrcHIU2ik0sGNOKVyCeZhuCZHlL9Luzsy6H9yMGIEhn7M nQ== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com with ESMTP id 3b2vjygqpu-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 14 Sep 2021 17:43:18 +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 0C444100034; Tue, 14 Sep 2021 17:43:16 +0200 (CEST) Received: from Webmail-eu.st.com (sfhdag2node2.st.com [10.75.127.5]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id C9D8C21B31E; Tue, 14 Sep 2021 17:43:16 +0200 (CEST) Received: from lmecxl0577.lme.st.com (10.75.127.45) by SFHDAG2NODE2.st.com (10.75.127.5) with Microsoft SMTP Server (TLS) id 15.0.1497.18; Tue, 14 Sep 2021 17:43:16 +0200 Subject: Re: [PATCH 4/4] iio: adc: stm32-dfsdm: add scale and offset support To: Jonathan Cameron CC: , , , , , , , , , , Arnaud POULIQUEN , Fabrice GASNIER References: <20200204101008.11411-1-olivier.moysan@st.com> <20200204101008.11411-5-olivier.moysan@st.com> <20200208161847.76c7d6e8@archlinux> <8400827e-5f3d-ad3f-99c8-986934b1a7b8@st.com> <20200214131113.70aa36b8@archlinux> <5b2e74a0-71bd-46d0-0096-b33ff17f780b@st.com> <20200214151011.20111e8c@archlinux> <78f4e4b9-ef4c-982f-7cd3-8d3052d99150@foss.st.com> <20210912182617.5635fa06@jic23-huawei> From: Olivier MOYSAN Message-ID: Date: Tue, 14 Sep 2021 17:43:15 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.13.0 MIME-Version: 1.0 In-Reply-To: <20210912182617.5635fa06@jic23-huawei> Content-Type: text/plain; charset="utf-8"; format=flowed Content-Language: en-US Content-Transfer-Encoding: 8bit X-Originating-IP: [10.75.127.45] X-ClientProxiedBy: SFHDAG2NODE2.st.com (10.75.127.5) To SFHDAG2NODE2.st.com (10.75.127.5) 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-14_06,2021-09-14_01,2020-04-07_01 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Jonathan, Thanks, for your comments. On 9/12/21 7:26 PM, Jonathan Cameron wrote: > On Fri, 10 Sep 2021 17:56:45 +0200 > Olivier MOYSAN wrote: > >> Hi Jonathan, >> >> On 9/10/21 4:05 PM, Olivier MOYSAN wrote: >>> >>> >>> >>> ST Restricted >>> >>> -----Original Message----- >>> From: Jonathan Cameron >>> Sent: vendredi 14 février 2020 16:10 >>> To: Olivier MOYSAN >>> Cc: robh+dt@kernel.org; mark.rutland@arm.com; knaack.h@gmx.de; lars@metafoo.de; devicetree@vger.kernel.org; linux-iio@vger.kernel.org; linux-kernel@vger.kernel.org; pmeerw@pmeerw.net; linux-stm32@st-md-mailman.stormreply.com; linux-arm-kernel@lists.infradead.org >>> Subject: Re: [PATCH 4/4] iio: adc: stm32-dfsdm: add scale and offset support >>> >>> On Fri, 14 Feb 2020 14:49:18 +0000 >>> Olivier MOYSAN wrote: >>> >>>> Hi Jonathan, >>>> >>>> On 2/14/20 2:11 PM, Jonathan Cameron wrote: >>>>> On Tue, 11 Feb 2020 15:19:01 +0000 >>>>> Olivier MOYSAN wrote: >>>>> >>>>>> Hi Jonathan, >>>>>> >>>>>> On 2/8/20 5:18 PM, Jonathan Cameron wrote: >>>>>>> On Tue, 4 Feb 2020 11:10:08 +0100 >>>>>>> Olivier Moysan wrote: >>>>>>> >>>>>>>> Add scale and offset attributes support to STM32 DFSDM. >>>>>>>> >>>>>>>> Signed-off-by: Olivier Moysan >>>>>>> Hmm. I can't remember this history of this but we've kind of ended >>>>>>> up backwards wrt to other consumer drivers. >>>>>>> >>>>>>> In some sense this is similar to the analog gyroscopes. In those >>>>>>> the consumer driver is the gyroscope which is consuming the raw >>>>>>> readings from an ADC connected to the channel. This results in us >>>>>>> getting readings reported by the gyroscope driver. >>>>>>> >>>>>>> Here we have a sigma delta convertor consuming the pulse train >>>>>>> from a sigma delta device. So the channels are reported by the >>>>>>> sigma delta receiver, whereas i think the nearest equivalent to >>>>>>> the analog voltage outputing gyroscopes would have been if we had >>>>>>> reported the channel values at the sigma delta converter. >>>>>> The DFSDM driver is currently used as a consumer of the sd modulator. >>>>>> The scale and offset values of the channels are already computed by >>>>>> the DFSDM driver, and provided by this driver to the IIO ABI. >>>>>> However, the DFSDM has no voltage reference, so it has to retrieve >>>>>> it from sd-modulator channels, for the scale factor computation. >>>>>> >>>>>>                                     scale  offset >>>>>>                                       ^      ^ >>>>>>                                       |      |       IIO ABI >>>>>> +-------------------------------------------------------------+ >>>>>>          +---------------+          +-------------+ >>>>>>          |sd driver      |          |DFSDM driver | >>>>>>          +---------------+          +-------------+ >>>>>> +-------------------------------------------------------------+ >>>>>>                                                          HW >>>>>>          +---------------+          +-------------+ >>>>>> +------->+ sd-modulator  +--------->+ DFSDM +--------> >>>>>> analog   +------+--------+          +-------------+ output input >>>>>> ^ >>>>>>                 | vref >>>>>>                 + >>>>>> >>>>>> >>>>>> Is it the topology your are expecting ? >>>>> It's not the one we'd expect if we are aligning with similar cases >>>>> elsewhere in IIO. For example, if we attach an analog accelerometer >>>>> to an ADC, we report the accel channels on the accelerometer not the >>>>> ADC. The equivalent would be to see the DFSDM as providing a >>>>> conversion service to the SD device which is actually executing the >>>>> measurement and has the input channels. >>>>> >>>>> >>>>>          scale  offset raw >>>>>            ^      ^ ^ >>>>>            |      |     |    IIO ABI >>>>> +-------------------------------------------------------------+ >>>>>          +---------------+          +-------------+ >>>>>          |sd driver      |          |DFSDM driver | >>>>>          +---------------+          +-------------+ >>>>> +-------------------------------------------------------------+ >>>>>                                                          HW >>>>>          +---------------+          +-------------+ >>>>> +------->+ sd-modulator  +--------->+ DFSDM +--------> >>>>> analog   +------+--------+          +-------------+ output >>>>> input           ^ >>>>>                 | vref >>>>>>                 + >>>>>> >>>> Thanks for your clarification. >>>> ok, moving to this logic is a significant change. >>>> I need to evaluate further the impact on the dfsdm driver. >>> >>> Understood! If we can't do it without potentially breaking users then such is life. >>> >>> Jonathan >>> >> >> I come back to this old, but still valid topic. > > I'd forgotten about this one, so apologies if it takes me a bit of time to > get back up to speed! > >> You mentioned the example of analog gyroscopes in a previous message. >> Looking at gyroscope drivers, I found rcar-gyroadc driver which shows > > Not a gyroscope driver despite the name :) I was thinking more of the > case where we have a gyroscope that can be wired up to a bunch of different > ADCs. > >> requirements similar to dfsdm needs: >> https://www.kernel.org/doc/Documentation/devicetree/bindings/iio/adc/renesas%2Crcar-gyroadc.yaml >> >> rcar-gyroadc driver main characterisitics: >> - the parent device (gyroadc) is a consumer of sub devices (SPI ADCs) >> - the channels are populated from the sub devices >> - the iio device is associated to the parent device > > I wouldn't necessarily take that as a golden example. We were still figuring > out how this stuff would fit together. > From what I recall (and it's been a few years) that device provides no > configuration type interfaces for the SPI ADCs - they end up having no > existence in the device model as a result. There is no means of > sharing anything between the ways this device uses the SPI ADCs and the > way any other device does. > >> >> >> I took the example of gyroadc to reconsider dfsdm topology and explore >> some variants according to IIO devices use. >> >> 1) current topology: one IIO device per SD modulator and one iio device >> per DFSDM filter >> The DFSDM is used as a consumer of SD modulator through the hw >> consumer API. >> * cons >> - SD modulator and DFSDM filter have their own channel >> specification. >> - DFSDM retrieves channels scale information from SD >> modulator to initialized its channels >> - SD modulator IIO sysfs interface is useless >> >> +------------+ +-------+ +---------+ sysfs >> | sd0 iiodev | --> | chan0 | --> | filter0 | -------> >> +------------+ +-------+ +---------+ >> | ^ >> | sysfs | >> v | >> | >> | >> | >> +------------+ +-------+ | >> | sd1 iiodev | --> | chan1 | ------+ >> +------------+ +-------+ >> | >> | sysfs >> v >> >> >> 2) "conversion service" topology: one IIO device per SD modulator >> * cons >> - Data transfers: in this case the converted data from >> DFSDM filter have to be sent back to SD modulator to be >> available on sysfs interface. >> - Scan mode: this topology seems not compatible with scan >> mode, where multiplexed channels are expected are on >> IIO device interface. >> >> => I don't find a proper way to address scan mode with multi SD >> modulator connected to one DFSM filter > > Good point, there isn't a means of combining the scans from multiple > IIO devices and that is what we end up having in this model. > > You can 'split' the channels so that enabling sd0 and sd1 buffered > mode will result in scans from the filter filling FIFOs for each of them > but that may not fit the use model you have in mind. > Yes, this model may be an option when we have independent data on each channel. If we want to handle data correlated in time, things become more tricky, yet. The following presentation shows some examples of use cases for STM32 DFSDM (page 20 to 24): https://st-onlinetraining.s3.amazonaws.com/STM32L4_System_Digital_Filter_for_SD_Modulators_interface_(DFSDM)/index.html Looking at 3-phase electricity meter example (page 23), the voltages from three SD modulators are captured and processed by one DFSDM filter. The mutiplexed filtered data can then be used for further processing. If we get the filtered data from three SD IIO devices, it looks difficult to guarantee time alignment between these data. It seems to me that the solution 2, may reduce the field of use cases that could be addressed by the DFSDM. > This sort of demux is more often done for when we have a consumer in > the form of say a touchscreen that uses a couple of channels off a > general purpose ADC. We have no reason to want to ensure any alignment > between the data going to the touchscreen and that going to the > who ever is interested in the other ADC channels. > >> >> +------------+ +-------+ +---------+ >> | sd0 iiodev | <--> | chan0 | <-> | filter0 | >> +------------+ +-------+ +---------+ >> | ^ >> | sysfs | >> v | >> | >> | >> | >> +------------+ +-------+ | >> | sd1 iiodev | <--> | chan1 | <-----+ >> +------------+ +-------+ >> | >> | sysfs >> v >> >> >> 3) gyroadc like topology: one iio device per DFSDM filter >> (no SD modulator iio device registered) >> For DFSDM scale and offset, the required information are SD >> modulator reference voltage and channel types. >> >> voltage reference: the regulator voltage can be retrieved as it >> is done in gyroadc driver. >> Maybe we can dropped merely SD modulator, and describe voltage >> as a property of the channel (through generic channel binding) >> This may be too restrictive if more hardware has to be >> configured in the SD modulator, yet. > > That is indeed the key question. Do we need to configure the modulator > devices? If we do then they need to have an existence in the device model. > Mapping them as IIO devices provides reusability across multiple > filter implementations. > We need to be able to manage a wide range of application. So, we have to be flexible enough to configure SD modulator when necessary. I agree, that the SD device has to be kept from this point of view. >> >> channel type: IIO generic channel binding could be used here >> instead of proprietary properties >> to describe the channels >> >> binding sample: >> dfsdm_pdm1: filter@1 { >> compatible = "st,stm32-dfsdm-adc"; >> reg = <1>; >> interrupts = ; >> dmas = <&dmamux1 102 0x400 0x01>; >> dma-names = "rx"; >> st,filter-order = <1>; >> >> channel@2 { >> reg = <2>; >> label = "in2"; >> st,adc-channel-types = "SPI_R"; >> st,adc-channel-clk-src = "CLKOUT_F"; >> >> sd@0 { ? >> reg = <0>; >> compatible = "sd-mod"; >> vref-supply = <&vref>; >> }; >> }; >> }; >> >> * cons >> - The sub devices are embedded in the driver and are not >> based on general device API. >> Alternatively, if we want to use standard device model >> and avoid the creation of an unrelevant IIO device for >> SD modulator, a specific type of device may be >> provided by IIO framework. This could be a kind of >> "backend" device without IIO sysfs interface attached. > > That may be an option. It was always on the list of things to do > to allow for IIO devices that have no 'IIO interface' to userspace. > The main usecase was SoC ADCs where all the channels are going to > other in kernel consumers, but it might be applicable here as well. > Can you see another alternative to solution 2, to allow full support of DFSDM features ? If 'backend' option turns out to be the most appropriated to match DFSDM constraints, I can prepare some patches to support it. Would you have some guidelines or requirements for the implementation of such feature, in this case ? Regards Olivier >> >> => This solution could be applicable but some details in the >> implementation will have to be clarified further. >> May we consider adding a "backend" device without IIO interface >> in the IIO framework ? >> May the SD modulator be dropped ? >> >> +-----+ +-------+ +----------------+ sysfs >> | sd0 | --> | chan0 | --> | filter0 iiodev | -------> >> +-----+ +-------+ +----------------+ >> ^ >> | >> | >> +-----+ +-------+ | >> | sd1 | --> | chan1 | ------+ >> +-----+ +-------+ >> >> >> Here there is a point that needs to be clarified in relation to the >> previous discussions I think. >> If I refer to the last comment of the current thread, I understand that >> you were expecting the IIO sysfs interface to be attached to the SD >> modulator. (solution 2) > > Yes. > >> For the gyroadc, the channels are indeed populated by the sub devices. >> However the IIO device corresponds to the ADC consumer and not the ADCs >> themselves. (solution 3) > > That one is a rather odd case because no generic handling is possible > of the ADCs. For example it doesn't use the ad7476 driver because we can't > talk to the device even though it's the same ADC as the ad7476 driver supports. > >> >> What is the the preferred approach for you ? > > I still favour solution 2, but if you need to have the channels cleanly > presented in a scan despite them coming from different modulators, then that > solution may not be sufficient and we need to think about how else to do > things. > > Jonathan > >> >> Thanks for your feedback >> Best regards >> Olivier >> >> >>>> >>>> Regards >>>> Olivier >>>>>> If not, I probably missedsomething. Could you please clarify this point ? >>>>>> >>>>>> Regards >>>>>> Olivier >>>>>>> This wasn't really an issue when the only values available were >>>>>>> raw, but if we are adding scale and offset, they are things that >>>>>>> belong to the ad1201 for example, not the upstream stm32-dfsdm unit. >>>>>>> >>>>>>> Thinking of it another way, we don't report an SPI ADC output in >>>>>>> the driver for the SPI master. >>>>>>> >>>>>>> Could we flip it around without breaking anything? >>>>>>> >>>>>>> Jonathan >>>>>>> >>>>>>>> --- >>>>>>>> drivers/iio/adc/stm32-dfsdm-adc.c | 105 +++++++++++++++++++++++++++++- >>>>>>>> 1 file changed, 102 insertions(+), 3 deletions(-) >>>>>>>> >>>>>>>> diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c >>>>>>>> b/drivers/iio/adc/stm32-dfsdm-adc.c >>>>>>>> index 07b9dfdf8e76..b85fd3e90496 100644 >>>>>>>> --- a/drivers/iio/adc/stm32-dfsdm-adc.c >>>>>>>> +++ b/drivers/iio/adc/stm32-dfsdm-adc.c >>>>>>>> @@ -10,6 +10,7 @@ >>>>>>>> #include >>>>>>>> #include >>>>>>>> #include >>>>>>>> +#include >>>>>>>> #include >>>>>>>> #include >>>>>>>> #include >>>>>>>> @@ -67,6 +68,13 @@ struct stm32_dfsdm_dev_data { >>>>>>>> const struct regmap_config *regmap_cfg; >>>>>>>> }; >>>>>>>> >>>>>>>> +struct stm32_dfsdm_sd_chan_info { >>>>>>>> + int scale_val; >>>>>>>> + int scale_val2; >>>>>>>> + int offset; >>>>>>>> + unsigned int differential; >>>>>>>> +}; >>>>>>>> + >>>>>>>> struct stm32_dfsdm_adc { >>>>>>>> struct stm32_dfsdm *dfsdm; >>>>>>>> const struct stm32_dfsdm_dev_data *dev_data; @@ -79,6 +87,7 >>>>>>>> @@ struct stm32_dfsdm_adc { >>>>>>>> struct iio_hw_consumer *hwc; >>>>>>>> struct completion completion; >>>>>>>> u32 *buffer; >>>>>>>> + struct stm32_dfsdm_sd_chan_info *sd_chan; >>>>>>>> >>>>>>>> /* Audio specific */ >>>>>>>> unsigned int spi_freq; /* SPI bus clock frequency */ @@ >>>>>>>> -1271,7 +1280,10 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, >>>>>>>> int *val2, long mask) >>>>>>>> { >>>>>>>> struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); >>>>>>>> - int ret; >>>>>>>> + struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; >>>>>>>> + struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast]; >>>>>>>> + u32 max = flo->max << (flo->lshift - chan->scan_type.shift); >>>>>>>> + int ret, idx = chan->scan_index; >>>>>>>> >>>>>>>> switch (mask) { >>>>>>>> case IIO_CHAN_INFO_RAW: >>>>>>>> @@ -1307,6 +1319,41 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, >>>>>>>> *val = adc->sample_freq; >>>>>>>> >>>>>>>> return IIO_VAL_INT; >>>>>>>> + >>>>>>>> + case IIO_CHAN_INFO_SCALE: >>>>>>>> + /* >>>>>>>> + * Scale is expressed in mV. >>>>>>>> + * When fast mode is disabled, actual resolution may be lower >>>>>>>> + * than 2^n, where n=realbits-1. >>>>>>>> + * This leads to underestimating input voltage. To >>>>>>>> + * compensate this deviation, the voltage reference can be >>>>>>>> + * corrected with a factor = realbits resolution / actual max >>>>>>>> + */ >>>>>>>> + *val = div_u64((u64)adc->sd_chan[idx].scale_val * >>>>>>>> + (u64)BIT(DFSDM_DATA_RES - 1), max); >>>>>>>> + *val2 = chan->scan_type.realbits; >>>>>>>> + if (adc->sd_chan[idx].differential) >>>>>>>> + *val *= 2; >>>>>>>> + >>>>>>>> + return IIO_VAL_FRACTIONAL_LOG2; >>>>>>>> + >>>>>>>> + case IIO_CHAN_INFO_OFFSET: >>>>>>>> + /* >>>>>>>> + * DFSDM output data are in the range [-2^n,2^n-1], >>>>>>>> + * with n=realbits-1. >>>>>>>> + * - Differential modulator: >>>>>>>> + * Offset correspond to SD modulator offset. >>>>>>>> + * - Single ended modulator: >>>>>>>> + * Input is in [0V,Vref] range, where 0V corresponds to -2^n. >>>>>>>> + * Add 2^n to offset. (i.e. middle of input range) >>>>>>>> + * offset = offset(sd) * vref / res(sd) * max / vref. >>>>>>>> + */ >>>>>>>> + *val = div_u64((u64)max * adc->sd_chan[idx].offset, >>>>>>>> + BIT(adc->sd_chan[idx].scale_val2 - 1)); >>>>>>>> + if (!adc->sd_chan[idx].differential) >>>>>>>> + *val += max; >>>>>>>> + >>>>>>>> + return IIO_VAL_INT; >>>>>>>> } >>>>>>>> >>>>>>>> return -EINVAL; >>>>>>>> @@ -1430,7 +1477,9 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, >>>>>>>> * IIO_CHAN_INFO_RAW: used to compute regular conversion >>>>>>>> * IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling >>>>>>>> */ >>>>>>>> - ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); >>>>>>>> + ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | >>>>>>>> + BIT(IIO_CHAN_INFO_SCALE) | >>>>>>>> + BIT(IIO_CHAN_INFO_OFFSET); >>>>>>>> ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | >>>>>>>> BIT(IIO_CHAN_INFO_SAMP_FREQ); >>>>>>>> >>>>>>>> @@ -1481,8 +1530,10 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) >>>>>>>> { >>>>>>>> struct iio_chan_spec *ch; >>>>>>>> struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); >>>>>>>> + struct iio_channel *channels, *chan; >>>>>>>> + struct stm32_dfsdm_sd_chan_info *sd_chan; >>>>>>>> int num_ch; >>>>>>>> - int ret, chan_idx; >>>>>>>> + int ret, chan_idx, val2; >>>>>>>> >>>>>>>> adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING; >>>>>>>> ret = stm32_dfsdm_compute_all_osrs(indio_dev, adc->oversamp); >>>>>>>> @@ -1506,6 +1557,22 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) >>>>>>>> if (!ch) >>>>>>>> return -ENOMEM; >>>>>>>> >>>>>>>> + /* Get SD modulator channels */ >>>>>>>> + channels = iio_channel_get_all(&indio_dev->dev); >>>>>>>> + if (IS_ERR(channels)) { >>>>>>>> + dev_err(&indio_dev->dev, "Failed to get channel %ld\n", >>>>>>>> + PTR_ERR(channels)); >>>>>>>> + return PTR_ERR(channels); >>>>>>>> + } >>>>>>>> + chan = &channels[0]; >>>>>>>> + >>>>>>>> + adc->sd_chan = devm_kzalloc(&indio_dev->dev, >>>>>>>> + sizeof(*adc->sd_chan) * num_ch, GFP_KERNEL); >>>>>>>> + if (!adc->sd_chan) >>>>>>>> + return -ENOMEM; >>>>>>>> + >>>>>>>> + sd_chan = adc->sd_chan; >>>>>>>> + >>>>>>>> for (chan_idx = 0; chan_idx < num_ch; chan_idx++) { >>>>>>>> ch[chan_idx].scan_index = chan_idx; >>>>>>>> ret = stm32_dfsdm_adc_chan_init_one(indio_dev, >>>>>>>> &ch[chan_idx]); @@ -1513,6 +1580,38 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) >>>>>>>> dev_err(&indio_dev->dev, "Channels init failed\n"); >>>>>>>> return ret; >>>>>>>> } >>>>>>>> + >>>>>>>> + if (!chan->indio_dev) >>>>>>>> + return -EINVAL; >>>>>>>> + >>>>>>>> + ret = iio_read_channel_scale(chan, &sd_chan->scale_val, >>>>>>>> + &sd_chan->scale_val2); >>>>>>>> + if (ret < 0) { >>>>>>>> + dev_err(&indio_dev->dev, >>>>>>>> + "Failed to get channel %d scale\n", chan_idx); >>>>>>>> + return ret; >>>>>>>> + } >>>>>>>> + >>>>>>>> + if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_OFFSET)) { >>>>>>>> + ret = iio_read_channel_offset(chan, &sd_chan->offset, >>>>>>>> + &val2); >>>>>>>> + if (ret < 0) { >>>>>>>> + dev_err(&indio_dev->dev, >>>>>>>> + "Failed to get channel %d offset\n", >>>>>>>> + chan_idx); >>>>>>>> + return ret; >>>>>>>> + } >>>>>>>> + } >>>>>>>> + >>>>>>>> + sd_chan->differential = chan->channel->differential; >>>>>>>> + >>>>>>>> + dev_dbg(&indio_dev->dev, "Channel %d %s scale ref=%d offset=%d", >>>>>>>> + chan_idx, chan->channel->differential ? >>>>>>>> + "differential" : "single-ended", >>>>>>>> + sd_chan->scale_val, sd_chan->offset); >>>>>>>> + >>>>>>>> + chan++; >>>>>>>> + sd_chan++; >>>>>>>> } >>>>>>>> >>>>>>>> indio_dev->num_channels = num_ch; >