From nobody Sat Sep 26 23:51:54 2026 Received: from mail-vk1-f171.google.com (mail-vk1-f171.google.com [209.85.221.171]) (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 249153CD8C5 for ; Fri, 28 Aug 2026 06:38:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899123; cv=none; b=YBEXDYXOkDEy2eUjnWyQnBVYZW5YommtFhLyITfsqMoxGYTXmUBsib2PJSGUFL3WEKWxTqL71ORVq/eDviEBen5VzJZLFSFxdqkUTDu8LXbkAspOJE2w38krj7vjF+rjgTf+HpV5r7dfoG4nM7bTlVRHKHsso/Mk++1bAnVM67g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899123; c=relaxed/simple; bh=Krf4k0YzPCfh28rpFAoWa340zlykWxBJ3urBqYrCa2I=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZdcUDfE71917Z6s82hePcmn4Ia/8wY3Nn9JzH0D0zsOlx1/r/dTN+fmNKBmSRteRqW138V+106QKLmGkbbVD09pGWQ8cwWp0766LZYg7Wqyf+hke0DaFKoQFzSEhK5Fq6zORiJp4smzsY7itSeENAtctp1Kroq4mKcc611KzuQU= 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=GmGFXTob; arc=none smtp.client-ip=209.85.221.171 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="GmGFXTob" Received: by mail-vk1-f171.google.com with SMTP id 71dfb90a1353d-5bfaa014978so328641e0c.3 for ; Thu, 27 Aug 2026 23:38:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787899121; x=1788503921; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=G5Uw2bvQ4z3aZMIzs9KIbg95WFBUx0+3WqEMDxXt7kU=; b=GmGFXTobeFsXTikgNUeZbAhWQZwkLC70u0zFLf4r09SaFFxZzfY8tF1kvIGq+NeGKc yk3+XD0K6LuZZh4rxnWej/79GKV8DjaFNK/1X5nXco+TmZaF9Qe0r0RgJGoXLuFw8JfS zvBAjiYO4SnEq3FyvfUF2bkEKdX0L/7hZG3Bhk1WpfeXhPCBW6mDK16XlCCVzqvsHkA1 egl+TL5j0bFOJ1DAVjID7iSIjNEdCThwm//fibFQV668GL8jShEMDMtDz41V4u4QfqSE 4jwbSBaGgBjyOv0LVvco9veW1VlXuOh/TKsQb30kP7BEUeUKFobZb52WHCWFOem2R9fm rZAg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787899121; x=1788503921; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=G5Uw2bvQ4z3aZMIzs9KIbg95WFBUx0+3WqEMDxXt7kU=; b=ou/aPDVUplXGIwLWfqqPA2dlDfqabgSdo+Pb8oBtPuSS/zHr8y/5F7Ca95TAgTFFe0 qHe5woPVEIaRwp6jM3mTf+PFkSfFrWxomEV/smsTgRblUjYQL43cfG2SfBSyH29TPu6B 19nWTnSzX1jYIJ6n11kq7VR7lhx/x0wRraTHPzyOlNlUp6HkXggkWCpBZG+iMaWb/zAb /wF5Pw5X3rNArMRe5GIecnaWTvl1gZsI3qnEd14ySuqt7AhhI7BH72l+irNqn4e+5ycA vd1CN7bjzP7vgOPa2BBS343QW0/K3mF7vocOyX0U/waqcOtkDEQqoGsBN6Xc5pq0MxgQ rZmQ== X-Forwarded-Encrypted: i=1; AHgh+RpKFB4+NRyPXYtCZfMiFd92uYJ7tHvFrLSo2oQQCYJ+aOZCpp2ZLFoJLRGUzAUyMNn+qUKxHd091JkP7i8=@vger.kernel.org X-Gm-Message-State: AFuF++mVsJhgn//C0qh58BjIfel2cb28n+iMpwWxGdvlIlAJxJSqNuoi D+2urTtLrYarnJJ0Xvb/fA8NASZ1nuB+DI7G9UVwVP+3qZbCF/8lK6CJ X-Gm-Gg: AR+sD11kNk5s6DnAg2mfJKXdslLQRKXavub7n4a9zfD/ADW9hgHmC1npxNLhw8BmFKw ZIlqCTP4lFzxFKkKjQi5SB9Ot4+LvBZ+7Y56OfgBvsNaz5aNODnM69K6j7gXIMSGZITQ9I3/j0h KFUnrnlgzfXsaaQAKXxaxu+yNx8XIWa6/A41HzzGO/ZICIQK8VioFT0W6REfJKkbgqBZ2jUEILh zlNGUerdZZV3juZT6CtGLRmFwHtm9KWqzypJ3MKY3Fc/WTYcXn9KWlJfFbKDG6F5hCxoumlowdJ xGiUEDKeo7IO6TKKP3GkfMw6dekNLWedgYmXbRvdTzw/ji3tGfNYxCWp9zt582SPWzdNuWuqr+d wqDJGffoYAfNC8Fy5vLC7R9hGag1ZGby/HzSj16ORQ4TEGWViEr2MlII+uHQ7hBSg2kSANknd2e vZZMUIC2AyWL2nNFzMD42t3FmVikOy+OLtozLE5FP5xX8j8+sX0VNwJtq2/Ykz8l5g X-Received: by 2002:a05:6102:50a9:b0:783:79ac:9dc3 with SMTP id ada2fe7eead31-7859a49efb7mr1250451137.10.1787899120853; Thu, 27 Aug 2026 23:38:40 -0700 (PDT) Received: from [192.168.100.153] ([2800:bf0:61:1127:ab87:5602:531c:8dfb]) by smtp.gmail.com with ESMTPSA id a1e0cc1a2514c-97e849d8494sm454195241.1.2026.08.27.23.38.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 23:38:40 -0700 (PDT) From: Kurt Borja Date: Fri, 28 Aug 2026 01:38:16 -0500 Subject: [PATCH v4 01/10] dt-bindings: adc: add excitation-current-chopping property Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260828-ads126x-v4-1-1dc27e9c0260@gmail.com> References: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> In-Reply-To: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , David Lechner Cc: =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=1728; i=kuurtb@gmail.com; h=from:subject:message-id; bh=Krf4k0YzPCfh28rpFAoWa340zlykWxBJ3urBqYrCa2I=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFkTdV6nztI6r94nsmnC0cozS0t97H71Wx9POvfO6799z e4NuhObO0pZGMS4GGTFFFnaExZ9exSV99bvQOh9mDmsTCBDGLg4BWAiCz8x/I+pOmUWk+7zpujz sgPLnpsK3Pr67MmKF9V3j0XGMOzPPreG4X9pp4TFsyO/Qx81JLz/8OD4xu646ikr3p+3sl15SEP 0zj1OAA== X-Developer-Key: i=kuurtb@gmail.com; a=openpgp; fpr=54D3BE170AEF777983C3C63B57E3B6585920A69A Add a generic excitation-current-chopping property. This is a feature seen frequently in ADCs that are designed to ratiometrically measure resistive loads, such as RTDs and strain gauges. Enabling this can reduce any error due to excitation current mismatch by swapping excitation sources of alternate conversions. This can have side-effects in timing and filter response, so it is not always desirable to enable this feature in some applications. Therefore, it is best to make this a property that can be enabled or disabled in the device tree. Suggested-by: David Lechner Signed-off-by: Kurt Borja Acked-by: Conor Dooley --- Documentation/devicetree/bindings/iio/adc/adc.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adc.yaml b/Documenta= tion/devicetree/bindings/iio/adc/adc.yaml index b673eaa5d072..fe20aa8f1bfc 100644 --- a/Documentation/devicetree/bindings/iio/adc/adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adc.yaml @@ -109,6 +109,14 @@ properties: sources. The index in the array corresponds to the same index in the excitation-channels array. =20 + excitation-current-chopping: + type: boolean + description: + If set, the excitation current sources are swapped and averaged on e= very + other conversion to reduce current mismatch. This generally comes at= the + expense of added settling time between conversions, so should be omi= tted + on systems with high-frequency signals or high data rate requirement= s. + burn-out-current-nanoamp: description: Burn-out current sources provide current to the channel's input pins= for --=20 2.55.0 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-vk1-f174.google.com (mail-vk1-f174.google.com [209.85.221.174]) (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 339AC3C1D60 for ; Fri, 28 Aug 2026 06:38:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899130; cv=none; b=urWVDjg19mgzHDcp+R6UT7GShZqorM4TKe4HMtSHmilUosGl4SP5FL8eykWmku5f5qNbxjt+UzvsqqAxwZZH/DXhr3uVhSPVli41v/ivT3xM7PbGl2oIz0Fb2qLC54oa9NtO6BOao5233gpywu8NnWdfWfiXE08Ktcj3ZI/qHzU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899130; c=relaxed/simple; bh=DDo13wwLlYbjGc+vmoTMKrXc8Q3Ay18o6BblG/u9PbA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dHKSSuz+25FOwSP0PGCy+AblvT9oHR6cvjlsq3T3jiqhbiOaIXxow4AF/wFK0C8WMgnbw301757716ZhjW3S0cw9M+Vnmd5RnKHi/oQOZfJeWquTMV9bk9H1QhFSayrsSIj56ENCs3kUMb2mNH/8za7wcwCGRF9dW2m6+z6Mxc8= 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=ZbOHUpAT; arc=none smtp.client-ip=209.85.221.174 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ZbOHUpAT" Received: by mail-vk1-f174.google.com with SMTP id 71dfb90a1353d-5c652293bcdso701743e0c.1 for ; Thu, 27 Aug 2026 23:38:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787899123; x=1788503923; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=jbHEcSo0Yi8Hel90njrfpBZZr+GuK02w+zwFa8IkLTQ=; b=ZbOHUpATu0ftaVFshrVS57VUljA2YRwYwmDV0pRbt/Kq2vThwN1lZMjiQ1tUX/fAvL 2SUKmdvNAKq99hyfaYhPFtMqy2h/yAJqEOY38kWtXyc4jXMxNInpPhdvDm9KrkVuuy/n 7XwKhaiUHPplzuH56CNuZzfRooB/UxjE0pYAreHp5poom+WVHDa2r5Nf/p4SKfDugn23 H/TumWQtjxHsWjcsFaDpFQ84sZ07mgmpXxZc+M804oohlLq7ZTNjVeVCtlD4WCHgKt/X 49Lj7jdPZkAnmLGduHIepBcUzf+mcVMfY0AgoEpawwd6CLAGLOoWTZE/3y9orD3gz3vI QITg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787899123; x=1788503923; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=jbHEcSo0Yi8Hel90njrfpBZZr+GuK02w+zwFa8IkLTQ=; b=Dz1Qni7XkywYfZZjKS/vz0sx63cMW3Ch0Obd6Bx8gsbB1FxuUTeN/q0ln3L6UTwS4m RbPRNAIDgyhYbFbNUzVNv1ytKyCyjnXsu8zAXBzYfpNhcEOh/JfcXiraT2xCnUpvTaLp qPOwo8MO0Bc0qstiKpACPckJjVyPLVMOtTgt0AVZRNKs1gLUDNgthYkvvnbiRqQzec5u QzXw37C5aW8+YUKHur5wBA5oJJI/5A6PMxfe6Af4B1AkXeT+eneGJL29LL9Zrnr5WYQe Fn3hOLpBUyppPiXVgU8sAY4iu1bABPtb7L48IzG3MNCsEBEFvteCnoOlaC4MwZC16274 gWxQ== X-Forwarded-Encrypted: i=1; AHgh+RpmhmhOlgz3aJ4kvlQk0aKK4clbPxhb/segsqQnsGhRtOjupjN/dic2yijwklP9kzdDextS12nIk1xvZTk=@vger.kernel.org X-Gm-Message-State: AFuF++kgDrwj1YSymrQZOysd4MI+AB+0CzZY+NjMIowgK952+mMl/y8V A/7e+3pU3AyNCEMI84veIi8O/PEiqBWzreqTgG8hBaNTsZ5EkTfWbS2B X-Gm-Gg: AR+sD109p425oad2O2Qw2fbJxaB6YBMNBmSV1Pd6jS++ga/aNDGX7gqRIGaIqu/kTC6 8fZVpP9EWvdri4V4eLKwK//dKMMnoKrZk9oR6lUQgie4E5paTffK0bjotoVEc0vcPV2l1Cscg7p bk5DM9++xX74SFNZCS/dEN73FgE+RhI0l85pumIPfGAoAgLX/X/oDvVyZGzDNi/AiKTd8L1fE2d l6kGdbDLdUR5/giP5ReRvvTCpy7pGZo0iAxNBv4FUyH6wlJ+MJ8CD0SqT2F/c2u6UrssOQWRnpX fQdQn83wX9ZossAMRJhfqft0jospVwX/n9Y6W6PBGQ7S9y89KIiFQVwZUP27AG+sHsKDgx8cMkT 4AM6B/dtRI8wggYbT0bDYm89cQXREpyX+feg0I3YAFfxxk+KI99uWeZV177b8d2O/F6baFYSl5H T1C/vI6XhgXUcRGnd2zIURNpMjSAncor6hKX0wyFA/WsUAfCt/kJcZaPhT7ULv3CFR X-Received: by 2002:a05:6122:9001:b0:5c6:7f44:b001 with SMTP id 71dfb90a1353d-5c680967056mr2104219e0c.0.1787899122940; Thu, 27 Aug 2026 23:38:42 -0700 (PDT) Received: from [192.168.100.153] ([2800:bf0:61:1127:ab87:5602:531c:8dfb]) by smtp.gmail.com with ESMTPSA id a1e0cc1a2514c-97e849d8494sm454195241.1.2026.08.27.23.38.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 23:38:42 -0700 (PDT) From: Kurt Borja Date: Fri, 28 Aug 2026 01:38:17 -0500 Subject: [PATCH v4 02/10] dt-bindings: iio: adc: support the TI ADS126x ADC family Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260828-ads126x-v4-2-1dc27e9c0260@gmail.com> References: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> In-Reply-To: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , David Lechner Cc: =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=12770; i=kuurtb@gmail.com; h=from:subject:message-id; bh=DDo13wwLlYbjGc+vmoTMKrXc8Q3Ay18o6BblG/u9PbA=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFkTdd7sqJ1hvVd+1nN9pvPXmsoEpA4vq/xzR2pPcXxtk ejaP+xLO0pZGMS4GGTFFFnaExZ9exSV99bvQOh9mDmsTCBDGLg4BWAi75cz/E9T1Amct+/um/lu 6/rVc99f6DZyDvyZf/FRz0u21+6WfncZ/uk/61i/tlA6QFqx6ib32VcKOx/p7H30feWHyXwpsy7 UpHACAA== X-Developer-Key: i=kuurtb@gmail.com; a=openpgp; fpr=54D3BE170AEF777983C3C63B57E3B6585920A69A The ADS1262 and ADS1263 are 32-bit, 38.4-kSPS delta-sigma ADCs with an integrated PGA, internal reference, excitation and burn-out current sources for sensor biasing and diagnostics. The ADS1263 is compatible with ADS1262, but includes a second auxiliary ADC (ADC2) to perform main channel (ADC1) cross-checking measurements, system background measurements, or temperature compensation of the primary sensor. Both parts can configure per-channel voltage reference source, excitation current sources (IDAC), plus input and IDAC chopping for offset and IDAC mismatch cancellation. This lets the device drive and ratiometrically measure RTDs and other resistive sensors. Signed-off-by: Kurt Borja Reviewed-by: David Lechner --- .../devicetree/bindings/iio/adc/ti,ads1262.yaml | 376 +++++++++++++++++= ++++ MAINTAINERS | 6 + 2 files changed, 382 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1262.yaml b/Do= cumentation/devicetree/bindings/iio/adc/ti,ads1262.yaml new file mode 100644 index 000000000000..7e26572388e4 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1262.yaml @@ -0,0 +1,376 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/ti,ads1262.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI ADS1262/ADS1263 analog to digital converter + +maintainers: + - Kurt Borja + +description: | + The ADS1262 and ADS1263 are 38.4-kSPS, delta-sigma (=CE=94=CE=A3) ADCs w= ith an + integrated PGA, reference, and internal fault monitors. The ADS1263 inte= grates + an auxiliary, 24-bit, =CE=94=CE=A3 ADC intended for background measureme= nts. + + Datasheets: + - ADS126x: https://www.ti.com/lit/ds/symlink/ads1262.pdf + +properties: + compatible: + oneOf: + - const: ti,ads1262 + - items: + - const: ti,ads1263 + - const: ti,ads1262 + + reg: + maxItems: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + spi-max-frequency: + maximum: 8000000 + + spi-cpha: true + + interrupts: + minItems: 1 + maxItems: 2 + description: Data ready (DRDY) interrupt lines. + + interrupt-names: + description: + The data ready (DRDY) signal has two independent interrupt lines. A + dedicated DRDY pin and a pin shared with the serial interface MISO p= in, + which is called DOUT/DRDY. + minItems: 1 + maxItems: 2 + items: + enum: [drdy, doutdrdy] + + start-gpios: + description: Start conversion control. + maxItems: 1 + + reset-gpios: + maxItems: 1 + + dvdd-supply: + description: Digital power supply. + + avdd-supply: + description: + Analog power supply. In bipolar supply configurations, the reported + voltage should be in reference to DGND. + + avss-supply: + description: + Negative analog power supply for bipolar configurations. AVSS can on= ly be + at or below the ground reference (DGND). If not described, AVSS is a= ssumed + to be connected to ground (0V). + + clocks: + maxItems: 1 + + '#io-channel-cells': + minimum: 1 + maximum: 2 + description: | + The first cell selects the channel by its reg. The second cell selec= ts + between the main ADC (ADC1) and the auxiliary ADC (ADC2) as follows: + 0: ADC1 + 1: ADC2 + + '#gpio-cells': + const: 2 + + gpio-controller: true + + regulators: + type: object + description: + List of regulators provided by this chip. + + properties: + vbias: + $ref: /schemas/regulator/regulator.yaml# + type: object + description: + Level-shift voltage output on the AINCOM pin. Its output is the + mid-voltage of the analog supply, (AVDD + AVSS) / 2, and is used= to + shift floating sensors to within the ADC input range. + unevaluatedProperties: false + + refout: + $ref: /schemas/regulator/regulator.yaml# + type: object + description: + Buffered internal voltage reference output on the REFOUT pin. + unevaluatedProperties: false + + additionalProperties: false + +patternProperties: + "^ain([0-9]|com)-supply$": + description: + Common-mode voltage supply connected to AIN or AINCOM. + + "^refp[1-3]-supply$": + description: + Positive voltage reference connected to REFP1 (AIN0), REFP2 (AIN2) or + REFP3 (AIN4). If this regulator is not described and a channel selec= ts + it as a reference source, then it's assumed to be connected to ground + (0V). + + "^refn[1-3]-supply$": + description: + Negative voltage reference connected to REFN1 (AIN1), REFN2 (AIN3) or + REFN3 (AIN5). If this regulator is not described and a channel selec= ts + it as a reference source, then it's assumed to be connected to ground + (0V). + + "^ti,refp[1-3]-refn[1-3]-resistor-ohms$": + description: + Magnitude of the external reference resistor connected between REFP<= N> + and REFN. In ratiometric configurations, such as RTD measurements= , the + IDAC excitation current returns through this resistor, generating the + reference voltage for the conversion. + + "^channel@[0-9a-f]+$": + $ref: /schemas/iio/adc/adc.yaml# + unevaluatedProperties: false + + properties: + reg: + maxItems: 1 + + single-channel: + minimum: 0 + maximum: 10 + + common-mode-channel: + minimum: 0 + maximum: 10 + default: 10 + + diff-channels: + items: + minimum: 0 + maximum: 10 + + input-chopping: true + + reference-sources: + minItems: 2 + description: + Indicates the reference sources for this channel. The first and = second + items are the positive (REFP) and negative (REFN) sources of the= main + ADC (ADC1). The third item is the reference source of the second= ary + ADC (ADC2) and must always have a positive differential voltage. + items: + - enum: [internal-p, refp1, refp2, refp3, avdd] + - enum: [internal-n, refn1, refn2, refn3, avss] + - enum: [internal, refp1-refn1, refp2-refn2, refp3-refn3, avdd-a= vss] + + ti,reference-reversal: + $ref: /schemas/types.yaml#/definitions/flag + description: + Indicates that the ADC1 (this has no effect on ADC2) reference v= oltage + for this channel has negative polarity and thus should be intern= ally + reversed. + + excitation-channels: + minItems: 1 + maxItems: 2 + description: + Selects the pins for the IDAC sources from 0 (AIN0) to 10 (AINCO= M). + The first value corresponds to IDAC1 and the second to IDAC2. + items: + minimum: 0 + maximum: 10 + + excitation-current-nanoamp: + minItems: 1 + maxItems: 2 + description: + The first value corresponds to IDAC1 and the second to IDAC2. + items: + enum: [50000, 100000, 250000, 500000, 750000, 1000000, 1500000, + 2000000, 2500000, 3000000] + + excitation-current-chopping: true + + burn-out-current-nanoamp: + description: + Selects current magnitude for the sensor bias current source. + enum: [500, 2000, 10000, 50000, 200000] + + ti,burn-out-resistor: + $ref: /schemas/types.yaml#/definitions/flag + description: + Instead of a fixed current, the sensor bias (burn-out) current s= ource + can be pulled using an internal 10 M=CE=A9 resistor. + + ti,burn-out-polarity: + $ref: /schemas/types.yaml#/definitions/string + description: + The sensor bias can be configured to either pull-up or pull-down= mode. + In pull-up mode, the current flows into the positive input and f= lows + out of the negative input. In pull-down mode, the polarities are + reversed. + enum: [pull-up, pull-down] + default: pull-up + + dependencies: + excitation-channels: [excitation-current-nanoamp] + excitation-current-nanoamp: [excitation-channels] + burn-out-current-nanoamp: + not: + required: + - ti,burn-out-resistor + + required: + - reg + + allOf: + - if: + properties: + excitation-channels: + maxItems: 1 + required: + - excitation-channels + then: + properties: + excitation-current-nanoamp: + maxItems: 1 + else: + properties: + excitation-current-nanoamp: + minItems: 2 + + oneOf: + - required: [single-channel] + - required: [diff-channels] + +dependencies: + interrupts: [interrupt-names] + interrupts-extended: [interrupt-names] + +required: + - compatible + - reg + - spi-cpha + - avdd-supply + - dvdd-supply + - '#address-cells' + - '#size-cells' + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + - if: + properties: + compatible: + contains: + const: ti,ads1263 + then: + properties: + '#io-channel-cells': + minimum: 1 + maximum: 2 + patternProperties: + "^channel@[0-9]+$": + properties: + reference-sources: + minItems: 3 + maxItems: 3 + default: [internal-p, internal-n, internal] + else: + properties: + '#io-channel-cells': + const: 1 + patternProperties: + "^channel@[0-9]+$": + properties: + reference-sources: + minItems: 2 + maxItems: 2 + default: [internal-p, internal-n] + +unevaluatedProperties: false + +examples: + - | + #include + #include + + spi { + #address-cells =3D <1>; + #size-cells =3D <0>; + + adc@0 { + compatible =3D "ti,ads1262"; + reg =3D <0>; + spi-max-frequency =3D <8000000>; + spi-cpha; + avdd-supply =3D <&avdd>; + dvdd-supply =3D <&dvdd>; + #address-cells =3D <1>; + #size-cells =3D <0>; + + interrupts-extended =3D <&gpio 0 IRQ_TYPE_EDGE_FALLING>; + interrupt-names =3D "drdy"; + + /* Typical common mode voltage configuration */ + aincom-supply =3D <&ads1262_vbias>; + + regulators { + ads1262_vbias: vbias { }; + }; + + channel@0 { + reg =3D <0>; + single-channel =3D <0>; + /* The VBIAS is enabled on pin 10 (AINCOM) */ + common-mode-channel =3D <10>; + }; + }; + }; + + - | + #include + #include + + spi { + #address-cells =3D <1>; + #size-cells =3D <0>; + + adc@0 { + compatible =3D "ti,ads1263", "ti,ads1262"; + reg =3D <0>; + spi-max-frequency =3D <8000000>; + spi-cpha; + avdd-supply =3D <&avdd>; + dvdd-supply =3D <&dvdd>; + #address-cells =3D <1>; + #size-cells =3D <0>; + + interrupts-extended =3D <&gpio 0 IRQ_TYPE_EDGE_FALLING>; + interrupt-names =3D "drdy"; + + ti,refp2-refn2-resistor-ohms =3D <3520>; + + channel@0 { + reg =3D <0>; + diff-channels =3D <4 5>; + reference-sources =3D "refp2", "refn2", "refp2-refn2"; + excitation-channels =3D <1 6>; + excitation-current-nanoamp =3D <500000 500000>; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index f3be900e5b9d..7593e33c5346 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27019,6 +27019,12 @@ S: Maintained F: Documentation/devicetree/bindings/iio/adc/ti,ads1018.yaml F: drivers/iio/adc/ti-ads1018.c =20 +TI ADS1262 ADC DRIVER +M: Kurt Borja +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/adc/ti,ads1262.yaml + TI ADS7924 ADC DRIVER M: Hugo Villeneuve L: linux-iio@vger.kernel.org --=20 2.55.0 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-vk1-f170.google.com (mail-vk1-f170.google.com [209.85.221.170]) (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 3E569353EC0 for ; Fri, 28 Aug 2026 06:38:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899129; cv=none; b=QS8vJ1BgIeWnKsU9N/mQg3HcGFD9WwDk+f9m4WiyY3aO+HHqQTNT2dIT1PuT71WCOUw9NqN7MHgQCLqkHeqBGIhQFmU3VX9DthrxnYZR9Sown0bEvvwA81InC6i5hazrv5mzS/PNsAvZiXJMzc5L+HofId7tkfX91ENDa2//S/k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899129; c=relaxed/simple; bh=qM+psbpPMKecS6Frc5TQrp5WPkK3AO5+QH56k7Jf9Mc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=l6mAThwKJUidN8uANFEhn/0kAEyv18WO1cCrmoFaj1dMN0igEjZe4x6qv1ktztvFHho8/oDxJNhUUY5hPcfq6TqUUAZisPTabA3C4WNzYQiexPTZtoJuyzyTBeXQxDj/0PRbJExFR76AwsNzpq0evgvwFd0ien6YeaqgVxH8l4c= 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=LUijQc1+; arc=none smtp.client-ip=209.85.221.170 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="LUijQc1+" Received: by mail-vk1-f170.google.com with SMTP id 71dfb90a1353d-5bfc5b77c02so420993e0c.0 for ; Thu, 27 Aug 2026 23:38:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787899125; x=1788503925; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=lxGjuUBDnyEZMCiyc70yqKTmThg3Adr3ktzRc+g6Nwo=; b=LUijQc1++f8W7crz95iFDIE4e83zaHE/eyaRL1Jz6qLfpfsX/9rm+2ph2Q5AAJZTff NqbNPNh7twZ9bL1yhfG7WUMYnmSc5M04i8HYFRToCbKgSKM9rzdCTPYN6zg0A57MgLnc KKhSALNK+XnHL2hhfZugdKh/JuhTBAaGpg9eKl7hU97/uwLUBJ/0n+1Ada4S9YGjucOJ hmthai3umdTTa18Jqid3maV+QEq0Q3udrs7HfMp588Pk8+ZMr+Cgd3De0OVeUvtWr83g Z99oQVg8B7G4OUYh51Ys6Q3Xsi6Wsq6inqegzvMRx87dGjTRP0wJ54SUBN3bSVgBEj6n i5jg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787899125; x=1788503925; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=lxGjuUBDnyEZMCiyc70yqKTmThg3Adr3ktzRc+g6Nwo=; b=KMI0AoL5gEv+A3mLfMSk7I0pavfucAfoaaiNupE/zz1RuBMWfLzIfIeSY6YsqJ6fq2 /RNmsn8joWSgUG5luKiz1/UXYmy+i/bEx/p6X+nS5ZkKbQZey4MLk/kH0uVrOk7Tombu NrzaeRJj1w/gQHMk128uQH2J8PXSM/HdZkEu56McDsvuqOysMy5NN+mX60DhVe3Njw5P QvH0GT6oCQU6VdPLcYNOtUyxc1zvEldfvs/hfENaqhqchRKA5+JszNCAMmKDTBCSuywO zqkWeBZ+mtf/GCY0XnXMjs5NYktVdVHBOeESAuZCbxjCGFdOBsNBK7QeRUWL8xpiWhXH WqFw== X-Forwarded-Encrypted: i=1; AHgh+RqG499oWLNX6TDYbxYtV4uFk38eUec6QdR5SS1xOPwjDmW19ha8eAF2BoQThPfOfayBOvIgkvcWNH1NNxE=@vger.kernel.org X-Gm-Message-State: AFuF++klzBSG67gmau7ssI0d/iLGvJK73AEpmGK+d0c5QTBf22Ov6C7t fvyPf7cFMEM3qpTpLs74yOxqK5PWBLdKSs6QBD8eYksjmxYiVaHE/NoO X-Gm-Gg: AR+sD13qnMVkWhW7XvXug3YErd1eu/M2hnGRMIHz/GFzAeO1GiGpPzFtmFbTHv1CiCP xvEnMAn04IoYTFN7QL6Qf5TGPo/sD43CGDJcM3dy2LioGGUMAof4K63V2kF+AYb01SPDhlOHzZH pq2khTdGNpsfIgekYYyBdAie37hhdXBNfUhFcJf236X3hwOmFer8001KCzwPNHbmgVnTPq+BphT dfZvzIy3gKgrnWMRG2tlcacSWEhIVYkEtHXWEVLsML/m7uYAKLJJbmkIxkIgTzyzcHoquEOK4Vn nVcFICseJcIDrfvpe+wlN4qY1DhA+UXuet8eMTzcEVZ7U4q+paIHT4pCGS7lhpFRwdm5z2oR/GA 0PWE2AIradPzRyzgxPsKJYhovKR9VajshLwgWsi0GYcbihqtcrQLyNTftAMBxbmrHq/GM/fQj/v yfBoMqapciuIQVnYKjYZ6BixzOasU7yZLL+XRpfuy53nq4TRIXbHeR7DBl+c/+9v00 X-Received: by 2002:a05:6122:886:b0:5bf:9461:91d with SMTP id 71dfb90a1353d-5c6814ccd75mr2041545e0c.5.1787899125022; Thu, 27 Aug 2026 23:38:45 -0700 (PDT) Received: from [192.168.100.153] ([2800:bf0:61:1127:ab87:5602:531c:8dfb]) by smtp.gmail.com with ESMTPSA id a1e0cc1a2514c-97e849d8494sm454195241.1.2026.08.27.23.38.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 23:38:44 -0700 (PDT) From: Kurt Borja Date: Fri, 28 Aug 2026 01:38:18 -0500 Subject: [PATCH v4 03/10] iio: adc: add the ti-ads1262 driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260828-ads126x-v4-3-1dc27e9c0260@gmail.com> References: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> In-Reply-To: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , David Lechner Cc: =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=29125; i=kuurtb@gmail.com; h=from:subject:message-id; bh=qM+psbpPMKecS6Frc5TQrp5WPkK3AO5+QH56k7Jf9Mc=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFkTdd4Er/Jw69Srm3Nm37G6IsHAvH0aGrYa0XJ/Wz8mT /27OGdqRykLgxgXg6yYIkt7wqJvj6Ly3vodCL0PM4eVCWQIAxenAEzkwheGf0qhT35U6U8RmmXo 4zFX/5JTVNsR1wXLZX2XL9u+2jFZw4KR4fammcwN3G5Xz011upOpMltt1YWWpoNPlzQabdU6F/M 3hAUA X-Developer-Key: i=kuurtb@gmail.com; a=openpgp; fpr=54D3BE170AEF777983C3C63B57E3B6585920A69A Add the ti-ads1262 driver with initial support for the primary ADC (ADC1). The ADS1263 auxiliary ADC (ADC2) is handled by a separate driver and interoperability considerations were taken into account. Various features such as accurate timeout delays, per-channel reference sources, scale, offset, settling latency, excitation currents and diagnostics are intentionally left out for future support. Signed-off-by: Kurt Borja --- MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 11 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ti-ads1262.c | 938 +++++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 951 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7593e33c5346..0607aa90a6b1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27024,6 +27024,7 @@ M: Kurt Borja L: linux-iio@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/iio/adc/ti,ads1262.yaml +F: drivers/iio/adc/ti-ads1262.c =20 TI ADS7924 ADC DRIVER M: Hugo Villeneuve diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 38e212a6f789..e51ce42bce94 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1860,6 +1860,17 @@ config TI_ADS124S08 This driver can also be built as a module. If so, the module will be called ti-ads124s08. =20 +config TI_ADS1262 + tristate "Texas Instruments ADS1262" + depends on SPI + select REGMAP + help + If you say yes here you get support for Texas Instruments ADS1262 and + ADS1263 ADC chips. + + This driver can also be built as a module. If so, the module will be + called ti-ads1262. + config TI_ADS1298 tristate "Texas Instruments ADS1298" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 9271a5e1ba01..989bed6fba3d 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -158,6 +158,7 @@ obj-$(CONFIG_TI_ADS1100) +=3D ti-ads1100.o obj-$(CONFIG_TI_ADS1119) +=3D ti-ads1119.o obj-$(CONFIG_TI_ADS112C14) +=3D ti-ads112c14.o obj-$(CONFIG_TI_ADS124S08) +=3D ti-ads124s08.o +obj-$(CONFIG_TI_ADS1262) +=3D ti-ads1262.o obj-$(CONFIG_TI_ADS1298) +=3D ti-ads1298.o obj-$(CONFIG_TI_ADS131E08) +=3D ti-ads131e08.o obj-$(CONFIG_TI_ADS131M02) +=3D ti-ads131m02.o diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c new file mode 100644 index 000000000000..d919144c23cb --- /dev/null +++ b/drivers/iio/adc/ti-ads1262.c @@ -0,0 +1,938 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Texas Instruments ADS1262 ADC driver + * + * Copyright (C) 2026 Kurt Borja + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define ADS1262_OPCODE_NOP 0x00 +#define ADS1262_OPCODE_RESET 0x06 +#define ADS1262_OPCODE_START1 0x08 +#define ADS1262_OPCODE_STOP1 0x0A +#define ADS1262_OPCODE_START2 0x0C +#define ADS1262_OPCODE_STOP2 0x0E +#define ADS1262_OPCODE_RDATA1 0x12 +#define ADS1262_OPCODE_RDATA2 0x14 +#define ADS1262_OPCODE_SYOCAL1 0x16 +#define ADS1262_OPCODE_SYGCAL1 0x17 +#define ADS1262_OPCODE_SFOCAL1 0x19 +#define ADS1262_OPCODE_SYOCAL2 0x1B +#define ADS1262_OPCODE_SYGCAL2 0x1C +#define ADS1262_OPCODE_SFOCAL2 0x1E +#define ADS1262_OPCODE_RREG 0x20 +#define ADS1262_OPCODE_WREG 0x40 + +#define ADS1262_ID_REG 0x00 +#define ADS1262_DEV_ID_MASK GENMASK(7, 5) +#define ADS1262_DEV_ID 0 +#define ADS1263_DEV_ID 1 +#define ADS1262_REV_ID_MASK GENMASK(4, 0) + +#define ADS1262_POWER_REG 0x01 +#define ADS1262_POWER_RESET_MASK BIT(4) +#define ADS1262_POWER_VBIAS_MASK BIT(1) +#define ADS1262_POWER_INTREF_MASK BIT(0) + +#define ADS1262_INTERFACE_REG 0x02 +#define ADS1262_INTERFACE_TIMEOUT_MASK BIT(3) +#define ADS1262_INTERFACE_STATUS_MASK BIT(2) +#define ADS1262_INTERFACE_CRC_MASK GENMASK(1, 0) + +#define ADS1262_MODE0_REG 0x03 +#define ADS1262_MODE0_REFREV_MASK BIT(7) +#define ADS1262_MODE0_RUNMODE_MASK BIT(6) +#define ADS1262_RUNMODE_CONTINUOUS 0 +#define ADS1262_RUNMODE_PULSE 1 +#define ADS1262_MODE0_IDAC_CHOP_MASK BIT(5) +#define ADS1262_MODE0_INPUT_CHOP_MASK BIT(4) +#define ADS1262_MODE0_DELAY_MASK GENMASK(3, 0) + +#define ADS1262_MODE1_REG 0x04 +#define ADS1262_MODE1_FILTER_MASK GENMASK(7, 5) +#define ADS1262_FILTER_FIR 4 +#define ADS1262_MODE1_SBADC_MASK BIT(4) +#define ADS1262_MODE1_SBPOL_MASK BIT(3) +#define ADS1262_MODE1_SBMAG_MASK GENMASK(2, 0) + +#define ADS1262_MODE2_REG 0x05 +#define ADS1262_MODE2_BYPASS_MASK BIT(7) +#define ADS1262_MODE2_GAIN_MASK GENMASK(6, 4) +#define ADS1262_MODE2_DR_MASK GENMASK(3, 0) +#define ADS1262_DR_2_5_SPS 0 +#define ADS1262_DR_5_SPS 1 +#define ADS1262_DR_10_SPS 2 +#define ADS1262_DR_16_6_SPS 3 +#define ADS1262_DR_20_SPS 4 +#define ADS1262_DR_50_SPS 5 +#define ADS1262_DR_60_SPS 6 +#define ADS1262_DR_100_SPS 7 +#define ADS1262_DR_400_SPS 8 +#define ADS1262_DR_1200_SPS 9 +#define ADS1262_DR_2400_SPS 10 +#define ADS1262_DR_4800_SPS 11 +#define ADS1262_DR_7200_SPS 12 +#define ADS1262_DR_14400_SPS 13 +#define ADS1262_DR_19200_SPS 14 +#define ADS1262_DR_38400_SPS 15 + +#define ADS1262_INPMUX_REG 0x06 +#define ADS1262_INPMUX_MUXP_MASK GENMASK(7, 4) +#define ADS1262_INPMUX_MUXN_MASK GENMASK(3, 0) +#define ADS1262_INPMUX_AIN1 1 +#define ADS1262_INPMUX_AINCOM 10 +#define ADS1262_INPMUX_TEMP 11 +#define ADS1262_INPMUX_AVDD 12 +#define ADS1262_INPMUX_DVDD 13 +#define ADS1262_INPMUX_TDAC 14 +#define ADS1262_INPMUX_FLOAT 15 + +#define ADS1262_OFCAL0_REG 0x07 +#define ADS1262_OFCAL1_REG 0x08 +#define ADS1262_OFCAL2_REG 0x09 +#define ADS1262_FSCAL0_REG 0x0A +#define ADS1262_FSCAL1_REG 0x0B +#define ADS1262_FSCAL2_REG 0x0C + +#define ADS1262_IDACMUX_REG 0x0D +#define ADS1262_IDACMUX_MUX2_MASK GENMASK(7, 4) +#define ADS1262_IDACMUX_MUX1_MASK GENMASK(3, 0) +#define ADS1262_IDACMUX_NO_CONN 0b1011 + +#define ADS1262_IDACMAG_REG 0x0E +#define ADS1262_IDACMAG_MAG2_MASK GENMASK(7, 4) +#define ADS1262_IDACMAG_MAG1_MASK GENMASK(3, 0) + +#define ADS1262_REFMUX_REG 0x0F +#define ADS1262_REFMUX_RMUXP_MASK GENMASK(5, 3) +#define ADS1262_REFMUX_RMUXN_MASK GENMASK(2, 0) + +#define ADS1262_TDACP_REG 0x10 +#define ADS1262_TDACP_OUTP_MASK BIT(7) +#define ADS1262_TDACP_MAGP_MASK GENMASK(4, 0) + +#define ADS1262_TDACN_REG 0x11 +#define ADS1262_TDACN_OUTN_MASK BIT(7) +#define ADS1262_TDACN_MAGN_MASK GENMASK(4, 0) + +#define ADS1262_GPIOCON_REG 0x12 +#define ADS1262_GPIODIR_REG 0x13 +#define ADS1262_GPIODAT_REG 0x14 + +#define ADS1262_ADC2CFG_REG 0x15 +#define ADS1262_ADC2CFG_DR2_MASK GENMASK(7, 6) +#define ADS1262_ADC2CFG_REF2_MASK GENMASK(5, 3) +#define ADS1262_ADC2CFG_GAIN2_MASK GENMASK(2, 0) + +#define ADS1262_ADC2MUX_REG 0x16 +#define ADS1262_ADC2MUX_MUXP2_MASK GENMASK(7, 4) +#define ADS1262_ADC2MUX_MUXN2_MASK GENMASK(3, 0) + +#define ADS1262_ADC2OFC0_REG 0x17 +#define ADS1262_ADC2OFC1_REG 0x18 +#define ADS1262_ADC2FSC0_REG 0x19 +#define ADS1262_ADC2FSC1_REG 0x1A + +#define ADS1262_REG_COUNT (ADS1262_ADC2FSC1_REG + 1) + +/* + * The power transition timing requirement is 65536 clock cycles, at the m= inimum + * clock frequency this is 65536 microseconds. + */ +#define ADS1262_POWER_TRANS_USECS 65536 + +#define ADS1262_NOMINAL_CLK_RATE 7372800 + +#define ADS1262_FW_CHANNEL_COUNT 16 +#define ADS1262_MON_CHANNEL_COUNT 4 +#define ADS1262_REGMAP_WRITE_SZ 8 +#define ADS1262_MONITOR_ADDR_OFFSET 100 + +#define ADS1262_ADC1_RESOLUTION 32 + +struct ads1262 { + struct spi_device *spi; + struct regmap *regmap; + struct gpio_desc *start_gpiod; + /* protects concurrent SPI transfers */ + struct mutex xfer_lock; + /* protects channel state */ + struct mutex chan_lock; + struct completion drdy; + unsigned long clk_rate; + u8 dev_id; +}; + +static const char * const ads1262_device_id_to_name[] =3D { + [ADS1262_DEV_ID] =3D "ads1262", + [ADS1263_DEV_ID] =3D "ads1263", +}; + +static const struct iio_chan_spec ads1262_monitor_chan_specs[] =3D { + { + .type =3D IIO_TEMP, + .channel =3D ADS1262_INPMUX_TEMP, + .channel2 =3D ADS1262_INPMUX_TEMP, + .address =3D ADS1262_MONITOR_ADDR_OFFSET + 0, + .scan_type =3D { + .format =3D IIO_SCAN_FORMAT_SIGNED_INT, + .realbits =3D ADS1262_ADC1_RESOLUTION, + .storagebits =3D 32, + .endianness =3D IIO_BE, + }, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), + }, + { + .type =3D IIO_VOLTAGE, + .channel =3D ADS1262_INPMUX_AVDD, + .channel2 =3D ADS1262_INPMUX_AVDD, + .indexed =3D 1, + .address =3D ADS1262_MONITOR_ADDR_OFFSET + 1, + .scan_type =3D { + .format =3D IIO_SCAN_FORMAT_SIGNED_INT, + .realbits =3D ADS1262_ADC1_RESOLUTION, + .storagebits =3D 32, + .endianness =3D IIO_BE, + }, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), + }, + { + .type =3D IIO_VOLTAGE, + .channel =3D ADS1262_INPMUX_DVDD, + .channel2 =3D ADS1262_INPMUX_DVDD, + .indexed =3D 1, + .address =3D ADS1262_MONITOR_ADDR_OFFSET + 2, + .scan_type =3D { + .format =3D IIO_SCAN_FORMAT_SIGNED_INT, + .realbits =3D ADS1262_ADC1_RESOLUTION, + .storagebits =3D 32, + .endianness =3D IIO_BE, + }, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), + }, + { + .type =3D IIO_VOLTAGE, + .channel =3D ADS1262_INPMUX_TDAC, + .channel2 =3D ADS1262_INPMUX_TDAC, + .indexed =3D 1, + .differential =3D 1, + .address =3D ADS1262_MONITOR_ADDR_OFFSET + 3, + .scan_type =3D { + .format =3D IIO_SCAN_FORMAT_SIGNED_INT, + .realbits =3D ADS1262_ADC1_RESOLUTION, + .storagebits =3D 32, + .endianness =3D IIO_BE, + }, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), + }, +}; + +static int ads1262_dev_send_cmd(struct ads1262 *st, u8 opcode) +{ + guard(mutex)(&st->xfer_lock); + + return spi_write_then_read(st->spi, &opcode, sizeof(opcode), NULL, 0); +} + +static int ads1262_dev_read_by_cmd(struct ads1262 *st, u8 cmd, __be32 *val) +{ + guard(mutex)(&st->xfer_lock); + + return spi_write_then_read(st->spi, &cmd, sizeof(cmd), val, sizeof(*val)); +} + +static int ads1262_dev_reset(struct ads1262 *st) +{ + struct device *dev =3D &st->spi->dev; + struct gpio_desc *reset_gpiod; + int ret; + + reset_gpiod =3D devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(reset_gpiod)) + return dev_err_probe(dev, PTR_ERR(reset_gpiod), + "failed to get reset GPIO\n"); + + if (reset_gpiod) { + /* + * Wait a power transition cycle to ensure we are in a + * powered-off state after acquiring the RESET GPIO. + */ + fsleep(ADS1262_POWER_TRANS_USECS); + + ret =3D gpiod_set_value_cansleep(reset_gpiod, 0); + if (ret) + return ret; + + fsleep(ADS1262_POWER_TRANS_USECS); + } else { + ret =3D ads1262_dev_send_cmd(st, ADS1262_OPCODE_RESET); + if (ret) + return ret; + /* + * The RESET timing requirement is 8 clock cycles, at the + * minimum clock rate this is 8 microseconds. + */ + fsleep(8); + } + + return 0; +} + +static int ads1262_dev_start(struct ads1262 *st) +{ + int ret; + + if (st->start_gpiod) + ret =3D gpiod_set_value_cansleep(st->start_gpiod, 1); + else + ret =3D ads1262_dev_send_cmd(st, ADS1262_OPCODE_START1); + + return ret; +} + +static int ads1262_dev_stop(struct ads1262 *st) +{ + int ret; + + if (st->start_gpiod) + ret =3D gpiod_set_value_cansleep(st->start_gpiod, 0); + else + ret =3D ads1262_dev_send_cmd(st, ADS1262_OPCODE_STOP1); + + return ret; +} + +static int ads1262_dev_start_one(struct ads1262 *st) +{ + int ret; + + ret =3D ads1262_dev_start(st); + if (ret) + return ret; + + if (st->start_gpiod) { + /* + * The START pulse timing requirement is 4 clock cycles, at the + * minimum clock rate this is 4 microseconds. + */ + fsleep(4); + return ads1262_dev_stop(st); + } + + return 0; +} + +static int ads1262_wait_for_conversion(struct ads1262 *st) +{ + u64 max_lat_ms; + long ret; + + /* + * The first conversion latency is affected by the channel's data rate, + * filter, the configurable conversion delay and whether chop mode + * and/or IDAC rotation mode are enabled. + * + * The worst possible latency is calculated by taking the lowest data + * rate (2.5 SPS) and the sinc4 filter. This gives a latency of 1600 ms + * (Table 9-13). Then we scale it by the actual clock rate and multiply + * by 4 to account for chop and IDAC rotation modes (Equation 20). + */ + max_lat_ms =3D 4 * div_u64(1600ULL * ADS1262_NOMINAL_CLK_RATE, st->clk_ra= te); + ret =3D wait_for_completion_interruptible_timeout(&st->drdy, + msecs_to_jiffies(max_lat_ms)); + if (ret < 0) + return ret; + if (!ret) + return -ETIMEDOUT; + + return 0; +} + +static int ads1262_channel_enable(struct ads1262 *st, + const struct iio_chan_spec *spec) +{ + guard(mutex)(&st->xfer_lock); + guard(mutex)(&st->chan_lock); + + return regmap_update_bits(st->regmap, ADS1262_INPMUX_REG, + ADS1262_INPMUX_MUXN_MASK | + ADS1262_INPMUX_MUXP_MASK, + FIELD_PREP(ADS1262_INPMUX_MUXN_MASK, spec->channel2) | + FIELD_PREP(ADS1262_INPMUX_MUXP_MASK, spec->channel)); +} + +static int ads1262_set_runmode(struct ads1262 *st, u8 runmode) +{ + guard(mutex)(&st->xfer_lock); + + return regmap_update_bits(st->regmap, ADS1262_MODE0_REG, + ADS1262_MODE0_RUNMODE_MASK, + FIELD_PREP(ADS1262_MODE0_RUNMODE_MASK, runmode)); +} + +static int ads1262_channel_read(struct iio_dev *indio_dev, + const struct iio_chan_spec *spec, __be32 *val) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + int ret; + + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + ret =3D ads1262_set_runmode(st, ADS1262_RUNMODE_PULSE); + if (ret) + return ret; + + ret =3D ads1262_channel_enable(st, spec); + if (ret) + return ret; + + reinit_completion(&st->drdy); + + ret =3D ads1262_dev_start_one(st); + if (ret) + return ret; + + ret =3D ads1262_wait_for_conversion(st); + if (ret) + return ret; + + return ads1262_dev_read_by_cmd(st, ADS1262_OPCODE_RDATA1, val); +} + +static int ads1262_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + __be32 raw; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret =3D ads1262_channel_read(indio_dev, chan, &raw); + if (ret) + return ret; + *val =3D be32_to_cpu(raw); + + return IIO_VAL_INT; + + default: + return -EOPNOTSUPP; + } +} + +static int ads1262_debugfs_reg_access(struct iio_dev *indio_dev, unsigned = int reg, + unsigned int writeval, unsigned int *readval) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + + guard(mutex)(&st->xfer_lock); + + if (readval) + return regmap_read(st->regmap, reg, readval); + + return regmap_write(st->regmap, reg, writeval); +} + +static int ads1262_fwnode_xlate(struct iio_dev *indio_dev, + const struct fwnode_reference_args *iiospec) +{ + /* REVISIT: the auxiliary ADC (ADC2) is currently not supported */ + if (iiospec->nargs > 1 && iiospec->args[1]) + return -EINVAL; + + if (!iiospec->nargs) + return 0; + + for (unsigned int i =3D 0; i < indio_dev->num_channels; i++) { + if (indio_dev->channels[i].address =3D=3D iiospec->args[0]) + return i; + } + + return -EINVAL; +} + +static const struct iio_info ads1262_iio_info =3D { + .read_raw =3D ads1262_read_raw, + .debugfs_reg_access =3D ads1262_debugfs_reg_access, + .fwnode_xlate =3D ads1262_fwnode_xlate, +}; + +static irqreturn_t ads1262_irq_handler(int irq, void *dev_id) +{ + struct ads1262 *st =3D dev_id; + + complete(&st->drdy); + + return IRQ_HANDLED; +} + +static int ads1262_dev_configure(struct ads1262 *st) +{ + struct device *dev =3D &st->spi->dev; + int id, ret; + + ret =3D ads1262_dev_reset(st); + if (ret) + return dev_err_probe(dev, ret, "failed to reset device\n"); + + guard(mutex)(&st->xfer_lock); + + ret =3D regmap_read(st->regmap, ADS1262_ID_REG, &id); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read device ID\n"); + + id =3D FIELD_GET(ADS1262_DEV_ID_MASK, id); + if (id > ADS1263_DEV_ID) { + dev_warn(dev, "unknown device ID %d\n", id); + id =3D ADS1262_DEV_ID; + } + st->dev_id =3D id; + + ret =3D regmap_clear_bits(st->regmap, ADS1262_POWER_REG, + ADS1262_POWER_RESET_MASK); + if (ret) + return ret; + + ret =3D regmap_set_bits(st->regmap, ADS1262_POWER_REG, + ADS1262_POWER_INTREF_MASK); + if (ret) + return ret; + + return regmap_clear_bits(st->regmap, ADS1262_INTERFACE_REG, + ADS1262_INTERFACE_STATUS_MASK | + ADS1262_INTERFACE_CRC_MASK); +} + +static bool ads1262_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADS1262_ID_REG ... ADS1262_ADC2FSC1_REG: + return true; + default: + return false; + } +} + +static bool ads1262_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADS1262_POWER_REG ... ADS1262_ADC2FSC1_REG: + return true; + default: + return false; + } +} + +static bool ads1262_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADS1262_POWER_REG: + case ADS1262_OFCAL0_REG ... ADS1262_FSCAL2_REG: + case ADS1262_GPIODAT_REG: + case ADS1262_ADC2OFC0_REG ... ADS1262_ADC2FSC1_REG: + return true; + default: + return false; + } +} + +static const struct reg_default ads1262_reg_defaults[] =3D { + { + .reg =3D ADS1262_INTERFACE_REG, + .def =3D FIELD_PREP_CONST(ADS1262_INTERFACE_STATUS_MASK, 1) + | FIELD_PREP_CONST(ADS1262_INTERFACE_CRC_MASK, 1) + }, + { + .reg =3D ADS1262_MODE0_REG, + .def =3D 0x00 + }, + { + .reg =3D ADS1262_MODE1_REG, + .def =3D FIELD_PREP_CONST(ADS1262_MODE1_FILTER_MASK, ADS1262_FILTER_FIR) + }, + { + .reg =3D ADS1262_MODE2_REG, + .def =3D FIELD_PREP_CONST(ADS1262_MODE2_DR_MASK, ADS1262_DR_20_SPS) + }, + { + .reg =3D ADS1262_INPMUX_REG, + .def =3D FIELD_PREP_CONST(ADS1262_INPMUX_MUXN_MASK, ADS1262_INPMUX_AIN1) + }, + { + .reg =3D ADS1262_IDACMUX_REG, + .def =3D FIELD_PREP_CONST(ADS1262_IDACMUX_MUX2_MASK, ADS1262_IDACMUX_NO_= CONN) + | FIELD_PREP_CONST(ADS1262_IDACMUX_MUX1_MASK, ADS1262_IDACMUX_NO_CO= NN) + }, + { + .reg =3D ADS1262_IDACMAG_REG, + .def =3D 0x00 + }, + { + .reg =3D ADS1262_REFMUX_REG, + .def =3D 0x00 + }, + { + .reg =3D ADS1262_TDACP_REG, + .def =3D 0x00 + }, + { + .reg =3D ADS1262_TDACN_REG, + .def =3D 0x00 + }, + { + .reg =3D ADS1262_GPIOCON_REG, + .def =3D 0x00 + }, + { + .reg =3D ADS1262_GPIODIR_REG, + .def =3D 0x00 + }, + { + .reg =3D ADS1262_ADC2CFG_REG, + .def =3D 0x00 + }, + { + .reg =3D ADS1262_ADC2MUX_REG, + .def =3D FIELD_PREP_CONST(ADS1262_ADC2MUX_MUXN2_MASK, ADS1262_INPMUX_AIN= 1) + }, +}; + +static const struct regmap_config ads1262_regmap_config =3D { + .reg_bits =3D 8, + .val_bits =3D 8, + .writeable_reg =3D ads1262_writeable_reg, + .readable_reg =3D ads1262_readable_reg, + .volatile_reg =3D ads1262_volatile_reg, + .reg_defaults =3D ads1262_reg_defaults, + .num_reg_defaults =3D ARRAY_SIZE(ads1262_reg_defaults), + .max_register =3D ADS1262_ADC2FSC1_REG, + .can_sleep =3D true, + .cache_type =3D REGCACHE_MAPLE, +}; + +static int ads1262_regmap_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, size_t val_size) +{ + struct ads1262 *st =3D context; + u8 tx[2]; + + lockdep_assert_held(&st->xfer_lock); + + /* + * The register read operation uses a two byte command header followed + * by the register data: + * + * byte 0: RREG opcode | register address + * byte 1: number of registers to transfer, minus one + * byte 2..: register data + */ + tx[0] =3D *(u8 *)reg_buf | ADS1262_OPCODE_RREG; + tx[1] =3D val_size - 1; + + return spi_write_then_read(st->spi, tx, sizeof(tx), val_buf, val_size); +} + +static int ads1262_regmap_gather_write(void *context, const void *reg_buf, + size_t reg_size, const void *val_buf, + size_t val_size) +{ + struct ads1262 *st =3D context; + u8 tx[ADS1262_REGMAP_WRITE_SZ + 2]; + + lockdep_assert_held(&st->xfer_lock); + + /* + * The register write operation uses a two byte command header followed + * by the register data: + * + * byte 0: WREG opcode | register address + * byte 1: number of registers to transfer, minus one + * byte 2..: register data + */ + tx[0] =3D *(u8 *)reg_buf | ADS1262_OPCODE_WREG; + tx[1] =3D val_size - 1; + memcpy(&tx[2], val_buf, val_size); + + return spi_write_then_read(st->spi, tx, 2 + val_size, NULL, 0); +} + +static int ads1262_regmap_write(void *context, const void *data, size_t co= unt) +{ + return ads1262_regmap_gather_write(context, data, 1, data + 1, + count - 1); +} + +static const struct regmap_bus ads1262_regmap_bus =3D { + .read =3D ads1262_regmap_read, + .gather_write =3D ads1262_regmap_gather_write, + .write =3D ads1262_regmap_write, + .reg_format_endian_default =3D REGMAP_ENDIAN_BIG, + .val_format_endian_default =3D REGMAP_ENDIAN_BIG, + .max_raw_write =3D ADS1262_REGMAP_WRITE_SZ, +}; + +static int ads1262_parse_channel_node(struct ads1262 *st, + struct iio_chan_spec *spec, + struct fwnode_handle *node) +{ + struct device *dev =3D &st->spi->dev; + u32 pins[2]; + int ret; + + if (fwnode_property_present(node, "single-channel")) { + ret =3D fwnode_property_read_u32(node, "single-channel", &pins[0]); + if (ret) + return dev_err_probe(dev, ret, "%pfwP: failed to read single-channel\n", + node); + + pins[1] =3D ADS1262_INPMUX_AINCOM; + + if (fwnode_property_present(node, "common-mode-channel")) { + ret =3D fwnode_property_read_u32(node, "common-mode-channel", &pins[1]); + if (ret) + return dev_err_probe(dev, ret, + "%pfwP: failed to read common-mode-channel\n", + node); + } + } else if (fwnode_property_present(node, "diff-channels")) { + ret =3D fwnode_property_read_u32_array(node, "diff-channels", pins, + ARRAY_SIZE(pins)); + if (ret) + return dev_err_probe(dev, ret, "%pfwP: failed to read diff-channels\n", + node); + + spec->differential =3D true; + } else { + return dev_err_probe(dev, -EINVAL, + "%pfwP: one of single-channel or diff-channels is required\n", + node); + } + + if (pins[0] > ADS1262_INPMUX_AINCOM || pins[1] > ADS1262_INPMUX_AINCOM) + return dev_err_probe(dev, -EINVAL, "%pfwP: input channels not in range\n= ", node); + + spec->channel =3D pins[0]; + spec->channel2 =3D pins[1]; + + return 0; +} + +static int ads1262_parse_channels(struct iio_dev *indio_dev) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + struct device *dev =3D &st->spi->dev; + struct iio_chan_spec *chan_specs; + unsigned int num_fw_channels, num_specs; + unsigned int i =3D 0; + u32 reg; + int ret; + + num_fw_channels =3D device_get_named_child_node_count(dev, "channel"); + if (num_fw_channels > ADS1262_FW_CHANNEL_COUNT) + return dev_err_probe(dev, -EINVAL, "too many channels\n"); + + /* Account for the monitor channels and timestamp */ + num_specs =3D num_fw_channels + ADS1262_MON_CHANNEL_COUNT + 1; + chan_specs =3D devm_kcalloc(dev, num_specs, sizeof(*chan_specs), GFP_KERN= EL); + if (!chan_specs) + return -ENOMEM; + + device_for_each_named_child_node_scoped(dev, node, "channel") { + struct iio_chan_spec *spec =3D &chan_specs[i]; + + ret =3D fwnode_property_read_u32(node, "reg", ®); + if (ret) + return dev_err_probe(dev, ret, "%pfwP: failed to read channel reg\n", n= ode); + if (reg >=3D ADS1262_MONITOR_ADDR_OFFSET) + return dev_err_probe(dev, -EINVAL, "%pfwP: reg out of range\n", node); + + ret =3D ads1262_parse_channel_node(st, spec, node); + if (ret) + return ret; + + spec->type =3D IIO_VOLTAGE; + spec->indexed =3D true; + spec->scan_index =3D i; + spec->address =3D reg; + spec->scan_type =3D (struct iio_scan_type) { + .format =3D IIO_SCAN_FORMAT_SIGNED_INT, + .realbits =3D ADS1262_ADC1_RESOLUTION, + .storagebits =3D 32, + .endianness =3D IIO_BE, + }; + spec->info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW); + + i++; + } + + memcpy(&chan_specs[i], ads1262_monitor_chan_specs, + sizeof(ads1262_monitor_chan_specs)); + + for (unsigned int mon =3D 0; mon < ADS1262_MON_CHANNEL_COUNT; mon++) { + chan_specs[i].scan_index =3D i; + i++; + } + + chan_specs[i] =3D IIO_CHAN_SOFT_TIMESTAMP(i); + i++; + + indio_dev->channels =3D chan_specs; + indio_dev->num_channels =3D i; + + return 0; +} + +static int ads1262_supply_setup(struct ads1262 *st) +{ + struct device *dev =3D &st->spi->dev; + int ret; + + ret =3D devm_regulator_get_enable(dev, "dvdd"); + if (ret) + return dev_err_probe(dev, ret, "failed to get dvdd regulator\n"); + + ret =3D devm_regulator_get_enable(dev, "avdd"); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to get avdd regulator\n"); + + ret =3D devm_regulator_get_enable_optional(dev, "avss"); + if (ret < 0 && ret !=3D -ENODEV) + return dev_err_probe(dev, ret, "failed to get avss regulator\n"); + + fsleep(ADS1262_POWER_TRANS_USECS); + + return 0; +} + +static int ads1262_spi_probe(struct spi_device *spi) +{ + struct device *dev =3D &spi->dev; + struct iio_dev *indio_dev; + struct ads1262 *st; + unsigned long rate; + struct clk *clk; + int irq; + int ret; + + indio_dev =3D devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + indio_dev->modes =3D INDIO_DIRECT_MODE; + indio_dev->info =3D &ads1262_iio_info; + + st =3D iio_priv(indio_dev); + st->spi =3D spi; + init_completion(&st->drdy); + + ret =3D devm_mutex_init(dev, &st->chan_lock); + if (ret) + return ret; + ret =3D devm_mutex_init(dev, &st->xfer_lock); + if (ret) + return ret; + + ret =3D ads1262_parse_channels(indio_dev); + if (ret) + return ret; + + ret =3D ads1262_supply_setup(st); + if (ret) + return ret; + + clk =3D devm_clk_get_optional_enabled(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "failed to get external clock\n"= ); + + rate =3D clk_get_rate(clk); + if (clk && !rate) + return dev_err_probe(dev, -EINVAL, "failed to get clock rate\n"); + st->clk_rate =3D rate ? rate : ADS1262_NOMINAL_CLK_RATE; + + st->start_gpiod =3D devm_gpiod_get_optional(dev, "start", GPIOD_OUT_LOW); + if (IS_ERR(st->start_gpiod)) + return dev_err_probe(dev, PTR_ERR(st->start_gpiod), + "failed to get start GPIO\n"); + + st->regmap =3D devm_regmap_init(dev, &ads1262_regmap_bus, st, + &ads1262_regmap_config); + if (IS_ERR(st->regmap)) + return PTR_ERR(st->regmap); + + ret =3D ads1262_dev_configure(st); + if (ret) + return dev_err_probe(dev, ret, "failed to configure device\n"); + + indio_dev->name =3D ads1262_device_id_to_name[st->dev_id]; + + /* + * REVISIT: This chip has software polling capabilities, which could be + * used to stop depending on the DRDY signal. + * + * Additionally, the MISO pin also can be used as a DRDY IRQ, in which + * case the interrupt would be named 'doutdrdy', but requires extra + * timing and synchronization considerations to be reliable. + */ + irq =3D fwnode_irq_get_byname(dev_fwnode(dev), "drdy"); + if (irq < 0) + return dev_err_probe(dev, irq, + "the 'drdy' IRQ is currently required for operation\n"); + + ret =3D devm_request_irq(dev, irq, ads1262_irq_handler, IRQF_NO_THREAD, + indio_dev->name, st); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id ads1262_of_match[] =3D { + { .compatible =3D "ti,ads1262" }, + { } +}; +MODULE_DEVICE_TABLE(of, ads1262_of_match); + +static const struct spi_device_id ads1262_spi_match[] =3D { + { .name =3D "ads1262" }, + { } +}; +MODULE_DEVICE_TABLE(spi, ads1262_spi_match); + +static struct spi_driver ads1262_spi_driver =3D { + .driver =3D { + .name =3D "ads1262", + .of_match_table =3D ads1262_of_match, + }, + .probe =3D ads1262_spi_probe, + .id_table =3D ads1262_spi_match, +}; +module_spi_driver(ads1262_spi_driver); + +MODULE_DESCRIPTION("Texas Instruments ADS1262 ADC driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kurt Borja "); --=20 2.55.0 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-vs1-f47.google.com (mail-vs1-f47.google.com [209.85.217.47]) (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 B8CB63CF022 for ; Fri, 28 Aug 2026 06:38:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.217.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899132; cv=none; b=sRkXDXQNH/KkKFES5US8ngXKezSoq0q0HKVAXQWS+F2r6RfHjY9mvqjI7tz6rcdl5fTitw0RzWhRuaNIDahRxF9J7eDSM/TKAsOkAqUprHcktYLippIRSLMMASdMJPbaq/M3qMYx6uBpDGwue9PgLEn/cchnkIjmSBkFFo3p354= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899132; c=relaxed/simple; bh=6aZMjagHvcH24IcCEzk87Oit7nVKdoCQ6sPY4en+24w=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=TSrb58qa6JGeGaAMgcuQg90fR8QyLur1SFJ5+Lvz76ac/LAWW2KjRN7XpioGxkboQcdVGyM1orCoIrLhb19eE3CGCZ824oWD3jEg8XHmmP2cUri2IGM51CbLzBP09qXx3xlUkv+mz6+Nm3M0s/flgzuOZYNObjdXHYbhRlIq2Mo= 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=mnVp+Nmj; arc=none smtp.client-ip=209.85.217.47 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mnVp+Nmj" Received: by mail-vs1-f47.google.com with SMTP id ada2fe7eead31-782e0fc1e55so160374137.3 for ; Thu, 27 Aug 2026 23:38:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787899127; x=1788503927; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=QHv5wdzqoT+8+ip3D8MQsdcFxzRbRYsfhtpZnwwMeCw=; b=mnVp+NmjzqXJ1adMbmQBmRqob7ECNbcU9ZgVWz8tp8aHCW/8I/9Mzf/tqZ6oqxg5Z0 BOA0PpQvSqQqhcVWAbE2YG2i9yxXJnyivjg796g7RVAtfk/r5uTw2rLxUKIFWsqoIi0z X0KfRO2o0F+VwF4pCUYlNSHOdYrjkjfkBBpE89RGhpURjbcHwHeCGV76Ah+nAYL3a7c2 0eslY+2FqI0Vq3sSCdrwGiTF7T4A11SXnlBYbeXiO1innTSDHYKU2CInf4oTYloIj0Zi jEEFPr0MLfZKsvABf41vdcskVGPJEBJjvIS8IxRoFuUGu5WUcpnqqHTMrKK6V3sY5sbR m8Yg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787899127; x=1788503927; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=QHv5wdzqoT+8+ip3D8MQsdcFxzRbRYsfhtpZnwwMeCw=; b=bP111q3j9hE2dzd7bN4nGZGXf0ZOPzCN5dZKF9u+nx/XQEkXmY3tsfn5lgryhW8SFG vqzUPLjcklRphaBpCPVtgNB0cg9t78xRJau9+XsjxZKksJheV4VHA5ehgBDCTZ12XgLE BFUnK7VBhD+/SLnzU1+etQCZzE38pRLmRZWxMjYdj2VWubqDooSBZx6wrk/9khg2cyUk ftaJF4kiSqZbpY+tni+rowHXnIcg8oUmoYpZhrwc/4mFAHPe/zwB8JTU92QKwMBp34Fo cY1UV9LJYRm1wC4jEObIL2qJxg/7IFGp8c1fFONgn8Q5svyY4ftliqXk4erwC6AADKs3 ZTlQ== X-Forwarded-Encrypted: i=1; AHgh+Rre+I4ObQuVp2K1xlvhU78EBP4ZpOtOiknItrnPwBGycgPFz0+7zFy0tZeMC6ctsrHJ69mIuNm6o13ZHg8=@vger.kernel.org X-Gm-Message-State: AFuF++mTaWvz6YcAyfc3gOkEgal3mn7ZbFVUSF1qZfhSsJqShHYNJHdH jUSBiWaK5REfP99dXpsmaFsYLqmrH0asHZ6+XyAOk2JpPwlJcE6eY+IS X-Gm-Gg: AR+sD13gdPq/JoMxiAcFK4OQYWkS5Y9jtQorbf3KutCbCT3Yy0O+DZfgdLOSbO9CSk0 bRoYwe7TKA7A0AfbjkIxD/xINIZLasb5zzSTRA8nuUeHd+LIXlMsZGwbdc5L3XH1Qn6tDv0k6Vu H3lXpLCpdrPSurXV4OJG5tAGi9utf+yLN/LNNRGfsRn+ZqhRSDfHmmTsl0awNtApQtiRxKuJ1Vq 0bFXSNPX8N0VAyMl6T6FpaAHWAPlUK8kTRo5RLEX396tKo6x72TyJpt9W8+yhdRVcROIAlnUpYZ qp8sHsl/3n/6hp9jRUdeGCUvu/k34opShZ0ioXYDU7KVM9QTivBPFEIFmj4NCu3xUegoMs6kk+Z jLB4+Msaiab2LwH19+TumQ4kfAE5J1CsrXUjwAoclQCJT5X6j9Tu4Q9+Yvuu47f+0Gkp983xuBR uJQN/bqnLD8/eMNe8tEMTwCJxQUBvc3DZp7tGyhRyLOacvewQqmM25z77kr7Y1yURJ1g== X-Received: by 2002:a05:6102:2907:b0:782:de7b:eead with SMTP id ada2fe7eead31-785962b3b4fmr1260614137.1.1787899126966; Thu, 27 Aug 2026 23:38:46 -0700 (PDT) Received: from [192.168.100.153] ([2800:bf0:61:1127:ab87:5602:531c:8dfb]) by smtp.gmail.com with ESMTPSA id a1e0cc1a2514c-97e849d8494sm454195241.1.2026.08.27.23.38.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 23:38:46 -0700 (PDT) From: Kurt Borja Date: Fri, 28 Aug 2026 01:38:19 -0500 Subject: [PATCH v4 04/10] iio: adc: ti-ads1262: support per-channel sampling frequency Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260828-ads126x-v4-4-1dc27e9c0260@gmail.com> References: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> In-Reply-To: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , David Lechner Cc: =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=12017; i=kuurtb@gmail.com; h=from:subject:message-id; bh=6aZMjagHvcH24IcCEzk87Oit7nVKdoCQ6sPY4en+24w=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFkTdd7c3/dxzckUQcMH02dZsKxo98m/ps/wmIH1crC5f CJLqe3JjlIWBjEuBlkxRZb2hEXfHkXlvfU7EHofZg4rE8gQBi5OAZjImWxGhiMhAneeKc9aVMMS yq35XfGm7X2X1h8x1k3blKSFuWc83MbIsHX5TDb5w1eZnd4nbAx+9WpBQO3HrM8tF19sm6UR733 iJTcA X-Developer-Key: i=kuurtb@gmail.com; a=openpgp; fpr=54D3BE170AEF777983C3C63B57E3B6585920A69A Add per-channel sampling frequency support. The "available" attribute is assigned per-channel too, in order to eventually support per-filter availability. Signed-off-by: Kurt Borja --- drivers/iio/adc/ti-ads1262.c | 233 +++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 228 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c index d919144c23cb..86ea9b6232d8 100644 --- a/drivers/iio/adc/ti-ads1262.c +++ b/drivers/iio/adc/ti-ads1262.c @@ -25,6 +25,7 @@ #include #include #include +#include =20 #include =20 @@ -99,6 +100,7 @@ #define ADS1262_DR_14400_SPS 13 #define ADS1262_DR_19200_SPS 14 #define ADS1262_DR_38400_SPS 15 +#define ADS1262_DR_COUNT (ADS1262_DR_38400_SPS + 1) =20 #define ADS1262_INPMUX_REG 0x06 #define ADS1262_INPMUX_MUXP_MASK GENMASK(7, 4) @@ -166,6 +168,7 @@ #define ADS1262_POWER_TRANS_USECS 65536 =20 #define ADS1262_NOMINAL_CLK_RATE 7372800 +#define ADS1262_MODULATOR_DIV 8 =20 #define ADS1262_FW_CHANNEL_COUNT 16 #define ADS1262_MON_CHANNEL_COUNT 4 @@ -174,10 +177,17 @@ =20 #define ADS1262_ADC1_RESOLUTION 32 =20 +struct ads1262_channel { + u8 data_rate; + u8 filter; +}; + struct ads1262 { struct spi_device *spi; struct regmap *regmap; struct gpio_desc *start_gpiod; + size_t num_channels; + struct ads1262_channel *channels; /* protects concurrent SPI transfers */ struct mutex xfer_lock; /* protects channel state */ @@ -185,6 +195,8 @@ struct ads1262 { struct completion drdy; unsigned long clk_rate; u8 dev_id; + int sampling_freq_table[ADS1262_DR_COUNT][2]; + int sampling_freq_fir[ADS1262_DR_16_6_SPS + 1][2]; }; =20 static const char * const ads1262_device_id_to_name[] =3D { @@ -204,7 +216,9 @@ static const struct iio_chan_spec ads1262_monitor_chan_= specs[] =3D { .storagebits =3D 32, .endianness =3D IIO_BE, }, - .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type =3D IIO_VOLTAGE, @@ -218,7 +232,9 @@ static const struct iio_chan_spec ads1262_monitor_chan_= specs[] =3D { .storagebits =3D 32, .endianness =3D IIO_BE, }, - .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type =3D IIO_VOLTAGE, @@ -232,7 +248,9 @@ static const struct iio_chan_spec ads1262_monitor_chan_= specs[] =3D { .storagebits =3D 32, .endianness =3D IIO_BE, }, - .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type =3D IIO_VOLTAGE, @@ -247,10 +265,66 @@ static const struct iio_chan_spec ads1262_monitor_cha= n_specs[] =3D { .storagebits =3D 32, .endianness =3D IIO_BE, }, - .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), }, }; =20 +static const struct ads1262_channel ads1262_default_channel =3D { + .data_rate =3D ADS1262_DR_20_SPS, + .filter =3D ADS1262_FILTER_FIR, +}; + +static const u32 ads1262_mod_decimator_a[] =3D { + [ADS1262_DR_2_5_SPS] =3D 64, + [ADS1262_DR_5_SPS] =3D 64, + [ADS1262_DR_10_SPS] =3D 64, + [ADS1262_DR_16_6_SPS] =3D 64, + [ADS1262_DR_20_SPS] =3D 64, + [ADS1262_DR_50_SPS] =3D 64, + [ADS1262_DR_60_SPS] =3D 64, + [ADS1262_DR_100_SPS] =3D 64, + [ADS1262_DR_400_SPS] =3D 64, + [ADS1262_DR_1200_SPS] =3D 64, + [ADS1262_DR_2400_SPS] =3D 64, + [ADS1262_DR_4800_SPS] =3D 64, + [ADS1262_DR_7200_SPS] =3D 64, + [ADS1262_DR_14400_SPS] =3D 64, + [ADS1262_DR_19200_SPS] =3D 48, + [ADS1262_DR_38400_SPS] =3D 24, +}; + +static const u32 ads1262_mod_decimator_b[] =3D { + [ADS1262_DR_2_5_SPS] =3D 5760, + [ADS1262_DR_5_SPS] =3D 2880, + [ADS1262_DR_10_SPS] =3D 1440, + [ADS1262_DR_16_6_SPS] =3D 864, + [ADS1262_DR_20_SPS] =3D 720, + [ADS1262_DR_50_SPS] =3D 288, + [ADS1262_DR_60_SPS] =3D 240, + [ADS1262_DR_100_SPS] =3D 144, + [ADS1262_DR_400_SPS] =3D 36, + [ADS1262_DR_1200_SPS] =3D 12, + [ADS1262_DR_2400_SPS] =3D 6, + [ADS1262_DR_4800_SPS] =3D 3, + [ADS1262_DR_7200_SPS] =3D 2, + [ADS1262_DR_14400_SPS] =3D 1, + [ADS1262_DR_19200_SPS] =3D 1, + [ADS1262_DR_38400_SPS] =3D 1, +}; + +static int ads1262_find_two(const int (*array)[2], size_t num_elements, in= t val, + int val2) +{ + for (unsigned int i =3D 0; i < num_elements; i++) { + if (val =3D=3D array[i][0] && val2 =3D=3D array[i][1]) + return i; + } + + return -EINVAL; +} + static int ads1262_dev_send_cmd(struct ads1262 *st, u8 opcode) { guard(mutex)(&st->xfer_lock); @@ -375,9 +449,18 @@ static int ads1262_wait_for_conversion(struct ads1262 = *st) static int ads1262_channel_enable(struct ads1262 *st, const struct iio_chan_spec *spec) { + struct ads1262_channel *chan =3D &st->channels[spec->scan_index]; + int ret; + guard(mutex)(&st->xfer_lock); guard(mutex)(&st->chan_lock); =20 + ret =3D regmap_update_bits(st->regmap, ADS1262_MODE2_REG, + ADS1262_MODE2_DR_MASK, + FIELD_PREP(ADS1262_MODE2_DR_MASK, chan->data_rate)); + if (ret) + return ret; + return regmap_update_bits(st->regmap, ADS1262_INPMUX_REG, ADS1262_INPMUX_MUXN_MASK | ADS1262_INPMUX_MUXP_MASK, @@ -429,6 +512,8 @@ static int ads1262_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { + struct ads1262 *st =3D iio_priv(indio_dev); + struct ads1262_channel *chan_data =3D &st->channels[chan->scan_index]; __be32 raw; int ret; =20 @@ -441,6 +526,83 @@ static int ads1262_read_raw(struct iio_dev *indio_dev, =20 return IIO_VAL_INT; =20 + case IIO_CHAN_INFO_SAMP_FREQ: { + guard(mutex)(&st->chan_lock); + + *val =3D st->sampling_freq_table[chan_data->data_rate][0]; + *val2 =3D st->sampling_freq_table[chan_data->data_rate][1]; + + return IIO_VAL_INT_PLUS_MICRO; + } + + default: + return -EOPNOTSUPP; + } +} + +static int ads1262_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, const int **vals, + int *type, int *length, long mask) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + struct ads1262_channel *chan_data =3D &st->channels[chan->scan_index]; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *type =3D IIO_VAL_INT_PLUS_MICRO; + + switch (chan_data->filter) { + case ADS1262_FILTER_FIR: + *vals =3D (const int *)st->sampling_freq_fir; + *length =3D ARRAY_SIZE(st->sampling_freq_fir) * 2; + return IIO_AVAIL_LIST; + default: + return -EOPNOTSUPP; + } + + default: + return -EOPNOTSUPP; + } +} + +static int ads1262_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + struct ads1262_channel *chan_data =3D &st->channels[chan->scan_index]; + int ret; + + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + guard(mutex)(&st->chan_lock); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + switch (chan_data->filter) { + case ADS1262_FILTER_FIR: + ret =3D ads1262_find_two(st->sampling_freq_fir, + ARRAY_SIZE(st->sampling_freq_fir), + val, val2); + if (ret < 0) + return ret; + break; + default: + return -EINVAL; + } + + ret =3D ads1262_find_two(st->sampling_freq_table, + ARRAY_SIZE(st->sampling_freq_table), + val, val2); + if (ret < 0) + return ret; + + chan_data->data_rate =3D ret; + + return 0; + default: return -EOPNOTSUPP; } @@ -479,6 +641,8 @@ static int ads1262_fwnode_xlate(struct iio_dev *indio_d= ev, =20 static const struct iio_info ads1262_iio_info =3D { .read_raw =3D ads1262_read_raw, + .read_avail =3D ads1262_read_avail, + .write_raw =3D ads1262_write_raw, .debugfs_reg_access =3D ads1262_debugfs_reg_access, .fwnode_xlate =3D ads1262_fwnode_xlate, }; @@ -697,6 +861,49 @@ static const struct regmap_bus ads1262_regmap_bus =3D { .max_raw_write =3D ADS1262_REGMAP_WRITE_SZ, }; =20 +static void ads1262_populate_samp_freqs(struct ads1262 *st) +{ + u64 freq_Hz, freq_uHz; + u32 freq_rem; + + for (unsigned int i =3D 0; i < ARRAY_SIZE(st->sampling_freq_table); i++) { + freq_uHz =3D div_u64(mul_u32_u32(st->clk_rate, MICRO), + ADS1262_MODULATOR_DIV * + ads1262_mod_decimator_a[i] * + ads1262_mod_decimator_b[i]); + freq_Hz =3D div_u64_rem(freq_uHz, MICRO, &freq_rem); + + st->sampling_freq_table[i][0] =3D (int)freq_Hz; + st->sampling_freq_table[i][1] =3D (int)freq_rem; + } + + for (unsigned int i =3D 0; i < ARRAY_SIZE(st->sampling_freq_fir); i++) { + /* + * The FIR filter does not support the 16.6 SPS data rate so it + * gets mapped to 20 SPS instead. + */ + switch (i) { + case ADS1262_DR_2_5_SPS ... ADS1262_DR_10_SPS: + st->sampling_freq_fir[i][0] =3D st->sampling_freq_table[i][0]; + st->sampling_freq_fir[i][1] =3D st->sampling_freq_table[i][1]; + break; + case ADS1262_DR_16_6_SPS: + st->sampling_freq_fir[i][0] =3D st->sampling_freq_table[ADS1262_DR_20_S= PS][0]; + st->sampling_freq_fir[i][1] =3D st->sampling_freq_table[ADS1262_DR_20_S= PS][1]; + break; + } + } +} + +static int ads1262_populate_tables(struct iio_dev *indio_dev) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + + ads1262_populate_samp_freqs(st); + + return 0; +} + static int ads1262_parse_channel_node(struct ads1262 *st, struct iio_chan_spec *spec, struct fwnode_handle *node) @@ -763,8 +970,15 @@ static int ads1262_parse_channels(struct iio_dev *indi= o_dev) if (!chan_specs) return -ENOMEM; =20 + st->num_channels =3D num_fw_channels + ADS1262_MON_CHANNEL_COUNT; + st->channels =3D devm_kcalloc(dev, st->num_channels, sizeof(*st->channels= ), + GFP_KERNEL); + if (!st->channels) + return -ENOMEM; + device_for_each_named_child_node_scoped(dev, node, "channel") { struct iio_chan_spec *spec =3D &chan_specs[i]; + struct ads1262_channel *chan =3D &st->channels[i]; =20 ret =3D fwnode_property_read_u32(node, "reg", ®); if (ret) @@ -772,6 +986,8 @@ static int ads1262_parse_channels(struct iio_dev *indio= _dev) if (reg >=3D ADS1262_MONITOR_ADDR_OFFSET) return dev_err_probe(dev, -EINVAL, "%pfwP: reg out of range\n", node); =20 + *chan =3D (struct ads1262_channel)ads1262_default_channel; + ret =3D ads1262_parse_channel_node(st, spec, node); if (ret) return ret; @@ -786,7 +1002,9 @@ static int ads1262_parse_channels(struct iio_dev *indi= o_dev) .storagebits =3D 32, .endianness =3D IIO_BE, }; - spec->info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW); + spec->info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SAMP_FREQ); + spec->info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ); =20 i++; } @@ -795,6 +1013,7 @@ static int ads1262_parse_channels(struct iio_dev *indi= o_dev) sizeof(ads1262_monitor_chan_specs)); =20 for (unsigned int mon =3D 0; mon < ADS1262_MON_CHANNEL_COUNT; mon++) { + st->channels[i] =3D (struct ads1262_channel)ads1262_default_channel; chan_specs[i].scan_index =3D i; i++; } @@ -890,6 +1109,10 @@ static int ads1262_spi_probe(struct spi_device *spi) =20 indio_dev->name =3D ads1262_device_id_to_name[st->dev_id]; =20 + ret =3D ads1262_populate_tables(indio_dev); + if (ret) + return ret; + /* * REVISIT: This chip has software polling capabilities, which could be * used to stop depending on the DRDY signal. --=20 2.55.0 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-vk1-f173.google.com (mail-vk1-f173.google.com [209.85.221.173]) (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 1629E3CE489 for ; Fri, 28 Aug 2026 06:38:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899135; cv=none; b=ALusP3zqkuTwnsifOB8f13E/iYRFG/XrjogneLc/t8wbRpO25SIOm1PGbtxi7f+j1BB0MY2iuGKZONtVSBIgSGuXu5KiSspHoCrrW3/EXLhqYt1JK/ab9GePZmKgUzNdm3Jq6sklLnLsW1fgok8Escze1awtKtOxOWoKBZbH6vw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899135; c=relaxed/simple; bh=ZMdhvA3VIRtd3kMp5WBL8nG7USOLWbSk+f5oUyciX1A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=HTXalcPIA2Z9YVzFnEi945qEKnL+ZnL6qw4KiMBGZk6+VBTiOsctYWJ5ytkHV8OIODzK+kr/Sy0Omlj/B2Rj+VRZ5sxlN2jpWYFKBoD59EbSA232YrMOkNSN7/ke+VJCDLp3sL5bxezJ1fOzoxhjnZhcbpegX5ePWSfACegb8rA= 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=r13xozoS; arc=none smtp.client-ip=209.85.221.173 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="r13xozoS" Received: by mail-vk1-f173.google.com with SMTP id 71dfb90a1353d-5bf959b820cso639590e0c.3 for ; Thu, 27 Aug 2026 23:38:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787899129; x=1788503929; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Mwsoxe8KhbSfGQ0zwt/NfFnLnBuMn+0YOw8VstSOLRs=; b=r13xozoSw3yzO7hWDtNtqz8mxfMdCf4ImFm/QdXjfiOusGyN/ReB9hnNpAgkTKX+qx jpmzLiq2mEoURjbG19FXtpwDgpFTr31T+FEoyZoWy/7hb+nh0Th4mHanG/+AbwNwKPOK bGFqzfwHIGu2Cil9u+GWJ8Ip2PlWbkbjlyVj1snhBns/2z+CiyOsFIzMqpV/9ihyQ4mg nlWYx7F/nJhJ7lzr8Io3rma7UqGHsulB29ovPZlbfZ7zQJVUFIqiPQeSVzJBvtiqQZDV A50O5Z73p6bo6z3U41Vvjr5Je/knI/D5w8A+8Og7LcEtM5DNGgSzc2oGjpSaYf89z6NO JLSA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787899129; x=1788503929; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=Mwsoxe8KhbSfGQ0zwt/NfFnLnBuMn+0YOw8VstSOLRs=; b=gHz4Gy3AG8TmaXOxQAStQSUexl5F58v71Ms5pcQTJZqFVcE3CVETKIyDpRZ5IwZnnC mK3xtiwli/q7QR6OQAaryOgpA1BhlJErai+Nwf8TOOfOgJTtFx8850zr2Wqt7dJlNPkM uN7Lkk0CPvAKqcoMmKCKQueejgCmULQQXl42K2UKB67ch8cZo6lXQPrLHKWMhTPAEU7e zWnPvR4kYVS2moqJuMTy4BI523ZqlzJDOVzrDyrsjq7ZmuCgd5ZbJX3q4w/1ab2kiddt 8Kcu2btf633Y1kpsVGBSg4s6dd+JIxRQUX388jzx++i2V/di0MfOgcmvQd/gAm9KlTW/ 2ylQ== X-Forwarded-Encrypted: i=1; AHgh+RrAgYx0d1G+HS2x6RhkPjjCFxh4SHQLV3r4Wq25FkK3674EAQ+QBe91G6wry3n0kTiO+Jh4X7R8Wcjzv4M=@vger.kernel.org X-Gm-Message-State: AFuF++l4J3+lo2Hzz8b/45hPk+zaZKi5Wv5ACN/wANRLWIygVfF5ZrNo UCF3KFSqAZz171Kn4otbh13R3Y9UPJnnS5IyFolqesYB8rhHvuQY12IZ X-Gm-Gg: AR+sD13Xe0AQWOUXRSa/vfYUm3fhuupzkJb9c6jTP8RvpaL4uu3NBcoxIn+81GixvsE b8lhv2U2vQUbftoeds+vCXL2jvWGsn7tVf8eK3TshEAvwB7WGqmZLVXp1Tl1XDjGKEaD5Na3NIY LTw+RvpHzuTWO2tZ3oFaPRe5EQjdoZac0LiKVcL/ko3Pl3Bkex6hKiagrpxgqKiIM/NrLHDFfsT jRmTD74eq6mkW+2s8tIeFOsqjk+7KHo0S+p2V+5E7YFOEBF2S4S7g0Bm8GRnni+bgN2FFZnzPyv fcEaqBAXZqBn7CP1XVr2oxMuyeg4bi/8Kvb9Qck8xdXZI/TF+qm3sLLNSeROD04kssB3nybB9NY EqEAIGgc41lEwVIVE9v7/JEtiq/mnPg+yBKrnbMBF044bWd5WFExWbFbiHRfZJFV8koyPGJEFAm Gi0Ib1R7DI8N4qN+KrSjy2hWcxbu5JlzBHGcDB/T5BJcXMHK7uRUIKebz2lK4o3Xzq X-Received: by 2002:a05:6122:469a:b0:5c6:6c75:81c9 with SMTP id 71dfb90a1353d-5c681776bb2mr2176026e0c.7.1787899129133; Thu, 27 Aug 2026 23:38:49 -0700 (PDT) Received: from [192.168.100.153] ([2800:bf0:61:1127:ab87:5602:531c:8dfb]) by smtp.gmail.com with ESMTPSA id a1e0cc1a2514c-97e849d8494sm454195241.1.2026.08.27.23.38.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 23:38:48 -0700 (PDT) From: Kurt Borja Date: Fri, 28 Aug 2026 01:38:20 -0500 Subject: [PATCH v4 05/10] iio: adc: ti-ads1262: support per-channel reference and gain Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260828-ads126x-v4-5-1dc27e9c0260@gmail.com> References: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> In-Reply-To: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , David Lechner Cc: =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=24067; i=kuurtb@gmail.com; h=from:subject:message-id; bh=ZMdhvA3VIRtd3kMp5WBL8nG7USOLWbSk+f5oUyciX1A=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFkTdd7sM2DMe8sRx9F32K7z21OFzVPqmG4rreFaxbCn6 tfq7U9nd5SyMIhxMciKKbK0Jyz69igq763fgdD7MHNYmUCGMHBxCsBEzhxnZOja8G3q0tZd5i/Y P62oe3K/yt1Ycf27WXsrj53tzHeVbV7C8L/iQZGqm17kzoW/989ssLv/eUHBLbe3a0QfpP2/syj rVggrAA== X-Developer-Key: i=kuurtb@gmail.com; a=openpgp; fpr=54D3BE170AEF777983C3C63B57E3B6585920A69A Allow each channel to select its voltage reference through the "reference-sources" firmware property. Then, use the reference voltage to calculate available scales. The PGA bypass handling is intentionally left out until more information about on its usual applications is gathered. The ADS1262 allows single-ended supply configurations or bipolar supply configurations. In single ended configurations both the analog and digital rails share the same ground, i.e. AVSS =3D DGND =3D 0 V. In bipolar supply configurations, AVSS can go below ground, e.g. AVSS =3D -2.5 V. If AVSS is below ground, the ADC can achieve true bipolar measurements and the external references can also have voltage levels below ground. This is currently an issue because the regulator subsystem doesn't support reading negative voltages. The ad4170-4 driver faces this problem too and the same workaround is used in this case: assume every regulator reports magnitudes (absolute values). If the chip has a bipolar supply configuration, then assume positive references are above ground (>=3D 0 V) and negative references are below ground (<=3D 0 V). This is not a hardware constraint, but it is the most common wiring. Signed-off-by: Kurt Borja --- drivers/iio/adc/ti-ads1262.c | 493 +++++++++++++++++++++++++++++++++++++++= +--- 1 file changed, 468 insertions(+), 25 deletions(-) diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c index 86ea9b6232d8..c87c0a66119a 100644 --- a/drivers/iio/adc/ti-ads1262.c +++ b/drivers/iio/adc/ti-ads1262.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -18,12 +19,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include =20 @@ -83,6 +86,7 @@ #define ADS1262_MODE2_REG 0x05 #define ADS1262_MODE2_BYPASS_MASK BIT(7) #define ADS1262_MODE2_GAIN_MASK GENMASK(6, 4) +#define ADS1262_GAIN_COUNT 6 #define ADS1262_MODE2_DR_MASK GENMASK(3, 0) #define ADS1262_DR_2_5_SPS 0 #define ADS1262_DR_5_SPS 1 @@ -123,7 +127,7 @@ #define ADS1262_IDACMUX_REG 0x0D #define ADS1262_IDACMUX_MUX2_MASK GENMASK(7, 4) #define ADS1262_IDACMUX_MUX1_MASK GENMASK(3, 0) -#define ADS1262_IDACMUX_NO_CONN 0b1011 +#define ADS1262_IDACMUX_NO_CONN 11 =20 #define ADS1262_IDACMAG_REG 0x0E #define ADS1262_IDACMAG_MAG2_MASK GENMASK(7, 4) @@ -131,7 +135,17 @@ =20 #define ADS1262_REFMUX_REG 0x0F #define ADS1262_REFMUX_RMUXP_MASK GENMASK(5, 3) +#define ADS1262_RMUXP_INTERNAL 0 +#define ADS1262_RMUXP_REFP1 1 +#define ADS1262_RMUXP_REFP2 2 +#define ADS1262_RMUXP_REFP3 3 +#define ADS1262_RMUXP_AVDD 4 #define ADS1262_REFMUX_RMUXN_MASK GENMASK(2, 0) +#define ADS1262_RMUXN_INTERNAL 0 +#define ADS1262_RMUXN_REFN1 1 +#define ADS1262_RMUXN_REFN2 2 +#define ADS1262_RMUXN_REFN3 3 +#define ADS1262_RMUXN_AVSS 4 =20 #define ADS1262_TDACP_REG 0x10 #define ADS1262_TDACP_OUTP_MASK BIT(7) @@ -169,9 +183,13 @@ =20 #define ADS1262_NOMINAL_CLK_RATE 7372800 #define ADS1262_MODULATOR_DIV 8 +#define ADS1262_INTERNAL_REFERENCE_uV 2500000 +#define ADS1262_TEMP_SLOPE_uV_C 420ULL +#define ADS1262_TEMP_ZERO_C 111900ULL =20 #define ADS1262_FW_CHANNEL_COUNT 16 #define ADS1262_MON_CHANNEL_COUNT 4 +#define ADS1262_EXT_REF_COUNT 3 #define ADS1262_REGMAP_WRITE_SZ 8 #define ADS1262_MONITOR_ADDR_OFFSET 100 =20 @@ -180,12 +198,21 @@ struct ads1262_channel { u8 data_rate; u8 filter; + u8 gain; + u8 ref_p; + u8 ref_n; + bool ref_reversal; + bool is_resistance; + size_t num_scales; + int scales[ADS1262_GAIN_COUNT][2]; }; =20 struct ads1262 { struct spi_device *spi; struct regmap *regmap; struct gpio_desc *start_gpiod; + struct regulator *avdd_supply; + struct regulator *avss_supply; size_t num_channels; struct ads1262_channel *channels; /* protects concurrent SPI transfers */ @@ -195,8 +222,12 @@ struct ads1262 { struct completion drdy; unsigned long clk_rate; u8 dev_id; + bool bipolar_supply; int sampling_freq_table[ADS1262_DR_COUNT][2]; int sampling_freq_fir[ADS1262_DR_16_6_SPS + 1][2]; + u32 rref_ohms[ADS1262_EXT_REF_COUNT][ADS1262_EXT_REF_COUNT]; + int refp_uV[ADS1262_EXT_REF_COUNT]; + int refn_uV[ADS1262_EXT_REF_COUNT]; }; =20 static const char * const ads1262_device_id_to_name[] =3D { @@ -217,8 +248,11 @@ static const struct iio_chan_spec ads1262_monitor_chan= _specs[] =3D { .endianness =3D IIO_BE, }, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SAMP_FREQ), - .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_SCALE), }, { .type =3D IIO_VOLTAGE, @@ -233,8 +267,10 @@ static const struct iio_chan_spec ads1262_monitor_chan= _specs[] =3D { .endianness =3D IIO_BE, }, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SAMP_FREQ), - .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_SCALE), }, { .type =3D IIO_VOLTAGE, @@ -249,8 +285,10 @@ static const struct iio_chan_spec ads1262_monitor_chan= _specs[] =3D { .endianness =3D IIO_BE, }, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SAMP_FREQ), - .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_SCALE), }, { .type =3D IIO_VOLTAGE, @@ -266,8 +304,10 @@ static const struct iio_chan_spec ads1262_monitor_chan= _specs[] =3D { .endianness =3D IIO_BE, }, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SAMP_FREQ), - .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_SCALE), }, }; =20 @@ -314,6 +354,24 @@ static const u32 ads1262_mod_decimator_b[] =3D { [ADS1262_DR_38400_SPS] =3D 1, }; =20 +static const char * const ads1262_ref_sources_pos[] =3D { + [ADS1262_RMUXP_INTERNAL] =3D "internal-p", + [ADS1262_RMUXP_REFP1] =3D "refp1", + [ADS1262_RMUXP_REFP2] =3D "refp2", + [ADS1262_RMUXP_REFP3] =3D "refp3", + [ADS1262_RMUXP_AVDD] =3D "avdd", + NULL +}; + +static const char * const ads1262_ref_sources_neg[] =3D { + [ADS1262_RMUXN_INTERNAL] =3D "internal-n", + [ADS1262_RMUXN_REFN1] =3D "refn1", + [ADS1262_RMUXN_REFN2] =3D "refn2", + [ADS1262_RMUXN_REFN3] =3D "refn3", + [ADS1262_RMUXN_AVSS] =3D "avss", + NULL +}; + static int ads1262_find_two(const int (*array)[2], size_t num_elements, in= t val, int val2) { @@ -325,6 +383,12 @@ static int ads1262_find_two(const int (*array)[2], siz= e_t num_elements, int val, return -EINVAL; } =20 +static bool ads1262_reference_is_external(int ref_p, int ref_n) +{ + return in_range(ref_p, ADS1262_RMUXP_REFP1, ADS1262_EXT_REF_COUNT) && + in_range(ref_n, ADS1262_RMUXN_REFN1, ADS1262_EXT_REF_COUNT); +} + static int ads1262_dev_send_cmd(struct ads1262 *st, u8 opcode) { guard(mutex)(&st->xfer_lock); @@ -455,17 +519,33 @@ static int ads1262_channel_enable(struct ads1262 *st, guard(mutex)(&st->xfer_lock); guard(mutex)(&st->chan_lock); =20 - ret =3D regmap_update_bits(st->regmap, ADS1262_MODE2_REG, - ADS1262_MODE2_DR_MASK, - FIELD_PREP(ADS1262_MODE2_DR_MASK, chan->data_rate)); + ret =3D regmap_update_bits(st->regmap, ADS1262_MODE0_REG, + ADS1262_MODE0_REFREV_MASK, + FIELD_PREP(ADS1262_MODE0_REFREV_MASK, chan->ref_reversal)); if (ret) return ret; =20 - return regmap_update_bits(st->regmap, ADS1262_INPMUX_REG, - ADS1262_INPMUX_MUXN_MASK | - ADS1262_INPMUX_MUXP_MASK, - FIELD_PREP(ADS1262_INPMUX_MUXN_MASK, spec->channel2) | - FIELD_PREP(ADS1262_INPMUX_MUXP_MASK, spec->channel)); + ret =3D regmap_update_bits(st->regmap, ADS1262_MODE2_REG, + ADS1262_MODE2_DR_MASK | + ADS1262_MODE2_GAIN_MASK, + FIELD_PREP(ADS1262_MODE2_DR_MASK, chan->data_rate) | + FIELD_PREP(ADS1262_MODE2_GAIN_MASK, chan->gain)); + if (ret) + return ret; + + ret =3D regmap_update_bits(st->regmap, ADS1262_INPMUX_REG, + ADS1262_INPMUX_MUXN_MASK | + ADS1262_INPMUX_MUXP_MASK, + FIELD_PREP(ADS1262_INPMUX_MUXN_MASK, spec->channel2) | + FIELD_PREP(ADS1262_INPMUX_MUXP_MASK, spec->channel)); + if (ret) + return ret; + + return regmap_update_bits(st->regmap, ADS1262_REFMUX_REG, + ADS1262_REFMUX_RMUXN_MASK | + ADS1262_REFMUX_RMUXP_MASK, + FIELD_PREP(ADS1262_REFMUX_RMUXN_MASK, chan->ref_n) | + FIELD_PREP(ADS1262_REFMUX_RMUXP_MASK, chan->ref_p)); } =20 static int ads1262_set_runmode(struct ads1262 *st, u8 runmode) @@ -514,6 +594,7 @@ static int ads1262_read_raw(struct iio_dev *indio_dev, { struct ads1262 *st =3D iio_priv(indio_dev); struct ads1262_channel *chan_data =3D &st->channels[chan->scan_index]; + u64 scale, offset; __be32 raw; int ret; =20 @@ -526,6 +607,34 @@ static int ads1262_read_raw(struct iio_dev *indio_dev, =20 return IIO_VAL_INT; =20 + case IIO_CHAN_INFO_SCALE: { + guard(mutex)(&st->chan_lock); + + *val =3D chan_data->scales[chan_data->gain][0]; + *val2 =3D chan_data->scales[chan_data->gain][1]; + + return IIO_VAL_DECIMAL64_PICO; + } + + case IIO_CHAN_INFO_OFFSET: { + guard(mutex)(&st->chan_lock); + + scale =3D iio_val_s64_compose(chan_data->scales[chan_data->gain][0], + chan_data->scales[chan_data->gain][1]); + + switch (chan->type) { + case IIO_TEMP: + offset =3D -mul_u64_u64_div_u64(ADS1262_TEMP_ZERO_C, + PICO * MILLIDEGREE_PER_DEGREE, + scale * ADS1262_TEMP_SLOPE_uV_C); + iio_val_s64_decompose(offset, val, val2); + + return IIO_VAL_INT_64; + default: + return -EOPNOTSUPP; + } + } + case IIO_CHAN_INFO_SAMP_FREQ: { guard(mutex)(&st->chan_lock); =20 @@ -548,6 +657,12 @@ static int ads1262_read_avail(struct iio_dev *indio_de= v, struct ads1262_channel *chan_data =3D &st->channels[chan->scan_index]; =20 switch (mask) { + case IIO_CHAN_INFO_SCALE: + *type =3D IIO_VAL_DECIMAL64_PICO; + *vals =3D (const int *)chan_data->scales; + *length =3D chan_data->num_scales * 2; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: *type =3D IIO_VAL_INT_PLUS_MICRO; =20 @@ -580,6 +695,16 @@ static int ads1262_write_raw(struct iio_dev *indio_dev, guard(mutex)(&st->chan_lock); =20 switch (mask) { + case IIO_CHAN_INFO_SCALE: + ret =3D ads1262_find_two(chan_data->scales, chan_data->num_scales, + val, val2); + if (ret < 0) + return ret; + + chan_data->gain =3D ret; + + return 0; + case IIO_CHAN_INFO_SAMP_FREQ: switch (chan_data->filter) { case ADS1262_FILTER_FIR: @@ -621,6 +746,17 @@ static int ads1262_debugfs_reg_access(struct iio_dev *= indio_dev, unsigned int re return regmap_write(st->regmap, reg, writeval); } =20 +static int ads1262_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_DECIMAL64_PICO; + default: + return IIO_VAL_INT_PLUS_MICRO; + } +} + static int ads1262_fwnode_xlate(struct iio_dev *indio_dev, const struct fwnode_reference_args *iiospec) { @@ -643,6 +779,7 @@ static const struct iio_info ads1262_iio_info =3D { .read_raw =3D ads1262_read_raw, .read_avail =3D ads1262_read_avail, .write_raw =3D ads1262_write_raw, + .write_raw_get_fmt =3D ads1262_write_raw_get_fmt, .debugfs_reg_access =3D ads1262_debugfs_reg_access, .fwnode_xlate =3D ads1262_fwnode_xlate, }; @@ -895,20 +1032,246 @@ static void ads1262_populate_samp_freqs(struct ads1= 262 *st) } } =20 +static void ads1262_calculate_scales(int (*scales)[2], size_t num_scales, + u32 full_scale, u64 mult, + u32 resolution) +{ + unsigned int i; + s64 val; + + /* + * Each scale in the table corresponds to a PGA gain configuration, + * which are given in powers of 2. + */ + for (i =3D 0; i < num_scales; i++) { + val =3D mul_u64_u64_shr(full_scale, mult, resolution - 1 + i); + iio_val_s64_decompose(val, &scales[i][0], &scales[i][1]); + } +} + +static int ads1262_populate_scales_resistance(struct ads1262 *st, + const struct iio_chan_spec *spec) +{ + struct ads1262_channel *chan =3D &st->channels[spec->scan_index]; + u32 full_scale; + + if (!ads1262_reference_is_external(chan->ref_p, chan->ref_n)) + return -EINVAL; + + full_scale =3D st->rref_ohms[chan->ref_p - 1][chan->ref_n - 1]; + + chan->num_scales =3D ARRAY_SIZE(chan->scales); + + ads1262_calculate_scales(chan->scales, chan->num_scales, full_scale, + PICO, ADS1262_ADC1_RESOLUTION); + + return 0; +} + +static int ads1262_populate_scales_temp(struct ads1262 *st, + const struct iio_chan_spec *spec) +{ + struct ads1262_channel *chan =3D &st->channels[spec->scan_index]; + u32 full_scale; + u64 mult; + + full_scale =3D ADS1262_INTERNAL_REFERENCE_uV; + mult =3D PICO * MILLIDEGREE_PER_DEGREE / ADS1262_TEMP_SLOPE_uV_C; + + chan->num_scales =3D 1; + + ads1262_calculate_scales(chan->scales, chan->num_scales, full_scale, + mult, ADS1262_ADC1_RESOLUTION); + + return 0; +} + +static int ads1262_populate_scales_voltage(struct ads1262 *st, + const struct iio_chan_spec *spec) +{ + struct device *dev =3D &st->spi->dev; + struct ads1262_channel *chan =3D &st->channels[spec->scan_index]; + int refp_uV, refn_uV; + u32 full_scale_uV; + u64 mult; + int ret; + + switch (chan->ref_p) { + case ADS1262_RMUXP_INTERNAL: + ret =3D st->avss_supply ? regulator_get_voltage(st->avss_supply) : 0; + if (ret < 0) + return dev_err_probe(dev, ret, "channel@%u: failed to get avss voltage\= n", + spec->scan_index); + + /* The internal reference negative is AVSS */ + refp_uV =3D -ret + ADS1262_INTERNAL_REFERENCE_uV; + break; + + case ADS1262_RMUXP_REFP1 ... ADS1262_RMUXP_REFP3: + refp_uV =3D st->refp_uV[chan->ref_p - 1]; + break; + + case ADS1262_RMUXP_AVDD: + ret =3D regulator_get_voltage(st->avdd_supply); + if (ret < 0) + return dev_err_probe(dev, ret, "channel@%u: failed to get avdd voltage\= n", + spec->scan_index); + refp_uV =3D ret; + break; + + default: + return -EINVAL; + } + + switch (chan->ref_n) { + case ADS1262_RMUXN_INTERNAL: + case ADS1262_RMUXN_AVSS: + ret =3D st->avss_supply ? regulator_get_voltage(st->avss_supply) : 0; + if (ret < 0) + return dev_err_probe(dev, ret, "channel@%u: failed to get avss voltage\= n", + spec->scan_index); + refn_uV =3D -ret; + break; + + case ADS1262_RMUXN_REFN1 ... ADS1262_RMUXN_REFN3: + refn_uV =3D st->refn_uV[chan->ref_n - 1]; + break; + + default: + return -EINVAL; + } + + full_scale_uV =3D abs(refp_uV - refn_uV); + if (full_scale_uV < 900000) + return dev_err_probe(dev, -EINVAL, "channel@%u: reference voltage below = 0.9V\n", + spec->scan_index); + + if (spec->channel >=3D ADS1262_INPMUX_AVDD && + spec->channel <=3D ADS1262_INPMUX_DVDD) { + /* The power supply monitors are scaled down by a factor of 4 */ + mult =3D 4; + chan->num_scales =3D 1; + } else { + mult =3D 1; + chan->num_scales =3D ARRAY_SIZE(chan->scales); + } + + ads1262_calculate_scales(chan->scales, chan->num_scales, full_scale_uV, + NANO * mult, ADS1262_ADC1_RESOLUTION); + + return 0; +} + +static int ads1262_parse_references(struct ads1262 *st) +{ + struct device *dev =3D &st->spi->dev; + unsigned int i, j; + char name[sizeof("ti,refpN-refnM-resistor-ohms")]; + u32 ohms; + int ret; + + for (i =3D ADS1262_RMUXP_REFP1; i <=3D ADS1262_RMUXP_REFP3; i++) { + scnprintf(name, sizeof(name), "refp%u", i); + ret =3D devm_regulator_get_enable_read_voltage(dev, name); + if (ret < 0 && ret !=3D -ENODEV) + return dev_err_probe(dev, ret, "failed to read reference voltage: %s\n", + name); + + st->refp_uV[i - 1] =3D ret =3D=3D -ENODEV ? 0 : ret; + } + + for (i =3D ADS1262_RMUXN_REFN1; i <=3D ADS1262_RMUXN_REFN3; i++) { + scnprintf(name, sizeof(name), "refn%u", i); + ret =3D devm_regulator_get_enable_read_voltage(dev, name); + if (ret < 0 && ret !=3D -ENODEV) + return dev_err_probe(dev, ret, "failed to read reference voltage: %s\n", + name); + + /* + * REVISIT: Currently the regulator subsystem doesn't support + * reading negative voltages. If we have a bipolar supply + * configuration (AVSS < 0), then we are forced to assume that + * negative references are either 0V (no regulator) or below + * ground magnitudes. + */ + if (st->bipolar_supply) + st->refn_uV[i - 1] =3D ret =3D=3D -ENODEV ? 0 : -ret; + else + st->refn_uV[i - 1] =3D ret =3D=3D -ENODEV ? 0 : ret; + } + + for (i =3D ADS1262_RMUXP_REFP1; i <=3D ADS1262_RMUXP_REFP3; i++) { + for (j =3D ADS1262_RMUXN_REFN1; j <=3D ADS1262_RMUXN_REFN3; j++) { + scnprintf(name, sizeof(name), + "ti,refp%u-refn%u-resistor-ohms", i, j); + + if (!device_property_present(dev, name)) + continue; + + ret =3D device_property_read_u32(dev, name, &ohms); + if (ret) + return dev_err_probe(dev, ret, + "failed to read reference resistor: %s\n", + name); + if (!ohms) + return dev_err_probe(dev, -EINVAL, + "reference resistor can't be 0 ohms: %s\n", + name); + + st->rref_ohms[i - 1][j - 1] =3D ohms; + } + } + + return 0; +} + static int ads1262_populate_tables(struct iio_dev *indio_dev) { struct ads1262 *st =3D iio_priv(indio_dev); + const struct iio_chan_spec *spec; + int ret; =20 ads1262_populate_samp_freqs(st); =20 + ret =3D ads1262_parse_references(st); + if (ret) + return ret; + + for (unsigned int i =3D 0; i < st->num_channels; i++) { + spec =3D &indio_dev->channels[i]; + + switch (spec->type) { + case IIO_VOLTAGE: + ret =3D ads1262_populate_scales_voltage(st, spec); + if (ret) + return ret; + break; + case IIO_TEMP: + ret =3D ads1262_populate_scales_temp(st, spec); + if (ret) + return ret; + break; + case IIO_RESISTANCE: + ret =3D ads1262_populate_scales_resistance(st, spec); + if (ret) + return ret; + break; + default: + return -EOPNOTSUPP; + } + } + return 0; } =20 static int ads1262_parse_channel_node(struct ads1262 *st, struct iio_chan_spec *spec, + struct ads1262_channel *chan, struct fwnode_handle *node) { struct device *dev =3D &st->spi->dev; + const char *sources[2]; + char name[sizeof("ti,refpN-refnM-resistor-ohms")]; u32 pins[2]; int ret; =20 @@ -947,6 +1310,38 @@ static int ads1262_parse_channel_node(struct ads1262 = *st, spec->channel =3D pins[0]; spec->channel2 =3D pins[1]; =20 + if (fwnode_property_present(node, "reference-sources")) { + ret =3D fwnode_property_read_string_array(node, "reference-sources", + sources, ARRAY_SIZE(sources)); + if (ret < 0) + return dev_err_probe(dev, ret, "%pfwP: failed to read reference-sources= \n", + node); + if (ret < 2) + return dev_err_probe(dev, -EINVAL, "%pfwP: missing reference-sources\n", + node); + + ret =3D match_string(ads1262_ref_sources_pos, -1, sources[0]); + if (ret < 0) + return dev_err_probe(dev, ret, "%pfwP: invalid positive reference sourc= e\n", + node); + chan->ref_p =3D ret; + + ret =3D match_string(ads1262_ref_sources_neg, -1, sources[1]); + if (ret < 0) + return dev_err_probe(dev, ret, "%pfwP: invalid negative reference sourc= e\n", + node); + chan->ref_n =3D ret; + + if (ads1262_reference_is_external(chan->ref_p, chan->ref_n)) { + scnprintf(name, sizeof(name), "ti,refp%u-refn%u-resistor-ohms", + chan->ref_p, chan->ref_n); + if (device_property_present(dev, name)) + chan->is_resistance =3D true; + } + } + + chan->ref_reversal =3D fwnode_property_read_bool(node, "ti,reference-reve= rsal"); + return 0; } =20 @@ -988,11 +1383,11 @@ static int ads1262_parse_channels(struct iio_dev *in= dio_dev) =20 *chan =3D (struct ads1262_channel)ads1262_default_channel; =20 - ret =3D ads1262_parse_channel_node(st, spec, node); + ret =3D ads1262_parse_channel_node(st, spec, chan, node); if (ret) return ret; =20 - spec->type =3D IIO_VOLTAGE; + spec->type =3D chan->is_resistance ? IIO_RESISTANCE : IIO_VOLTAGE; spec->indexed =3D true; spec->scan_index =3D i; spec->address =3D reg; @@ -1003,8 +1398,10 @@ static int ads1262_parse_channels(struct iio_dev *in= dio_dev) .endianness =3D IIO_BE, }; spec->info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SAMP_FREQ); - spec->info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ); + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_SCALE); + spec->info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_SCALE); =20 i++; } @@ -1027,6 +1424,14 @@ static int ads1262_parse_channels(struct iio_dev *in= dio_dev) return 0; } =20 +static void ads1262_regulator_disable(void *data) +{ + struct regulator *supply =3D data; + + if (supply) + regulator_disable(supply); +} + static int ads1262_supply_setup(struct ads1262 *st) { struct device *dev =3D &st->spi->dev; @@ -1036,14 +1441,52 @@ static int ads1262_supply_setup(struct ads1262 *st) if (ret) return dev_err_probe(dev, ret, "failed to get dvdd regulator\n"); =20 - ret =3D devm_regulator_get_enable(dev, "avdd"); - if (ret < 0) + st->avdd_supply =3D devm_regulator_get(dev, "avdd"); + ret =3D PTR_ERR_OR_ZERO(st->avdd_supply); + if (ret) return dev_err_probe(dev, ret, "failed to get avdd regulator\n"); =20 - ret =3D devm_regulator_get_enable_optional(dev, "avss"); - if (ret < 0 && ret !=3D -ENODEV) + ret =3D regulator_enable(st->avdd_supply); + if (ret) + return ret; + + ret =3D devm_add_action_or_reset(dev, ads1262_regulator_disable, + st->avdd_supply); + if (ret) + return ret; + + /* + * REVISIT: The AVSS supply has a minimum of -2.5V and maximum of 0V. + * Currently the regulator subsystem doesn't support negative voltages, + * so we assume the value returned here is actually the magnitude + * (absolute value). + * + * This limitation forces us to assume that, if we have a bipolar supply + * (AVSS < 0V), all negative references are below ground (REFN <=3D 0V) + * and positive references are above ground (REFP >=3D 0V), as this is the + * most common configuration. + */ + st->avss_supply =3D devm_regulator_get_optional(dev, "avss"); + ret =3D PTR_ERR_OR_ZERO(st->avss_supply); + if (ret && ret !=3D -ENODEV) return dev_err_probe(dev, ret, "failed to get avss regulator\n"); =20 + if (ret !=3D -ENODEV) { + ret =3D regulator_enable(st->avss_supply); + if (ret) + return ret; + + ret =3D devm_add_action_or_reset(dev, ads1262_regulator_disable, + st->avss_supply); + if (ret) + return ret; + + st->bipolar_supply =3D true; + } else { + st->avss_supply =3D NULL; + st->bipolar_supply =3D false; + } + fsleep(ADS1262_POWER_TRANS_USECS); =20 return 0; --=20 2.55.0 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-vs1-f51.google.com (mail-vs1-f51.google.com [209.85.217.51]) (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 56E1E17B425 for ; Fri, 28 Aug 2026 06:38:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.217.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899134; cv=none; b=O/ofiO52hOJI/MG0LB07E7me5HA6Ids7loOgML4QdKovdUiF7GF+Trs4GXPXbLfXQLNhlXUsSvkLBrTbrQAIsvtK4nUpwtJ2v4mjZSUSFCKsb9VfW1bsFo61SFqDUsJTLS93BYdnXoT9rt1WgwUx0Taz5aTg3kOVjFKoZr0VDCQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899134; c=relaxed/simple; bh=jBnuNfFaNy+lYevkOT79mOgADpfoXMW0c9FuXIA5WWY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Fio9YsdLzzV+Kj+k24ZLikDvDZ6Cq184uIwZAkrAJAzPVoPEya0J1hMxLS+oEt1vmDtW/W5dkvDahP8IYyMnzpcnW473swkNQZy6qILdSY375DTwoUjOKWxSw1LZij6sEuqxIIZg6GdDU9CdFuhOvVYTZhgsmqXbS+Ki7jAlCIA= 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=G5miVteJ; arc=none smtp.client-ip=209.85.217.51 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="G5miVteJ" Received: by mail-vs1-f51.google.com with SMTP id ada2fe7eead31-77bf3334d14so368813137.1 for ; Thu, 27 Aug 2026 23:38:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787899131; x=1788503931; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=hcOlTatZtiMtegG+sIDHWIx8wVSL0Q7Xb7hEFQvq7zQ=; b=G5miVteJq064cTyZyjT0ACmOINFtxxWOrOPD8enRbI/Oly1Id0MZSKc9YHys0OR1Dg QQe95gpoTfCtfdOdSRsFY/xzO3Msk9S5ATNbs08ZN24lTVz9xPcjHFoZLhWfRSZsSVC7 xX+QR1TlrQIPXAbS/9nXaVpkqX2y0OuOrSCovOLGTri6SLpT3zPpqs52+SPuQn80YMF0 OX4OAEcaH8xKAolyll+jIoK/iNcglL5MFhWezkrneoJlYQe4JLQV3+XyNnHGjHeJ1gYt dEzQ32i9In3GTU91f6tHRTA7HdAHQHHJTwrMYUMcheWACshlF+2QLQOLBxbu5yUyg3zu FX5A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787899131; x=1788503931; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=hcOlTatZtiMtegG+sIDHWIx8wVSL0Q7Xb7hEFQvq7zQ=; b=K1q7DUD1mib25zg3ivAzSqO9atSxorlOcyZ9Ijyrp1my3yVKE3wNUqktdBymer7I+N nfIGzsaH7V7iNFwY0Ehhr4PcR7tiCFeYJywq7X9UN1oA5jJlJPt/1If+DqPF2BHH/nEz EI17UD2HYCnHqnNZXUrAua+XCifzE6PYphUa1+rPCo/W6X+9m2CTK0uZbDmn0reVbBm9 UCZg01IWatMnd+LrMFTRG2nEUo0piIbf/773VmxCiLMS2TMJgwMw2Fvw/IEjtaZdxYLL urC1LwHIcfZVWacB2Y3TsMEBlLldq/beEr99SnfBRwUgooB4rxtXoZnZzuvaSntKUwyp 9zSg== X-Forwarded-Encrypted: i=1; AHgh+RoJxGyx7zWtn9ENQrJEdvFKP8Oo0SaHSrrYcya/d1gfTtJym/e5+LQ8Qn8zKZo5iTbVZM8O13+apl6YQWE=@vger.kernel.org X-Gm-Message-State: AFuF++kXs8/Hfh2SOBqz4mr2ZwQRvuVpZgpnjai3XnC1Nc10XruIXdCt G7B8imNf0q6pioK68hW8j2qSmmx0gDsH+KnAT/IY10fIMBX7Wmk5eyV3 X-Gm-Gg: AR+sD12+suN/NuK2ah70zKe43GCZjUX0H/GI9bXSNjHRtiPGUSC4dh9Chj7QcBLe0vU knreDYnCqQ8QzODHMm0XjvXH/AFz69LvsKlH4sXEuyXdY7c6PTndtRvaKCnM8yjIxJVLA0/BFtN FbH4tvTxb8ADJGPg8ch9jIYm+6u4laVlqBbeDSYbHBuIQpatSDKSwwIj/Aah+7WsYb8OSLoSHRP KGihbHbueoIWYjxa4nI3hqkyi1fJT9i/Y9/72Ei4owpcE1rPPgjMwye4tl6oNYA+/s2iNmDGmch +B1lb95t2CoIiOwm05hdARhmkrE+gL81j3Taa+8InL5tY8CRWZ7crkg979rl+oos1j+VF8DLscM uuJQLKlb1vEzsoWsMMSjJmzGigbP2g5roa4bPZLsrc6JwFIj41dLmqPgStCONlor3PWxHk0Dvt6 gZDSxDlge6J9u8tpncd7/MLePgm8cfaRQlEVHCSabC85ZkHvyjWcMOotjYm8ffuALM X-Received: by 2002:a05:6102:3e83:b0:779:c38e:de53 with SMTP id ada2fe7eead31-7859956a1cdmr1778891137.10.1787899131018; Thu, 27 Aug 2026 23:38:51 -0700 (PDT) Received: from [192.168.100.153] ([2800:bf0:61:1127:ab87:5602:531c:8dfb]) by smtp.gmail.com with ESMTPSA id a1e0cc1a2514c-97e849d8494sm454195241.1.2026.08.27.23.38.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 23:38:50 -0700 (PDT) From: Kurt Borja Date: Fri, 28 Aug 2026 01:38:21 -0500 Subject: [PATCH v4 06/10] iio: adc: ti-ads1262: support input chopping Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260828-ads126x-v4-6-1dc27e9c0260@gmail.com> References: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> In-Reply-To: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , David Lechner Cc: =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=3240; i=kuurtb@gmail.com; h=from:subject:message-id; bh=jBnuNfFaNy+lYevkOT79mOgADpfoXMW0c9FuXIA5WWY=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFkTdd6031zRuqLFyVz66v4vesfMzvmHhlYFRc2PkQ7Ly pryj/l4RykLgxgXg6yYIkt7wqJvj6Ly3vodCL0PM4eVCWQIAxenAExk5SuGf7YGAqskZljs+Kzg ZNu/78XZ7yuez/ivru6knPoiZ8Nv7xRGhi4NvWU2zmWppzu/WkibqggtfcjgG7Ca90oxe9FJQ6N 8LgA= X-Developer-Key: i=kuurtb@gmail.com; a=openpgp; fpr=54D3BE170AEF777983C3C63B57E3B6585920A69A Enable per-channel input chopping via the "input-chopping" property. As the device withholds the first conversion in chop mode, single reads are taken in CONTINUOUS run mode with a brief start/stop pulse, as recommended by the datasheet (Section 9.4.1.2). Reviewed-by: David Lechner Signed-off-by: Kurt Borja --- drivers/iio/adc/ti-ads1262.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c index c87c0a66119a..4d38da092001 100644 --- a/drivers/iio/adc/ti-ads1262.c +++ b/drivers/iio/adc/ti-ads1262.c @@ -203,6 +203,7 @@ struct ads1262_channel { u8 ref_n; bool ref_reversal; bool is_resistance; + bool input_chop; size_t num_scales; int scales[ADS1262_GAIN_COUNT][2]; }; @@ -464,7 +465,7 @@ static int ads1262_dev_stop(struct ads1262 *st) return ret; } =20 -static int ads1262_dev_start_one(struct ads1262 *st) +static int ads1262_dev_start_one(struct ads1262 *st, u8 runmode) { int ret; =20 @@ -472,7 +473,7 @@ static int ads1262_dev_start_one(struct ads1262 *st) if (ret) return ret; =20 - if (st->start_gpiod) { + if (runmode =3D=3D ADS1262_RUNMODE_CONTINUOUS || st->start_gpiod) { /* * The START pulse timing requirement is 4 clock cycles, at the * minimum clock rate this is 4 microseconds. @@ -520,7 +521,9 @@ static int ads1262_channel_enable(struct ads1262 *st, guard(mutex)(&st->chan_lock); =20 ret =3D regmap_update_bits(st->regmap, ADS1262_MODE0_REG, + ADS1262_MODE0_INPUT_CHOP_MASK | ADS1262_MODE0_REFREV_MASK, + FIELD_PREP(ADS1262_MODE0_INPUT_CHOP_MASK, chan->input_chop) | FIELD_PREP(ADS1262_MODE0_REFREV_MASK, chan->ref_reversal)); if (ret) return ret; @@ -561,13 +564,26 @@ static int ads1262_channel_read(struct iio_dev *indio= _dev, const struct iio_chan_spec *spec, __be32 *val) { struct ads1262 *st =3D iio_priv(indio_dev); + struct ads1262_channel *chan =3D &st->channels[spec->scan_index]; + u8 runmode; int ret; =20 IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); if (IIO_DEV_ACQUIRE_FAILED(claim)) return -EBUSY; =20 - ret =3D ads1262_set_runmode(st, ADS1262_RUNMODE_PULSE); + /* + * When a channel has chop mode or IDAC rotation mode, the first + * conversion is always withheld so the datasheet suggests using the + * CONTINUOUS mode and briefly starting and stopping conversions to + * achieve the same effect (Section 9.4.1.2). + */ + if (chan->input_chop) + runmode =3D ADS1262_RUNMODE_CONTINUOUS; + else + runmode =3D ADS1262_RUNMODE_PULSE; + + ret =3D ads1262_set_runmode(st, runmode); if (ret) return ret; =20 @@ -577,7 +593,7 @@ static int ads1262_channel_read(struct iio_dev *indio_d= ev, =20 reinit_completion(&st->drdy); =20 - ret =3D ads1262_dev_start_one(st); + ret =3D ads1262_dev_start_one(st, runmode); if (ret) return ret; =20 @@ -1340,6 +1356,7 @@ static int ads1262_parse_channel_node(struct ads1262 = *st, } } =20 + chan->input_chop =3D fwnode_property_read_bool(node, "input-chopping"); chan->ref_reversal =3D fwnode_property_read_bool(node, "ti,reference-reve= rsal"); =20 return 0; --=20 2.55.0 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-ua1-f48.google.com (mail-ua1-f48.google.com [209.85.222.48]) (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 36E17389116 for ; Fri, 28 Aug 2026 06:38:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899136; cv=none; b=A3Vvg7aj96cRvUGArGkPAFA/3qYzZi27NUsV+rOmchL4RksCoHscSFhXpvgzPPfYhx8ePqy8ccZJcLEG069eY+rv0nQMlfhuOAjlZ0AHHErOCtppJ6loEIzWc1UgCEbeI/aFlqZoD3QFjkOZKmF9olxUbnIMWRjWjBE6YGwEGAU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899136; c=relaxed/simple; bh=JuqZvTQwb5rkp+99vgWNtC19RzZ4Hw4K1sqB6JYbqnM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=FhBD63BZ8ZamlzgQxyXxH1+KAXqkMs6UTCQIgic+PN62RWVMK4B03P+PeOURH/rmX7Z1Y9G1pdqwm8CKoobDm0CMD0N75i4x+YuZOWNomjmSAK8AYMlreqJOkiz3pAlBwyLCeweYKeULsvcouF2mLDKFqm8144ovCC8tMutcTMM= 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=cWRtayY5; arc=none smtp.client-ip=209.85.222.48 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="cWRtayY5" Received: by mail-ua1-f48.google.com with SMTP id a1e0cc1a2514c-977ba4d3b49so435491241.1 for ; Thu, 27 Aug 2026 23:38:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787899133; x=1788503933; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=D+O09DWKYxbpMQbMh4vwOBWFTUZ3w5vfYeuNgWL21cE=; b=cWRtayY5XW0FuGQv2wrde3RB2fcQsNgLzRl9qSekf9wsdbGiybTGwp2m3M7wz56gbc +8lxZeJvr1LmOxWdj7W72+TYWrsmkeEkXYR8Pz5qqVKsGt8qAQ0g41SIv+B5CMAREcsC LO2EUjcT+rmADJUjDJuDT1tQ+iuC1e4exFO4oRkGHQRCm9Agf/hs3SHkhYgSOViqbavs tVL56dEL+ndSbtGD+rI0s5Ubn4fduCCd1KpAKQEffsrlZgr37ViZSChqwi/TNpRWC76W DxMnoa8k/mK+PNv9e3nPrRVIM2KhHYgLkv2Jtv0O2icwkf9eN0AOfCbHd8KVIMuDKRYQ o8pg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787899133; x=1788503933; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=D+O09DWKYxbpMQbMh4vwOBWFTUZ3w5vfYeuNgWL21cE=; b=mnRq/XDy560SM/a6DPWeVsD0stCS2UyMeYRvW7ixhbDYIqS01ejk09lRsD0i/X3qb8 YeH84uJW/ZrQsZJEz82kSleQoZZgc2H0gDNNffb9dEDp3HtG1utF7V3V/E/z/gJkrjQA aNp7vMvEsmx5BaKLl8UCQRfUrVwDAwWetlHs0//t5taVa5+V5wrlbt/gwgZx63+vu9iT E6gADAaaS54jYsDpWTA8cdRl4TrDuTvmCH9OW9u6PtMBceFTrgWuiTQr+97thGJ4HxkJ MQ97PNfnNEwyZ41jzEXYVSGBGiuCbSvTWc6gEWduHDq2q7ej5rbWn8bpqNbLx9sqyI5R wGhQ== X-Forwarded-Encrypted: i=1; AHgh+RoCJv1ZklVAPYy/CJhZOBxxideoY41+lly/iXsaaG8k896QOSJILtbhrDrUxAbfqyzbkHWe2VzTj5uZLqE=@vger.kernel.org X-Gm-Message-State: AFuF++kGJDubZ5ZRa5jpoQeLgAKBlJv1BLoJIjmxj2BpcndutU0bv4TU FZ2ul3olxD8V+vBe36EblGpsUYG3kAvXn+K9mA1Xl+6jV/ysj7SotTbK X-Gm-Gg: AR+sD138MztO2+fNuHS9jPew18C2k5+w0wJO6XdTzFYIG8SKw3aoFh56YRhuYHPIUBj kdEMLHZzET7viUj0yYJmhVGhgc8VZS1/4ZWlC5v3M840krDUqmmcKDLyWASbLlsItMswrs0PjD8 TEv+rLTPclG4dub51j4ocqcENyw8XpLen9TmrVHdmIn2WayubfsRUSKRtPtKPK1EDjFF90gL3RF xPZ+QoHbLInuOJb3ME/xQl5ZPDG+IUZL/BZrj0JXsFo+4arc7ebS0JHPpqa3swwinxvbKNdlpyF KUwBfuXeixqzApahfZ7uGJMGGqbQ28A2bpiKVmCqMIsBAxkuu6/vUshYyhCkUP8D5jzsrZK91es 5jPxoB7QgmC9cmcs9Fk5YIYJ7VbTgemrNON4PoyVHJKX0LfrfHEWNM5L8Mp0KnuOSmX6ZWNlspB Yco1T+xLVGff5yVTTekk9/7JZQtK/4z1mWfDAEUtPnybfPuEQ6Uk+QlAYH0hscAhBY X-Received: by 2002:a05:6102:2253:b0:783:c17c:e7de with SMTP id ada2fe7eead31-7841d55ca7bmr2285358137.9.1787899132930; Thu, 27 Aug 2026 23:38:52 -0700 (PDT) Received: from [192.168.100.153] ([2800:bf0:61:1127:ab87:5602:531c:8dfb]) by smtp.gmail.com with ESMTPSA id a1e0cc1a2514c-97e849d8494sm454195241.1.2026.08.27.23.38.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 23:38:52 -0700 (PDT) From: Kurt Borja Date: Fri, 28 Aug 2026 01:38:22 -0500 Subject: [PATCH v4 07/10] iio: adc: ti-ads1262: support excitation currents Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260828-ads126x-v4-7-1dc27e9c0260@gmail.com> References: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> In-Reply-To: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , David Lechner Cc: =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=5946; i=kuurtb@gmail.com; h=from:subject:message-id; bh=JuqZvTQwb5rkp+99vgWNtC19RzZ4Hw4K1sqB6JYbqnM=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFkTdd4Iif9g33q1KEyX462RTdbPQ06M9q2HxEMUvRX5t ZN+Wlh1lLIwiHExyIopsrQnLPr2KCrvrd+B0Pswc1iZQIYwcHEKwES2BjEyPGz9nKU2+63d4UkN zx8pzYiLn9C8nc3FvHra1htPsnnF7BgZpgYVn1DgzuYM/mOuciBwY/e9u0HGX6ft5hKVmpBWEu3 GBgA= X-Developer-Key: i=kuurtb@gmail.com; a=openpgp; fpr=54D3BE170AEF777983C3C63B57E3B6585920A69A Support the two IDAC excitation current sources. Each channel can route its IDAC1/IDAC2 outputs to a pin via the "excitation-channels" property and select a magnitude via "excitation-current-nanoamp". Reviewed-by: David Lechner Signed-off-by: Kurt Borja --- drivers/iio/adc/ti-ads1262.c | 87 ++++++++++++++++++++++++++++++++++++++++= ++-- 1 file changed, 84 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c index 4d38da092001..04566d00d7cb 100644 --- a/drivers/iio/adc/ti-ads1262.c +++ b/drivers/iio/adc/ti-ads1262.c @@ -198,12 +198,15 @@ struct ads1262_channel { u8 data_rate; u8 filter; + u8 idac_mux[2]; + u8 idac_mag[2]; u8 gain; u8 ref_p; u8 ref_n; bool ref_reversal; bool is_resistance; bool input_chop; + bool idac_chop; size_t num_scales; int scales[ADS1262_GAIN_COUNT][2]; }; @@ -315,6 +318,7 @@ static const struct iio_chan_spec ads1262_monitor_chan_= specs[] =3D { static const struct ads1262_channel ads1262_default_channel =3D { .data_rate =3D ADS1262_DR_20_SPS, .filter =3D ADS1262_FILTER_FIR, + .idac_mux =3D { ADS1262_IDACMUX_NO_CONN, ADS1262_IDACMUX_NO_CONN }, }; =20 static const u32 ads1262_mod_decimator_a[] =3D { @@ -373,6 +377,21 @@ static const char * const ads1262_ref_sources_neg[] = =3D { NULL }; =20 +static const u32 ads1262_idac_mags_nA[] =3D { + 0, 50000, 100000, 250000, 500000, 750000, 1000000, 1500000, /* 0..7 */ + 2000000, 2500000, 3000000 /* 8..10 */ +}; + +static int ads1262_find_one(const u32 *array, size_t num_elements, u32 val) +{ + for (unsigned int i =3D 0; i < num_elements; i++) { + if (val =3D=3D array[i]) + return i; + } + + return -EINVAL; +} + static int ads1262_find_two(const int (*array)[2], size_t num_elements, in= t val, int val2) { @@ -522,8 +541,10 @@ static int ads1262_channel_enable(struct ads1262 *st, =20 ret =3D regmap_update_bits(st->regmap, ADS1262_MODE0_REG, ADS1262_MODE0_INPUT_CHOP_MASK | + ADS1262_MODE0_IDAC_CHOP_MASK | ADS1262_MODE0_REFREV_MASK, FIELD_PREP(ADS1262_MODE0_INPUT_CHOP_MASK, chan->input_chop) | + FIELD_PREP(ADS1262_MODE0_IDAC_CHOP_MASK, chan->idac_chop) | FIELD_PREP(ADS1262_MODE0_REFREV_MASK, chan->ref_reversal)); if (ret) return ret; @@ -544,6 +565,22 @@ static int ads1262_channel_enable(struct ads1262 *st, if (ret) return ret; =20 + ret =3D regmap_update_bits(st->regmap, ADS1262_IDACMUX_REG, + ADS1262_IDACMUX_MUX1_MASK | + ADS1262_IDACMUX_MUX2_MASK, + FIELD_PREP(ADS1262_IDACMUX_MUX1_MASK, chan->idac_mux[0]) | + FIELD_PREP(ADS1262_IDACMUX_MUX2_MASK, chan->idac_mux[1])); + if (ret) + return ret; + + ret =3D regmap_update_bits(st->regmap, ADS1262_IDACMAG_REG, + ADS1262_IDACMAG_MAG1_MASK | + ADS1262_IDACMAG_MAG2_MASK, + FIELD_PREP(ADS1262_IDACMAG_MAG1_MASK, chan->idac_mag[0]) | + FIELD_PREP(ADS1262_IDACMAG_MAG2_MASK, chan->idac_mag[1])); + if (ret) + return ret; + return regmap_update_bits(st->regmap, ADS1262_REFMUX_REG, ADS1262_REFMUX_RMUXN_MASK | ADS1262_REFMUX_RMUXP_MASK, @@ -578,7 +615,7 @@ static int ads1262_channel_read(struct iio_dev *indio_d= ev, * CONTINUOUS mode and briefly starting and stopping conversions to * achieve the same effect (Section 9.4.1.2). */ - if (chan->input_chop) + if (chan->input_chop || chan->idac_chop) runmode =3D ADS1262_RUNMODE_CONTINUOUS; else runmode =3D ADS1262_RUNMODE_PULSE; @@ -1288,8 +1325,8 @@ static int ads1262_parse_channel_node(struct ads1262 = *st, struct device *dev =3D &st->spi->dev; const char *sources[2]; char name[sizeof("ti,refpN-refnM-resistor-ohms")]; - u32 pins[2]; - int ret; + u32 pins[2], mags[2]; + int count, ret; =20 if (fwnode_property_present(node, "single-channel")) { ret =3D fwnode_property_read_u32(node, "single-channel", &pins[0]); @@ -1356,7 +1393,51 @@ static int ads1262_parse_channel_node(struct ads1262= *st, } } =20 + if (fwnode_property_present(node, "excitation-channels")) { + count =3D fwnode_property_count_u32(node, "excitation-channels"); + if (count < 0) + return dev_err_probe(dev, count, + "%pfwP: failed to count excitation-channels\n", node); + + pins[0] =3D ADS1262_IDACMUX_NO_CONN; + pins[1] =3D ADS1262_IDACMUX_NO_CONN; + ret =3D fwnode_property_read_u32_array(node, "excitation-channels", + pins, min(count, ARRAY_SIZE(pins))); + if (ret) + return dev_err_probe(dev, ret, + "%pfwP: failed to read excitation-channels\n", node); + if (pins[0] > ADS1262_IDACMUX_NO_CONN || pins[1] > ADS1262_IDACMUX_NO_CO= NN) + return dev_err_probe(dev, -EINVAL, + "%pfwP: excitation-channels not in range\n", node); + chan->idac_mux[0] =3D pins[0]; + chan->idac_mux[1] =3D pins[1]; + + mags[0] =3D 0; + mags[1] =3D 0; + ret =3D fwnode_property_read_u32_array(node, "excitation-current-nanoamp= ", + mags, min(count, ARRAY_SIZE(mags))); + if (ret) + return dev_err_probe(dev, ret, + "%pfwP: failed to read excitation-current-nanoamp\n", + node); + + ret =3D ads1262_find_one(ads1262_idac_mags_nA, + ARRAY_SIZE(ads1262_idac_mags_nA), mags[0]); + if (ret < 0) + return dev_err_probe(dev, ret, + "%pfwP: invalid excitation-current-nanoamp\n", node); + chan->idac_mag[0] =3D ret; + + ret =3D ads1262_find_one(ads1262_idac_mags_nA, + ARRAY_SIZE(ads1262_idac_mags_nA), mags[1]); + if (ret < 0) + return dev_err_probe(dev, ret, + "%pfwP: invalid excitation-current-nanoamp\n", node); + chan->idac_mag[1] =3D ret; + } + chan->input_chop =3D fwnode_property_read_bool(node, "input-chopping"); + chan->idac_chop =3D fwnode_property_read_bool(node, "excitation-current-c= hopping"); chan->ref_reversal =3D fwnode_property_read_bool(node, "ti,reference-reve= rsal"); =20 return 0; --=20 2.55.0 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-vk1-f181.google.com (mail-vk1-f181.google.com [209.85.221.181]) (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 0BDDE3D0935 for ; Fri, 28 Aug 2026 06:38:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899138; cv=none; b=F6eUbi34Cl6QvVkIJKyMwCkwoIis/8cwbihY0kOnIjM93xedPY4S5ZDePHUSdilA9Iw6qldCb4noAfAqd6VMX87UB8E6dkxmAuhGeoD75qDKFCua9wSQ0U2T8VC6FdlTCgkO3ek//vXEQR+r+P0+V95NF2uDhyR7QU2vsTailwQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899138; c=relaxed/simple; bh=TMHFl5L/alFHgu3VeMCweylXc4tFsdHYF8XBRmES1Hk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=JB3VRWTBhjoJCmqnlbBxS5XvFGuewCgi1L1kKzKakCk/J0EzDKQ+ra/1NR0T1B2ZnC4T3vnWMRL9DBoeddSjBPTpruBZOncygwNeGfBjxJWM9u298ny+lb/cpfsBJ/6n91XCudtwk9+RUU4s2d9rh5u8KQlXM6SmbYfK8lmyzOE= 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=YkpH2jx2; arc=none smtp.client-ip=209.85.221.181 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="YkpH2jx2" Received: by mail-vk1-f181.google.com with SMTP id 71dfb90a1353d-5bfb3347ce0so288207e0c.2 for ; Thu, 27 Aug 2026 23:38:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787899135; x=1788503935; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=XsfiQ/UpYrylb/xt1NWt3tkBeV1xOu5S1pAOKlyMNac=; b=YkpH2jx2WUPEK2FUQ76rBHBHzkB3GGooxRO0p6pK3VlvN+H3lY7Q3lcFYjEb8bu44v BT2VCiazsE3wqBe+PnOgHdKTwGotFLg7YCU6MgIP/2rQak0h6BEMQl2olGYyj6f3e2Wh SeoqgAk85IbI4yqv99ejMgUxZrjpHJbwOs9ZAqiDJtG2cAVJLn8dPwQH0cWwfhyo+YQS mTth4Cm4gK0m3WeOxthZprUpWSARZuEWPOp7FMGdodGKppabrwDmkVrNZJuh8FEW3ApE FG/D/v2A8fb9eaKMxynHgT6QSqQAARPBO/EGwkfbFc/CTiAw+UxnR8rgF9FldbPaEt0T K1hw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787899135; x=1788503935; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=XsfiQ/UpYrylb/xt1NWt3tkBeV1xOu5S1pAOKlyMNac=; b=cl9CFoeevtavErps1jGEAWgJwCp36+VxaavlsV8TfF1QxXI5uV7YeI/kaFvGOMiFgL a7ucECJHp4NV7D3ii8zpoBw+O4Z+qOk2T1Y/mqOIXJwW+VV0Q39gofxtd6qYlhuKyZZg gUmSnHZzsKFcftmPazhDYz6vw7Xa5XnMy4OFWha9iXlq11snSP8005ZFuImFDZf/OaFZ y/itBa39qVJuIOYdXZZNYE9wCAfTrALKeNRGVCnPKi/N695bRTgiLtq7aGqxRWbF8owd SD1QXy+9R4PczDKB5l3sNeAdE5GVdqMznbpyxcDjE8Lx0Xykjh7eWO4hE0AwLjWldQpL 3+UQ== X-Forwarded-Encrypted: i=1; AHgh+Rr1Euxbsz7uHJYh/F6eV9T+ZYdeyxROTktWmKO9i2LPwrx7Bt5NCpPnYGrSmH1jCJhM/88snhVzXcyf6z4=@vger.kernel.org X-Gm-Message-State: AFuF++lPTb53VyaRYblZNAtmbMFwAWGS1PUW5hsl1rdqGxpDlH6E6i6z nFdtjUJJyyIGwo+edAn7yd2oeyhIYRq5HjO+6A6QZbZWX3va6y9sZIVq X-Gm-Gg: AR+sD101TJDjeYyvhkLeXcQHgOaUDBJWm/aqbu+VXXtj/Ra77kCaFiRAnvzZr7BTT4C kdZ6LAU/mkjCnI4WyGbRabS+vzsS/jDepxevRdo3sDONfq+71G4a/fWo5puAomWI/WXa5Cx+fsp DU0bz+rPkgQ09+GQH5d3+2PI6cMWNWBEpl05xu+mPoExnsEUL+anLv9AGegG3TqzSoO5VOv2nWr LHnVdLqWzkiP+4bQBrd+3YBSmyjgAJRl5bxrytz/NSDxUTzmmFCL3N0QrX4zhyKWyXH4CwZXpH6 P4YBQxFhW9vxB9FsRw7CuaX/W6mre+M7aHPSgJWUDVs7ninVSk4Oo4lfOPaXBJpGUHxEbZD7ErP 3ZjwV8JAB1SLTWDmvfQFmSSRdwOpvUBGZOY6O9k9uv1upHw26OepbBA2T1ZQxd+XAMHP0JbSz3M 7e/6lxV93u1lLWvRYDYKKdu19DJVz8SeliXXOFWsZeCJe5EGGLYdH3diji31blejFc X-Received: by 2002:a05:6102:5128:b0:780:7e65:f0ab with SMTP id ada2fe7eead31-7859822155fmr1205317137.1.1787899134840; Thu, 27 Aug 2026 23:38:54 -0700 (PDT) Received: from [192.168.100.153] ([2800:bf0:61:1127:ab87:5602:531c:8dfb]) by smtp.gmail.com with ESMTPSA id a1e0cc1a2514c-97e849d8494sm454195241.1.2026.08.27.23.38.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 23:38:54 -0700 (PDT) From: Kurt Borja Date: Fri, 28 Aug 2026 01:38:23 -0500 Subject: [PATCH v4 08/10] iio: adc: ti-ads1262: support triggered buffer sampling Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260828-ads126x-v4-8-1dc27e9c0260@gmail.com> References: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> In-Reply-To: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , David Lechner Cc: =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=12103; i=kuurtb@gmail.com; h=from:subject:message-id; bh=TMHFl5L/alFHgu3VeMCweylXc4tFsdHYF8XBRmES1Hk=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFkTdd7s10k9Nkf2uOexEwlWfGe0a16aP3p0qql5oc5lh WDXecIvOkpZGMS4GGTFFFnaExZ9exSV99bvQOh9mDmsTCBDGLg4BWAi3DmMDNf4nsiedMkw1hN+ /eflptx/Z5gXz335rFex0Hv2oZ82V+8z/I/InVq5qiMkslVon+yzJRnpXKel95h0qLxy593F7NE eyAUA X-Developer-Key: i=kuurtb@gmail.com; a=openpgp; fpr=54D3BE170AEF777983C3C63B57E3B6585920A69A Add triggered buffer support and a data-ready (DRDY) hardware trigger. Signed-off-by: Kurt Borja --- drivers/iio/adc/Kconfig | 2 + drivers/iio/adc/ti-ads1262.c | 305 +++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 307 insertions(+) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index e51ce42bce94..2b60ade01e90 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1864,6 +1864,8 @@ config TI_ADS1262 tristate "Texas Instruments ADS1262" depends on SPI select REGMAP + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help If you say yes here you get support for Texas Instruments ADS1262 and ADS1263 ADC chips. diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c index 04566d00d7cb..3f6d34a08b29 100644 --- a/drivers/iio/adc/ti-ads1262.c +++ b/drivers/iio/adc/ti-ads1262.c @@ -33,6 +33,9 @@ #include =20 #include +#include +#include +#include =20 #define ADS1262_OPCODE_NOP 0x00 #define ADS1262_OPCODE_RESET 0x06 @@ -191,6 +194,7 @@ #define ADS1262_MON_CHANNEL_COUNT 4 #define ADS1262_EXT_REF_COUNT 3 #define ADS1262_REGMAP_WRITE_SZ 8 +#define ADS1262_SPI_XFER_SZ 13 #define ADS1262_MONITOR_ADDR_OFFSET 100 =20 #define ADS1262_ADC1_RESOLUTION 32 @@ -214,6 +218,7 @@ struct ads1262_channel { struct ads1262 { struct spi_device *spi; struct regmap *regmap; + struct iio_trigger *trig; struct gpio_desc *start_gpiod; struct regulator *avdd_supply; struct regulator *avss_supply; @@ -224,6 +229,8 @@ struct ads1262 { /* protects channel state */ struct mutex chan_lock; struct completion drdy; + struct spi_message msg; + struct spi_transfer xfer; unsigned long clk_rate; u8 dev_id; bool bipolar_supply; @@ -232,6 +239,11 @@ struct ads1262 { u32 rref_ohms[ADS1262_EXT_REF_COUNT][ADS1262_EXT_REF_COUNT]; int refp_uV[ADS1262_EXT_REF_COUNT]; int refn_uV[ADS1262_EXT_REF_COUNT]; + IIO_DECLARE_BUFFER_WITH_TS(__be32, scan_buffer, + ADS1262_FW_CHANNEL_COUNT + + ADS1262_MON_CHANNEL_COUNT); + u8 tx[ADS1262_SPI_XFER_SZ] __aligned(IIO_DMA_MINALIGN); + u8 rx[ADS1262_SPI_XFER_SZ]; }; =20 static const char * const ads1262_device_id_to_name[] =3D { @@ -837,10 +849,284 @@ static const struct iio_info ads1262_iio_info =3D { .fwnode_xlate =3D ads1262_fwnode_xlate, }; =20 +static int ads1262_buffer_postenable_mult(struct iio_dev *indio_dev) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + + /* + * When multiple channels are selected, we use a single transfer to both + * enable channels, start and then read conversions with a full-duplex + * optimized method. The transfer buffer holds up to four contiguous + * commands: two register write commands, and start and stop commands if + * no START GPIO is provided. + * + * The buffer is arranged as follows: + * + * byte 0-1: write protocol header + * byte 2-5: MODE0, MODE1, MODE2, INPMUX register data + * byte 6-7: write protocol header + * byte 8-10: IDACMUX, IDACMAG, REFMUX register data + * byte 11: START1 command + * byte 12: STOP1 command + */ + if (st->start_gpiod) + st->xfer.len =3D 11; + else + st->xfer.len =3D 13; + + static_assert(13 <=3D ADS1262_SPI_XFER_SZ); + + return spi_optimize_message(st->spi, &st->msg); +} + +static int ads1262_buffer_postenable_one(struct iio_dev *indio_dev) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + unsigned long i; + int ret; + + i =3D find_first_bit(indio_dev->active_scan_mask, + iio_get_masklength(indio_dev)); + ret =3D ads1262_channel_enable(st, &indio_dev->channels[i]); + if (ret) + return ret; + + ret =3D ads1262_set_runmode(st, ADS1262_RUNMODE_CONTINUOUS); + if (ret) + return ret; + + static_assert(5 <=3D ADS1262_SPI_XFER_SZ); + + st->xfer.len =3D 5; + memset(st->tx, 0, st->xfer.len); + /* + * When only one channel is selected, we can't really avoid concurrent + * device activity from happening between the DRDY signal and data + * retrieval, thus we read by command. The transfer buffer holds the + * command (RDATA1) plus the 4 conversion bytes (5 bytes total). + */ + st->tx[0] =3D ADS1262_OPCODE_RDATA1; + + ret =3D spi_optimize_message(st->spi, &st->msg); + if (ret) + return ret; + + ret =3D ads1262_dev_start(st); + if (ret) { + spi_unoptimize_message(&st->msg); + return ret; + } + + return 0; +} + +static int ads1262_buffer_postenable(struct iio_dev *indio_dev) +{ + int ret; + + if (iio_validate_scan_mask_onehot(indio_dev, + indio_dev->active_scan_mask)) + ret =3D ads1262_buffer_postenable_one(indio_dev); + else + ret =3D ads1262_buffer_postenable_mult(indio_dev); + + return ret; +} + +static int ads1262_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + + if (iio_validate_scan_mask_onehot(indio_dev, + indio_dev->active_scan_mask)) { + ads1262_dev_stop(st); + } else { + regcache_drop_region(st->regmap, ADS1262_MODE0_REG, + ADS1262_INPMUX_REG); + regcache_drop_region(st->regmap, ADS1262_IDACMUX_REG, + ADS1262_REFMUX_REG); + } + + spi_unoptimize_message(&st->msg); + + return 0; +} + +static bool ads1262_validate_scan_mask(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + + if (st->trig && indio_dev->trig =3D=3D st->trig) + return iio_validate_scan_mask_onehot(indio_dev, scan_mask); + + return true; +} + +static const struct iio_buffer_setup_ops ads1262_buffer_ops =3D { + .postenable =3D ads1262_buffer_postenable, + .predisable =3D ads1262_buffer_predisable, + .validate_scan_mask =3D ads1262_validate_scan_mask, +}; + +static void ads1262_channel_prep_tx(struct ads1262 *st, + const struct iio_chan_spec *spec) +{ + struct ads1262_channel *chan =3D &st->channels[spec->scan_index]; + u8 runmode; + + guard(mutex)(&st->chan_lock); + + /* + * Input chopping and IDAC rotation modes require the continuous + * conversion mode. + * + * This condition only matters when we have an START GPIO, in which case + * the pulse mode is preferred for its predictability: one conversion + * per rising edge. Briefly pulsing the START GPIO (4 uS) should have + * the same effect almost every time, unless the pulse lasts more than + * ~208 uS, which should be rare even if the task is preempted. + * + * If we rely solely on conversion control commands, both modes are + * equivalent because START1 and STOP1 commands are send contiguously on + * the same transfer. + */ + if (chan->input_chop || chan->idac_chop) + runmode =3D ADS1262_RUNMODE_CONTINUOUS; + else + runmode =3D ADS1262_RUNMODE_PULSE; + + st->tx[0] =3D ADS1262_MODE0_REG | ADS1262_OPCODE_WREG; + st->tx[1] =3D ADS1262_INPMUX_REG - ADS1262_MODE0_REG; + st->tx[2] =3D FIELD_PREP(ADS1262_MODE0_INPUT_CHOP_MASK, chan->input_chop)= | + FIELD_PREP(ADS1262_MODE0_IDAC_CHOP_MASK, chan->idac_chop) | + FIELD_PREP(ADS1262_MODE0_RUNMODE_MASK, runmode) | + FIELD_PREP(ADS1262_MODE0_REFREV_MASK, chan->ref_reversal); + st->tx[3] =3D FIELD_PREP(ADS1262_MODE1_FILTER_MASK, chan->filter); + st->tx[4] =3D FIELD_PREP(ADS1262_MODE2_DR_MASK, chan->data_rate) | + FIELD_PREP(ADS1262_MODE2_GAIN_MASK, chan->gain); + st->tx[5] =3D FIELD_PREP(ADS1262_INPMUX_MUXP_MASK, spec->channel) | + FIELD_PREP(ADS1262_INPMUX_MUXN_MASK, spec->channel2); + + st->tx[6] =3D ADS1262_IDACMUX_REG | ADS1262_OPCODE_WREG; + st->tx[7] =3D ADS1262_REFMUX_REG - ADS1262_IDACMUX_REG; + st->tx[8] =3D FIELD_PREP(ADS1262_IDACMUX_MUX1_MASK, chan->idac_mux[0]) | + FIELD_PREP(ADS1262_IDACMUX_MUX2_MASK, chan->idac_mux[1]); + st->tx[9] =3D FIELD_PREP(ADS1262_IDACMAG_MAG1_MASK, chan->idac_mag[0]) | + FIELD_PREP(ADS1262_IDACMAG_MAG2_MASK, chan->idac_mag[1]); + st->tx[10] =3D FIELD_PREP(ADS1262_REFMUX_RMUXP_MASK, chan->ref_p) | + FIELD_PREP(ADS1262_REFMUX_RMUXN_MASK, chan->ref_n); + + /* + * If we have an START GPIO, the transfer length is 11 so these last two + * bytes are ignored. + */ + st->tx[11] =3D ADS1262_OPCODE_START1; + st->tx[12] =3D ADS1262_OPCODE_STOP1; +} + +static int ads1262_fill_buffer_mult(struct iio_dev *indio_dev) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + unsigned int chan; + int i =3D -1; + int ret; + + /* + * This routine enables and reads channels in a full-duplex fashion. + * + * When a channel is enabled, the previous conversion is clocked out of + * the shift data register on the same transfer (Section 9.4.7.1). This + * allows for low latency software sequencing but forbids any + * communication with the chip in-between or data corruption may occur, + * hence the need to take the xfer_lock for the whole operation. + */ + guard(mutex)(&st->xfer_lock); + + iio_for_each_active_channel(indio_dev, chan) { + ads1262_channel_prep_tx(st, &indio_dev->channels[chan]); + + reinit_completion(&st->drdy); + + ret =3D spi_sync(st->spi, &st->msg); + if (ret) + return ret; + + if (st->start_gpiod) { + gpiod_set_value_cansleep(st->start_gpiod, 1); + fsleep(4); + gpiod_set_value_cansleep(st->start_gpiod, 0); + } + + if (i > -1) + memcpy(&st->scan_buffer[i], st->rx, sizeof(st->scan_buffer[i])); + i++; + + ret =3D ads1262_wait_for_conversion(st); + if (ret) + return ret; + } + + memset(st->tx, 0, st->xfer.len); + ret =3D spi_sync(st->spi, &st->msg); + if (ret) + return ret; + + memcpy(&st->scan_buffer[i], st->rx, sizeof(st->scan_buffer[i])); + + return 0; +} + +static int ads1262_fill_buffer_one(struct iio_dev *indio_dev) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + int ret; + + guard(mutex)(&st->xfer_lock); + + ret =3D spi_sync(st->spi, &st->msg); + if (ret) + return ret; + + /* In command mode the conversion data is found at offset 1 */ + memcpy(st->scan_buffer, &st->rx[1], sizeof(*st->scan_buffer)); + + return 0; +} + +static irqreturn_t ads1262_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf =3D p; + struct iio_dev *indio_dev =3D pf->indio_dev; + struct ads1262 *st =3D iio_priv(indio_dev); + s64 ts =3D pf->timestamp; + unsigned int weight; + int ret; + + weight =3D bitmap_weight(indio_dev->active_scan_mask, + iio_get_masklength(indio_dev)); + + if (weight =3D=3D 1) + ret =3D ads1262_fill_buffer_one(indio_dev); + else + ret =3D ads1262_fill_buffer_mult(indio_dev); + if (ret) + goto out_notify_done; + + iio_push_to_buffers_with_ts(indio_dev, st->scan_buffer, + sizeof(st->scan_buffer), ts); + +out_notify_done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + static irqreturn_t ads1262_irq_handler(int irq, void *dev_id) { struct ads1262 *st =3D dev_id; =20 + iio_trigger_poll(st->trig); complete(&st->drdy); =20 return IRQ_HANDLED; @@ -1609,6 +1895,9 @@ static int ads1262_spi_probe(struct spi_device *spi) st =3D iio_priv(indio_dev); st->spi =3D spi; init_completion(&st->drdy); + st->xfer.tx_buf =3D st->tx; + st->xfer.rx_buf =3D st->rx; + spi_message_init_with_transfers(&st->msg, &st->xfer, 1); =20 ret =3D devm_mutex_init(dev, &st->chan_lock); if (ret) @@ -1654,6 +1943,22 @@ static int ads1262_spi_probe(struct spi_device *spi) if (ret) return ret; =20 + ret =3D devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + ads1262_trigger_handler, + &ads1262_buffer_ops); + if (ret) + return ret; + + st->trig =3D devm_iio_trigger_alloc(dev, "%s-dev%d-drdy", indio_dev->name, + iio_device_id(indio_dev)); + if (!st->trig) + return -ENOMEM; + iio_trigger_set_drvdata(st->trig, st); + ret =3D devm_iio_trigger_register(dev, st->trig); + if (ret) + return ret; + /* * REVISIT: This chip has software polling capabilities, which could be * used to stop depending on the DRDY signal. --=20 2.55.0 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-vs1-f53.google.com (mail-vs1-f53.google.com [209.85.217.53]) (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 CF9583D25CC for ; Fri, 28 Aug 2026 06:38:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.217.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899140; cv=none; b=D2UUVkbYyZI5xKQXCql+gnimMm5ntSDlkzD1Icva30IXUjToRWPQd8lPfKpTc/CocteZNWWD1xk/qpLKo1JIHe2WYKpUT27UDBOXMTSpeuG98dt+Eseq4MAuYd4llnw5cw+w4eprVE5qzjh1EqBJylhDRpWZN6p+xwIaFt/c27I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899140; c=relaxed/simple; bh=awLx3251t6HAnsVHNTGEYJXrS1sww/D1jVL1AboaEro=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=t6hTEgfPQ2wzrqSZ2ggCWuMHm65hRua+of/GnN839d6rhVo4nutZ+2TQ7fDKzrtzEddTciaNn1SzA6kSY86MAbfPuIV3WrYj0OGb2dB67UNFBE+AVzXZrW0WkLpkQgphiG/xxURvMs6MiDh2myqji3Uk3ZgiZGAZXckpP2c+TYg= 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=DRkgHXMd; arc=none smtp.client-ip=209.85.217.53 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="DRkgHXMd" Received: by mail-vs1-f53.google.com with SMTP id ada2fe7eead31-765c077b5c1so197900137.3 for ; Thu, 27 Aug 2026 23:38:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787899137; x=1788503937; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=H45UkJcpynWSM6p3u8+zxGMMVZ+9d4Z2GwcIBMNn4Wk=; b=DRkgHXMdlS2xipubcTxUvCMYG2WVDUOfbvooNSqzHwav7G+oir9KVfZ06XpGaASLSg exSLe6CuXbrBe6ifX2Fwlgf1RzBTTJsjc3NWvJ9r2z0jDTN+TSI9wfleuSM20mDs8XRZ GkCBEsx1lS0IJb13WlZMnRH2py7z/UPn5c0eDpDZrBwmtgtPOWHbCk7WCb89s87YGWu9 iG8cdcHbxxOfYWv9YFOt3r7Y3dirxIyTNh7BgMj0vxElLGlN4RNAGAIT4C1xJirLsRuk 7kL/T70Zg27EfTYLRG9Wkh2BEYai72gyt/6M9Jrl3hqLaYcwvQA9xiCRWfdvafpUS9UG Y5MQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787899137; x=1788503937; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=H45UkJcpynWSM6p3u8+zxGMMVZ+9d4Z2GwcIBMNn4Wk=; b=Z0pIRyHHzM2Ef7xKGPDxeGiEW0/ZCGg/LWnNNbZGbGUpBO5BVEttxt0xSaI0RjniNU YclqCAcQcAspSiVz+cScR/T7DxxpPdLqb8Q3cnIj3iSkSWfC+cvWvgzLyauHmDisUEGo x+W0PAv96Qg5+keJmBezQwuSvIpk3DDIvCFpILaYiDhQnD5+yggbLdVSg4Chc0qr6mzY YPw8L3WWd+iDy/ligByffPby60+IuPJzIIsFIvv8AjEd8hyPvkeXbs2gvT78Iv+apHw3 xHQ0Xr95e8Bu7kKvMMoPPgTf6ccnnioOhyRunNE3ZWkd/LrGQvyb/AqxFZKsppS3qLMh n4wQ== X-Forwarded-Encrypted: i=1; AHgh+RpSZz2BNm/T5SLaA8h/xxPzMf/CltyfCWlJd8XYLlSwI68MdL0BLT9Q6ayFfnsdLbWtsM8Q3Gt8fT6S0oY=@vger.kernel.org X-Gm-Message-State: AFuF++lSuS3MOuD2kPHSnmjWAcm0EyCL1xXd3xANtDg3eh76eF/geVtD bAKZR90C1mn6UOHZsJDWF9rD71mibWd8NZlZ/g2FRY5nBAE8i/8yNn25 X-Gm-Gg: AR+sD13eSVHKgoxxCuEFe1R7EkRdqkTUukEV6W6NaLzjfNL3MIlduFeZkiTVobgwjpa C60kfRg6/Q0uUyYIay7qXcPOXYYPXtsqalgi+SOuYGRaDKDa8myGyejc0748CgXCffdyq5nnE2V R+UWs3Pya/sCELjTR40URJc4Pd0sbGX7oAJzMr2y8HsGWVGwj6tiXCBn1zidohKBtwlXZEkdh27 m7LSIPmqkimRZeSgJrtQDXRBrMZ1F2cSf2coRBSBrIxz7knXAMyJ1f63HvrQ45F7qiFLdSyEvXm Kf5KrpreHARyaiPw6jnUr3/G830KLEDzjr6YqnCEeyIx9bfqkX9eLdshTaqaxLLw8Qjl9dFVn0r gUfMVdigWbTzQS0G+NI9AsPAp5Y0/+6tQnwzEhWlWkKCVhJyp8Nj+xgx0htPbpCC5DaKqUB9LUd /oxrvceCFSZ64GIIoye87aGQsangdrDwC58/SDgpSqdsU7raPYXJryw+7IyzDR8AQQvnENETYSW M8= X-Received: by 2002:a05:6102:831c:b0:785:c39b:6a1 with SMTP id ada2fe7eead31-785c39b30f1mr567577137.6.1787899136690; Thu, 27 Aug 2026 23:38:56 -0700 (PDT) Received: from [192.168.100.153] ([2800:bf0:61:1127:ab87:5602:531c:8dfb]) by smtp.gmail.com with ESMTPSA id a1e0cc1a2514c-97e849d8494sm454195241.1.2026.08.27.23.38.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 23:38:56 -0700 (PDT) From: Kurt Borja Date: Fri, 28 Aug 2026 01:38:24 -0500 Subject: [PATCH v4 09/10] iio: adc: ti-ads1262: support REFOUT and VBIAS regulators Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260828-ads126x-v4-9-1dc27e9c0260@gmail.com> References: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> In-Reply-To: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , David Lechner Cc: =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=4665; i=kuurtb@gmail.com; h=from:subject:message-id; bh=awLx3251t6HAnsVHNTGEYJXrS1sww/D1jVL1AboaEro=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFkTdd4oLX6VJJ3+u922OXPW1B1B1xVX8jzfcEWz44lR2 HpO7Z7dHaUsDGJcDLJiiiztCYu+PYrKe+t3IPQ+zBxWJpAhDFycAjARv/+MDKsDureeneUeEPi/ Ym0hO+/tN8dEn3zhaub5X7vIcEXY54uMDBubVlxv8L2m5t4rWXW17+i+X9zy4oVc/HKRMp4e2nw HOAA= X-Developer-Key: i=kuurtb@gmail.com; a=openpgp; fpr=54D3BE170AEF777983C3C63B57E3B6585920A69A Register the "refout" and "vbias" regulators to be able to use them as common mode supplies. Signed-off-by: Kurt Borja --- drivers/iio/adc/Kconfig | 1 + drivers/iio/adc/ti-ads1262.c | 119 +++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 120 insertions(+) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 2b60ade01e90..4548fec1f86f 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1864,6 +1864,7 @@ config TI_ADS1262 tristate "Texas Instruments ADS1262" depends on SPI select REGMAP + select REGULATOR select IIO_BUFFER select IIO_TRIGGERED_BUFFER help diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c index 3f6d34a08b29..4784142f35c9 100644 --- a/drivers/iio/adc/ti-ads1262.c +++ b/drivers/iio/adc/ti-ads1262.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1132,6 +1133,120 @@ static irqreturn_t ads1262_irq_handler(int irq, voi= d *dev_id) return IRQ_HANDLED; } =20 +static int ads1262_vbias_enable(struct regulator_dev *rdev) +{ + struct ads1262 *st =3D rdev_get_drvdata(rdev); + + guard(mutex)(&st->xfer_lock); + + return regmap_set_bits(st->regmap, ADS1262_POWER_REG, + ADS1262_POWER_VBIAS_MASK); +} + +static int ads1262_vbias_disable(struct regulator_dev *rdev) +{ + struct ads1262 *st =3D rdev_get_drvdata(rdev); + + guard(mutex)(&st->xfer_lock); + + return regmap_clear_bits(st->regmap, ADS1262_POWER_REG, + ADS1262_POWER_VBIAS_MASK); +} + +static int ads1262_vbias_is_enabled(struct regulator_dev *rdev) +{ + struct ads1262 *st =3D rdev_get_drvdata(rdev); + + guard(mutex)(&st->xfer_lock); + + return regmap_test_bits(st->regmap, ADS1262_POWER_REG, + ADS1262_POWER_VBIAS_MASK); +} + +static int ads1262_vbias_get_voltage(struct regulator_dev *rdev) +{ + struct ads1262 *st =3D rdev_get_drvdata(rdev); + int avdd_uV, avss_uV; + + avdd_uV =3D regulator_get_voltage(st->avdd_supply); + if (avdd_uV < 0) + return avdd_uV; + + avss_uV =3D st->avss_supply ? regulator_get_voltage(st->avss_supply) : 0; + if (avss_uV < 0) + return avss_uV; + + return DIV_ROUND_CLOSEST(avdd_uV - avss_uV, 2); +} + +static const struct regulator_ops ads1262_vbias_regulator_ops =3D { + .enable =3D ads1262_vbias_enable, + .disable =3D ads1262_vbias_disable, + .is_enabled =3D ads1262_vbias_is_enabled, + .get_voltage =3D ads1262_vbias_get_voltage, +}; + +static int ads1262_refout_is_enabled(struct regulator_dev *rdev) +{ + struct ads1262 *st =3D rdev_get_drvdata(rdev); + + guard(mutex)(&st->xfer_lock); + + return regmap_test_bits(st->regmap, ADS1262_POWER_REG, + ADS1262_POWER_INTREF_MASK); +} + +static const struct regulator_ops ads1262_refout_regulator_ops =3D { + .is_enabled =3D ads1262_refout_is_enabled, +}; + +static const struct regulator_desc ads1262_vbias_regulator_desc =3D { + .name =3D "vbias", + .of_match =3D "vbias", + .regulators_node =3D "regulators", + .supply_name =3D "avdd", + .ops =3D &ads1262_vbias_regulator_ops, + .type =3D REGULATOR_VOLTAGE, + .owner =3D THIS_MODULE, +}; + +static const struct regulator_desc ads1262_refout_regulator_desc =3D { + .name =3D "refout", + .of_match =3D "refout", + .regulators_node =3D "regulators", + .supply_name =3D "avdd", + .n_voltages =3D 1, + .fixed_uV =3D 2500000, + .ops =3D &ads1262_refout_regulator_ops, + .type =3D REGULATOR_VOLTAGE, + .owner =3D THIS_MODULE, +}; + +static int ads1262_register_regulators(struct ads1262 *st) +{ + struct device *dev =3D &st->spi->dev; + struct regulator_config config =3D { + .dev =3D dev, + .driver_data =3D st, + }; + struct regulator_dev *rdev; + + struct fwnode_handle *reg_node __free(fwnode_handle) =3D + device_get_named_child_node(dev, "regulators"); + if (!reg_node) + return 0; + + rdev =3D devm_regulator_register(dev, &ads1262_refout_regulator_desc, + &config); + if (IS_ERR(rdev)) + return PTR_ERR(rdev); + + rdev =3D devm_regulator_register(dev, &ads1262_vbias_regulator_desc, + &config); + + return PTR_ERR_OR_ZERO(rdev); +} + static int ads1262_dev_configure(struct ads1262 *st) { struct device *dev =3D &st->spi->dev; @@ -1939,6 +2054,10 @@ static int ads1262_spi_probe(struct spi_device *spi) =20 indio_dev->name =3D ads1262_device_id_to_name[st->dev_id]; =20 + ret =3D ads1262_register_regulators(st); + if (ret) + return ret; + ret =3D ads1262_populate_tables(indio_dev); if (ret) return ret; --=20 2.55.0 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-vk1-f179.google.com (mail-vk1-f179.google.com [209.85.221.179]) (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 CD6D63CC7CD for ; Fri, 28 Aug 2026 06:38:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899141; cv=none; b=IuSFou5467Vu4ja16MB9fdzgI5bo5L5vRRxGG9m+AN4ZCe6ELCiMXgMjB6PLwOYujJ7uYNmGttKQ4eMaJeRP2UtOAZdo7MAzAAuXMQb/xCC1Jfx17RixeIjgfNw3qTuCRqCwJ3CJVk811sKX0HyqxaVtZJzwDiL21Q67qFEG+2c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899141; c=relaxed/simple; bh=kIuk2ofxCh+dUdzkbAX8VlLSbdR9YEZLCsPMWA1qZzM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=MlDDAujes70K7R8AyBc7S8d47mLvNpX17z0AAF6okwGroCVk353GWI1Rsk/BqjNOJSI10s2ILWi2i1iNwJE+9mcqvL/PHQAC2iN4b7n39swWRZz+E6Cn20/Paosrh5xQZmhUIDfEhpAKD+g2xJ54nHRTowFwRUOZFok9GJyePWA= 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=oU/PGske; arc=none smtp.client-ip=209.85.221.179 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="oU/PGske" Received: by mail-vk1-f179.google.com with SMTP id 71dfb90a1353d-5c66eefc868so522085e0c.3 for ; Thu, 27 Aug 2026 23:38:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787899138; x=1788503938; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=HWgdfydiuC7rf3YRqBTUUeAY2p6P2oJlqHhrcTc/eMA=; b=oU/PGskeFPP8KhKis06W3gbQ9JaAHNKkhB8bNSX7PBSswdxF4zSBye4/lZ5dIJBSIV vGuZ3OZBNi7jz+DNuu0YRwrLrCyFtVIJqD1nPEMGH5duK9eG1UupTHHTkLIB9pgCl6EI inHMlOw61bHLwA5o4BjwBf64XDuQ0dv9+Sg8vFoVzAoNTXhC3u3FQEn4BsBQXyrYH+Xn ZTQna+UPs2B1q0wEc9eFi7eZNuVZWQS1gzJ9eSXcpGIuPkHW+Xy7R2lg0PW/qOw8b/c9 XizFRTD2dbRA4MTHQxrqIiYB/6Sl0KEuVmEoROtusNX1nhKBgLneBw9JPUdpu8SbZj8m PCkQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787899138; x=1788503938; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=HWgdfydiuC7rf3YRqBTUUeAY2p6P2oJlqHhrcTc/eMA=; b=g/HUFqOv5chKYzCEd1gnThi4LOi2t9C6TyKOUqoEPbjs+4tpppRZvXzQf1n/4ZfEVI cXWU/P5mdVrsdwBeVi52uyq05f8zVL25NXyD/8CpvgNXvoOsd/6SbvvuojsHS9ICwTO8 C36nzOOGPntezsvdpfK34cqepVef3hQv/TpF1ubg3tyFw7MusZxDeSU/389jRRbfIJYc 0pkCFjW4qsXkxb9ILvtRO5W2GApdCTZPQfgAmSDp3i1tCWX0c5jmJHXq/6uPGWkRpxmD W1JlRiYup1aTzzHJuGmlz21h/uYXtpKTPgi74jp93rSmE8BX6zrmSqWOA0qF9+6aQkDA aarw== X-Forwarded-Encrypted: i=1; AHgh+RopT654/UEJbN4jlW1CiyHtktJw0fM7lFRvKE2vt8WM6UKQ0NxbvoEgfYTSD31b/ve5NQELI4XCt8lDUZM=@vger.kernel.org X-Gm-Message-State: AFuF++k/2ioKqiw15g8cg5xu2Slp5zk210gYG6j9ODWT946r1U9Hjtlk qNWze/QUOcAA/Vf9pBtKTTIj54WUiN0EywxIez0h63p2Lh2/sCIcMHyV X-Gm-Gg: AR+sD13uD3v7UzPE9umrRr1CsPsNNT3cs0joCv7hmAAPDvvVAx4rlMBeEZEvL2HJdZP 1neE4tbbJfOWJukVJjWQxHFFFG5MxtFBSfAZlctQTqrK3J7XdSQRn94NMIzXei7dfms4613w6w8 t83bFA9X5ngZUw8XGzA6i0V22kNr9aZDNHQGMAtWBm9EjME0td+bXYkXDBc1WcvluhyiNj4pdZV nKyRcBUYdvlxFpBVMbgC7cqc6WluSe2ptYnbsq9Gd0meZpQtu01+CyPKVtshUw9oOi0zZcx/nht tbp14qOlPmuPB5Aq66+81YOSkfT2WN+eCA2VwTIOhyib8UEmLHw2K6NyKZljwbQr6kZ+0jDdpgX Z+QKaLE7aDwDiwYGpRuS+qQ3nUrZlsgST8FYMaS3giGfbtDdCkRRArbOp8u96ailwjGDTxHWNTL XCiKF2rAb6jMVWMCgNpjhqdVl1e/PPV5YEa7Mp5k4gP5xEPkRgHNmXRhBMkVYToof4 X-Received: by 2002:a05:6102:149e:b0:785:5a17:739b with SMTP id ada2fe7eead31-785939481a8mr1780174137.0.1787899138581; Thu, 27 Aug 2026 23:38:58 -0700 (PDT) Received: from [192.168.100.153] ([2800:bf0:61:1127:ab87:5602:531c:8dfb]) by smtp.gmail.com with ESMTPSA id a1e0cc1a2514c-97e849d8494sm454195241.1.2026.08.27.23.38.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Aug 2026 23:38:58 -0700 (PDT) From: Kurt Borja Date: Fri, 28 Aug 2026 01:38:25 -0500 Subject: [PATCH v4 10/10] iio: adc: ti-ads1262: support common mode supplies Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260828-ads126x-v4-10-1dc27e9c0260@gmail.com> References: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> In-Reply-To: <20260828-ads126x-v4-0-1dc27e9c0260@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , David Lechner Cc: =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=2778; i=kuurtb@gmail.com; h=from:subject:message-id; bh=kIuk2ofxCh+dUdzkbAX8VlLSbdR9YEZLCsPMWA1qZzM=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFkTdd5oJopumcNwqnO9zPc702t2xVY/XeTq51qZURJzv P3+qzMvOkpZGMS4GGTFFFnaExZ9exSV99bvQOh9mDmsTCBDGLg4BWAiadMYGT7bqqrs3aJ1aH6u r9u30iXndi5qMWG7xW12/NSHZxlVp+wYGY5yzMxfUbYnZOGh+VtvHMrtkT+x2PrumcJwheX36/f diuADAA== X-Developer-Key: i=kuurtb@gmail.com; a=openpgp; fpr=54D3BE170AEF777983C3C63B57E3B6585920A69A Enable common mode regulators. The usual configuration is to have our own 'vbias' regulator connected internally as common mode voltage on the AINCOM pin. Signed-off-by: Kurt Borja --- drivers/iio/adc/ti-ads1262.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c index 4784142f35c9..c7ad1cf1a15d 100644 --- a/drivers/iio/adc/ti-ads1262.c +++ b/drivers/iio/adc/ti-ads1262.c @@ -240,6 +240,7 @@ struct ads1262 { u32 rref_ohms[ADS1262_EXT_REF_COUNT][ADS1262_EXT_REF_COUNT]; int refp_uV[ADS1262_EXT_REF_COUNT]; int refn_uV[ADS1262_EXT_REF_COUNT]; + int common_mode_uV[ADS1262_INPMUX_AINCOM + 1]; IIO_DECLARE_BUFFER_WITH_TS(__be32, scan_buffer, ADS1262_FW_CHANNEL_COUNT + ADS1262_MON_CHANNEL_COUNT); @@ -695,6 +696,13 @@ static int ads1262_read_raw(struct iio_dev *indio_dev, scale * ADS1262_TEMP_SLOPE_uV_C); iio_val_s64_decompose(offset, val, val2); =20 + return IIO_VAL_INT_64; + + case IIO_VOLTAGE: + offset =3D mul_u64_u64_div_u64(st->common_mode_uV[chan->channel2], + NANO, scale); + iio_val_s64_decompose(offset, val, val2); + return IIO_VAL_INT_64; default: return -EOPNOTSUPP; @@ -1133,6 +1141,28 @@ static irqreturn_t ads1262_irq_handler(int irq, void= *dev_id) return IRQ_HANDLED; } =20 +static int ads1262_parse_common_mode_supplies(struct ads1262 *st) +{ + struct device *dev =3D &st->spi->dev; + char name[sizeof("aincom")]; + int ret; + + for (unsigned int i =3D 0; i <=3D ADS1262_INPMUX_AINCOM; i++) { + if (i < ADS1262_INPMUX_AINCOM) + scnprintf(name, sizeof(name), "ain%u", i); + else + scnprintf(name, sizeof(name), "aincom"); + + ret =3D devm_regulator_get_enable_read_voltage(dev, name); + if (ret < 0 && ret !=3D -ENODEV) + return dev_err_probe(dev, ret, + "failed to get common mode supply: %s\n", name); + st->common_mode_uV[i] =3D ret !=3D -ENODEV ? ret : 0; + } + + return 0; +} + static int ads1262_vbias_enable(struct regulator_dev *rdev) { struct ads1262 *st =3D rdev_get_drvdata(rdev); @@ -1902,6 +1932,9 @@ static int ads1262_parse_channels(struct iio_dev *ind= io_dev) spec->info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_SCALE); =20 + if (!chan->is_resistance && !spec->differential) + spec->info_mask_separate |=3D BIT(IIO_CHAN_INFO_OFFSET); + i++; } =20 @@ -2058,6 +2091,10 @@ static int ads1262_spi_probe(struct spi_device *spi) if (ret) return ret; =20 + ret =3D ads1262_parse_common_mode_supplies(st); + if (ret) + return ret; + ret =3D ads1262_populate_tables(indio_dev); if (ret) return ret; --=20 2.55.0