Message ID | 20240208172459.280189-6-alisa.roman@analog.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel+bounces-58454-ouuuleilei=gmail.com@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:50ea:b0:106:860b:bbdd with SMTP id r10csp327448dyd; Thu, 8 Feb 2024 09:27:55 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCUu03T4wSOHxpNLq4aHNotn6Rp4QXOqDeKVYAg4HcOB4uOM9ZtZZu4TB8CHdd9sw26nPCkjPMLhI1LMk7YK2aByQ1a1TQ== X-Google-Smtp-Source: AGHT+IGL9Gtvwdr7Zspl05yW7GBF9n1aswpBRDtrCjHmZsSFNfoUw2dgvS2GWvYaKOc/UdxmhQLJ X-Received: by 2002:a05:6402:3455:b0:560:64f4:cbd1 with SMTP id l21-20020a056402345500b0056064f4cbd1mr6628335edc.19.1707413275720; Thu, 08 Feb 2024 09:27:55 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1707413275; cv=pass; d=google.com; s=arc-20160816; b=Aqd0pGZxAScfI1WOIM717biJl64d2yqoM3bPKk8ygEDTG6JY6nMH1Cgyzu/EMmAhO8 a8C6hS/0GJP57A9XPPbcTf6+1khe+zWdaegjngcClk5BOI9YIqjxiw5mTXRtCSXnzRNy 4U1keEtJEY2oLTlzvG23x2FLqiblMFKPBm47zeureqdXvHsUBbpBSHRJeGGuY15I0Tue VDYrDNrTv0eD2Lq9/XhNAazXBaub/jLUNivmGmVf28hBj1cSH+xRIfsapOnMpD2K3g3S rguuQNfo1gIzAYN/52aq5V0vRPSmyLYCARUTgqGdamt8KED+kOZl4kMXUP+MkkDPDuaz RniA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=RvcPIhBw0ZkFOGOMebGpiUEgt1YSGQvRZVRF+GXWk7A=; fh=YTG70YB/He+Hi/s5Ws8zv0lAnGdnvasaNJGwzb2FP0Y=; b=zn2shPdfXqsRKBTvV/FX/pPKbbHNTH6cKIDs4qW1aOIbuF9BNej9buteamk+/1xraU 0KvMYq1f7i/ypHUJC9YYDeOSM5g5yYwUITiek+f/6r7QRhhRO8ySgf3/QUXJmLfABQtj NkDRIgr0fCaBemXPCl/yVkGV9qLJ27oY1V5TDFxLmF6ROPK/8/EAw3LyFkWn7I4uAOXj gRleIXPhOG8KTXXe2ctunxkgkNqtF3g6gOOTEAxQ/SfCf80mui8yO/eew67TeF16nTFu 71LRpWoRCcE4bX8zFNFWztdtR02lvXsYApgkQKu+vNT+u+hWYsRkqCIcEEugYWT/O6tk rvnQ==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=fiZbUpof; arc=pass (i=1 spf=pass spfdomain=gmail.com dkim=pass dkdomain=gmail.com dmarc=pass fromdomain=gmail.com); spf=pass (google.com: domain of linux-kernel+bounces-58454-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-58454-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com X-Forwarded-Encrypted: i=2; AJvYcCXneNxxNggKGu1BsuZbVrJJg8S6qw3Lp73syhgmbJqoMAMaiqHm4U0qtBdMCqGoQru49RhuN99yu0hwpIVA50yAbFFCaw== Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [2604:1380:4601:e00::3]) by mx.google.com with ESMTPS id l1-20020a50d6c1000000b0056079bf85a6si1077268edj.370.2024.02.08.09.27.55 for <ouuuleilei@gmail.com> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Feb 2024 09:27:55 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-58454-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) client-ip=2604:1380:4601:e00::3; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=fiZbUpof; arc=pass (i=1 spf=pass spfdomain=gmail.com dkim=pass dkdomain=gmail.com dmarc=pass fromdomain=gmail.com); spf=pass (google.com: domain of linux-kernel+bounces-58454-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-58454-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id 2E7991F2C0B4 for <ouuuleilei@gmail.com>; Thu, 8 Feb 2024 17:27:14 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 028831272A7; Thu, 8 Feb 2024 17:25:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="fiZbUpof" Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9014286ACF; Thu, 8 Feb 2024 17:25:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707413146; cv=none; b=qMNcw5Rf6HPzgJWNmDvbyXLWyg3cwFg/tXB/RqwqICj03QV5ESJUFCOkBUshhG4LJAuo9UebzfDm+7YVHegKr2RN8dxkFXL9Ct5eYxyqVV0tBzfdrdJMJxABUtJOFV/FBQLzoVmfiAj77WLM6qIaPqyJyfieZteNsrAet9ppur4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707413146; c=relaxed/simple; bh=1HQw7aGBJQueXsgK8nlu0IkoBW2nbmv0iJsbuP5EPAw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=rcO+AUlfXZuWizG6sBpr8bbrNoxm2+9rf02FGK/BkEavtUxEABT4jegnG1Zxzednp2ss1V97V56c+V75p8fZzvo06EE6FJYGRoWFQBKTCt43Zol23mW0gqvzm6tfNfFUQFiSV7WTW7+R8f8umIBKDDrMLbJsalfglp2bi0PtBSc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=fiZbUpof; arc=none smtp.client-ip=209.85.128.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-4104ebb050fso808315e9.2; Thu, 08 Feb 2024 09:25:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1707413143; x=1708017943; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=RvcPIhBw0ZkFOGOMebGpiUEgt1YSGQvRZVRF+GXWk7A=; b=fiZbUpofqYNLhg5pfCyucF3GK57BEB6e+a0uDT0tC0tHSwL3cqbBAG8u3lvYBpI8aQ EMT3qDjp8he1b6gxLGMrm/CZNS/QyYChwdnQrw9vSGqmC9ifKOA35u62lmYwSfupJpSl BJt/xgU+r3Dwdh8rR3LyX0InKu3Zh84GQ//6eJtmiaRRU1xPed0NhEIshfdokTbdeKzg xpg50+8rctJjI6awTQ62u+nqzNQ//uBNVhQyXjzrcBr8UZjLoTBVQQ+okvjqXicKmHuc fHMQrLAL6b0KiEpTSrOOevFzLUjmrHzFmwE2xQ7QUAoMPh7zMCmFJdDAiZJaCd5mXRbG cR3g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1707413143; x=1708017943; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=RvcPIhBw0ZkFOGOMebGpiUEgt1YSGQvRZVRF+GXWk7A=; b=cJOPAO4kv25xNd8lE/pu1KJo1FCE3bNrxHHLC+v7KKJeF3kFON2jwGQP2jqqeZ1dEB koZmjmVjvBVDpSMHWc8g0SVZYuIFWAJQIYWJFr7JkcgcKM42N9VauxeMlrbjcQy6ycgL LExc9UOV83IEYf75WaH8sOZMKXCveu9M//4Wb+7oOFj++vd4Nj+K9XELuUT0FNKYBbKd onKNN38vo3+y0rkzqzzlVxQsAHnzTu1A4Sdeh3bh72U0MI7wDw9NCbw9W6k1Cp2mr6nB djQyDEsN0uBGqnYcqrdCI3n7NTuE2Fxuay5kA/0WJACVIHlz0NDLpY3qA5MwKi+VN/aO oBvA== X-Forwarded-Encrypted: i=1; AJvYcCVDSLZJe31S1Frs5wshu7t9/O6ezGi2TE7lEhxTU3ixq06lSbOU43elRTH4vm0u4XwZyp6Q276mFM9FS6Fe+RQEAwbxnmj+BHXR8BBFMakvD8qTj0qiNm0eVx50vIH9+xsG2hRT0+AA/g8ct3wILs1TPJjF9eeed2ZSf+ERaY26asXakA== X-Gm-Message-State: AOJu0Yz4NfunG8BEsaEDdtGPbWSszSY+U0AnWoOfj6TA39DWIVr5AQvv WYUMHhvmbHZqrbzmqC/E/3rC6xwRyJNyBFZv/c398DIApelWhUQ5 X-Received: by 2002:a05:600c:1994:b0:40e:f8a2:4a8e with SMTP id t20-20020a05600c199400b0040ef8a24a8emr12943wmq.15.1707413142561; Thu, 08 Feb 2024 09:25:42 -0800 (PST) X-Forwarded-Encrypted: i=1; AJvYcCUy2Lx9C0JEW11MumnivrJ0/F/oIJy2+qqQ305t5zacf//2NKr2KDDy6hOB5dMNjvjZrppYeWUKhikiaPC+8ywvx3TEkYYl0KcBsQXkGXzwXIUeWlhXNG5BEuq3ZfUSsvNqSY/WdGR0iwKUgIRRK0WVuUSRqU0tK9XNGQxfILrwicQOxZNBQu5st4RCr8BT2gyGqvjG6ub8PB1q+0Oai1CjCTSyBsJsI7YREwg94CVw/rAkV/22dnMty+XSpE3M22Qj5OoBqv+QV5gh9YK7Zgyl0iku15JaCLpOEeSwneitNRelwAQ4Z49vhYzjXj/V7mAUQaIrEXLsSbwspQttHR7dSn263vr2cuXxTrQHu2PEkEUgbwf89TGQ+d1rN9Oro0V1lPT/xsfl9MqBVYbycXQixGgpJciSX70pvtcaVpDd5W4RNS4zyalhTuVVVF3eHinBSvuHUzXAOU9lPQsFJDaXkUUv11WjIj+ALF2N+/ywf2pTsu1pSjxrfU5EOk6Bh4sOzQp31FzF7SAwZQ== Received: from spiri.. ([5.2.194.157]) by smtp.gmail.com with ESMTPSA id w9-20020a05600c474900b004101f27737asm2238214wmo.29.2024.02.08.09.25.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Feb 2024 09:25:42 -0800 (PST) From: Alisa-Dariana Roman <alisadariana@gmail.com> X-Google-Original-From: Alisa-Dariana Roman <alisa.roman@analog.com> To: Cc: alexandru.tachici@analog.com, alisa.roman@analog.com, alisadariana@gmail.com, conor+dt@kernel.org, devicetree@vger.kernel.org, dlechner@baylibre.com, jic23@kernel.org, krzysztof.kozlowski+dt@linaro.org, krzysztof.kozlowski@linaro.org, lars@metafoo.de, linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, michael.hennerich@analog.com, robh+dt@kernel.org, Nuno Sa <nuno.sa@analog.com> Subject: [PATCH v3 5/5] iio: adc: ad7192: Add AD7194 support Date: Thu, 8 Feb 2024 19:24:59 +0200 Message-Id: <20240208172459.280189-6-alisa.roman@analog.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240208172459.280189-1-alisa.roman@analog.com> References: <20240208172459.280189-1-alisa.roman@analog.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: <linux-kernel.vger.kernel.org> List-Subscribe: <mailto:linux-kernel+subscribe@vger.kernel.org> List-Unsubscribe: <mailto:linux-kernel+unsubscribe@vger.kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1790352582950380004 X-GMAIL-MSGID: 1790352582950380004 |
Series |
None
|
|
Commit Message
Alisa-Dariana Roman
Feb. 8, 2024, 5:24 p.m. UTC
Unlike the other AD719Xs, AD7194 has configurable differential channels. The default configuration for these channels can be changed from the devicetree. The default configuration is hardcoded in order to have a stable number of channels. Also modify config AD7192 description for better scaling. Moved ad7192_chip_info struct definition to allow use of callback function parse_channels(). Signed-off-by: Alisa-Dariana Roman <alisa.roman@analog.com> Reviewed-by: Nuno Sa <nuno.sa@analog.com> --- drivers/iio/adc/Kconfig | 11 ++- drivers/iio/adc/ad7192.c | 150 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 148 insertions(+), 13 deletions(-)
Comments
On Thu, Feb 8, 2024 at 11:25 AM Alisa-Dariana Roman <alisadariana@gmail.com> wrote: > > Unlike the other AD719Xs, AD7194 has configurable differential > channels. The default configuration for these channels can be changed > from the devicetree. > > The default configuration is hardcoded in order to have a stable number > of channels. > > Also modify config AD7192 description for better scaling. > > Moved ad7192_chip_info struct definition to allow use of callback > function parse_channels(). > > Signed-off-by: Alisa-Dariana Roman <alisa.roman@analog.com> > Reviewed-by: Nuno Sa <nuno.sa@analog.com> > --- > drivers/iio/adc/Kconfig | 11 ++- > drivers/iio/adc/ad7192.c | 150 ++++++++++++++++++++++++++++++++++++--- > 2 files changed, 148 insertions(+), 13 deletions(-) > > diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig > index 59ae1d17b50d..8062a4d1cbe7 100644 > --- a/drivers/iio/adc/Kconfig > +++ b/drivers/iio/adc/Kconfig > @@ -71,12 +71,17 @@ config AD7124 > called ad7124. > > config AD7192 > - tristate "Analog Devices AD7190 AD7192 AD7193 AD7195 ADC driver" > + tristate "Analog Devices AD7192 and similar ADC driver" > depends on SPI > select AD_SIGMA_DELTA > help > - Say yes here to build support for Analog Devices AD7190, > - AD7192, AD7193 or AD7195 SPI analog to digital converters (ADC). > + Say yes here to build support for Analog Devices SPI analog to digital > + converters (ADC): > + - AD7190 > + - AD7192 > + - AD7193 > + - AD7194 > + - AD7195 > If unsure, say N (but it's safe to say "Y"). > > To compile this driver as a module, choose M here: the > diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c > index d8393ac048e7..a3ff60ed6f63 100644 > --- a/drivers/iio/adc/ad7192.c > +++ b/drivers/iio/adc/ad7192.c > @@ -1,6 +1,6 @@ > // SPDX-License-Identifier: GPL-2.0 > /* > - * AD7190 AD7192 AD7193 AD7195 SPI ADC driver > + * AD7192 and similar SPI ADC driver > * > * Copyright 2011-2015 Analog Devices Inc. > */ > @@ -125,10 +125,39 @@ > #define AD7193_CH_AIN8 0x480 /* AIN7 - AINCOM */ > #define AD7193_CH_AINCOM 0x600 /* AINCOM - AINCOM */ > > +#define AD7194_CH_TEMP 0x100 /* Temp sensor */ > +#define AD7194_CH_AIN1 0x400 /* AIN1 - AINCOM */ > +#define AD7194_CH_AIN2 0x410 /* AIN2 - AINCOM */ > +#define AD7194_CH_AIN3 0x420 /* AIN3 - AINCOM */ > +#define AD7194_CH_AIN4 0x430 /* AIN4 - AINCOM */ > +#define AD7194_CH_AIN5 0x440 /* AIN5 - AINCOM */ > +#define AD7194_CH_AIN6 0x450 /* AIN6 - AINCOM */ > +#define AD7194_CH_AIN7 0x460 /* AIN7 - AINCOM */ > +#define AD7194_CH_AIN8 0x470 /* AIN8 - AINCOM */ > +#define AD7194_CH_AIN9 0x480 /* AIN9 - AINCOM */ > +#define AD7194_CH_AIN10 0x490 /* AIN10 - AINCOM */ > +#define AD7194_CH_AIN11 0x4A0 /* AIN11 - AINCOM */ > +#define AD7194_CH_AIN12 0x4B0 /* AIN12 - AINCOM */ > +#define AD7194_CH_AIN13 0x4C0 /* AIN13 - AINCOM */ > +#define AD7194_CH_AIN14 0x4D0 /* AIN14 - AINCOM */ > +#define AD7194_CH_AIN15 0x4E0 /* AIN15 - AINCOM */ > +#define AD7194_CH_AIN16 0x4F0 /* AIN16 - AINCOM */ > +#define AD7194_CH_POS_MASK GENMASK(7, 4) > +#define AD7194_CH_POS(x) FIELD_PREP(AD7194_CH_POS_MASK, (x)) AD7194_CH_POS_MASK isn't used elsewhere, so maybe just this? #define AD7194_CH_POS(x) FIELD_PREP(GENMASK(7, 4), (x)) > +#define AD7194_CH_NEG_MASK GENMASK(3, 0) > +#define AD7194_CH_NEG(x) FIELD_PREP(AD7194_CH_NEG_MASK, (x)) > +#define AD7194_CH_DIFF(pos, neg) \ > + (AD7194_CH_POS(pos) | AD7194_CH_NEG(neg)) You could also add `((neg) == 0 ? BIT(10) : 0) | ...` and then use this macro to define AD7194_CH_AINx. #define AD7194_CH_AIN1 AD7194_CH_DIFF(1, 0) > +#define AD7194_CH_DIFF_START 0 > +#define AD7194_CH_DIFF_NR 8 > +#define AD7194_CH_AIN_START 1 > +#define AD7194_CH_AIN_NR 16 > + > /* ID Register Bit Designations (AD7192_REG_ID) */ > #define CHIPID_AD7190 0x4 > #define CHIPID_AD7192 0x0 > #define CHIPID_AD7193 0x2 > +#define CHIPID_AD7194 0x3 > #define CHIPID_AD7195 0x6 > #define AD7192_ID_MASK GENMASK(3, 0) > > @@ -166,17 +195,10 @@ enum { > ID_AD7190, > ID_AD7192, > ID_AD7193, > + ID_AD7194, > ID_AD7195, > }; > > -struct ad7192_chip_info { > - unsigned int chip_id; > - const char *name; > - const struct iio_chan_spec *channels; > - u8 num_channels; > - const struct iio_info *info; > -}; > - > struct ad7192_state { > const struct ad7192_chip_info *chip_info; > struct regulator *avdd; > @@ -197,6 +219,15 @@ struct ad7192_state { > struct ad_sigma_delta sd; > }; > > +struct ad7192_chip_info { > + unsigned int chip_id; > + const char *name; > + const struct iio_chan_spec *channels; > + u8 num_channels; > + const struct iio_info *info; > + int (*parse_channels)(struct ad7192_state *st); > +}; > + > static const char * const ad7192_syscalib_modes[] = { > [AD7192_SYSCALIB_ZERO_SCALE] = "zero_scale", > [AD7192_SYSCALIB_FULL_SCALE] = "full_scale", > @@ -918,6 +949,15 @@ static const struct iio_info ad7192_info = { > .update_scan_mode = ad7192_update_scan_mode, > }; > > +static const struct iio_info ad7194_info = { > + .read_raw = ad7192_read_raw, > + .write_raw = ad7192_write_raw, > + .write_raw_get_fmt = ad7192_write_raw_get_fmt, > + .read_avail = ad7192_read_avail, > + .validate_trigger = ad_sd_validate_trigger, > + .update_scan_mode = ad7192_update_scan_mode, > +}; Isn't this identical to ad7192_info and ad7195_info now that .attrs is removed? It seems like we could consolidate here. > + > static const struct iio_info ad7195_info = { > .read_raw = ad7192_read_raw, > .write_raw = ad7192_write_raw, > @@ -1009,6 +1049,80 @@ static const struct iio_chan_spec ad7193_channels[] = { > IIO_CHAN_SOFT_TIMESTAMP(14), > }; > > +static struct iio_chan_spec ad7194_channels[] = { > + AD7193_DIFF_CHANNEL(0, 1, 2, 0x001), > + AD7193_DIFF_CHANNEL(1, 3, 4, 0x023), > + AD7193_DIFF_CHANNEL(2, 5, 6, 0x045), > + AD7193_DIFF_CHANNEL(3, 7, 8, 0x067), > + AD7193_DIFF_CHANNEL(4, 9, 10, 0x089), > + AD7193_DIFF_CHANNEL(5, 11, 12, 0x0AB), > + AD7193_DIFF_CHANNEL(6, 13, 14, 0x0CD), > + AD7193_DIFF_CHANNEL(7, 15, 16, 0x0EF), > + AD719x_TEMP_CHANNEL(8, AD7194_CH_TEMP), > + AD7193_CHANNEL(9, 1, AD7194_CH_AIN1), > + AD7193_CHANNEL(10, 2, AD7194_CH_AIN2), > + AD7193_CHANNEL(11, 3, AD7194_CH_AIN3), > + AD7193_CHANNEL(12, 4, AD7194_CH_AIN4), > + AD7193_CHANNEL(13, 5, AD7194_CH_AIN5), > + AD7193_CHANNEL(14, 6, AD7194_CH_AIN6), > + AD7193_CHANNEL(15, 7, AD7194_CH_AIN7), > + AD7193_CHANNEL(16, 8, AD7194_CH_AIN8), > + AD7193_CHANNEL(17, 9, AD7194_CH_AIN9), > + AD7193_CHANNEL(18, 10, AD7194_CH_AIN10), > + AD7193_CHANNEL(19, 11, AD7194_CH_AIN11), > + AD7193_CHANNEL(20, 12, AD7194_CH_AIN12), > + AD7193_CHANNEL(21, 13, AD7194_CH_AIN13), > + AD7193_CHANNEL(22, 14, AD7194_CH_AIN14), > + AD7193_CHANNEL(23, 15, AD7194_CH_AIN15), > + AD7193_CHANNEL(24, 16, AD7194_CH_AIN16), Shouldn't these be differential channels since they are pseudo-differential inputs measuring the difference between AINx and AINCOM? > + IIO_CHAN_SOFT_TIMESTAMP(25), > +}; i.e. like this (where AINCOM is voltage0 AINx is voltagex) static struct iio_chan_spec ad7194_channels[] = { AD7193_DIFF_CHANNEL(0, 1, 0, AD7194_CH_AIN1), AD7193_DIFF_CHANNEL(1, 2, 0, AD7194_CH_AIN2), AD7193_DIFF_CHANNEL(2, 3, 0, AD7194_CH_AIN3), AD7193_DIFF_CHANNEL(3, 4, 0, AD7194_CH_AIN4), AD7193_DIFF_CHANNEL(4, 5, 0, AD7194_CH_AIN5), AD7193_DIFF_CHANNEL(5, 6, 0, AD7194_CH_AIN6), AD7193_DIFF_CHANNEL(6, 7, 0, AD7194_CH_AIN7), AD7193_DIFF_CHANNEL(7, 8, 0, AD7194_CH_AIN8), AD7193_DIFF_CHANNEL(8, 9, 0, AD7194_CH_AIN9), AD7193_DIFF_CHANNEL(9, 10, 0, AD7194_CH_AIN10), AD7193_DIFF_CHANNEL(10, 11, 0, AD7194_CH_AIN11), AD7193_DIFF_CHANNEL(11, 12, 0, AD7194_CH_AIN12), AD7193_DIFF_CHANNEL(12, 13, 0, AD7194_CH_AIN13), AD7193_DIFF_CHANNEL(13, 14, 0, AD7194_CH_AIN14), AD7193_DIFF_CHANNEL(14, 15, 0, AD7194_CH_AIN15), AD7193_DIFF_CHANNEL(15, 16, 0, AD7194_CH_AIN16), AD719x_TEMP_CHANNEL(16, AD7194_CH_TEMP), IIO_CHAN_SOFT_TIMESTAMP(17), }; > + > +static int ad7192_parse_channel(struct fwnode_handle *child) > +{ > + u32 reg, ain[2]; > + int ret; > + > + ret = fwnode_property_read_u32(child, "reg", ®); > + if (ret) > + return ret; > + > + if (!in_range(reg, AD7194_CH_DIFF_START, AD7194_CH_DIFF_NR)) > + return -EINVAL; > + > + ret = fwnode_property_read_u32_array(child, "diff-channels", ain, > + ARRAY_SIZE(ain)); > + if (ret) > + return ret; > + > + if (!in_range(ain[0], AD7194_CH_AIN_START, AD7194_CH_AIN_NR) || > + !in_range(ain[1], AD7194_CH_AIN_START, AD7194_CH_AIN_NR)) > + return -EINVAL; > + > + ad7194_channels[reg].channel = ain[0]; > + ad7194_channels[reg].channel2 = ain[1]; > + ad7194_channels[reg].address = AD7194_CH_DIFF(ain[0], ain[1]); .. then the suggested change to AD7194_CH_DIFF above also make this work when ain[1] is zero which should be allowed in the range check immediately before this. > + > + return 0; > +} > + > +static int ad7192_parse_channels(struct ad7192_state *st) > +{ > + struct device *dev = &st->sd.spi->dev; > + struct fwnode_handle *child; > + int ret; > + > + device_for_each_child_node(dev, child) { > + ret = ad7192_parse_channel(child); > + if (ret) { > + fwnode_handle_put(child); > + return ret; > + } > + } > + > + return 0; > +} > + > static const struct ad7192_chip_info ad7192_chip_info_tbl[] = { > [ID_AD7190] = { > .chip_id = CHIPID_AD7190, > @@ -1031,6 +1145,14 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = { > .num_channels = ARRAY_SIZE(ad7193_channels), > .info = &ad7192_info, > }, > + [ID_AD7194] = { > + .chip_id = CHIPID_AD7194, > + .name = "ad7194", > + .channels = ad7194_channels, > + .num_channels = ARRAY_SIZE(ad7194_channels), > + .info = &ad7194_info, > + .parse_channels = ad7192_parse_channels, > + }, > [ID_AD7195] = { > .chip_id = CHIPID_AD7195, > .name = "ad7195", > @@ -1142,6 +1264,12 @@ static int ad7192_probe(struct spi_device *spi) > } > } > > + if (st->chip_info->parse_channels) { > + ret = st->chip_info->parse_channels(st); > + if (ret) > + return ret; > + } > + > ret = ad7192_setup(st); > if (ret) > return ret; > @@ -1153,6 +1281,7 @@ static const struct of_device_id ad7192_of_match[] = { > { .compatible = "adi,ad7190", .data = &ad7192_chip_info_tbl[ID_AD7190] }, > { .compatible = "adi,ad7192", .data = &ad7192_chip_info_tbl[ID_AD7192] }, > { .compatible = "adi,ad7193", .data = &ad7192_chip_info_tbl[ID_AD7193] }, > + { .compatible = "adi,ad7194", .data = &ad7192_chip_info_tbl[ID_AD7194] }, > { .compatible = "adi,ad7195", .data = &ad7192_chip_info_tbl[ID_AD7195] }, > {} > }; > @@ -1162,6 +1291,7 @@ static const struct spi_device_id ad7192_ids[] = { > { "ad7190", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7190] }, > { "ad7192", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7192] }, > { "ad7193", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] }, > + { "ad7194", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7194] }, > { "ad7195", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] }, > {} > }; > @@ -1178,6 +1308,6 @@ static struct spi_driver ad7192_driver = { > module_spi_driver(ad7192_driver); > > MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); > -MODULE_DESCRIPTION("Analog Devices AD7190, AD7192, AD7193, AD7195 ADC"); > +MODULE_DESCRIPTION("Analog Devices AD7192 and similar ADC"); > MODULE_LICENSE("GPL v2"); > MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); > -- > 2.34.1 >
Hello and thank you for the feedback! On 09.02.2024 00:27, David Lechner wrote: > On Thu, Feb 8, 2024 at 11:25 AM Alisa-Dariana Roman > <alisadariana@gmail.com> wrote: >> >> Unlike the other AD719Xs, AD7194 has configurable differential >> channels. The default configuration for these channels can be changed >> from the devicetree. .. >> >> +static const struct iio_info ad7194_info = { >> + .read_raw = ad7192_read_raw, >> + .write_raw = ad7192_write_raw, >> + .write_raw_get_fmt = ad7192_write_raw_get_fmt, >> + .read_avail = ad7192_read_avail, >> + .validate_trigger = ad_sd_validate_trigger, >> + .update_scan_mode = ad7192_update_scan_mode, >> +}; > > Isn't this identical to ad7192_info and ad7195_info now that .attrs is > removed? It seems like we could consolidate here. Those are not exactly identical since: 92 has bridge switch attribute, 95 has bridge switch and ac excitation attributes and 94 has no custom attributes. I used a different info structure for 94 in order to avoid showing extra attributes. > >> + >> static const struct iio_info ad7195_info = { >> .read_raw = ad7192_read_raw, >> .write_raw = ad7192_write_raw, >> @@ -1009,6 +1049,80 @@ static const struct iio_chan_spec ad7193_channels[] = { >> IIO_CHAN_SOFT_TIMESTAMP(14), >> }; >> >> +static struct iio_chan_spec ad7194_channels[] = { >> + AD7193_DIFF_CHANNEL(0, 1, 2, 0x001), >> + AD7193_DIFF_CHANNEL(1, 3, 4, 0x023), >> + AD7193_DIFF_CHANNEL(2, 5, 6, 0x045), >> + AD7193_DIFF_CHANNEL(3, 7, 8, 0x067), >> + AD7193_DIFF_CHANNEL(4, 9, 10, 0x089), >> + AD7193_DIFF_CHANNEL(5, 11, 12, 0x0AB), >> + AD7193_DIFF_CHANNEL(6, 13, 14, 0x0CD), >> + AD7193_DIFF_CHANNEL(7, 15, 16, 0x0EF), >> + AD719x_TEMP_CHANNEL(8, AD7194_CH_TEMP), >> + AD7193_CHANNEL(9, 1, AD7194_CH_AIN1), >> + AD7193_CHANNEL(10, 2, AD7194_CH_AIN2), >> + AD7193_CHANNEL(11, 3, AD7194_CH_AIN3), >> + AD7193_CHANNEL(12, 4, AD7194_CH_AIN4), >> + AD7193_CHANNEL(13, 5, AD7194_CH_AIN5), >> + AD7193_CHANNEL(14, 6, AD7194_CH_AIN6), >> + AD7193_CHANNEL(15, 7, AD7194_CH_AIN7), >> + AD7193_CHANNEL(16, 8, AD7194_CH_AIN8), >> + AD7193_CHANNEL(17, 9, AD7194_CH_AIN9), >> + AD7193_CHANNEL(18, 10, AD7194_CH_AIN10), >> + AD7193_CHANNEL(19, 11, AD7194_CH_AIN11), >> + AD7193_CHANNEL(20, 12, AD7194_CH_AIN12), >> + AD7193_CHANNEL(21, 13, AD7194_CH_AIN13), >> + AD7193_CHANNEL(22, 14, AD7194_CH_AIN14), >> + AD7193_CHANNEL(23, 15, AD7194_CH_AIN15), >> + AD7193_CHANNEL(24, 16, AD7194_CH_AIN16), > > Shouldn't these be differential channels since they are > pseudo-differential inputs measuring the difference between AINx and > AINCOM? > >> + IIO_CHAN_SOFT_TIMESTAMP(25), >> +}; > > i.e. like this (where AINCOM is voltage0 AINx is voltagex) > > static struct iio_chan_spec ad7194_channels[] = { > AD7193_DIFF_CHANNEL(0, 1, 0, AD7194_CH_AIN1), > AD7193_DIFF_CHANNEL(1, 2, 0, AD7194_CH_AIN2), > AD7193_DIFF_CHANNEL(2, 3, 0, AD7194_CH_AIN3), > AD7193_DIFF_CHANNEL(3, 4, 0, AD7194_CH_AIN4), > AD7193_DIFF_CHANNEL(4, 5, 0, AD7194_CH_AIN5), > AD7193_DIFF_CHANNEL(5, 6, 0, AD7194_CH_AIN6), > AD7193_DIFF_CHANNEL(6, 7, 0, AD7194_CH_AIN7), > AD7193_DIFF_CHANNEL(7, 8, 0, AD7194_CH_AIN8), > AD7193_DIFF_CHANNEL(8, 9, 0, AD7194_CH_AIN9), > AD7193_DIFF_CHANNEL(9, 10, 0, AD7194_CH_AIN10), > AD7193_DIFF_CHANNEL(10, 11, 0, AD7194_CH_AIN11), > AD7193_DIFF_CHANNEL(11, 12, 0, AD7194_CH_AIN12), > AD7193_DIFF_CHANNEL(12, 13, 0, AD7194_CH_AIN13), > AD7193_DIFF_CHANNEL(13, 14, 0, AD7194_CH_AIN14), > AD7193_DIFF_CHANNEL(14, 15, 0, AD7194_CH_AIN15), > AD7193_DIFF_CHANNEL(15, 16, 0, AD7194_CH_AIN16), > AD719x_TEMP_CHANNEL(16, AD7194_CH_TEMP), > IIO_CHAN_SOFT_TIMESTAMP(17), > }; > I tried to follow the existing style of the driver: for each pseudo-differential channel(AINx - AINCOM) there is an iio channel like this in_voltagex_raw; and for each differential channel(AINx - AINy) there is an iio channel like this in_voltagex-in_voltagey_raw. AD7194 has 16 pseudo-differential channels/8 fully differential channels so I thought the (AINx - AINCOM) channels should be static and only the 8 differential ones could be configured by the user from the devicetree by choosing the input pins. The existing style of the driver, AD7192 has 4 pseudo differential channels and 2 (non configurable) differential channels: static const struct iio_chan_spec ad7192_channels[] = { AD719x_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M), AD719x_DIFF_CHANNEL(1, 3, 4, AD7192_CH_AIN3P_AIN4M), AD719x_TEMP_CHANNEL(2, AD7192_CH_TEMP), AD719x_DIFF_CHANNEL(3, 2, 2, AD7192_CH_AIN2P_AIN2M), AD719x_CHANNEL(4, 1, AD7192_CH_AIN1), AD719x_CHANNEL(5, 2, AD7192_CH_AIN2), AD719x_CHANNEL(6, 3, AD7192_CH_AIN3), AD719x_CHANNEL(7, 4, AD7192_CH_AIN4), IIO_CHAN_SOFT_TIMESTAMP(8), }; Would it be better to respect the existing style or to do like you suggested and have a total of 16 differential channels that are configurable from the device tree? Kind regards, Alisa-Dariana Roman
On Thu, Feb 15, 2024 at 7:22 AM Alisa-Dariana Roman <alisadariana@gmail.com> wrote: > > Hello and thank you for the feedback! > > On 09.02.2024 00:27, David Lechner wrote: > > On Thu, Feb 8, 2024 at 11:25 AM Alisa-Dariana Roman > > <alisadariana@gmail.com> wrote: > >> > >> Unlike the other AD719Xs, AD7194 has configurable differential > >> channels. The default configuration for these channels can be changed > >> from the devicetree. > > ... > > >> > >> +static const struct iio_info ad7194_info = { > >> + .read_raw = ad7192_read_raw, > >> + .write_raw = ad7192_write_raw, > >> + .write_raw_get_fmt = ad7192_write_raw_get_fmt, > >> + .read_avail = ad7192_read_avail, > >> + .validate_trigger = ad_sd_validate_trigger, > >> + .update_scan_mode = ad7192_update_scan_mode, > >> +}; > > > > Isn't this identical to ad7192_info and ad7195_info now that .attrs is > > removed? It seems like we could consolidate here. > > Those are not exactly identical since: 92 has bridge switch attribute, > 95 has bridge switch and ac excitation attributes and 94 has no custom > attributes. I used a different info structure for 94 in order to avoid > showing extra attributes. > Ah, I see what you mean. I didn't look close enough at the other patch removing one attribute to see that were still other attributes. > > > >> + > >> static const struct iio_info ad7195_info = { > >> .read_raw = ad7192_read_raw, > >> .write_raw = ad7192_write_raw, > >> @@ -1009,6 +1049,80 @@ static const struct iio_chan_spec ad7193_channels[] = { > >> IIO_CHAN_SOFT_TIMESTAMP(14), > >> }; > >> > >> +static struct iio_chan_spec ad7194_channels[] = { > >> + AD7193_DIFF_CHANNEL(0, 1, 2, 0x001), > >> + AD7193_DIFF_CHANNEL(1, 3, 4, 0x023), > >> + AD7193_DIFF_CHANNEL(2, 5, 6, 0x045), > >> + AD7193_DIFF_CHANNEL(3, 7, 8, 0x067), > >> + AD7193_DIFF_CHANNEL(4, 9, 10, 0x089), > >> + AD7193_DIFF_CHANNEL(5, 11, 12, 0x0AB), > >> + AD7193_DIFF_CHANNEL(6, 13, 14, 0x0CD), > >> + AD7193_DIFF_CHANNEL(7, 15, 16, 0x0EF), > >> + AD719x_TEMP_CHANNEL(8, AD7194_CH_TEMP), > >> + AD7193_CHANNEL(9, 1, AD7194_CH_AIN1), > >> + AD7193_CHANNEL(10, 2, AD7194_CH_AIN2), > >> + AD7193_CHANNEL(11, 3, AD7194_CH_AIN3), > >> + AD7193_CHANNEL(12, 4, AD7194_CH_AIN4), > >> + AD7193_CHANNEL(13, 5, AD7194_CH_AIN5), > >> + AD7193_CHANNEL(14, 6, AD7194_CH_AIN6), > >> + AD7193_CHANNEL(15, 7, AD7194_CH_AIN7), > >> + AD7193_CHANNEL(16, 8, AD7194_CH_AIN8), > >> + AD7193_CHANNEL(17, 9, AD7194_CH_AIN9), > >> + AD7193_CHANNEL(18, 10, AD7194_CH_AIN10), > >> + AD7193_CHANNEL(19, 11, AD7194_CH_AIN11), > >> + AD7193_CHANNEL(20, 12, AD7194_CH_AIN12), > >> + AD7193_CHANNEL(21, 13, AD7194_CH_AIN13), > >> + AD7193_CHANNEL(22, 14, AD7194_CH_AIN14), > >> + AD7193_CHANNEL(23, 15, AD7194_CH_AIN15), > >> + AD7193_CHANNEL(24, 16, AD7194_CH_AIN16), > > > > Shouldn't these be differential channels since they are > > pseudo-differential inputs measuring the difference between AINx and > > AINCOM? > > > >> + IIO_CHAN_SOFT_TIMESTAMP(25), > >> +}; > > > > i.e. like this (where AINCOM is voltage0 AINx is voltagex) > > > > static struct iio_chan_spec ad7194_channels[] = { > > AD7193_DIFF_CHANNEL(0, 1, 0, AD7194_CH_AIN1), > > AD7193_DIFF_CHANNEL(1, 2, 0, AD7194_CH_AIN2), > > AD7193_DIFF_CHANNEL(2, 3, 0, AD7194_CH_AIN3), > > AD7193_DIFF_CHANNEL(3, 4, 0, AD7194_CH_AIN4), > > AD7193_DIFF_CHANNEL(4, 5, 0, AD7194_CH_AIN5), > > AD7193_DIFF_CHANNEL(5, 6, 0, AD7194_CH_AIN6), > > AD7193_DIFF_CHANNEL(6, 7, 0, AD7194_CH_AIN7), > > AD7193_DIFF_CHANNEL(7, 8, 0, AD7194_CH_AIN8), > > AD7193_DIFF_CHANNEL(8, 9, 0, AD7194_CH_AIN9), > > AD7193_DIFF_CHANNEL(9, 10, 0, AD7194_CH_AIN10), > > AD7193_DIFF_CHANNEL(10, 11, 0, AD7194_CH_AIN11), > > AD7193_DIFF_CHANNEL(11, 12, 0, AD7194_CH_AIN12), > > AD7193_DIFF_CHANNEL(12, 13, 0, AD7194_CH_AIN13), > > AD7193_DIFF_CHANNEL(13, 14, 0, AD7194_CH_AIN14), > > AD7193_DIFF_CHANNEL(14, 15, 0, AD7194_CH_AIN15), > > AD7193_DIFF_CHANNEL(15, 16, 0, AD7194_CH_AIN16), > > AD719x_TEMP_CHANNEL(16, AD7194_CH_TEMP), > > IIO_CHAN_SOFT_TIMESTAMP(17), > > }; > > > > I tried to follow the existing style of the driver: for each > pseudo-differential channel(AINx - AINCOM) there is an iio channel like > this in_voltagex_raw; and for each differential channel(AINx - AINy) > there is an iio channel like this in_voltagex-in_voltagey_raw. AD7194 > has 16 pseudo-differential channels/8 fully differential channels so I > thought the (AINx - AINCOM) channels should be static and only the 8 > differential ones could be configured by the user from the devicetree by > choosing the input pins. > > The existing style of the driver, AD7192 has 4 pseudo differential > channels and 2 (non configurable) differential channels: > static const struct iio_chan_spec ad7192_channels[] = { > AD719x_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M), > AD719x_DIFF_CHANNEL(1, 3, 4, AD7192_CH_AIN3P_AIN4M), > AD719x_TEMP_CHANNEL(2, AD7192_CH_TEMP), > AD719x_DIFF_CHANNEL(3, 2, 2, AD7192_CH_AIN2P_AIN2M), > AD719x_CHANNEL(4, 1, AD7192_CH_AIN1), > AD719x_CHANNEL(5, 2, AD7192_CH_AIN2), > AD719x_CHANNEL(6, 3, AD7192_CH_AIN3), > AD719x_CHANNEL(7, 4, AD7192_CH_AIN4), > IIO_CHAN_SOFT_TIMESTAMP(8), > }; > > Would it be better to respect the existing style or to do like you > suggested and have a total of 16 differential channels that are > configurable from the device tree? Looking at Table 20 in the AD7192 datasheet, I can see why AD7192 was done this way since only certain combinations of inputs can be used together. (Although I think indexes 4 to 7 should really be differential because they are the difference between the input and AINCOM which may not be GND, but it is probably too late to fix that.) Tables 22, 23 and 24 in the AD7194 datasheet show that this chip is much more configurable than AD7192 when it comes to assigning channels. There are basically no restrictions on which inputs can be used together. So I am still confident that my suggestion is the way to go for AD7194. (Although I didn't actually try it on hardware, so can't be 100% confident. But at least 90% confident :-p)
On Thu, 15 Feb 2024 11:13:19 -0600 David Lechner <dlechner@baylibre.com> wrote: > On Thu, Feb 15, 2024 at 7:22 AM Alisa-Dariana Roman > <alisadariana@gmail.com> wrote: > > > > Hello and thank you for the feedback! > > > > On 09.02.2024 00:27, David Lechner wrote: > > > On Thu, Feb 8, 2024 at 11:25 AM Alisa-Dariana Roman > > > <alisadariana@gmail.com> wrote: > > >> > > >> Unlike the other AD719Xs, AD7194 has configurable differential > > >> channels. The default configuration for these channels can be changed > > >> from the devicetree. > > > > ... > > > > >> > > >> +static const struct iio_info ad7194_info = { > > >> + .read_raw = ad7192_read_raw, > > >> + .write_raw = ad7192_write_raw, > > >> + .write_raw_get_fmt = ad7192_write_raw_get_fmt, > > >> + .read_avail = ad7192_read_avail, > > >> + .validate_trigger = ad_sd_validate_trigger, > > >> + .update_scan_mode = ad7192_update_scan_mode, > > >> +}; > > > > > > Isn't this identical to ad7192_info and ad7195_info now that .attrs is > > > removed? It seems like we could consolidate here. > > > > Those are not exactly identical since: 92 has bridge switch attribute, > > 95 has bridge switch and ac excitation attributes and 94 has no custom > > attributes. I used a different info structure for 94 in order to avoid > > showing extra attributes. > > > > Ah, I see what you mean. I didn't look close enough at the other patch > removing one attribute to see that were still other attributes. > > > > > > >> + > > >> static const struct iio_info ad7195_info = { > > >> .read_raw = ad7192_read_raw, > > >> .write_raw = ad7192_write_raw, > > >> @@ -1009,6 +1049,80 @@ static const struct iio_chan_spec ad7193_channels[] = { > > >> IIO_CHAN_SOFT_TIMESTAMP(14), > > >> }; > > >> > > >> +static struct iio_chan_spec ad7194_channels[] = { > > >> + AD7193_DIFF_CHANNEL(0, 1, 2, 0x001), > > >> + AD7193_DIFF_CHANNEL(1, 3, 4, 0x023), > > >> + AD7193_DIFF_CHANNEL(2, 5, 6, 0x045), > > >> + AD7193_DIFF_CHANNEL(3, 7, 8, 0x067), > > >> + AD7193_DIFF_CHANNEL(4, 9, 10, 0x089), > > >> + AD7193_DIFF_CHANNEL(5, 11, 12, 0x0AB), > > >> + AD7193_DIFF_CHANNEL(6, 13, 14, 0x0CD), > > >> + AD7193_DIFF_CHANNEL(7, 15, 16, 0x0EF), > > >> + AD719x_TEMP_CHANNEL(8, AD7194_CH_TEMP), > > >> + AD7193_CHANNEL(9, 1, AD7194_CH_AIN1), > > >> + AD7193_CHANNEL(10, 2, AD7194_CH_AIN2), > > >> + AD7193_CHANNEL(11, 3, AD7194_CH_AIN3), > > >> + AD7193_CHANNEL(12, 4, AD7194_CH_AIN4), > > >> + AD7193_CHANNEL(13, 5, AD7194_CH_AIN5), > > >> + AD7193_CHANNEL(14, 6, AD7194_CH_AIN6), > > >> + AD7193_CHANNEL(15, 7, AD7194_CH_AIN7), > > >> + AD7193_CHANNEL(16, 8, AD7194_CH_AIN8), > > >> + AD7193_CHANNEL(17, 9, AD7194_CH_AIN9), > > >> + AD7193_CHANNEL(18, 10, AD7194_CH_AIN10), > > >> + AD7193_CHANNEL(19, 11, AD7194_CH_AIN11), > > >> + AD7193_CHANNEL(20, 12, AD7194_CH_AIN12), > > >> + AD7193_CHANNEL(21, 13, AD7194_CH_AIN13), > > >> + AD7193_CHANNEL(22, 14, AD7194_CH_AIN14), > > >> + AD7193_CHANNEL(23, 15, AD7194_CH_AIN15), > > >> + AD7193_CHANNEL(24, 16, AD7194_CH_AIN16), > > > > > > Shouldn't these be differential channels since they are > > > pseudo-differential inputs measuring the difference between AINx and > > > AINCOM? > > > > > >> + IIO_CHAN_SOFT_TIMESTAMP(25), > > >> +}; > > > > > > i.e. like this (where AINCOM is voltage0 AINx is voltagex) > > > > > > static struct iio_chan_spec ad7194_channels[] = { > > > AD7193_DIFF_CHANNEL(0, 1, 0, AD7194_CH_AIN1), > > > AD7193_DIFF_CHANNEL(1, 2, 0, AD7194_CH_AIN2), > > > AD7193_DIFF_CHANNEL(2, 3, 0, AD7194_CH_AIN3), > > > AD7193_DIFF_CHANNEL(3, 4, 0, AD7194_CH_AIN4), > > > AD7193_DIFF_CHANNEL(4, 5, 0, AD7194_CH_AIN5), > > > AD7193_DIFF_CHANNEL(5, 6, 0, AD7194_CH_AIN6), > > > AD7193_DIFF_CHANNEL(6, 7, 0, AD7194_CH_AIN7), > > > AD7193_DIFF_CHANNEL(7, 8, 0, AD7194_CH_AIN8), > > > AD7193_DIFF_CHANNEL(8, 9, 0, AD7194_CH_AIN9), > > > AD7193_DIFF_CHANNEL(9, 10, 0, AD7194_CH_AIN10), > > > AD7193_DIFF_CHANNEL(10, 11, 0, AD7194_CH_AIN11), > > > AD7193_DIFF_CHANNEL(11, 12, 0, AD7194_CH_AIN12), > > > AD7193_DIFF_CHANNEL(12, 13, 0, AD7194_CH_AIN13), > > > AD7193_DIFF_CHANNEL(13, 14, 0, AD7194_CH_AIN14), > > > AD7193_DIFF_CHANNEL(14, 15, 0, AD7194_CH_AIN15), > > > AD7193_DIFF_CHANNEL(15, 16, 0, AD7194_CH_AIN16), > > > AD719x_TEMP_CHANNEL(16, AD7194_CH_TEMP), > > > IIO_CHAN_SOFT_TIMESTAMP(17), > > > }; > > > > > > > I tried to follow the existing style of the driver: for each > > pseudo-differential channel(AINx - AINCOM) there is an iio channel like > > this in_voltagex_raw; and for each differential channel(AINx - AINy) > > there is an iio channel like this in_voltagex-in_voltagey_raw. AD7194 > > has 16 pseudo-differential channels/8 fully differential channels so I > > thought the (AINx - AINCOM) channels should be static and only the 8 > > differential ones could be configured by the user from the devicetree by > > choosing the input pins. > > > > The existing style of the driver, AD7192 has 4 pseudo differential > > channels and 2 (non configurable) differential channels: > > static const struct iio_chan_spec ad7192_channels[] = { > > AD719x_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M), > > AD719x_DIFF_CHANNEL(1, 3, 4, AD7192_CH_AIN3P_AIN4M), > > AD719x_TEMP_CHANNEL(2, AD7192_CH_TEMP), > > AD719x_DIFF_CHANNEL(3, 2, 2, AD7192_CH_AIN2P_AIN2M), > > AD719x_CHANNEL(4, 1, AD7192_CH_AIN1), > > AD719x_CHANNEL(5, 2, AD7192_CH_AIN2), > > AD719x_CHANNEL(6, 3, AD7192_CH_AIN3), > > AD719x_CHANNEL(7, 4, AD7192_CH_AIN4), > > IIO_CHAN_SOFT_TIMESTAMP(8), > > }; > > > > Would it be better to respect the existing style or to do like you > > suggested and have a total of 16 differential channels that are > > configurable from the device tree? > > Looking at Table 20 in the AD7192 datasheet, I can see why AD7192 was > done this way since only certain combinations of inputs can be used > together. (Although I think indexes 4 to 7 should really be > differential because they are the difference between the input and > AINCOM which may not be GND, but it is probably too late to fix that.) Ground is never absolute anyway, but we could indeed be relative to something that changes. Ah well - no one has asked for it on that part I guess so not important. > > Tables 22, 23 and 24 in the AD7194 datasheet show that this chip is > much more configurable than AD7192 when it comes to assigning > channels. There are basically no restrictions on which inputs can be > used together. So I am still confident that my suggestion is the way > to go for AD7194. (Although I didn't actually try it on hardware, so > can't be 100% confident. But at least 90% confident :-p) You would have to define a channel number for aincom. There is an explicit example in the datasheet of it being at 2.5V using a reference supply. I wonder what expectation here is. Allways a reference regulator on that pin, or an actually varying input? Maybe in long term we want to support both options - so if aincom-supply is provided these are single ended with an offset, but if not they are differential channels between channel X and channel AINCOM. Note though that this mode is described a pseudo differential which normally means a fixed voltage on the negative. So gut feeling from me is treat them as single ended and add an aincom-supply + the offsets that result if that is provided in DT and voltage from it is non 0. What fun. Jonathan
On Fri, Feb 16, 2024 at 8:22 AM Jonathan Cameron <jic23@kernel.org> wrote: > > On Thu, 15 Feb 2024 11:13:19 -0600 > David Lechner <dlechner@baylibre.com> wrote: > .. > > > > Tables 22, 23 and 24 in the AD7194 datasheet show that this chip is > > much more configurable than AD7192 when it comes to assigning > > channels. There are basically no restrictions on which inputs can be > > used together. So I am still confident that my suggestion is the way > > to go for AD7194. (Although I didn't actually try it on hardware, so > > can't be 100% confident. But at least 90% confident :-p) > > You would have to define a channel number for aincom. There is an explicit > example in the datasheet of it being at 2.5V using a reference supply. > > I wonder what expectation here is. Allways a reference regulator on that pin, or > an actually varying input? Maybe in long term we want to support both > options - so if aincom-supply is provided these are single ended with > an offset, but if not they are differential channels between channel X and > channel AINCOM. > > Note though that this mode is described a pseudo differential which normally > means a fixed voltage on the negative. > > So gut feeling from me is treat them as single ended and add an > aincom-supply + the offsets that result if that is provided in DT and > voltage from it is non 0. Calling AINCOM a supply doesn't sound right to me since usually this signal is coming somewhere external, i.e. you have a twisted pair connected to AIN1 and AINCOM going to some signal source that may be hot-pluggable and not known at compile time. As an example, if AINCOM was modeled as a supply, then we would have to change the device tree every time we changed the voltage offset on the signal generator while we are testing using an evaluation board.
On Fri, 16 Feb 2024 10:57:33 -0600 David Lechner <dlechner@baylibre.com> wrote: > On Fri, Feb 16, 2024 at 8:22 AM Jonathan Cameron <jic23@kernel.org> wrote: > > > > On Thu, 15 Feb 2024 11:13:19 -0600 > > David Lechner <dlechner@baylibre.com> wrote: > > > > ... > > > > > > > Tables 22, 23 and 24 in the AD7194 datasheet show that this chip is > > > much more configurable than AD7192 when it comes to assigning > > > channels. There are basically no restrictions on which inputs can be > > > used together. So I am still confident that my suggestion is the way > > > to go for AD7194. (Although I didn't actually try it on hardware, so > > > can't be 100% confident. But at least 90% confident :-p) > > > > You would have to define a channel number for aincom. There is an explicit > > example in the datasheet of it being at 2.5V using a reference supply. > > > > I wonder what expectation here is. Allways a reference regulator on that pin, or > > an actually varying input? Maybe in long term we want to support both > > options - so if aincom-supply is provided these are single ended with > > an offset, but if not they are differential channels between channel X and > > channel AINCOM. > > > > Note though that this mode is described a pseudo differential which normally > > means a fixed voltage on the negative. > > > > So gut feeling from me is treat them as single ended and add an > > aincom-supply + the offsets that result if that is provided in DT and > > voltage from it is non 0. > > Calling AINCOM a supply doesn't sound right to me since usually this > signal is coming somewhere external, i.e. you have a twisted pair > connected to AIN1 and AINCOM going to some signal source that may be > hot-pluggable and not known at compile time. As an example, if AINCOM > was modeled as a supply, then we would have to change the device tree > every time we changed the voltage offset on the signal generator while > we are testing using an evaluation board. We tend to stick away from designing features to support testing with devboards where external wiring is involved because anything could be wired up there. (Examples are things like shunt resistors - normally they are DT only) So sometimes it's a bit painful to work with such boards. The main focus has to be production devices or at least stable set ups where a fixed DT is sufficient. So I'm more interested in focusing on production device use cases. Do we have an information on how this is this used in those environments? Jonathan
On Sat, Feb 17, 2024 at 10:25 AM Jonathan Cameron <jic23@kernel.org> wrote: > > On Fri, 16 Feb 2024 10:57:33 -0600 > David Lechner <dlechner@baylibre.com> wrote: > > > On Fri, Feb 16, 2024 at 8:22 AM Jonathan Cameron <jic23@kernel.org> wrote: > > > > > > On Thu, 15 Feb 2024 11:13:19 -0600 > > > David Lechner <dlechner@baylibre.com> wrote: > > > > > > > ... > > > > > > > > > > Tables 22, 23 and 24 in the AD7194 datasheet show that this chip is > > > > much more configurable than AD7192 when it comes to assigning > > > > channels. There are basically no restrictions on which inputs can be > > > > used together. So I am still confident that my suggestion is the way > > > > to go for AD7194. (Although I didn't actually try it on hardware, so > > > > can't be 100% confident. But at least 90% confident :-p) > > > > > > You would have to define a channel number for aincom. There is an explicit > > > example in the datasheet of it being at 2.5V using a reference supply. > > > > > > I wonder what expectation here is. Allways a reference regulator on that pin, or > > > an actually varying input? Maybe in long term we want to support both > > > options - so if aincom-supply is provided these are single ended with > > > an offset, but if not they are differential channels between channel X and > > > channel AINCOM. > > > > > > Note though that this mode is described a pseudo differential which normally > > > means a fixed voltage on the negative. > > > > > > So gut feeling from me is treat them as single ended and add an > > > aincom-supply + the offsets that result if that is provided in DT and > > > voltage from it is non 0. > > > > Calling AINCOM a supply doesn't sound right to me since usually this > > signal is coming somewhere external, i.e. you have a twisted pair > > connected to AIN1 and AINCOM going to some signal source that may be > > hot-pluggable and not known at compile time. As an example, if AINCOM > > was modeled as a supply, then we would have to change the device tree > > every time we changed the voltage offset on the signal generator while > > we are testing using an evaluation board. > > We tend to stick away from designing features to support testing with > devboards where external wiring is involved because anything could be > wired up there. (Examples are things like shunt resistors - normally > they are DT only) So sometimes it's a bit painful to work with such boards. > The main focus has to be production devices or at least stable set ups > where a fixed DT is sufficient. > > So I'm more interested in focusing on production device use cases. > Do we have an information on how this is this used in those environments? > Point taken. I also checked with an apps engineer at ADI and it does sound like AINCOM should be a supply.
On Thu, Feb 15, 2024 at 11:13 AM David Lechner <dlechner@baylibre.com> wrote: > > On Thu, Feb 15, 2024 at 7:22 AM Alisa-Dariana Roman > <alisadariana@gmail.com> wrote: > > > > Hello and thank you for the feedback! > > > > On 09.02.2024 00:27, David Lechner wrote: > > > On Thu, Feb 8, 2024 at 11:25 AM Alisa-Dariana Roman > > > <alisadariana@gmail.com> wrote: > > >> > > >> Unlike the other AD719Xs, AD7194 has configurable differential > > >> channels. The default configuration for these channels can be changed > > >> from the devicetree. > > > > ... > > > > >> > > >> +static const struct iio_info ad7194_info = { > > >> + .read_raw = ad7192_read_raw, > > >> + .write_raw = ad7192_write_raw, > > >> + .write_raw_get_fmt = ad7192_write_raw_get_fmt, > > >> + .read_avail = ad7192_read_avail, > > >> + .validate_trigger = ad_sd_validate_trigger, > > >> + .update_scan_mode = ad7192_update_scan_mode, > > >> +}; > > > > > > Isn't this identical to ad7192_info and ad7195_info now that .attrs is > > > removed? It seems like we could consolidate here. > > > > Those are not exactly identical since: 92 has bridge switch attribute, > > 95 has bridge switch and ac excitation attributes and 94 has no custom > > attributes. I used a different info structure for 94 in order to avoid > > showing extra attributes. > > > > Ah, I see what you mean. I didn't look close enough at the other patch > removing one attribute to see that were still other attributes. > > > > > > >> + > > >> static const struct iio_info ad7195_info = { > > >> .read_raw = ad7192_read_raw, > > >> .write_raw = ad7192_write_raw, > > >> @@ -1009,6 +1049,80 @@ static const struct iio_chan_spec ad7193_channels[] = { > > >> IIO_CHAN_SOFT_TIMESTAMP(14), > > >> }; > > >> > > >> +static struct iio_chan_spec ad7194_channels[] = { > > >> + AD7193_DIFF_CHANNEL(0, 1, 2, 0x001), > > >> + AD7193_DIFF_CHANNEL(1, 3, 4, 0x023), > > >> + AD7193_DIFF_CHANNEL(2, 5, 6, 0x045), > > >> + AD7193_DIFF_CHANNEL(3, 7, 8, 0x067), > > >> + AD7193_DIFF_CHANNEL(4, 9, 10, 0x089), > > >> + AD7193_DIFF_CHANNEL(5, 11, 12, 0x0AB), > > >> + AD7193_DIFF_CHANNEL(6, 13, 14, 0x0CD), > > >> + AD7193_DIFF_CHANNEL(7, 15, 16, 0x0EF), > > >> + AD719x_TEMP_CHANNEL(8, AD7194_CH_TEMP), > > >> + AD7193_CHANNEL(9, 1, AD7194_CH_AIN1), > > >> + AD7193_CHANNEL(10, 2, AD7194_CH_AIN2), > > >> + AD7193_CHANNEL(11, 3, AD7194_CH_AIN3), > > >> + AD7193_CHANNEL(12, 4, AD7194_CH_AIN4), > > >> + AD7193_CHANNEL(13, 5, AD7194_CH_AIN5), > > >> + AD7193_CHANNEL(14, 6, AD7194_CH_AIN6), > > >> + AD7193_CHANNEL(15, 7, AD7194_CH_AIN7), > > >> + AD7193_CHANNEL(16, 8, AD7194_CH_AIN8), > > >> + AD7193_CHANNEL(17, 9, AD7194_CH_AIN9), > > >> + AD7193_CHANNEL(18, 10, AD7194_CH_AIN10), > > >> + AD7193_CHANNEL(19, 11, AD7194_CH_AIN11), > > >> + AD7193_CHANNEL(20, 12, AD7194_CH_AIN12), > > >> + AD7193_CHANNEL(21, 13, AD7194_CH_AIN13), > > >> + AD7193_CHANNEL(22, 14, AD7194_CH_AIN14), > > >> + AD7193_CHANNEL(23, 15, AD7194_CH_AIN15), > > >> + AD7193_CHANNEL(24, 16, AD7194_CH_AIN16), > > > > > > Shouldn't these be differential channels since they are > > > pseudo-differential inputs measuring the difference between AINx and > > > AINCOM? > > > > > >> + IIO_CHAN_SOFT_TIMESTAMP(25), > > >> +}; > > > > > > i.e. like this (where AINCOM is voltage0 AINx is voltagex) > > > > > > static struct iio_chan_spec ad7194_channels[] = { > > > AD7193_DIFF_CHANNEL(0, 1, 0, AD7194_CH_AIN1), > > > AD7193_DIFF_CHANNEL(1, 2, 0, AD7194_CH_AIN2), > > > AD7193_DIFF_CHANNEL(2, 3, 0, AD7194_CH_AIN3), > > > AD7193_DIFF_CHANNEL(3, 4, 0, AD7194_CH_AIN4), > > > AD7193_DIFF_CHANNEL(4, 5, 0, AD7194_CH_AIN5), > > > AD7193_DIFF_CHANNEL(5, 6, 0, AD7194_CH_AIN6), > > > AD7193_DIFF_CHANNEL(6, 7, 0, AD7194_CH_AIN7), > > > AD7193_DIFF_CHANNEL(7, 8, 0, AD7194_CH_AIN8), > > > AD7193_DIFF_CHANNEL(8, 9, 0, AD7194_CH_AIN9), > > > AD7193_DIFF_CHANNEL(9, 10, 0, AD7194_CH_AIN10), > > > AD7193_DIFF_CHANNEL(10, 11, 0, AD7194_CH_AIN11), > > > AD7193_DIFF_CHANNEL(11, 12, 0, AD7194_CH_AIN12), > > > AD7193_DIFF_CHANNEL(12, 13, 0, AD7194_CH_AIN13), > > > AD7193_DIFF_CHANNEL(13, 14, 0, AD7194_CH_AIN14), > > > AD7193_DIFF_CHANNEL(14, 15, 0, AD7194_CH_AIN15), > > > AD7193_DIFF_CHANNEL(15, 16, 0, AD7194_CH_AIN16), > > > AD719x_TEMP_CHANNEL(16, AD7194_CH_TEMP), > > > IIO_CHAN_SOFT_TIMESTAMP(17), > > > }; > > > > > > > I tried to follow the existing style of the driver: for each > > pseudo-differential channel(AINx - AINCOM) there is an iio channel like > > this in_voltagex_raw; and for each differential channel(AINx - AINy) > > there is an iio channel like this in_voltagex-in_voltagey_raw. AD7194 > > has 16 pseudo-differential channels/8 fully differential channels so I > > thought the (AINx - AINCOM) channels should be static and only the 8 > > differential ones could be configured by the user from the devicetree by > > choosing the input pins. > > > > The existing style of the driver, AD7192 has 4 pseudo differential > > channels and 2 (non configurable) differential channels: > > static const struct iio_chan_spec ad7192_channels[] = { > > AD719x_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M), > > AD719x_DIFF_CHANNEL(1, 3, 4, AD7192_CH_AIN3P_AIN4M), > > AD719x_TEMP_CHANNEL(2, AD7192_CH_TEMP), > > AD719x_DIFF_CHANNEL(3, 2, 2, AD7192_CH_AIN2P_AIN2M), > > AD719x_CHANNEL(4, 1, AD7192_CH_AIN1), > > AD719x_CHANNEL(5, 2, AD7192_CH_AIN2), > > AD719x_CHANNEL(6, 3, AD7192_CH_AIN3), > > AD719x_CHANNEL(7, 4, AD7192_CH_AIN4), > > IIO_CHAN_SOFT_TIMESTAMP(8), > > }; > > > > Would it be better to respect the existing style or to do like you > > suggested and have a total of 16 differential channels that are > > configurable from the device tree? Now that we have it sorted that AINCOM should be a supply, it does sound like we should more closely follow the pattern from AD7192. But to cover every possible programmable combination of AINx to AINy, we would need 256 differential channels (16 * 16) in addition to the other channels. Realistically, we probably don't need that many though. Since I see that AD7192 has a differential channel where uses AIN2 for both + and - I guess having 16 differential channels that are configured via device tree would be enough to allow all 16 AINx inputs to be used this way. Is there a use case where the same AINx would be assigned to multiple channels at the same time? > > Looking at Table 20 in the AD7192 datasheet, I can see why AD7192 was > done this way since only certain combinations of inputs can be used > together. (Although I think indexes 4 to 7 should really be > differential because they are the difference between the input and > AINCOM which may not be GND, but it is probably too late to fix that.) > > Tables 22, 23 and 24 in the AD7194 datasheet show that this chip is > much more configurable than AD7192 when it comes to assigning > channels. There are basically no restrictions on which inputs can be > used together. So I am still confident that my suggestion is the way > to go for AD7194. (Although I didn't actually try it on hardware, so > can't be 100% confident. But at least 90% confident :-p)
On Mon, 19 Feb 2024 10:33:45 -0600 David Lechner <dlechner@baylibre.com> wrote: > On Thu, Feb 15, 2024 at 11:13 AM David Lechner <dlechner@baylibrecom> wrote: > > > > On Thu, Feb 15, 2024 at 7:22 AM Alisa-Dariana Roman > > <alisadariana@gmail.com> wrote: > > > > > > Hello and thank you for the feedback! > > > > > > On 09.02.2024 00:27, David Lechner wrote: > > > > On Thu, Feb 8, 2024 at 11:25 AM Alisa-Dariana Roman > > > > <alisadariana@gmail.com> wrote: > > > >> > > > >> Unlike the other AD719Xs, AD7194 has configurable differential > > > >> channels. The default configuration for these channels can be changed > > > >> from the devicetree. > > > > > > ... > > > > > > >> > > > >> +static const struct iio_info ad7194_info = { > > > >> + .read_raw = ad7192_read_raw, > > > >> + .write_raw = ad7192_write_raw, > > > >> + .write_raw_get_fmt = ad7192_write_raw_get_fmt, > > > >> + .read_avail = ad7192_read_avail, > > > >> + .validate_trigger = ad_sd_validate_trigger, > > > >> + .update_scan_mode = ad7192_update_scan_mode, > > > >> +}; > > > > > > > > Isn't this identical to ad7192_info and ad7195_info now that .attrs is > > > > removed? It seems like we could consolidate here. > > > > > > Those are not exactly identical since: 92 has bridge switch attribute, > > > 95 has bridge switch and ac excitation attributes and 94 has no custom > > > attributes. I used a different info structure for 94 in order to avoid > > > showing extra attributes. > > > > > > > Ah, I see what you mean. I didn't look close enough at the other patch > > removing one attribute to see that were still other attributes. > > > > > > > > > >> + > > > >> static const struct iio_info ad7195_info = { > > > >> .read_raw = ad7192_read_raw, > > > >> .write_raw = ad7192_write_raw, > > > >> @@ -1009,6 +1049,80 @@ static const struct iio_chan_spec ad7193_channels[] = { > > > >> IIO_CHAN_SOFT_TIMESTAMP(14), > > > >> }; > > > >> > > > >> +static struct iio_chan_spec ad7194_channels[] = { > > > >> + AD7193_DIFF_CHANNEL(0, 1, 2, 0x001), > > > >> + AD7193_DIFF_CHANNEL(1, 3, 4, 0x023), > > > >> + AD7193_DIFF_CHANNEL(2, 5, 6, 0x045), > > > >> + AD7193_DIFF_CHANNEL(3, 7, 8, 0x067), > > > >> + AD7193_DIFF_CHANNEL(4, 9, 10, 0x089), > > > >> + AD7193_DIFF_CHANNEL(5, 11, 12, 0x0AB), > > > >> + AD7193_DIFF_CHANNEL(6, 13, 14, 0x0CD), > > > >> + AD7193_DIFF_CHANNEL(7, 15, 16, 0x0EF), > > > >> + AD719x_TEMP_CHANNEL(8, AD7194_CH_TEMP), > > > >> + AD7193_CHANNEL(9, 1, AD7194_CH_AIN1), > > > >> + AD7193_CHANNEL(10, 2, AD7194_CH_AIN2), > > > >> + AD7193_CHANNEL(11, 3, AD7194_CH_AIN3), > > > >> + AD7193_CHANNEL(12, 4, AD7194_CH_AIN4), > > > >> + AD7193_CHANNEL(13, 5, AD7194_CH_AIN5), > > > >> + AD7193_CHANNEL(14, 6, AD7194_CH_AIN6), > > > >> + AD7193_CHANNEL(15, 7, AD7194_CH_AIN7), > > > >> + AD7193_CHANNEL(16, 8, AD7194_CH_AIN8), > > > >> + AD7193_CHANNEL(17, 9, AD7194_CH_AIN9), > > > >> + AD7193_CHANNEL(18, 10, AD7194_CH_AIN10), > > > >> + AD7193_CHANNEL(19, 11, AD7194_CH_AIN11), > > > >> + AD7193_CHANNEL(20, 12, AD7194_CH_AIN12), > > > >> + AD7193_CHANNEL(21, 13, AD7194_CH_AIN13), > > > >> + AD7193_CHANNEL(22, 14, AD7194_CH_AIN14), > > > >> + AD7193_CHANNEL(23, 15, AD7194_CH_AIN15), > > > >> + AD7193_CHANNEL(24, 16, AD7194_CH_AIN16), > > > > > > > > Shouldn't these be differential channels since they are > > > > pseudo-differential inputs measuring the difference between AINx and > > > > AINCOM? > > > > > > > >> + IIO_CHAN_SOFT_TIMESTAMP(25), > > > >> +}; > > > > > > > > i.e. like this (where AINCOM is voltage0 AINx is voltagex) > > > > > > > > static struct iio_chan_spec ad7194_channels[] = { > > > > AD7193_DIFF_CHANNEL(0, 1, 0, AD7194_CH_AIN1), > > > > AD7193_DIFF_CHANNEL(1, 2, 0, AD7194_CH_AIN2), > > > > AD7193_DIFF_CHANNEL(2, 3, 0, AD7194_CH_AIN3), > > > > AD7193_DIFF_CHANNEL(3, 4, 0, AD7194_CH_AIN4), > > > > AD7193_DIFF_CHANNEL(4, 5, 0, AD7194_CH_AIN5), > > > > AD7193_DIFF_CHANNEL(5, 6, 0, AD7194_CH_AIN6), > > > > AD7193_DIFF_CHANNEL(6, 7, 0, AD7194_CH_AIN7), > > > > AD7193_DIFF_CHANNEL(7, 8, 0, AD7194_CH_AIN8), > > > > AD7193_DIFF_CHANNEL(8, 9, 0, AD7194_CH_AIN9), > > > > AD7193_DIFF_CHANNEL(9, 10, 0, AD7194_CH_AIN10), > > > > AD7193_DIFF_CHANNEL(10, 11, 0, AD7194_CH_AIN11), > > > > AD7193_DIFF_CHANNEL(11, 12, 0, AD7194_CH_AIN12), > > > > AD7193_DIFF_CHANNEL(12, 13, 0, AD7194_CH_AIN13), > > > > AD7193_DIFF_CHANNEL(13, 14, 0, AD7194_CH_AIN14), > > > > AD7193_DIFF_CHANNEL(14, 15, 0, AD7194_CH_AIN15), > > > > AD7193_DIFF_CHANNEL(15, 16, 0, AD7194_CH_AIN16), > > > > AD719x_TEMP_CHANNEL(16, AD7194_CH_TEMP), > > > > IIO_CHAN_SOFT_TIMESTAMP(17), > > > > }; > > > > > > > > > > I tried to follow the existing style of the driver: for each > > > pseudo-differential channel(AINx - AINCOM) there is an iio channel like > > > this in_voltagex_raw; and for each differential channel(AINx - AINy) > > > there is an iio channel like this in_voltagex-in_voltagey_raw. AD7194 > > > has 16 pseudo-differential channels/8 fully differential channels so I > > > thought the (AINx - AINCOM) channels should be static and only the 8 > > > differential ones could be configured by the user from the devicetree by > > > choosing the input pins. > > > > > > The existing style of the driver, AD7192 has 4 pseudo differential > > > channels and 2 (non configurable) differential channels: > > > static const struct iio_chan_spec ad7192_channels[] = { > > > AD719x_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M), > > > AD719x_DIFF_CHANNEL(1, 3, 4, AD7192_CH_AIN3P_AIN4M), > > > AD719x_TEMP_CHANNEL(2, AD7192_CH_TEMP), > > > AD719x_DIFF_CHANNEL(3, 2, 2, AD7192_CH_AIN2P_AIN2M), > > > AD719x_CHANNEL(4, 1, AD7192_CH_AIN1), > > > AD719x_CHANNEL(5, 2, AD7192_CH_AIN2), > > > AD719x_CHANNEL(6, 3, AD7192_CH_AIN3), > > > AD719x_CHANNEL(7, 4, AD7192_CH_AIN4), > > > IIO_CHAN_SOFT_TIMESTAMP(8), > > > }; > > > > > > Would it be better to respect the existing style or to do like you > > > suggested and have a total of 16 differential channels that are > > > configurable from the device tree? > > > Now that we have it sorted that AINCOM should be a supply, it does > sound like we should more closely follow the pattern from AD7192. But > to cover every possible programmable combination of AINx to AINy, we > would need 256 differential channels (16 * 16) in addition to the > other channels. Realistically, we probably don't need that many > though. Since I see that AD7192 has a differential channel where uses > AIN2 for both + and - I guess having 16 differential channels that are > configured via device tree would be enough to allow all 16 AINx inputs > to be used this way. Is there a use case where the same AINx would be > assigned to multiple channels at the same time? If there are very large numbers of options, common solution is to move to dynamic assignment and channel nodes so DT specifies what is wired. In theory we then allow all combinations at the same time but rely on common sense to restrict it. I don't suggest channel nodes for most drivers because it adds complexity and a few unwired channels being exposed is rarely a problem (mostly people buy the right sized ADC). For cases like this though it can reduce things to a manageable level. Also little purpose in supporting 1-2 and 2-1 which can simplify things somewhat. However that can also be left unconstrained on assumption common sense will be exercised in the DT. > > > > > Looking at Table 20 in the AD7192 datasheet, I can see why AD7192 was > > done this way since only certain combinations of inputs can be used > > together. (Although I think indexes 4 to 7 should really be > > differential because they are the difference between the input and > > AINCOM which may not be GND, but it is probably too late to fix that.) > > > > Tables 22, 23 and 24 in the AD7194 datasheet show that this chip is > > much more configurable than AD7192 when it comes to assigning > > channels. There are basically no restrictions on which inputs can be > > used together. So I am still confident that my suggestion is the way > > to go for AD7194. (Although I didn't actually try it on hardware, so > > can't be 100% confident. But at least 90% confident :-p)
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 59ae1d17b50d..8062a4d1cbe7 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -71,12 +71,17 @@ config AD7124 called ad7124. config AD7192 - tristate "Analog Devices AD7190 AD7192 AD7193 AD7195 ADC driver" + tristate "Analog Devices AD7192 and similar ADC driver" depends on SPI select AD_SIGMA_DELTA help - Say yes here to build support for Analog Devices AD7190, - AD7192, AD7193 or AD7195 SPI analog to digital converters (ADC). + Say yes here to build support for Analog Devices SPI analog to digital + converters (ADC): + - AD7190 + - AD7192 + - AD7193 + - AD7194 + - AD7195 If unsure, say N (but it's safe to say "Y"). To compile this driver as a module, choose M here: the diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index d8393ac048e7..a3ff60ed6f63 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * AD7190 AD7192 AD7193 AD7195 SPI ADC driver + * AD7192 and similar SPI ADC driver * * Copyright 2011-2015 Analog Devices Inc. */ @@ -125,10 +125,39 @@ #define AD7193_CH_AIN8 0x480 /* AIN7 - AINCOM */ #define AD7193_CH_AINCOM 0x600 /* AINCOM - AINCOM */ +#define AD7194_CH_TEMP 0x100 /* Temp sensor */ +#define AD7194_CH_AIN1 0x400 /* AIN1 - AINCOM */ +#define AD7194_CH_AIN2 0x410 /* AIN2 - AINCOM */ +#define AD7194_CH_AIN3 0x420 /* AIN3 - AINCOM */ +#define AD7194_CH_AIN4 0x430 /* AIN4 - AINCOM */ +#define AD7194_CH_AIN5 0x440 /* AIN5 - AINCOM */ +#define AD7194_CH_AIN6 0x450 /* AIN6 - AINCOM */ +#define AD7194_CH_AIN7 0x460 /* AIN7 - AINCOM */ +#define AD7194_CH_AIN8 0x470 /* AIN8 - AINCOM */ +#define AD7194_CH_AIN9 0x480 /* AIN9 - AINCOM */ +#define AD7194_CH_AIN10 0x490 /* AIN10 - AINCOM */ +#define AD7194_CH_AIN11 0x4A0 /* AIN11 - AINCOM */ +#define AD7194_CH_AIN12 0x4B0 /* AIN12 - AINCOM */ +#define AD7194_CH_AIN13 0x4C0 /* AIN13 - AINCOM */ +#define AD7194_CH_AIN14 0x4D0 /* AIN14 - AINCOM */ +#define AD7194_CH_AIN15 0x4E0 /* AIN15 - AINCOM */ +#define AD7194_CH_AIN16 0x4F0 /* AIN16 - AINCOM */ +#define AD7194_CH_POS_MASK GENMASK(7, 4) +#define AD7194_CH_POS(x) FIELD_PREP(AD7194_CH_POS_MASK, (x)) +#define AD7194_CH_NEG_MASK GENMASK(3, 0) +#define AD7194_CH_NEG(x) FIELD_PREP(AD7194_CH_NEG_MASK, (x)) +#define AD7194_CH_DIFF(pos, neg) \ + (AD7194_CH_POS(pos) | AD7194_CH_NEG(neg)) +#define AD7194_CH_DIFF_START 0 +#define AD7194_CH_DIFF_NR 8 +#define AD7194_CH_AIN_START 1 +#define AD7194_CH_AIN_NR 16 + /* ID Register Bit Designations (AD7192_REG_ID) */ #define CHIPID_AD7190 0x4 #define CHIPID_AD7192 0x0 #define CHIPID_AD7193 0x2 +#define CHIPID_AD7194 0x3 #define CHIPID_AD7195 0x6 #define AD7192_ID_MASK GENMASK(3, 0) @@ -166,17 +195,10 @@ enum { ID_AD7190, ID_AD7192, ID_AD7193, + ID_AD7194, ID_AD7195, }; -struct ad7192_chip_info { - unsigned int chip_id; - const char *name; - const struct iio_chan_spec *channels; - u8 num_channels; - const struct iio_info *info; -}; - struct ad7192_state { const struct ad7192_chip_info *chip_info; struct regulator *avdd; @@ -197,6 +219,15 @@ struct ad7192_state { struct ad_sigma_delta sd; }; +struct ad7192_chip_info { + unsigned int chip_id; + const char *name; + const struct iio_chan_spec *channels; + u8 num_channels; + const struct iio_info *info; + int (*parse_channels)(struct ad7192_state *st); +}; + static const char * const ad7192_syscalib_modes[] = { [AD7192_SYSCALIB_ZERO_SCALE] = "zero_scale", [AD7192_SYSCALIB_FULL_SCALE] = "full_scale", @@ -918,6 +949,15 @@ static const struct iio_info ad7192_info = { .update_scan_mode = ad7192_update_scan_mode, }; +static const struct iio_info ad7194_info = { + .read_raw = ad7192_read_raw, + .write_raw = ad7192_write_raw, + .write_raw_get_fmt = ad7192_write_raw_get_fmt, + .read_avail = ad7192_read_avail, + .validate_trigger = ad_sd_validate_trigger, + .update_scan_mode = ad7192_update_scan_mode, +}; + static const struct iio_info ad7195_info = { .read_raw = ad7192_read_raw, .write_raw = ad7192_write_raw, @@ -1009,6 +1049,80 @@ static const struct iio_chan_spec ad7193_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(14), }; +static struct iio_chan_spec ad7194_channels[] = { + AD7193_DIFF_CHANNEL(0, 1, 2, 0x001), + AD7193_DIFF_CHANNEL(1, 3, 4, 0x023), + AD7193_DIFF_CHANNEL(2, 5, 6, 0x045), + AD7193_DIFF_CHANNEL(3, 7, 8, 0x067), + AD7193_DIFF_CHANNEL(4, 9, 10, 0x089), + AD7193_DIFF_CHANNEL(5, 11, 12, 0x0AB), + AD7193_DIFF_CHANNEL(6, 13, 14, 0x0CD), + AD7193_DIFF_CHANNEL(7, 15, 16, 0x0EF), + AD719x_TEMP_CHANNEL(8, AD7194_CH_TEMP), + AD7193_CHANNEL(9, 1, AD7194_CH_AIN1), + AD7193_CHANNEL(10, 2, AD7194_CH_AIN2), + AD7193_CHANNEL(11, 3, AD7194_CH_AIN3), + AD7193_CHANNEL(12, 4, AD7194_CH_AIN4), + AD7193_CHANNEL(13, 5, AD7194_CH_AIN5), + AD7193_CHANNEL(14, 6, AD7194_CH_AIN6), + AD7193_CHANNEL(15, 7, AD7194_CH_AIN7), + AD7193_CHANNEL(16, 8, AD7194_CH_AIN8), + AD7193_CHANNEL(17, 9, AD7194_CH_AIN9), + AD7193_CHANNEL(18, 10, AD7194_CH_AIN10), + AD7193_CHANNEL(19, 11, AD7194_CH_AIN11), + AD7193_CHANNEL(20, 12, AD7194_CH_AIN12), + AD7193_CHANNEL(21, 13, AD7194_CH_AIN13), + AD7193_CHANNEL(22, 14, AD7194_CH_AIN14), + AD7193_CHANNEL(23, 15, AD7194_CH_AIN15), + AD7193_CHANNEL(24, 16, AD7194_CH_AIN16), + IIO_CHAN_SOFT_TIMESTAMP(25), +}; + +static int ad7192_parse_channel(struct fwnode_handle *child) +{ + u32 reg, ain[2]; + int ret; + + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) + return ret; + + if (!in_range(reg, AD7194_CH_DIFF_START, AD7194_CH_DIFF_NR)) + return -EINVAL; + + ret = fwnode_property_read_u32_array(child, "diff-channels", ain, + ARRAY_SIZE(ain)); + if (ret) + return ret; + + if (!in_range(ain[0], AD7194_CH_AIN_START, AD7194_CH_AIN_NR) || + !in_range(ain[1], AD7194_CH_AIN_START, AD7194_CH_AIN_NR)) + return -EINVAL; + + ad7194_channels[reg].channel = ain[0]; + ad7194_channels[reg].channel2 = ain[1]; + ad7194_channels[reg].address = AD7194_CH_DIFF(ain[0], ain[1]); + + return 0; +} + +static int ad7192_parse_channels(struct ad7192_state *st) +{ + struct device *dev = &st->sd.spi->dev; + struct fwnode_handle *child; + int ret; + + device_for_each_child_node(dev, child) { + ret = ad7192_parse_channel(child); + if (ret) { + fwnode_handle_put(child); + return ret; + } + } + + return 0; +} + static const struct ad7192_chip_info ad7192_chip_info_tbl[] = { [ID_AD7190] = { .chip_id = CHIPID_AD7190, @@ -1031,6 +1145,14 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = { .num_channels = ARRAY_SIZE(ad7193_channels), .info = &ad7192_info, }, + [ID_AD7194] = { + .chip_id = CHIPID_AD7194, + .name = "ad7194", + .channels = ad7194_channels, + .num_channels = ARRAY_SIZE(ad7194_channels), + .info = &ad7194_info, + .parse_channels = ad7192_parse_channels, + }, [ID_AD7195] = { .chip_id = CHIPID_AD7195, .name = "ad7195", @@ -1142,6 +1264,12 @@ static int ad7192_probe(struct spi_device *spi) } } + if (st->chip_info->parse_channels) { + ret = st->chip_info->parse_channels(st); + if (ret) + return ret; + } + ret = ad7192_setup(st); if (ret) return ret; @@ -1153,6 +1281,7 @@ static const struct of_device_id ad7192_of_match[] = { { .compatible = "adi,ad7190", .data = &ad7192_chip_info_tbl[ID_AD7190] }, { .compatible = "adi,ad7192", .data = &ad7192_chip_info_tbl[ID_AD7192] }, { .compatible = "adi,ad7193", .data = &ad7192_chip_info_tbl[ID_AD7193] }, + { .compatible = "adi,ad7194", .data = &ad7192_chip_info_tbl[ID_AD7194] }, { .compatible = "adi,ad7195", .data = &ad7192_chip_info_tbl[ID_AD7195] }, {} }; @@ -1162,6 +1291,7 @@ static const struct spi_device_id ad7192_ids[] = { { "ad7190", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7190] }, { "ad7192", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7192] }, { "ad7193", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] }, + { "ad7194", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7194] }, { "ad7195", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] }, {} }; @@ -1178,6 +1308,6 @@ static struct spi_driver ad7192_driver = { module_spi_driver(ad7192_driver); MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); -MODULE_DESCRIPTION("Analog Devices AD7190, AD7192, AD7193, AD7195 ADC"); +MODULE_DESCRIPTION("Analog Devices AD7192 and similar ADC"); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA);