From nobody Tue Sep 29 11:48:55 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 B82653AA1B0 for ; Sat, 8 Aug 2026 03:58:53 +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=1786161535; cv=none; b=q//decPHL6qz0DODayuh73n0Zogq4LyT2d8vq0+yUUv3xg+r37LyS3tC24XSePo5pcMBC+m1XulbIzhuM2bxZdjQtxkjRArvkInYMfSKssliEuLm23a+h+86dHa1RuxXhnvwztYbizWTa6gtIQSc43+6rwZBEH7kQ5PD2x4WaeM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786161535; c=relaxed/simple; bh=xOuI2uvaogVpXoU3ek4Ue/485BwfxthxD11w9S8ZIsw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=AQ84Rgpfj0WWaH7mEV5dyKsbMZn0ZufWa830xuXWQUidNqwzdDwGGrqs6sqTUatt7KCciRxkU+nAU6hJi5ajTypO1+/ZZkdMSZY6HAYIdhgD++LpHMtowuJeFBnJwRkjqw/Rh1gxF0uGqBSSYsn+DX11HHdxEELPjCffatxO92Y= 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=SgRhVm6j; 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="SgRhVm6j" Received: by mail-vk1-f179.google.com with SMTP id 71dfb90a1353d-5c4105393feso167695e0c.1 for ; Fri, 07 Aug 2026 20:58:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786161532; x=1786766332; 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=lbxFbepJjdL7JygBXwv8r/FSSSnS2NcO8+/iu/4Xj90=; b=SgRhVm6jb8ScDakuSv+Aa68F8lSiNdAOi3BBAN9pVm+kz+WPT/5A+wyah8HinoPsHo /aYT7094Be84BgkUQ1H/sdi44ZRaEmt3ZtCpOQ0HE2P67Z/QQTpCbasbGe7QJwZJMbtY eyZlA9Q1VkO9QU7Ha+0oXrLbDTsQ/ubAYno39z+bCokptIilqJ2A9TxXU9YSXEMnGHDJ OLGyMaXMpybt81CEqJl/NSy/FWI9vYXQQUIHqVSrLbsx14YPNK7Obublic2L60GPC8e1 UiiYDf0djZ08kilOxWfiz0MipI1mI5wklZ5wzklkXac2lBKPI9XMLdjRc6h1Q/VRGL9J JERw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786161532; x=1786766332; 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=lbxFbepJjdL7JygBXwv8r/FSSSnS2NcO8+/iu/4Xj90=; b=Js9WRjoG4P90hAtG8ZjopTWzlLXJp8kSuhb9dEOIBq0ja3977hIUZKJQ5TtfsIXll2 mIadyhg6sMKsdD9SF3rvkpFZikgVRvU0iqC9WsnjWTgKIGz4J0X8LkgmVu4R6EASEo3d y33hVv1OwWjpuU8wck4M2aaBFNeJmiekZ6/hlg2NUwlLqT8aIy7eQR3ATM73AiBFSQlh 6CUlf8v6e93Mm7IT2v/KBeGvM79RtHlQavUgEvACrneRUUPP3/WKuq+ZEgpUuA4n7Jjy 4caQNhZkyxSyeWL+T8eeEAPBCA9p0jpE8VsTXDsgksg9I4C6UHElvEvDraTBCjXY8pmy /ilw== X-Forwarded-Encrypted: i=1; AHgh+RqxRQu++fNXjoXx7uC7sntGU97acqbV1uTp7qexA/uOuS4lX/biqYkezo6PXI+8pTTy5Id2BrmlwGHlnWM=@vger.kernel.org X-Gm-Message-State: AOJu0YwD58v/0zawRt9W90+R3ppBCHg0DG/SoMj26Ns93zXLCz3zveqR O1W5Tutz6g7QzzuGxk4hcoCN7dGj+DGQYgUnklIYjj4E6cv7sNyPf4rk X-Gm-Gg: AR+sD13vlS0oa497+YsZCxRdaXLPpTOb75hlx4GAFGWEJjIxbNjOtWr3g0701alU4N7 +R88DLXxc01DBuKKjS4QhBD3xBZjiH65XHZmIEHbdSdBlXHnxXWudlzt2r+okofha03e53huCHb 5vKseuuO6XrOWy5Ba9UWHrAjTSamke5oVzYyu6vAPQde2Myj4FihnLuNt9fN9H4R4fLyvnA5zGy 77XDVM1GxnB1Dw0tnUzJpFT8n9Ho6RSiEbYy3GkTYlWck2CDV0tL9s++lw6pqzY2miH7dvEGIiC 6VnMNRohv9b4tRgbVkr8dOMBJQd3578WPbrNtDkk5ipIXMuTFi9/dIvZTzNP/C82bVy0qiuNR7Q gB3LrOVFUeH8rVe1zqb2JRGMz2t0pkbhS3Tpy4TBRS2f61iV96dK4lp858p6pWOYDIlZOqfr8WN YrTHAQ5lYUnI5QcnQcjMPM/bKDnZRXLztuWXNR9/KN9YCga5bSB2iVsysVbl0= X-Received: by 2002:a05:6122:d0b:b0:5bf:bc5e:e24 with SMTP id 71dfb90a1353d-5c3fa02925amr2239835e0c.12.1786161532522; Fri, 07 Aug 2026 20:58:52 -0700 (PDT) Received: from [192.168.100.6] ([2800:bf0:82:11a2:7ac4:1f2:947b:2b6]) by smtp.gmail.com with ESMTPSA id 71dfb90a1353d-5c40b212fa6sm1432936e0c.16.2026.08.07.20.58.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Aug 2026 20:58:52 -0700 (PDT) From: Kurt Borja Date: Fri, 07 Aug 2026 22:58:23 -0500 Subject: [PATCH v3 1/9] 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: <20260807-ads126x-v3-1-f89925d72792@gmail.com> References: <20260807-ads126x-v3-0-f89925d72792@gmail.com> In-Reply-To: <20260807-ads126x-v3-0-f89925d72792@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Linus Walleij , Bartosz Golaszewski , 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, linux-gpio@vger.kernel.org, Jonathan Cameron X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=12839; i=kuurtb@gmail.com; h=from:subject:message-id; bh=xOuI2uvaogVpXoU3ek4Ue/485BwfxthxD11w9S8ZIsw=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFllK8tLFmz/F7nor96HitZfJzldXhc+VX0tKlr7J+KJr ooxD+uxjlIWBjEuBlkxRZb2hEXfHkXlvfU7EHofZg4rE8gQBi5OAZjIgjCG/+4Sj7WLt/UUBb4K F0xZHyJvvVzvfte91b9W3DzBcUU0poXhD9/uExuFjn9mCpt74Iv0qy69xqevba2DDsx5FOiS1KC dyw0A 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 adds a second, 24-bit delta-sigma ADC (ADC2) for background measurements. Each can configure its own voltage reference source, the two excitation current sources (IDAC), plus input and excitation channels rotation for offset and IDAC mismatch cancellation. This lets the device drive and ratiometrically measure RTDs and other resistive sensors. Signed-off-by: Kurt Borja --- .../devicetree/bindings/iio/adc/ti,ads1262.yaml | 379 +++++++++++++++++= ++++ MAINTAINERS | 6 + 2 files changed, 385 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..c43ba7abb391 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1262.yaml @@ -0,0 +1,379 @@ +# 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: + description: Data Ready (DRDY) interrupt line. + maxItems: 1 + + interrupt-names: + description: + Specify which pin should be configured as Data Ready interrupt. + enum: [drdy, dout-drdy] + + 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 it's reg. The second cell sele= cts + between ADC1 (0) and ADC2 (1). + + '#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 not described, its 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 not described, its 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-9]+$": + $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: + description: | + In addition to the analog input pins 0 (AIN0) - 10 (AINCOM), the= re are + special inputs that can be selected from the following values: + 11: Temperature sensor monitor + 12: Analog power supply monitor + 13: Digital power supply monitor + 14: TDAC test signal + items: + minimum: 0 + maximum: 14 + + 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, refp1, refp2, refp3, avdd] + - enum: [internal, 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] + + 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 + + input-chopping: true + + ti,idac-rotation: + $ref: /schemas/types.yaml#/definitions/flag + description: + Automatically swap the IDAC1 and IDAC2 connections of alternate + conversions. The ADC averages the alternate conversions to elimi= nate + IDAC mismatch. + + 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': + const: 2 + patternProperties: + "^channel@[0-9]+$": + properties: + reference-sources: + minItems: 3 + maxItems: 3 + default: [internal, internal, internal] + else: + properties: + '#io-channel-cells': + const: 1 + patternProperties: + "^channel@[0-9]+$": + properties: + reference-sources: + minItems: 2 + maxItems: 2 + default: [internal, internal] + +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 { + regulator-name =3D "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 04fa5322d9f7..e9248979b801 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27001,6 +27001,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 Tue Sep 29 11:48:55 2026 Received: from mail-vk1-f178.google.com (mail-vk1-f178.google.com [209.85.221.178]) (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 96E403B71A6 for ; Sat, 8 Aug 2026 03:58:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786161538; cv=none; b=lgjiologgrtPy3xV3pNaFeUAj8WBwswgSf8O3whtnjlpGEk9B/La+o3bGXKvC/zoSLoQqa3Bd4TR5ZY0Cv5TSYhiO3m6NjHCMuFv/mKW9zR9WhQlwZXDcAxSqxnK/NmnGtb6pxZd1vrMMLfxjfnWczDXMFI/XYO37MKmJ1pkAR4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786161538; c=relaxed/simple; bh=CvrGOCn7U7uZ0sRlrVy9tzLAGI+QOjo835DiJl1KiWQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=lF83aZV9iCz61z+iYViAsIewRUv654Yacqcf3ULN8QehWREhlkfDORL+GG+Psvycvi5W5Y4ggf0VB2noBzKsFo4axXhXHvpg5jjTpa6njgLKBEmRkF6pLR7hUy5VkHUcL+3wHDPxugFv2lBkoM7Zg+L3oSz5neJGfm1NRpBQSvA= 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=EAHa85k+; arc=none smtp.client-ip=209.85.221.178 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="EAHa85k+" Received: by mail-vk1-f178.google.com with SMTP id 71dfb90a1353d-5c2c0df0b45so69846e0c.1 for ; Fri, 07 Aug 2026 20:58:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786161534; x=1786766334; 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=dAlBmg+SAGiE1EmSqmWetavoPb4EdPoSaiq6YE9hmhM=; b=EAHa85k+9+cVf8rQPJZQ8AHNHd6dF8AFbVhYvk/oAJ8F8UijhvaOHBifIcE3Jddt9p nd7s4ZraQLfdZae/xSJkU7/Pj/NjWoTbEPN6W/YhFCaP3hjR9TvU5i3aXU4TmyMkCv3f QbAduev6VgN8vtehGzv7YZI526K32CYBXaRv/Rr6WHIRFaPblJu2u5gQCnvXrfCF44fn swy6l9vSvkEIvGKBeK9QIlkn+Xx8GftOi80krUUJJsRWh2RcznUIis4slyz5r2E7BDdj 4cBWXIqrbtnrdfDdzhhdNCxbZIOyyik0llV1mtsO5qZOxnSdNnZdCCCT7MiyVEGUhXmD XGzw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786161534; x=1786766334; 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=dAlBmg+SAGiE1EmSqmWetavoPb4EdPoSaiq6YE9hmhM=; b=fBTrMo6ZDqIdveJZPNfaydx1IxTXYSFQP2Dwlw2V4aALQM8Tcw5M8c4B7yFNpa+iEO iy0tWVOal9HlVUBk/cBYY5bDMGDYZh0OjOqOB5XAoZhbarfCz9LTPGgs/VVI2BZbPH34 diVo7fszqs0RxyRLxhMCadpQtMp4+PWAkTjB/0wIojhzNMjqZhKhMtj6V8peUoOEqZA5 nuW/cQUXqglxnR9yk1vBQv8HDeg/OboK6xmEsdsVp4PNprEGWprQziVv75F2WUJOJ/M3 tMq1SzowEZnO8PjdxUAgv0S36jvElrKMNWEBzl9rGsVX1x2kRz4vpSAqh+2jaG+OCztX +e2A== X-Forwarded-Encrypted: i=1; AHgh+RrlN1w9Qr7xkb5bT9ifKYoIvp1JqEhWs0WMazn5Zxl4Koo97LR+3uEaNhM1dSwvxcdc30tJtOLjJ7It/V0=@vger.kernel.org X-Gm-Message-State: AOJu0Yy4kuZeeX+234LI7srP6JjsaA0/WpD6YfOuWDm1N37koT/5Jjvl ZuxM4nthbF1DS5Eo3KJxR5C6sBelLSo8E83MdEd1LbbHERgEKrcL6jWi X-Gm-Gg: AR+sD13aiRB9aF5ORVwMLDvXR2GEGD3oimEBdcydBgNCOIBYF+HiCnUbPgsp8W4ziVJ fsADgQ/kMy8cNdVl2fevRCJ6kfx7PPvm/3QJuVxFdYRbGDGJ8E4Qo9BSHRWJlv4RNwLkYk+7T4H u6LjKJLD/MbyjJ3jQ+2C5Yog4nuSrOu9MPuG+41AJzJnFGSeZOKlpXbnPUgoqa/eHTwa3ArAfec iOGtcrcV9qyz18Y0UBletkAXSMGPY3D1gSwomkSzUFZuOBsyIHtD3vMHfkpTcQBBsnHtXFlgmWU S4VzfduPiR1A6gvGgEZ0C2I8q3zAm7anj9HotkL5WgoLLnI/TA1vlmpRSse48eD5LTpZZ88o/V7 CrhLI6cVxopi5/GUStxCwLWCD3BgO9ucZTj1ULDz5OQYzPl/gRA5CaKRtGeSXk3TtJOgJr1FuBN WOgvb5rIrthLT0/WPc+oxoMP66uoJUT46oyjyu1Nbf6OkLwD7EUaRGRCSV4gmkVirhzvrpcg== X-Received: by 2002:a05:6122:2492:b0:5c1:781:7122 with SMTP id 71dfb90a1353d-5c3d907e08amr3054689e0c.3.1786161534377; Fri, 07 Aug 2026 20:58:54 -0700 (PDT) Received: from [192.168.100.6] ([2800:bf0:82:11a2:7ac4:1f2:947b:2b6]) by smtp.gmail.com with ESMTPSA id 71dfb90a1353d-5c40b212fa6sm1432936e0c.16.2026.08.07.20.58.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Aug 2026 20:58:54 -0700 (PDT) From: Kurt Borja Date: Fri, 07 Aug 2026 22:58:24 -0500 Subject: [PATCH v3 2/9] 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: <20260807-ads126x-v3-2-f89925d72792@gmail.com> References: <20260807-ads126x-v3-0-f89925d72792@gmail.com> In-Reply-To: <20260807-ads126x-v3-0-f89925d72792@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Linus Walleij , Bartosz Golaszewski , 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, linux-gpio@vger.kernel.org, Jonathan Cameron X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=26029; i=kuurtb@gmail.com; h=from:subject:message-id; bh=CvrGOCn7U7uZ0sRlrVy9tzLAGI+QOjo835DiJl1KiWQ=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFllK8vjbotJ1wqcvGzxZ6GtT8ixytx4wX4n75LwA63S8 /awntPoKGVhEONikBVTZGlPWPTtUVTeW78Dofdh5rAygQxh4OIUgIlE9zL8U3rsIL6d9Y7OCV62 NiWOw2Uds+I7iyL0M84tY6z43P3jFyPDdJeMeLsDSdqFH84pCXbUa3S0tupahXD2PYkvL752N5M NAA== 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. Signed-off-by: Kurt Borja --- MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 11 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ti-ads1262.c | 847 +++++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 860 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index e9248979b801..3ee4a2f80733 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27006,6 +27006,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 990e7b3e7212..dbf76427912b 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1841,6 +1841,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 dcec0abb03b7..f85b89859fe9 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -157,6 +157,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..d78e5e3ae13e --- /dev/null +++ b/drivers/iio/adc/ti-ads1262.c @@ -0,0 +1,847 @@ +// 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 + +#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_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_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_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_INPMUX_REG 0x06 +#define ADS1262_INPMUX_MUXP_MASK GENMASK(7, 4) +#define ADS1262_INPMUX_MUXN_MASK GENMASK(3, 0) + +#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 0xB + +#define ADS1262_IDACMAG_REG 0x0E + +#define ADS1262_REFMUX_REG 0x0F +#define ADS1262_TDACP_REG 0x10 +#define ADS1262_TDACN_REG 0x11 +#define ADS1262_GPIOCON_REG 0x12 +#define ADS1262_GPIODIR_REG 0x13 +#define ADS1262_GPIODAT_REG 0x14 +#define ADS1262_ADC2CFG_REG 0x15 + +#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 0x1B + +#define ADS1262_MAX_CHANNEL_COUNT 16 +#define ADS1262_MAX_REGMAP_WRITE 8 +#define ADS1262_ADC1_RESOLUTION 32 + +enum { + ADS1262_RUNMODE_CONTINUOUS, + ADS1262_RUNMODE_PULSE, +}; + +enum { + ADS1262_FILTER_SINC1, + ADS1262_FILTER_SINC2, + ADS1262_FILTER_SINC3, + ADS1262_FILTER_SINC4, + ADS1262_FILTER_FIR, +}; + +enum { + ADS1262_DR_2_5_SPS, + ADS1262_DR_5_SPS, + ADS1262_DR_10_SPS, + ADS1262_DR_16_6_SPS, + ADS1262_DR_20_SPS, + ADS1262_DR_50_SPS, + ADS1262_DR_60_SPS, + ADS1262_DR_100_SPS, + ADS1262_DR_400_SPS, + ADS1262_DR_1200_SPS, + ADS1262_DR_2400_SPS, + ADS1262_DR_4800_SPS, + ADS1262_DR_7200_SPS, + ADS1262_DR_14400_SPS, + ADS1262_DR_19200_SPS, + ADS1262_DR_38400_SPS, +}; + +enum { + ADS1262_INPMUX_AIN0, + ADS1262_INPMUX_AIN1, + ADS1262_INPMUX_AIN2, + ADS1262_INPMUX_AIN3, + ADS1262_INPMUX_AIN4, + ADS1262_INPMUX_AIN5, + ADS1262_INPMUX_AIN6, + ADS1262_INPMUX_AIN7, + ADS1262_INPMUX_AIN8, + ADS1262_INPMUX_AIN9, + ADS1262_INPMUX_AINCOM, + ADS1262_INPMUX_TEMP, + ADS1262_INPMUX_AVDD, + ADS1262_INPMUX_DVDD, + ADS1262_INPMUX_TDAC, + ADS1262_INPMUX_FLOAT, +}; + +struct ads1262_chip_info { + const char *name; +}; + +struct ads1262 { + struct spi_device *spi; + struct regmap *regmap; + struct gpio_desc *reset_gpiod; + struct gpio_desc *start_gpiod; + unsigned long clk_rate; + + /* Protects channel state */ + struct mutex chan_lock; + unsigned int num_channels; + struct completion drdy; + + /* Protects transfer buffers and concurrent SPI transfers */ + struct mutex xfer_lock; +}; + +static int ads1262_dev_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) +{ + int ret; + + if (st->reset_gpiod) { + ret =3D gpiod_set_value_cansleep(st->reset_gpiod, 1); + if (ret) + return ret; + + /* + * The RESET pulse timing requirement is 4 clock cycles, at the + * minimum clock rate this is 4 microseconds. + */ + fsleep(4); + + ret =3D gpiod_set_value_cansleep(st->reset_gpiod, 0); + if (ret) + return ret; + + /* + * The RESET timing requirement is 8 clock cycles, at the + * minimum clock rate this is 8 microseconds + */ + fsleep(8); + } else { + ret =3D ads1262_dev_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_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_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(mul_u32_u32(1600, 7372800), st->clk_rate); + + 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) +{ + u8 val; + + guard(mutex)(&st->xfer_lock); + guard(mutex)(&st->chan_lock); + + val =3D FIELD_PREP(ADS1262_INPMUX_MUXN_MASK, spec->channel2) | + FIELD_PREP(ADS1262_INPMUX_MUXP_MASK, spec->channel); + return regmap_update_bits(st->regmap, ADS1262_INPMUX_REG, + ADS1262_INPMUX_MUXN_MASK | + ADS1262_INPMUX_MUXP_MASK, val); +} + +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 sign_extend32(be32_to_cpu(raw), ADS1262_ADC1_RESOLUTION - 1); + + 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_bypassed(st->regmap, reg, readval); + + return regmap_write(st->regmap, reg, writeval); +} + +static const struct iio_info ads1262_iio_info =3D { + .read_raw =3D ads1262_read_raw, + .debugfs_reg_access =3D ads1262_debugfs_reg_access, +}; + +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 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_clear_bits(st->regmap, ADS1262_POWER_REG, + ADS1262_POWER_RESET_MASK); + if (ret) + return ret; + + ret =3D regmap_clear_bits(st->regmap, ADS1262_INTERFACE_REG, + ADS1262_INTERFACE_STATUS_MASK | + ADS1262_INTERFACE_CRC_MASK); + if (ret) + return ret; + + return 0; +} + +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 { + { ADS1262_INTERFACE_REG, + FIELD_PREP_CONST(ADS1262_INTERFACE_STATUS_MASK, true) | + FIELD_PREP_CONST(ADS1262_INTERFACE_CRC_MASK, true) }, + { ADS1262_MODE0_REG, 0x00 }, + { ADS1262_MODE1_REG, + FIELD_PREP_CONST(ADS1262_MODE1_FILTER_MASK, ADS1262_FILTER_FIR) }, + { ADS1262_MODE2_REG, + FIELD_PREP_CONST(ADS1262_MODE2_DR_MASK, ADS1262_DR_20_SPS) }, + { ADS1262_INPMUX_REG, + FIELD_PREP_CONST(ADS1262_INPMUX_MUXN_MASK, ADS1262_INPMUX_AIN1) }, + { ADS1262_IDACMUX_REG, + FIELD_PREP_CONST(ADS1262_IDACMUX_MUX2_MASK, ADS1262_IDACMUX_NO_CONN) | + FIELD_PREP_CONST(ADS1262_IDACMUX_MUX1_MASK, ADS1262_IDACMUX_NO_CONN) }, + { ADS1262_IDACMAG_REG, 0x00 }, + { ADS1262_REFMUX_REG, 0x00 }, + { ADS1262_TDACP_REG, 0x00 }, + { ADS1262_TDACN_REG, 0x00 }, + { ADS1262_GPIOCON_REG, 0x00 }, + { ADS1262_GPIODIR_REG, 0x00 }, + { ADS1262_ADC2CFG_REG, 0x00 }, + { ADS1262_ADC2MUX_REG, + FIELD_PREP_CONST(ADS1262_ADC2MUX_MUXN2_MASK, ADS1262_INPMUX_AIN1) }, +}; + +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 + */ + memcpy(tx, reg_buf, 1); + tx[0] |=3D 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_MAX_REGMAP_WRITE + 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 + */ + memcpy(tx, reg_buf, 1); + tx[0] |=3D 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_MAX_REGMAP_WRITE, +}; + +static int ads1262_gpio_setup(struct ads1262 *st) +{ + struct device *dev =3D &st->spi->dev; + + 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->reset_gpiod =3D devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(st->reset_gpiod)) + return dev_err_probe(dev, PTR_ERR(st->reset_gpiod), + "failed to get reset GPIO\n"); + + /* + * The power transition timing requirement is 65536 clock cycles, at the + * minimum clock frequency this is 65536 microseconds. + */ + fsleep(65536); + + return 0; +} + +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, "%s: failed to read single-channel\n", + fwnode_get_name(node)); + + pins[1] =3D ADS1262_INPMUX_AINCOM; + fwnode_property_read_u32(node, "common-mode-channel", &pins[1]); + } 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, "%s: failed to read diff-channels\n", + fwnode_get_name(node)); + + if (pins[0] <=3D ADS1262_INPMUX_AINCOM || pins[1] <=3D ADS1262_INPMUX_AI= NCOM) + spec->differential =3D true; + } else { + return dev_err_probe(dev, -ENXIO, + "%s: one of single-channel or diff-channels is required\n", + fwnode_get_name(node)); + } + + if (pins[0] >=3D ADS1262_INPMUX_FLOAT || pins[1] >=3D ADS1262_INPMUX_FLOA= T) + return dev_err_probe(dev, -EINVAL, "%s: input channels not in range\n", + fwnode_get_name(node)); + + if ((pins[0] >=3D ADS1262_INPMUX_TEMP || + pins[1] >=3D ADS1262_INPMUX_TEMP) && pins[0] !=3D pins[1]) + return dev_err_probe(dev, -EINVAL, + "%s: monitor channels must be selected symmetrically\n", + fwnode_get_name(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 *specs; + unsigned long used_regs =3D 0; + int num_specs; + u32 reg; + int ret; + + st->num_channels =3D device_get_named_child_node_count(dev, "channel"); + if (!st->num_channels) + return dev_err_probe(dev, -ENXIO, "no 'channel' nodes configured\n"); + if (st->num_channels > ADS1262_MAX_CHANNEL_COUNT) + return dev_err_probe(dev, -EINVAL, "too many channels\n"); + + /* Account for the timestamp channel */ + num_specs =3D st->num_channels + 1; + specs =3D devm_kcalloc(dev, num_specs, sizeof(*specs), GFP_KERNEL); + if (!specs) + return -ENOMEM; + + device_for_each_named_child_node_scoped(dev, node, "channel") { + ret =3D fwnode_property_read_u32(node, "reg", ®); + if (ret) + return dev_err_probe(dev, ret, "%s: failed to read channel reg\n", + fwnode_get_name(node)); + if (reg >=3D st->num_channels) + return dev_err_probe(dev, -EINVAL, "%s: reg out of range\n", + fwnode_get_name(node)); + + static_assert(ADS1262_MAX_CHANNEL_COUNT < BITS_PER_LONG); + if (__test_and_set_bit(reg, &used_regs)) + return dev_err_probe(dev, -EINVAL, "%s: duplicated channel reg\n", + fwnode_get_name(node)); + + specs[reg].scan_index =3D reg; + specs[reg].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, + }; + + ret =3D ads1262_parse_channel_node(st, &specs[reg], node); + if (ret) + return ret; + + if (specs[reg].channel =3D=3D ADS1262_INPMUX_TEMP) + specs[reg].type =3D IIO_TEMP; + else + specs[reg].type =3D IIO_VOLTAGE; + + if (specs[reg].channel !=3D ADS1262_INPMUX_TEMP) + specs[reg].indexed =3D true; + + specs[reg].info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW); + } + + specs[num_specs - 1] =3D IIO_CHAN_SOFT_TIMESTAMP(num_specs - 1); + + indio_dev->channels =3D specs; + indio_dev->num_channels =3D num_specs; + + 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"); + + return 0; +} + +static int ads1262_spi_probe(struct spi_device *spi) +{ + const struct ads1262_chip_info *info; + struct device *dev =3D &spi->dev; + struct iio_dev *indio_dev; + struct ads1262 *st; + unsigned long rate; + struct clk *clk; + int irq; + int ret; + + info =3D spi_get_device_match_data(spi); + if (!info) + return -EINVAL; + + indio_dev =3D devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + indio_dev->name =3D info->name; + 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; + + 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, -ENXIO, "failed to get clock rate\n"); + st->clk_rate =3D rate ? rate : 7372800; + + ret =3D ads1262_supply_setup(st); + if (ret) + return ret; + + ret =3D ads1262_gpio_setup(st); + if (ret) + return ret; + + 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"); + + /* + * REVISIT: This chip has software polling capabilities, which could be + * used to stop depending on the 'drdy' IRQ. + * + * Additionally, the MISO pin also can be used as a DRDY IRQ, in which + * case the interrupt would be named 'dout-drdy', but requires a lot of + * 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, + info->name, st); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct ads1262_chip_info ads1262_chip_info =3D { + .name =3D "ads1262", +}; + +static const struct of_device_id ads1262_of_match[] =3D { + { .compatible =3D "ti,ads1262", .data =3D &ads1262_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ads1262_of_match); + +static const struct spi_device_id ads1262_spi_match[] =3D { + { .name =3D "ads1262", .driver_data =3D (kernel_ulong_t)&ads1262_chip_inf= o }, + { } +}; +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 Tue Sep 29 11:48:55 2026 Received: from mail-vk1-f172.google.com (mail-vk1-f172.google.com [209.85.221.172]) (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 420DB3B7B98 for ; Sat, 8 Aug 2026 03:58:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786161539; cv=none; b=sN5hKQqaJTqycYJ0NqZapKTFJJnVLyTJGgiHPliTJoG0CLXs41hhBSZ7VT2M/JbvoTu+TNE0WrPQRb26FHbJ9ZkwHvgtHaU7FVsHKzNdHktcSQII6chHpQvTfOqE1yLwMtZEJXN2XN6PEil1AiLSKYCG12dLWoK2VpWpID0ENaE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786161539; c=relaxed/simple; bh=G+m4JpteOwH1Zo2tIqYoGuuzgz1W67Q67Aw+8oU4NjM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=d0B6q6/puA171fToybGfofySUl/LC5JgrKcv81o/b444FwIDbBFb8/Diyv8eiYWSK2AgzAe+IhLKc2W0NqVOKObvcsc0Hwy57ZZaEK1QNMZaAoGBrSObBkSJTMKPZz+6WA8rEX6PVvR8ugBoaPK9hhrTtDOsA/TaWXpluyvPBtg= 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=otcdFQnm; arc=none smtp.client-ip=209.85.221.172 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="otcdFQnm" Received: by mail-vk1-f172.google.com with SMTP id 71dfb90a1353d-5c2c46a428eso157943e0c.2 for ; Fri, 07 Aug 2026 20:58:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786161536; x=1786766336; 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=lrTqoTQOzou37Z6mnJvLS7m03O+NZx1RHl2W3+gwCEY=; b=otcdFQnmlStaWfXUZZfsMEHaFTGvSwg3usbpqXh46oGAmWMTK3sEXEVSZMD77BRjHA bQv2Qmk8eO9UbHEOUwRJe7M8rbOg/LE3bHdtz7QPCyDZhmrknVE9exRrZX/qKMB4PgNe 5pucba3yGsiJvT/B4WNu6RDSiEfMqRWGJI9CZ6rZPKNLw+NdSfMYCgN6LmtIapwYxVcB v5rOEbTgU39YAK+BmWHkywKSSQFBrTaGyva946ZuXjQcrS4V9N9dtlWRDiwsas8/36nR LP8nWjdB/rj07MBSoruygY1G5JvfHdmyei47tgUDDxhgfUSI5bByo//pG6dQ+uBR6xjc ipQQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786161536; x=1786766336; 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=lrTqoTQOzou37Z6mnJvLS7m03O+NZx1RHl2W3+gwCEY=; b=fal+0JRb8lnZKfcNkky2nlH89hewU2t2gTfZ85v3WGmn84BzsnGe81Qibxq2P7AuZN TxAZxyIfis7f8i14ycPNoe9qSaNL9uOTAalxHLWmpMPQnV+bL2fOazInI/FRnAI6y9Gt iLqXIlQsKiTPoNIYUe9+lCzICjRKOtL8S23NQRkSng0n/xWk7FNyuH4aCD4r5BX93MEC XBNXqv5VlPb8bLVUwvLqkZGIjKTj2vBxPixJZP9Qa61fW7U8jVxsn149P2ePyuMw0x42 qSzLOYhqIIzH4Lb5wkZc257VlJWa28tljw2KZXjfP74nwFiKVWRcsBPLFSynyLPgvLWv rrAg== X-Forwarded-Encrypted: i=1; AHgh+RqQAIq9ZKonyr5SrMoslXh9CKI61+18TdSWjtqVprLC/5+gVJZ7jrQg9cVNs+rhOkob4YAZ117qWhxIoqU=@vger.kernel.org X-Gm-Message-State: AOJu0YyU0h1rYCKhmM1DHcWshYVyCrCHVlHp5sStlKWHRRiXlj3LpOWQ cdN6e5mC/GyfxbORkmYqOfvuc72w0PtQC1qP7ScKT2bZ1T0hOhOqFART X-Gm-Gg: AR+sD11Ny0k94yDefZp1T30DVzH1VD8ZYN6NSS0rIjyCTFj5vUPineaTqGUxtk5S1ES dhVB/zAICqJkCx2iKc8MGLxOc7xTO0KLoNXjEjRR0eXZciqIZpXg1o7YWKx78wFIs/jj+Eo2fZF hiBZWopx/xMPoOJp357TeQasMjG72oX+RlFuOlHMUMErC09Jd+NmVyn+IV7DSpZ1CO22fT11yKj qEnlojP37NsfYuvRLAO8GPx3xP4TIxOlKRFbf2z4fmdJxQ7ijtI62Hk84cJr/+e5rWaM2Tu79Wf UOjIZBKUIZUMO3c+OwpRsce6bQJCDXCYH7JARW2KZbdRMVd151rnqWFZ5BYrr4gWmZjr5QTWtCs vWo1Lc0wxyZH5hfS0AbsxZmd79zc8wz/UXAvtAkqRy/c9IntqPoh5DGAHPB5eI3EFHDDkATSZDQ BtGfhAec0VYRqHCQsoowYJZSChQQF7BH0ei96hCciEmRIcnkMcaXf3EjwqV73nggOHdeqtXA== X-Received: by 2002:a05:6122:4085:b0:5c2:c0b2:9880 with SMTP id 71dfb90a1353d-5c4112ef01dmr834216e0c.1.1786161536147; Fri, 07 Aug 2026 20:58:56 -0700 (PDT) Received: from [192.168.100.6] ([2800:bf0:82:11a2:7ac4:1f2:947b:2b6]) by smtp.gmail.com with ESMTPSA id 71dfb90a1353d-5c40b212fa6sm1432936e0c.16.2026.08.07.20.58.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Aug 2026 20:58:55 -0700 (PDT) From: Kurt Borja Date: Fri, 07 Aug 2026 22:58:25 -0500 Subject: [PATCH v3 3/9] 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: <20260807-ads126x-v3-3-f89925d72792@gmail.com> References: <20260807-ads126x-v3-0-f89925d72792@gmail.com> In-Reply-To: <20260807-ads126x-v3-0-f89925d72792@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Linus Walleij , Bartosz Golaszewski , 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, linux-gpio@vger.kernel.org, Jonathan Cameron X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=8180; i=kuurtb@gmail.com; h=from:subject:message-id; bh=G+m4JpteOwH1Zo2tIqYoGuuzgz1W67Q67Aw+8oU4NjM=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFllK8tZj5UKLE8qipONtLw6Z0/C5HCFrepL/fzTvrRuu q+mpHG0o5SFQYyLQVZMkaU9YdG3R1F5b/0OhN6HmcPKBDKEgYtTACby9QMjQ/c5/2bxyd/2MKXc DWR3WrzboZPr1sXKuh9aPac+X9knys7wv0Qza9eq6af/uwbxFM3j2JcxyahmDk99ZvlU/Sl6Ru/ +8wEA 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 | 159 +++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 158 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c index d78e5e3ae13e..b3b7b1249102 100644 --- a/drivers/iio/adc/ti-ads1262.c +++ b/drivers/iio/adc/ti-ads1262.c @@ -26,6 +26,7 @@ #include #include #include +#include =20 #include =20 @@ -148,6 +149,7 @@ enum { ADS1262_DR_14400_SPS, ADS1262_DR_19200_SPS, ADS1262_DR_38400_SPS, + ADS1262_DR_COUNT, }; =20 enum { @@ -173,6 +175,11 @@ struct ads1262_chip_info { const char *name; }; =20 +struct ads1262_channel { + u8 data_rate; + int samp_freqs[ADS1262_DR_COUNT][2]; +}; + struct ads1262 { struct spi_device *spi; struct regmap *regmap; @@ -183,12 +190,47 @@ struct ads1262 { /* Protects channel state */ struct mutex chan_lock; unsigned int num_channels; + struct ads1262_channel *channels; struct completion drdy; =20 /* Protects transfer buffers and concurrent SPI transfers */ struct mutex xfer_lock; }; =20 +static const u32 ads1262_data_rate_div[] =3D { + [ADS1262_DR_2_5_SPS] =3D 8 * 64 * 5760, + [ADS1262_DR_5_SPS] =3D 8 * 64 * 2880, + [ADS1262_DR_10_SPS] =3D 8 * 64 * 1440, + [ADS1262_DR_16_6_SPS] =3D 8 * 64 * 864, + [ADS1262_DR_20_SPS] =3D 8 * 64 * 720, + [ADS1262_DR_50_SPS] =3D 8 * 64 * 288, + [ADS1262_DR_60_SPS] =3D 8 * 64 * 240, + [ADS1262_DR_100_SPS] =3D 8 * 64 * 144, + [ADS1262_DR_400_SPS] =3D 8 * 64 * 36, + [ADS1262_DR_1200_SPS] =3D 8 * 64 * 12, + [ADS1262_DR_2400_SPS] =3D 8 * 64 * 6, + [ADS1262_DR_4800_SPS] =3D 8 * 64 * 3, + [ADS1262_DR_7200_SPS] =3D 8 * 64 * 2, + [ADS1262_DR_14400_SPS] =3D 8 * 64 * 1, + [ADS1262_DR_19200_SPS] =3D 8 * 48 * 1, + [ADS1262_DR_38400_SPS] =3D 8 * 24 * 1, +}; + +static int ads1262_find_two(const int (*array)[2], size_t num_elements, in= t val, + int val2) +{ + int i; + + for (i =3D 0; i < num_elements; i++) { + if (val =3D=3D array[i][0] && val2 =3D=3D array[i][1]) + break; + } + if (i =3D=3D num_elements) + return -EINVAL; + + return i; +} + static int ads1262_dev_cmd(struct ads1262 *st, u8 opcode) { guard(mutex)(&st->xfer_lock); @@ -316,11 +358,19 @@ 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; u8 val; =20 guard(mutex)(&st->xfer_lock); guard(mutex)(&st->chan_lock); =20 + val =3D FIELD_PREP(ADS1262_MODE2_DR_MASK, chan->data_rate); + ret =3D regmap_update_bits(st->regmap, ADS1262_MODE2_REG, + ADS1262_MODE2_DR_MASK, val); + if (ret) + return ret; + val =3D FIELD_PREP(ADS1262_INPMUX_MUXN_MASK, spec->channel2) | FIELD_PREP(ADS1262_INPMUX_MUXP_MASK, spec->channel); return regmap_update_bits(st->regmap, ADS1262_INPMUX_REG, @@ -372,6 +422,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 @@ -384,6 +436,65 @@ 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 chan_data->samp_freqs[chan_data->data_rate][0]; + *val2 =3D chan_data->samp_freqs[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; + *vals =3D (const int *)chan_data->samp_freqs; + *length =3D ARRAY_SIZE(chan_data->samp_freqs) * 2; + return IIO_AVAIL_LIST; + + 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: + ret =3D ads1262_find_two(chan_data->samp_freqs, + ARRAY_SIZE(chan_data->samp_freqs), + val, val2); + if (ret < 0) + return -EINVAL; + + chan_data->data_rate =3D ret; + + return 0; + default: return -EOPNOTSUPP; } @@ -404,6 +515,8 @@ static int ads1262_debugfs_reg_access(struct iio_dev *i= ndio_dev, unsigned int re =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, }; =20 @@ -575,6 +688,36 @@ static const struct regmap_bus ads1262_regmap_bus =3D { .max_raw_write =3D ADS1262_MAX_REGMAP_WRITE, }; =20 +static void ads1262_populate_samp_freqs(struct ads1262 *st, + struct ads1262_channel *chan) +{ + int freq_Hz, freq_rem; + u64 freq_uHz; + + for (unsigned int i =3D 0; i < ARRAY_SIZE(chan->samp_freqs); i++) { + freq_uHz =3D div_u64(mul_u32_u32(st->clk_rate, MICRO), + ads1262_data_rate_div[i]); + freq_Hz =3D div_u64_rem(freq_uHz, MICRO, &freq_rem); + + chan->samp_freqs[i][0] =3D freq_Hz; + chan->samp_freqs[i][1] =3D freq_rem; + } +} + +static int ads1262_populate_tables(struct iio_dev *indio_dev) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + struct ads1262_channel *chan; + + for (unsigned int i =3D 0; i < st->num_channels; i++) { + chan =3D &st->channels[i]; + + ads1262_populate_samp_freqs(st, chan); + } + + return 0; +} + static int ads1262_gpio_setup(struct ads1262 *st) { struct device *dev =3D &st->spi->dev; @@ -661,6 +804,11 @@ static int ads1262_parse_channels(struct iio_dev *indi= o_dev) if (st->num_channels > ADS1262_MAX_CHANNEL_COUNT) return dev_err_probe(dev, -EINVAL, "too many channels\n"); =20 + st->channels =3D devm_kcalloc(dev, st->num_channels, sizeof(*st->channels= ), + GFP_KERNEL); + if (!st->channels) + return -ENOMEM; + /* Account for the timestamp channel */ num_specs =3D st->num_channels + 1; specs =3D devm_kcalloc(dev, num_specs, sizeof(*specs), GFP_KERNEL); @@ -681,6 +829,8 @@ static int ads1262_parse_channels(struct iio_dev *indio= _dev) return dev_err_probe(dev, -EINVAL, "%s: duplicated channel reg\n", fwnode_get_name(node)); =20 + st->channels[reg].data_rate =3D ADS1262_DR_20_SPS; + specs[reg].scan_index =3D reg; specs[reg].scan_type =3D (struct iio_scan_type) { .format =3D IIO_SCAN_FORMAT_SIGNED_INT, @@ -701,7 +851,10 @@ static int ads1262_parse_channels(struct iio_dev *indi= o_dev) if (specs[reg].channel !=3D ADS1262_INPMUX_TEMP) specs[reg].indexed =3D true; =20 - specs[reg].info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW); + specs[reg].info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SAMP_FREQ); + specs[reg].info_mask_separate_available =3D + BIT(IIO_CHAN_INFO_SAMP_FREQ); } =20 specs[num_specs - 1] =3D IIO_CHAN_SOFT_TIMESTAMP(num_specs - 1); @@ -786,6 +939,10 @@ static int ads1262_spi_probe(struct spi_device *spi) if (ret) return ret; =20 + ret =3D ads1262_populate_tables(indio_dev); + if (ret) + return ret; + st->regmap =3D devm_regmap_init(dev, &ads1262_regmap_bus, st, &ads1262_regmap_config); if (IS_ERR(st->regmap)) --=20 2.55.0 From nobody Tue Sep 29 11:48:55 2026 Received: from mail-vk1-f169.google.com (mail-vk1-f169.google.com [209.85.221.169]) (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 375183B892D for ; Sat, 8 Aug 2026 03:58:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786161543; cv=none; b=fHy3rkkeosfvPB2h6S70DUX/CcblXeXEVDNOTF0Y/yVVaoXi7WPSO5TWKjIq/CNl75Ow+L2sIS8hjB0VST3u+IDQ63XLKvLs/0TOGnHg4uQziM9JXHNDktpeVflRvwOFwdVYJ5WeepkB+6xuFIGpbseHRovK3aw00eCCyx1s2LE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786161543; c=relaxed/simple; bh=rKTg6Z6bdmNBcOyQxmrNHPC5g7lyGZef9+Jc/z/tVAQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UhZAWljrA0XcLBy1DC8CehdS62sL3KwSdwiPua55kE8YXkJFz/U59SUMMI162dxpVnUwFW2OYLiUZ6d7jAbIJwD3vWHzjdMzeETx56EQVNHGldK+HZv4b+Uw2SyIyBGMglg869wJUOXfl5/MdZZ0lc7/02Hy4FTQO/M4pnbYTw4= 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=iLAM25eP; arc=none smtp.client-ip=209.85.221.169 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="iLAM25eP" Received: by mail-vk1-f169.google.com with SMTP id 71dfb90a1353d-5bf5370d38fso65022e0c.2 for ; Fri, 07 Aug 2026 20:58:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786161538; x=1786766338; 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=7DnKvLjulZND4V/08SqsRVJDgo0f0h8OLuOe9xeaCYg=; b=iLAM25eP2vjDmEdr++PyDpgnuJ56kiNaPZlumiq0u+Zi+5MLZq7bWXOm59qS+NZbsL 8B/fj++cbiw8Avr+vpFn08Du0agD9bi4ZrGNhRR1SL8ilbDa1NHjxiH6uzH+rsNwIPH5 rQdv4VC0h29v4gGD9knrbtkLGd6plroimX2+BXpg3qP69BIxqo1sgE9aaeerNicsb/4d UmeKtQHRmJ38/E5KxQ+EiGQLdjT91rc8LukEoydtrTk6dNDjSXbXR1vNpvx+Sf94vp+r kUgS9WNpMEgqJ53RfAe90W4qx/smezLzNktjNYIybHZiQ9bIovkkWk0LpJrRDvmkdOV1 Sa8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786161538; x=1786766338; 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=7DnKvLjulZND4V/08SqsRVJDgo0f0h8OLuOe9xeaCYg=; b=irXvTuAgKoLuSnmuMviwQDRYdh2C96oqkeUySyt5OSVkWUnFUVbT8f616M36cFtA4n +NwjhNy/XEhMuUJlPcsrBU4ZwgUlHNX4epGauIAyhivDEqSOjf12MNrohTdNr3BEBdMG i2N5k3kJUTru3aKFvoucEkrQ5YcO5pgD8C3aA5IvOrm07F9ARHTouGSJONGhwX6SrR4r 0cQHfMU2Mp6dwZaBRtEosMDzOUW73ILBidjZfd7bm9hmAiY/bKhvzprpqMECW94pgXZy NWuRCJkzQUNyx3redwIJXU5RjZT0MpZQGnymApwZIG6E0+cSfYlTbSYl9grFbKvvgYrJ mAqw== X-Forwarded-Encrypted: i=1; AHgh+RomNmnOVCcuZkjFFKtNrsmBBqhEcYHwkfVqz3lJRA+xlRX+wpO8eJUJ/sc8iLQ9Bm+gQpDkMQ42lzk5E4c=@vger.kernel.org X-Gm-Message-State: AOJu0YwjAQ2nITCdxceSNgkIJ2rU2GArLQDd/3QaYmsK6RqAZwq4ZoNt WXHx34Ju0bbWJO0nmZjswq5paoScThtqkK0hUFBaWYyTAvEpotTZxWGG X-Gm-Gg: AR+sD13JR9GzCDLVAoQjBn2HI8fchdeiX1LK93I/8QTNJTXFwXf4Nedu7FPJnGhe/W5 ki3GCmTrgST54oMbo+ucwmvEFYi5SmrSwOaEovm4gWe9fS1xtnZsJ4n83UUiGVMhPHkEQ8AXoXt W9SF3vFujcAKGOJXqWbzQJqZaMNmec36wqnB6qz78CSyjQLs51o6pQuhY2QZG6Oj6nha1TMd/VR K0XtmFvEzG25Dgfe47epQZ5Fq2/XiAvU4bXvQzwnCofjwzKgs/K1I60soD66/Gj1H+KHJDzqQQl qIVm9+F6Q/lcS/tHnXBNf3lVBKghHf19JX/95dTTt6e7PKecFxBgo2Ye7362c0CaHB7uqbdtd4/ YgKVQlbuj/7LWULSUUqEolT++U74mhp6WdRDZYVDJKjeznI6Tz771DIbmH4GEXK3/SGVEXq65O5 f2VDXJ/kb823wTKOoKphCAiDlPolOnNYImweeo0szg1WoOMNzdFW6gUOeuerM= X-Received: by 2002:a05:6102:c10:b0:75f:e517:ec96 with SMTP id ada2fe7eead31-760e3194fc4mr6814637137.0.1786161537974; Fri, 07 Aug 2026 20:58:57 -0700 (PDT) Received: from [192.168.100.6] ([2800:bf0:82:11a2:7ac4:1f2:947b:2b6]) by smtp.gmail.com with ESMTPSA id 71dfb90a1353d-5c40b212fa6sm1432936e0c.16.2026.08.07.20.58.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Aug 2026 20:58:57 -0700 (PDT) From: Kurt Borja Date: Fri, 07 Aug 2026 22:58:26 -0500 Subject: [PATCH v3 4/9] 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: <20260807-ads126x-v3-4-f89925d72792@gmail.com> References: <20260807-ads126x-v3-0-f89925d72792@gmail.com> In-Reply-To: <20260807-ads126x-v3-0-f89925d72792@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Linus Walleij , Bartosz Golaszewski , 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, linux-gpio@vger.kernel.org, Jonathan Cameron X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=19827; i=kuurtb@gmail.com; h=from:subject:message-id; bh=rKTg6Z6bdmNBcOyQxmrNHPC5g7lyGZef9+Jc/z/tVAQ=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFllK8tfNJ+55t2tx6H0p5Tj4jkmue6l7Rf9g3ZtnJ574 tzdlM7sjlIWBjEuBlkxRZb2hEXfHkXlvfU7EHofZg4rE8gQBi5OAZjIAS6Gf2YP/vh+az5Swybc uuekuJaG1zONb89/vy50ubmAPSzuywVGhlVXubse1R2e+8l7ycat+v0zuyW+2/5IYp287MpujyO d7MwA 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 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 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 | 417 +++++++++++++++++++++++++++++++++++++++= ++-- 1 file changed, 406 insertions(+), 11 deletions(-) diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c index b3b7b1249102..360ce01a5871 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,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +27,7 @@ #include #include #include +#include #include #include =20 @@ -97,6 +100,9 @@ #define ADS1262_IDACMAG_REG 0x0E =20 #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_TDACN_REG 0x11 #define ADS1262_GPIOCON_REG 0x12 @@ -117,8 +123,12 @@ =20 #define ADS1262_MAX_CHANNEL_COUNT 16 #define ADS1262_MAX_REGMAP_WRITE 8 +#define ADS1262_EXT_REF_COUNT 3 #define ADS1262_ADC1_RESOLUTION 32 =20 +#define ADS1262_TEMP_SLOPE_uV_C 420ULL +#define ADS1262_TEMP_ZERO_C 111900ULL + enum { ADS1262_RUNMODE_CONTINUOUS, ADS1262_RUNMODE_PULSE, @@ -171,12 +181,38 @@ enum { ADS1262_INPMUX_FLOAT, }; =20 +enum { + ADS1262_RMUXP_INTERNAL, + ADS1262_RMUXP_REFP1, + ADS1262_RMUXP_REFP2, + ADS1262_RMUXP_REFP3, + ADS1262_RMUXP_AVDD, + ADS1262_RMUXP_COUNT +}; + +enum { + ADS1262_RMUXN_INTERNAL, + ADS1262_RMUXN_REFN1, + ADS1262_RMUXN_REFN2, + ADS1262_RMUXN_REFN3, + ADS1262_RMUXN_AVSS, + ADS1262_RMUXN_COUNT +}; + struct ads1262_chip_info { const char *name; }; =20 struct ads1262_channel { u8 data_rate; + u8 gain; + u8 ref_p; + u8 ref_n; + bool ref_reversal; + bool is_resistance; + int offset; + int scales[6][2]; + size_t num_scales; int samp_freqs[ADS1262_DR_COUNT][2]; }; =20 @@ -192,6 +228,12 @@ struct ads1262 { unsigned int num_channels; struct ads1262_channel *channels; struct completion drdy; + u32 rref_ohms[ADS1262_EXT_REF_COUNT][ADS1262_EXT_REF_COUNT]; + int refp_uV[ADS1262_RMUXP_COUNT]; + int refn_uV[ADS1262_RMUXN_COUNT]; + bool need_avdd_uV; + bool need_avss_uV; + bool bipolar_supply; =20 /* Protects transfer buffers and concurrent SPI transfers */ struct mutex xfer_lock; @@ -216,6 +258,24 @@ static const u32 ads1262_data_rate_div[] =3D { [ADS1262_DR_38400_SPS] =3D 8 * 24 * 1, }; =20 +static const char * const ads1262_ref_sources_pos[] =3D { + [ADS1262_RMUXP_INTERNAL] =3D "internal", + [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", + [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) { @@ -231,6 +291,12 @@ static int ads1262_find_two(const int (*array)[2], siz= e_t num_elements, int val, return i; } =20 +static bool ads1262_ref_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_cmd(struct ads1262 *st, u8 opcode) { guard(mutex)(&st->xfer_lock); @@ -365,17 +431,33 @@ static int ads1262_channel_enable(struct ads1262 *st, guard(mutex)(&st->xfer_lock); guard(mutex)(&st->chan_lock); =20 - val =3D FIELD_PREP(ADS1262_MODE2_DR_MASK, chan->data_rate); + val =3D FIELD_PREP(ADS1262_MODE0_REFREV_MASK, chan->ref_reversal); + ret =3D regmap_update_bits(st->regmap, ADS1262_MODE0_REG, + ADS1262_MODE0_REFREV_MASK, val); + if (ret) + return ret; + + val =3D FIELD_PREP(ADS1262_MODE2_DR_MASK, chan->data_rate) | + FIELD_PREP(ADS1262_MODE2_GAIN_MASK, chan->gain); ret =3D regmap_update_bits(st->regmap, ADS1262_MODE2_REG, - ADS1262_MODE2_DR_MASK, val); + ADS1262_MODE2_DR_MASK | + ADS1262_MODE2_GAIN_MASK, val); if (ret) return ret; =20 val =3D FIELD_PREP(ADS1262_INPMUX_MUXN_MASK, spec->channel2) | FIELD_PREP(ADS1262_INPMUX_MUXP_MASK, spec->channel); - return regmap_update_bits(st->regmap, ADS1262_INPMUX_REG, + ret =3D regmap_update_bits(st->regmap, ADS1262_INPMUX_REG, ADS1262_INPMUX_MUXN_MASK | ADS1262_INPMUX_MUXP_MASK, val); + if (ret) + return ret; + + val =3D FIELD_PREP(ADS1262_REFMUX_RMUXN_MASK, chan->ref_n) | + FIELD_PREP(ADS1262_REFMUX_RMUXP_MASK, chan->ref_p); + return regmap_update_bits(st->regmap, ADS1262_REFMUX_REG, + ADS1262_REFMUX_RMUXN_MASK | + ADS1262_REFMUX_RMUXP_MASK, val); } =20 static int ads1262_set_runmode(struct ads1262 *st, u8 runmode) @@ -436,6 +518,26 @@ 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: { + if (chan->type !=3D IIO_TEMP) + return -EPERM; + + guard(mutex)(&st->chan_lock); + + *val =3D chan_data->offset; + + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_SAMP_FREQ: { guard(mutex)(&st->chan_lock); =20 @@ -458,6 +560,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; *vals =3D (const int *)chan_data->samp_freqs; @@ -484,6 +592,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: ret =3D ads1262_find_two(chan_data->samp_freqs, ARRAY_SIZE(chan_data->samp_freqs), @@ -513,10 +631,22 @@ 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 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, }; =20 @@ -688,6 +818,91 @@ static const struct regmap_bus ads1262_regmap_bus =3D { .max_raw_write =3D ADS1262_MAX_REGMAP_WRITE, }; =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; + + 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 (WARN_ON(!ads1262_ref_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 device *dev =3D &st->spi->dev; + struct ads1262_channel *chan =3D &st->channels[spec->scan_index]; + u32 full_scale; + u64 mult; + + full_scale =3D abs(st->refp_uV[chan->ref_p] - st->refn_uV[chan->ref_n]); + if (full_scale < 900000) + return dev_err_probe(dev, -EINVAL, "channel@%u: reference voltage below = 0.9V\n", + spec->scan_index); + + chan->offset =3D -div_s64(ADS1262_TEMP_ZERO_C << + (ADS1262_ADC1_RESOLUTION - 1), full_scale); + + chan->num_scales =3D 1; + + mult =3D PICO * MILLIDEGREE_PER_DEGREE / ADS1262_TEMP_SLOPE_uV_C; + 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]; + u32 full_scale; + u64 mult; + + full_scale =3D abs(st->refp_uV[chan->ref_p] - st->refn_uV[chan->ref_n]); + if (full_scale < 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) { + chan->num_scales =3D 1; + mult =3D 4; + } else { + chan->num_scales =3D ARRAY_SIZE(chan->scales); + mult =3D 1; + } + + ads1262_calculate_scales(chan->scales, chan->num_scales, full_scale, + NANO * mult, ADS1262_ADC1_RESOLUTION); + + return 0; +} + static void ads1262_populate_samp_freqs(struct ads1262 *st, struct ads1262_channel *chan) { @@ -707,12 +922,102 @@ static void ads1262_populate_samp_freqs(struct ads12= 62 *st, static int ads1262_populate_tables(struct iio_dev *indio_dev) { struct ads1262 *st =3D iio_priv(indio_dev); + const struct iio_chan_spec *spec; struct ads1262_channel *chan; + int ret; + =20 for (unsigned int i =3D 0; i < st->num_channels; i++) { + spec =3D &indio_dev->channels[i]; chan =3D &st->channels[i]; =20 ads1262_populate_samp_freqs(st, chan); + + 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; +} + +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; + + st->refp_uV[ADS1262_RMUXP_INTERNAL] =3D st->refn_uV[ADS1262_RMUXN_AVSS] += 2500000; + st->refn_uV[ADS1262_RMUXN_INTERNAL] =3D st->refn_uV[ADS1262_RMUXN_AVSS]; + + 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] =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] =3D ret =3D=3D -ENODEV ? 0 : -ret; + else + st->refn_uV[i] =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; + } } =20 return 0; @@ -745,7 +1050,10 @@ static int ads1262_parse_channel_node(struct ads1262 = *st, struct iio_chan_spec *spec, struct fwnode_handle *node) { + struct ads1262_channel *chan =3D &st->channels[spec->scan_index]; 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 @@ -785,6 +1093,49 @@ 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, "%s: failed to read reference-sources\n", + fwnode_get_name(node)); + if (ret < 2) + return dev_err_probe(dev, -EINVAL, "%s: missing reference-sources\n", + fwnode_get_name(node)); + + ret =3D match_string(ads1262_ref_sources_pos, -1, sources[0]); + if (ret < 0) + return dev_err_probe(dev, ret, "%s: invalid positive reference source\n= ", + fwnode_get_name(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, "%s: invalid negative reference source\n= ", + fwnode_get_name(node)); + chan->ref_n =3D ret; + + if ((chan->ref_p =3D=3D ADS1262_RMUXP_INTERNAL || + chan->ref_n =3D=3D ADS1262_RMUXN_INTERNAL) && chan->ref_p !=3D chan= ->ref_n) + return dev_err_probe(dev, -EINVAL, + "%s: the internal reference must be selected symmetrically\n", + fwnode_get_name(node)); + + if (chan->ref_p =3D=3D ADS1262_RMUXP_AVDD) + st->need_avdd_uV =3D true; + if (chan->ref_n =3D=3D ADS1262_RMUXN_AVSS) + st->need_avss_uV =3D true; + + if (ads1262_ref_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 @@ -845,6 +1196,8 @@ static int ads1262_parse_channels(struct iio_dev *indi= o_dev) =20 if (specs[reg].channel =3D=3D ADS1262_INPMUX_TEMP) specs[reg].type =3D IIO_TEMP; + else if (st->channels[reg].is_resistance) + specs[reg].type =3D IIO_RESISTANCE; else specs[reg].type =3D IIO_VOLTAGE; =20 @@ -852,9 +1205,14 @@ static int ads1262_parse_channels(struct iio_dev *ind= io_dev) specs[reg].indexed =3D true; =20 specs[reg].info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SAMP_FREQ); + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_SCALE); + if (specs[reg].channel =3D=3D ADS1262_INPMUX_TEMP) + specs[reg].info_mask_separate |=3D BIT(IIO_CHAN_INFO_OFFSET); + specs[reg].info_mask_separate_available =3D - BIT(IIO_CHAN_INFO_SAMP_FREQ); + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_SCALE); } =20 specs[num_specs - 1] =3D IIO_CHAN_SOFT_TIMESTAMP(num_specs - 1); @@ -874,13 +1232,46 @@ 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) - return dev_err_probe(dev, ret, "failed to get avdd regulator\n"); + if (st->need_avdd_uV) { + ret =3D devm_regulator_get_enable_read_voltage(dev, "avdd"); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to get avdd voltage\n"); =20 - 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"); + st->refp_uV[ADS1262_RMUXP_AVDD] =3D ret; + } else { + ret =3D devm_regulator_get_enable(dev, "avdd"); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to get avdd regulator\n"); + } + + /* + * 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. + */ + if (st->need_avss_uV) { + ret =3D devm_regulator_get_enable_read_voltage(dev, "avss"); + if (ret < 0 && ret !=3D -ENODEV) + return dev_err_probe(dev, ret, "failed to get avss voltage\n"); + + if (ret !=3D -ENODEV) { + st->refn_uV[ADS1262_RMUXN_AVSS] =3D -ret; + st->bipolar_supply =3D true; + } + } else { + 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"); + + if (ret !=3D -ENODEV) + st->bipolar_supply =3D true; + } =20 return 0; } @@ -939,6 +1330,10 @@ static int ads1262_spi_probe(struct spi_device *spi) if (ret) return ret; =20 + ret =3D ads1262_parse_references(st); + if (ret) + return ret; + ret =3D ads1262_populate_tables(indio_dev); if (ret) return ret; --=20 2.55.0 From nobody Tue Sep 29 11:48:55 2026 Received: from mail-vk1-f177.google.com (mail-vk1-f177.google.com [209.85.221.177]) (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 D26623BB113 for ; Sat, 8 Aug 2026 03:59:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786161542; cv=none; b=HMjfre0o/OP/ma2ytp2J//BcKS7B3w+mBorc7hbKCSldmu7VeAID7oKieqRzwtLvPDuIA7ATOZlaA/6+dbqHYhU02kq+KofSMcLjP5M2aSSp/XypzAkR5r4BeDQ9QKz9f6dmMNAmLZ5TcXPQyKbVpNRaLGDAZYWGjHhP3r0PiYA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786161542; c=relaxed/simple; bh=VvzU2b+Z5pKj30/fjUw7xXFFO/Jtm5Yb6ds+h+Vgx40=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fKF16dsyRCGoIgQfNyMi+g/NF3aEzWAuKE0/WB9y6Yp96/lqVEDsA2+ZoUSztQPV3RX8ECpoF7nVweWjnH7r8Z5KJtqiDYZn8+WF8H1HW2nwpPZ7S7q3E+AhI8OsGhzOAjypuACPDRfdmQLyMKft7FJLl3aD61AF+dfX+5douEM= 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=X3Slnrdn; arc=none smtp.client-ip=209.85.221.177 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="X3Slnrdn" Received: by mail-vk1-f177.google.com with SMTP id 71dfb90a1353d-5bfaf91daa2so58182e0c.0 for ; Fri, 07 Aug 2026 20:59:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786161540; x=1786766340; 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=U/2Cl37wCOBLY6P0gy/ZiqOf7MT5GkHf8SZj+ieZ6Us=; b=X3SlnrdnZ8gYCfwN007Ys6+U1kgy3Fq101Xf2uBiWiOKwnSMK5gPmi43xRKRN6xGNi JgunXeM+SgDa8/GgJAFU1D7e2KQJHFPe5DCIFW+bN5eulJM5hY/U0dviYJj31tHge6S2 eqMysfWzg6TRa6PmEIbgjH//wVjTDq+Ipuckl8J3ekCKyx3l7pQA7W1+eu/GaWoNBrFm EVZsWydFIfTnwftg9JAFUfjHl8Og84ml6hFX+q0NSeT86g0xB3oo97fWF1wU/UCdZ+bR MjuI78Iz+Xi9qTZVdoMa5P1LRRzAW2ZtOGkTxksG1wMJQyYv5Jxh3gK5+9mnMq6NIUUy YW3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786161540; x=1786766340; 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=U/2Cl37wCOBLY6P0gy/ZiqOf7MT5GkHf8SZj+ieZ6Us=; b=kewSSJ+Gf/kqcHzmW5KGmqCE7Xr+UJ/77z31Bsf7syhU0126dqFqtvWeDvBFVK+QsS aW79PhIikF7YwkkJjLJbeZ8vyVb8x4tBvJ7cqWLGBQwdiHPX39BSjG1Gw4tGtagFppJb 6PW9MT42Oi6bkKVAP7vrQZHWF6VZUo7F5BsUXX6cvv9eTtFN7LosCg56l9mWYcWM5CJp /E47P39edrgHtcDjMKpS+QlSSgarEMc4Tx4AtL/PR/UN/1TBUocnBZYR9IPFfy4JUT38 cIzJVkkwa+Ucg1rM++GMXBe41tixi+LbWl6tIKh+RnTL/XRvSRuFdVHgibP8avN1fprF 780Q== X-Forwarded-Encrypted: i=1; AHgh+RqE+6faOS8eoWgcsnlqtF6nsA4CGBltJzzML7qSJw1pItPCOMQM+HPdJUXAIqmPoiMgcB10BhzTpd6Pvjc=@vger.kernel.org X-Gm-Message-State: AOJu0Yx0Mc3cMitDt9tE76AVqHNvOCryyW7aFrnexFCGQpkzeI1jK0p5 0LZO5kahbv6rBna39xS/oMhOKxHAsE5t4Q2oKAumJwgkbF+7SMHEDKT+ X-Gm-Gg: AR+sD1134xo/JbfZlFtYsQoJi1RmsyFiBVtFmeJkoSZezn3zfD7hvwi6qA7kQ4KDyoj hFHZgebhFEOVG1SjcjBdCfk4iOItzav5Uo7VTa09k2+KcETxBi+qunn50I9lxrOYpGDVGeSSCK8 ddKSV6tEmX4VG0ZnTVT+VGLqHSWFDi2mVQrJThfEuDgxrVUnavxTyuyAidAsytYOLrXiRsbaekm U3XawWGiDVDgdZ/mdowTuB96dz2125RrTmuPgjkLLtS5D22Fmt8oMMFNvn/P9tMSeaeGBFyKubC 7/P/MoTi7XKO9PR8WUVfQBYkLy/AyY56rO1d0kCO9Q/r30qM70V3IAObPnOv8qn3r7tnlgLlIXH BS7+7C1+5Nr5XqJuB5j67ceQ2rj47OVa7yY1tpgHz0BEy9KwE1hHb9rN/crryX8yGHkxxFZxZmC TZJnt47+bQb/Veaq02n62Goa3afOxKa9GB1ebMFl0MMJ+OGmB3Ud6moAqY6QY= X-Received: by 2002:a05:6122:d0b:b0:5bf:a181:d46d with SMTP id 71dfb90a1353d-5c4092da348mr906491e0c.3.1786161539719; Fri, 07 Aug 2026 20:58:59 -0700 (PDT) Received: from [192.168.100.6] ([2800:bf0:82:11a2:7ac4:1f2:947b:2b6]) by smtp.gmail.com with ESMTPSA id 71dfb90a1353d-5c40b212fa6sm1432936e0c.16.2026.08.07.20.58.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Aug 2026 20:58:59 -0700 (PDT) From: Kurt Borja Date: Fri, 07 Aug 2026 22:58:27 -0500 Subject: [PATCH v3 5/9] 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: <20260807-ads126x-v3-5-f89925d72792@gmail.com> References: <20260807-ads126x-v3-0-f89925d72792@gmail.com> In-Reply-To: <20260807-ads126x-v3-0-f89925d72792@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Linus Walleij , Bartosz Golaszewski , 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, linux-gpio@vger.kernel.org, Jonathan Cameron X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=3294; i=kuurtb@gmail.com; h=from:subject:message-id; bh=VvzU2b+Z5pKj30/fjUw7xXFFO/Jtm5Yb6ds+h+Vgx40=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFllKysyqn8/NFS6ZbqsfsaL4rdHZLQWxn/pfn/dvP8Au 0tbTJVbRykLgxgXg6yYIkt7wqJvj6Ly3vodCL0PM4eVCWQIAxenAEzER5/hn+2l2hqFlkZ3vb+T tUr1I9kb1u5pu6fIz8rVuzf0r5oiD8P/UlXBhHt8e5asWiD8+/Q+1y3bY5n7f098uehJppiE+YN gbgA= 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). Signed-off-by: Kurt Borja Reviewed-by: David Lechner --- drivers/iio/adc/ti-ads1262.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c index 360ce01a5871..e2659941e1af 100644 --- a/drivers/iio/adc/ti-ads1262.c +++ b/drivers/iio/adc/ti-ads1262.c @@ -210,6 +210,7 @@ struct ads1262_channel { u8 ref_n; bool ref_reversal; bool is_resistance; + bool input_chop; int offset; int scales[6][2]; size_t num_scales; @@ -374,7 +375,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 @@ -382,7 +383,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. @@ -431,8 +432,10 @@ static int ads1262_channel_enable(struct ads1262 *st, guard(mutex)(&st->xfer_lock); guard(mutex)(&st->chan_lock); =20 - val =3D FIELD_PREP(ADS1262_MODE0_REFREV_MASK, chan->ref_reversal); + val =3D FIELD_PREP(ADS1262_MODE0_INPUT_CHOP_MASK, chan->input_chop) | + FIELD_PREP(ADS1262_MODE0_REFREV_MASK, chan->ref_reversal); ret =3D regmap_update_bits(st->regmap, ADS1262_MODE0_REG, + ADS1262_MODE0_INPUT_CHOP_MASK | ADS1262_MODE0_REFREV_MASK, val); if (ret) return ret; @@ -473,13 +476,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 @@ -489,7 +505,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 @@ -1134,6 +1150,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 Tue Sep 29 11:48:55 2026 Received: from mail-vk1-f169.google.com (mail-vk1-f169.google.com [209.85.221.169]) (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 1A01E3BADBD for ; Sat, 8 Aug 2026 03:59:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786161544; cv=none; b=rNOgrksrvgq/ZvXyTL2CH1nOAvUYybU21Ewq4H5+2Eo+29j3sjIW0TPuzneQK07u7Pfqwt6cDSDIXDGaKytVo4GlVRAbOwDcK0nTwbMBqupdSadqNdUoy+PQxHoc+nIemHVbARmA79STj7klaxGw0sj7j7bG7Z1s0W8jCpljb+U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786161544; c=relaxed/simple; bh=bIpvMMa4U2CGo++dRegyRF9eL9wseA8Sf0kiZsyR1Ek=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=bfV23vNq0xfcZKatwyc/Mq5fzqcq3C3mTg0yUQuq74oWJk2AtQSv+4IYVY/0AbhAHAlbqxLivIq7rE9mGhBkZeRsdCKx8in1K9V/yuYjQsxDfi1LKKTNuzIbKhdwQFhukJe74EhjnD6yf7S5MHcWI4/9sJowpMWWA2Jt7kUn7xE= 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=LMyBInlY; arc=none smtp.client-ip=209.85.221.169 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="LMyBInlY" Received: by mail-vk1-f169.google.com with SMTP id 71dfb90a1353d-5bf9506704fso76867e0c.2 for ; Fri, 07 Aug 2026 20:59:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786161541; x=1786766341; 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=JHoYBqcl+n61cEQGO8t2siDqeVUfdNDd2mseqU1bHQo=; b=LMyBInlYZzXgybyjvo8UPKRjmPKYUGn40DvA9nrdbXLgwvOX8vDIkBS9Cbo5p5/4Q3 MEifOjiRqUrR+yXvBSxCMzOQFF//0zkA3bqg4sJ1yyq/9JWXlq31IWedwJ3kfGkPuvXl cMJLtOkGVhQvkQb/Rsvt2ZHaJUxtruYV+uOQv7PC9VsxSlv0AT4ZrKrtpdDZlNZx8sC3 HzNM38c/d48kCGNGYlBaOiy8MdBpuc3tSUKnVoRb793z7kC3yuIdrfk5di+DxR/xJX4U bmVfRXa1M1dznyCaVuNBkwsubQ7PG2RdtiHWCHk/L8AFioT+4BTQLpznkgvDgXKvZluw IIvA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786161541; x=1786766341; 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=JHoYBqcl+n61cEQGO8t2siDqeVUfdNDd2mseqU1bHQo=; b=LGsPDFRh7it7g9iWVZ4cge2R2R/dZbyp2qR83BZgH0UwKdiLSeTCAAW6r44w0I7poD ZNuf2lpja4v/DMVsoVoSbU0P/Djz/CzpvCf8sWqK5qVCfYtZjxz8JjMY7gG2CRHt90n2 gb70Ns2VZJNPXAdhEqQ2qQudWPIEUCFLzZvytPAsnr86b6x08BAKfNaLzXdXJYPz7jHt 424pEl2XIi0wqmzOS8VodZ+d5em3gSljWWAzSBgnwaO/rYsrgjiID6LHwpw08w8hUTPl IXZIxIqkDoR97eSwBOx5rq5n4a4GuC/wKgJEeKRa09PXxFaEfjBioZRW18r6E8N94ZFS TP6Q== X-Forwarded-Encrypted: i=1; AHgh+Rq6KmhIKIxVSa2PdH3hdlrjcOm0A4gJbbklF2H4lg+PKoTgSvSv4Wtl69c9r53qiyGahRSzNTLtc/Cu8/o=@vger.kernel.org X-Gm-Message-State: AOJu0Yz2MVVgYUAGkYw5H02C1NI8j07Z3BuBSerSu3V+6umpjoUwahOw 4R07xC9uThtAO2hyVDxJ2jQpFuJVusrPiB95Ep7h4APUztFFZpvrML+T X-Gm-Gg: AR+sD13jzVEU07pFyDPFjfrm6AY5LX3tGQxkcb4PlZmluasiBNgZhP3bjsW0IdU/xYQ uKsRp/TpezIva2zhFWpoPBaI6K4xLkuRNF/2edLqaPo0KJB2MWncZh6VUF3EAD93atA2HcBlBps My4c2uGZ/sBgJ2goFyUG1QARmlEwkriU0NBzKh5MpFI7bqwlKJQynGNnU4GQ+MfxiAp6qNdjhvz eDprV7ilh1w8vQ4chKr9lT/83equYGaQc2kJLvtnXxwku/fRcxsn3hHhGT+WIIYcY1hE54le8Zl EgsJO7j/AJ4pC84r7alqVTuXelSNSf8Wh9umcjvm1SSlmX+Q64d+WI4cG9P0bhWV+4Ohhk59YXv 4IACH7pAOEAzwGULA3s21aJxoofTy16DWw9ERXp5UNOeumosTifu8XD5XPADfgdqagKBXy6E+g4 vvQh2m2cOqHePF7t2rv6zolyU5PR1rDaOiMXZnURIBj6Pghc62M3mxqAvqwbI= X-Received: by 2002:a05:6102:5108:b0:608:9a34:c8ea with SMTP id ada2fe7eead31-760e9e49872mr6923015137.10.1786161541530; Fri, 07 Aug 2026 20:59:01 -0700 (PDT) Received: from [192.168.100.6] ([2800:bf0:82:11a2:7ac4:1f2:947b:2b6]) by smtp.gmail.com with ESMTPSA id 71dfb90a1353d-5c40b212fa6sm1432936e0c.16.2026.08.07.20.58.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Aug 2026 20:59:01 -0700 (PDT) From: Kurt Borja Date: Fri, 07 Aug 2026 22:58:28 -0500 Subject: [PATCH v3 6/9] 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: <20260807-ads126x-v3-6-f89925d72792@gmail.com> References: <20260807-ads126x-v3-0-f89925d72792@gmail.com> In-Reply-To: <20260807-ads126x-v3-0-f89925d72792@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Linus Walleij , Bartosz Golaszewski , 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, linux-gpio@vger.kernel.org, Jonathan Cameron X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=6635; i=kuurtb@gmail.com; h=from:subject:message-id; bh=bIpvMMa4U2CGo++dRegyRF9eL9wseA8Sf0kiZsyR1Ek=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFllKytuvDb5+MLnwV+ul3VndxxITghzcPhh8LsgvdJFk ndra6xXRykLgxgXg6yYIkt7wqJvj6Ly3vodCL0PM4eVCWQIAxenAExkVRvD/+g9v6W2sUW4fbX7 uoNr1ar/mvY61/TdgxYFtl362JUdcpKRYbvf1P1Lan3c+zsu66tESZQJWTsWbeaM+Z3V48BhWdD OCwA= 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". Signed-off-by: Kurt Borja Reviewed-by: David Lechner --- drivers/iio/adc/ti-ads1262.c | 101 +++++++++++++++++++++++++++++++++++++++= ++-- 1 file changed, 98 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c index e2659941e1af..d5464b4f2bfb 100644 --- a/drivers/iio/adc/ti-ads1262.c +++ b/drivers/iio/adc/ti-ads1262.c @@ -98,6 +98,8 @@ #define ADS1262_IDACMUX_NO_CONN 0xB =20 #define ADS1262_IDACMAG_REG 0x0E +#define ADS1262_IDACMAG_MAG2_MASK GENMASK(7, 4) +#define ADS1262_IDACMAG_MAG1_MASK GENMASK(3, 0) =20 #define ADS1262_REFMUX_REG 0x0F #define ADS1262_REFMUX_RMUXP_MASK GENMASK(5, 3) @@ -205,12 +207,15 @@ struct ads1262_chip_info { =20 struct ads1262_channel { u8 data_rate; + 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; int offset; int scales[6][2]; size_t num_scales; @@ -277,6 +282,25 @@ 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, 2000000, + 2500000, 3000000 +}; + +static int ads1262_find_one(const int *array, size_t num_elements, int val) +{ + int i; + + for (i =3D 0; i < num_elements; i++) { + if (val =3D=3D array[i]) + break; + } + if (i =3D=3D num_elements) + return -EINVAL; + + return i; +} + static int ads1262_find_two(const int (*array)[2], size_t num_elements, in= t val, int val2) { @@ -433,9 +457,11 @@ static int ads1262_channel_enable(struct ads1262 *st, guard(mutex)(&st->chan_lock); =20 val =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_REFREV_MASK, chan->ref_reversal); ret =3D regmap_update_bits(st->regmap, ADS1262_MODE0_REG, ADS1262_MODE0_INPUT_CHOP_MASK | + ADS1262_MODE0_IDAC_CHOP_MASK | ADS1262_MODE0_REFREV_MASK, val); if (ret) return ret; @@ -456,6 +482,22 @@ static int ads1262_channel_enable(struct ads1262 *st, if (ret) return ret; =20 + val =3D FIELD_PREP(ADS1262_IDACMUX_MUX1_MASK, chan->idac_mux[0]) | + FIELD_PREP(ADS1262_IDACMUX_MUX2_MASK, chan->idac_mux[1]); + ret =3D regmap_update_bits(st->regmap, ADS1262_IDACMUX_REG, + ADS1262_IDACMUX_MUX1_MASK | + ADS1262_IDACMUX_MUX2_MASK, val); + if (ret) + return ret; + + val =3D FIELD_PREP(ADS1262_IDACMAG_MAG1_MASK, chan->idac_mag[0]) | + FIELD_PREP(ADS1262_IDACMAG_MAG2_MASK, chan->idac_mag[1]); + ret =3D regmap_update_bits(st->regmap, ADS1262_IDACMAG_REG, + ADS1262_IDACMAG_MAG1_MASK | + ADS1262_IDACMAG_MAG2_MASK, val); + if (ret) + return ret; + val =3D FIELD_PREP(ADS1262_REFMUX_RMUXN_MASK, chan->ref_n) | FIELD_PREP(ADS1262_REFMUX_RMUXP_MASK, chan->ref_p); return regmap_update_bits(st->regmap, ADS1262_REFMUX_REG, @@ -490,7 +532,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; @@ -1070,8 +1112,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]); @@ -1150,7 +1192,58 @@ 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, + "%s: failed to count excitation-channels\n", + fwnode_get_name(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, "%s: failed to read excitation-channels\= n", + fwnode_get_name(node)); + if (pins[0] > ADS1262_IDACMUX_NO_CONN || pins[1] > ADS1262_IDACMUX_NO_CO= NN) + return dev_err_probe(dev, -EINVAL, "%s: excitation-channels not in rang= e\n", + fwnode_get_name(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 =3D=3D -EOVERFLOW) + return dev_err_probe(dev, ret, + "%s: excitation-current-nanoamp size mismatch\n", + fwnode_get_name(node)); + if (ret) + return dev_err_probe(dev, ret, + "%s: failed to read excitation-current-nanoamp\n", + fwnode_get_name(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, + "%s: invalid excitation-current-nanoamp\n", + fwnode_get_name(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, + "%s: invalid excitation-current-nanoamp\n", + fwnode_get_name(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, "ti,idac-rotation"); chan->ref_reversal =3D fwnode_property_read_bool(node, "ti,reference-reve= rsal"); =20 return 0; @@ -1198,6 +1291,8 @@ static int ads1262_parse_channels(struct iio_dev *ind= io_dev) fwnode_get_name(node)); =20 st->channels[reg].data_rate =3D ADS1262_DR_20_SPS; + st->channels[reg].idac_mux[0] =3D ADS1262_IDACMUX_NO_CONN; + st->channels[reg].idac_mux[1] =3D ADS1262_IDACMUX_NO_CONN; =20 specs[reg].scan_index =3D reg; specs[reg].scan_type =3D (struct iio_scan_type) { --=20 2.55.0 From nobody Tue Sep 29 11:48:55 2026 Received: from mail-ua1-f49.google.com (mail-ua1-f49.google.com [209.85.222.49]) (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 A87183BED55 for ; Sat, 8 Aug 2026 03:59:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786161546; cv=none; b=rPiT+XAY78bwQk1qyfe7UunyyTG4CV6zK5oXS9KlkMM8FQpR79IpT93v1JEeBK2D4ca/wm4XVHllEIdJH2O8XsnxO/Jme2/9xjofEg4Edithg1PDJy01sbJ8uaDqo/LTbVnGKMR5L/+qd6jaHypGsXm9KJjkIafoJkh44RTQHaI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786161546; c=relaxed/simple; bh=lAS6V9MAqcWApu/3/HSXVhClPehcPza6w767sLpTNlI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Sa6MVaUEFR62y263XKqFgkvsY/MHItSOzWCUBdwuHEGKtJEkBlyA59/3g195Xt/PcYBsDcuIYWur+OkN1E5XaMRFA2k8rEk0SxzLOiFpX3akNIhc6sZEvQMxCzBn5UXSAR0qe8cRFgIP5YsIGW/VQcra3tEL5SNiYeUEcsaqUnw= 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=eriwJAdJ; arc=none smtp.client-ip=209.85.222.49 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="eriwJAdJ" Received: by mail-ua1-f49.google.com with SMTP id a1e0cc1a2514c-9773c6ea885so32390241.3 for ; Fri, 07 Aug 2026 20:59:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786161543; x=1786766343; 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=OCu9EEJYvjKKKw6KIIpKa31vtWBqeSGX25tRhPYIKmQ=; b=eriwJAdJqhVQSdJPAg9Zhe5Nporrn5spxvYz+yBLmNEXfdEx4mUfXPRKDDFkUQnV6Q 7YNXhPbaSiSVDIF6RL5jjkzGxiAhDXQQGNbiEz3EtLNFr2Bq5R/HrdsnqC/ft0iQFAkV O2Qq+0Mr3DeeAct67DkMZcy+WdElclncuHLPiyCdBMsZGQsl5RZMdUQSBG8tuG2HHl1s 2cY6Xvez7IGgfEr3hxvSv7vwiu0BG/ZN3o331A1kJVvBrU7jyHUgOC1gJE0G7hWYWJgt elOPfTpmsGTzliwWzPlbeBmP6j2vVI8RiZno2BnTiQXoPuolo8ONrq5CJc1RYio8l2Tg npvQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786161543; x=1786766343; 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=OCu9EEJYvjKKKw6KIIpKa31vtWBqeSGX25tRhPYIKmQ=; b=UNsuDUTKIUkN7Ck/QE/MjnEI8zEsYxMwgxXvDQx5CG+wdeC0zpjEAREkG+H1+9gPSU Gkf0N752/+BhqR3aDymDDo6hLDFPWmPQD5YUO3PkV4y2TN6JwjlPDnr54w6tEVhePFMz mEVQVkf4UVAa48seLdVP+kWlsX/ik9XTDoyoUVuWY5g9jD28G5wAXqTPOyyf0RmYCiSH ms/lTEufCgVGidDRs8CnDXGvc67zd2RCiAQDJGio+GFzlhkbAJGCCdWPL2YTu0ePrDE9 9mPnDAkOAopoOR/bzk1jKSI2D4aATgXep8A3ckWSbunHmCiyblIYHhNTGUAmjAmMziU9 yWnA== X-Forwarded-Encrypted: i=1; AHgh+Rp+aAmPcUiMi8UIP2r81SyY7uNCZrBgsFngvq237ohv8NJJD5ucJ5rbRD9jddCCptyBBQdqTMqhEphCsak=@vger.kernel.org X-Gm-Message-State: AOJu0YxhFhAkOTYM7ChJUeCdl9EDlCWBBzP7guELH1R4Bjix3Nu3eUS8 l/QSRo25f0ojuQgkSTJiNedkZ/ugzFRBzxSogFkDRm4Z5aAEDZwWbQ/b X-Gm-Gg: AR+sD12FS+vUYW4f2Zg0aTpLpXWGY5eFEvNHSam3C3AZF402BhIAoverf07HGq9tQxY egnpMhl0VZXB8yaCiL9SwGATiPOKWatIRnYvwNpDa762V/Lp0XHS6JaSlQFsYuFvNotY3AcV/fQ 90ey8DL7jVAM/yq3F2n8KGHGDCiyPi8/KL50mmSW1xAM3iZOWQMgMyYQXE2fai5Vg6YIyxTL97d gZvYKT5WFk+iTPlX5UUqoWWOt0w9oQkfmhgsyAplrTPUmYrnIcj1sSpGNoVR8d5uSH2ZlPIUFOq +Ipw0F6EWKtsXYaDP+VC37m1SBqqCqD6vv5aVXbEA/j50R4b2RThsPwlhw8LSRLQt+MXUr4es1f j8gVj38i1A/uQ6b25vC0wM2tw70qFmJsK0OFx0DimKolD1F/EzRdMixK8F4hDxqkgfqVa0lhwr2 oyGzYaqaFs/skM0o4TCIyWsJvgdz8ixkuUtMsg7PHUmDaO/zRNMEaZwYPOP1I= X-Received: by 2002:a05:6102:2c81:b0:737:9edc:36f8 with SMTP id ada2fe7eead31-760e6ed513amr7243312137.1.1786161543362; Fri, 07 Aug 2026 20:59:03 -0700 (PDT) Received: from [192.168.100.6] ([2800:bf0:82:11a2:7ac4:1f2:947b:2b6]) by smtp.gmail.com with ESMTPSA id 71dfb90a1353d-5c40b212fa6sm1432936e0c.16.2026.08.07.20.59.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Aug 2026 20:59:02 -0700 (PDT) From: Kurt Borja Date: Fri, 07 Aug 2026 22:58:29 -0500 Subject: [PATCH v3 7/9] 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: <20260807-ads126x-v3-7-f89925d72792@gmail.com> References: <20260807-ads126x-v3-0-f89925d72792@gmail.com> In-Reply-To: <20260807-ads126x-v3-0-f89925d72792@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Linus Walleij , Bartosz Golaszewski , 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, linux-gpio@vger.kernel.org, Jonathan Cameron X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=10087; i=kuurtb@gmail.com; h=from:subject:message-id; bh=lAS6V9MAqcWApu/3/HSXVhClPehcPza6w767sLpTNlI=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFllKyvkfCSWVm3YEpzlKewotyZ21ZILx5vnfpdM+bl6F tv/cxPzO0pZGMS4GGTFFFnaExZ9exSV99bvQOh9mDmsTCBDGLg4BWAiaWyMDKcCYj+/5WCaYVXY feg612nF/VvEp0Zz5XHxiz69dTn36XuG36wNK36VXH26f9kZ1XWHdhvk7/hdJXzAcFJpZOS1D5X 3/3MCAA== 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 | 264 +++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 266 insertions(+) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index dbf76427912b..b9b561be8347 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1845,6 +1845,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 d5464b4f2bfb..24a7ecb9fbd4 100644 --- a/drivers/iio/adc/ti-ads1262.c +++ b/drivers/iio/adc/ti-ads1262.c @@ -34,6 +34,9 @@ #include =20 #include +#include +#include +#include =20 #define ADS1262_OPCODE_NOP 0x00 #define ADS1262_OPCODE_RESET 0x06 @@ -225,6 +228,7 @@ struct ads1262_channel { struct ads1262 { struct spi_device *spi; struct regmap *regmap; + struct iio_trigger *trig; struct gpio_desc *reset_gpiod; struct gpio_desc *start_gpiod; unsigned long clk_rate; @@ -241,8 +245,16 @@ struct ads1262 { bool need_avss_uV; bool bipolar_supply; =20 + IIO_DECLARE_BUFFER_WITH_TS(__be32, scan_buffer, + ADS1262_MAX_CHANNEL_COUNT); + /* Protects transfer buffers and concurrent SPI transfers */ struct mutex xfer_lock; + struct spi_message msg; + struct spi_transfer xfer; + + u8 tx[11] __aligned(IIO_DMA_MINALIGN); + u8 rx[11] __aligned(IIO_DMA_MINALIGN); }; =20 static const u32 ads1262_data_rate_div[] =3D { @@ -708,10 +720,242 @@ static const struct iio_info ads1262_iio_info =3D { .debugfs_reg_access =3D ads1262_debugfs_reg_access, }; =20 +static int ads1262_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + unsigned int weight; + unsigned long i; + int ret; + + weight =3D bitmap_weight(indio_dev->active_scan_mask, + iio_get_masklength(indio_dev)); + + if (weight > 1) { + /* + * Multiple channels use software sequencing: a single + * contiguous transfer rewrites the per-channel configuration + * registers in two (non-contiguous) groups. + * + * Group 1: write protocol (2 bytes) + MODE0, MODE1, MODE2, + * INPMUX (4 registers). + * + * Group 2: write protocol (2 bytes) + IDACMUX, IDACMAG, + * REFMUX (3 registers). + * + * Total: 11 bytes + */ + st->xfer.len =3D 11; + } else { + /* + * A single channel is read by command (RDATA1), so the transfer + * holds the command byte plus the 4 conversion bytes. + * + * Total: 5 bytes + */ + st->xfer.len =3D 5; + + /* + * When only one channel is enabled, we can't really avoid SPI + * activity from happening when the auxiliary ADC is in use, + * thus we have to read from the data-holding register (command + * mode). + */ + memset(st->tx, 0, st->xfer.len); + st->tx[0] =3D ADS1262_OPCODE_RDATA1; + + 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; + + 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_postdisable(struct iio_dev *indio_dev) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + unsigned int weight; + + ads1262_dev_stop(st); + spi_unoptimize_message(&st->msg); + + weight =3D bitmap_weight(indio_dev->active_scan_mask, + iio_get_masklength(indio_dev)); + if (weight > 1) { + regcache_drop_region(st->regmap, ADS1262_MODE0_REG, + ADS1262_INPMUX_REG); + regcache_drop_region(st->regmap, ADS1262_IDACMUX_REG, + ADS1262_REFMUX_REG); + } + + return 0; +} + +static const struct iio_buffer_setup_ops ads1262_buffer_ops =3D { + .preenable =3D ads1262_buffer_preenable, + .postdisable =3D ads1262_buffer_postdisable, +}; + +static int ads1262_enable_and_read_last(struct ads1262 *st, + const struct iio_chan_spec *spec, + __be32 *val) +{ + struct ads1262_channel *chan; + int ret; + + lockdep_assert_held(&st->xfer_lock); + + if (spec) { + guard(mutex)(&st->chan_lock); + + chan =3D &st->channels[spec->scan_index]; + + /* Group 1: MODE0, MODE1, MODE2, INPMUX */ + 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, ADS1262_RUNMODE_CONTINUOUS) | + FIELD_PREP(ADS1262_MODE0_REFREV_MASK, chan->ref_reversal); + st->tx[3] =3D FIELD_PREP(ADS1262_MODE1_FILTER_MASK, ADS1262_FILTER_FIR); + 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); + + /* Group 2: IDACMUX, IDACMAG, REFMUX */ + 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); + } else { + memset(st->tx, 0, sizeof(st->tx)); + } + + ret =3D spi_sync(st->spi, &st->msg); + if (ret) + return ret; + + memcpy(val, st->rx, sizeof(*val)); + + return 0; +} + +static int ads1262_fill_buffer_mult(struct iio_dev *indio_dev) +{ + struct ads1262 *st =3D iio_priv(indio_dev); + unsigned int chan; + __be32 val; + 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) { + ret =3D ads1262_enable_and_read_last(st, &indio_dev->channels[chan], + &val); + if (ret) + return ret; + + /* + * After writing to the channel configuration registers, the + * conversion-cycle is restarted and the data registers are + * cleared. This means we have to reinit the completion after + * enabling to avoid reading stale data. + */ + reinit_completion(&st->drdy); + + if (i > -1) + st->scan_buffer[i] =3D val; + i++; + + ret =3D ads1262_wait_for_conversion(st); + if (ret) + return ret; + } + + return ads1262_enable_and_read_last(st, NULL, &st->scan_buffer[i]); +} + +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; @@ -1414,6 +1658,10 @@ static int ads1262_spi_probe(struct spi_device *spi) st->spi =3D spi; init_completion(&st->drdy); =20 + st->xfer.tx_buf =3D st->tx; + st->xfer.rx_buf =3D st->rx; + spi_message_init_with_transfers(&st->msg, &st->xfer, 1); + ret =3D devm_mutex_init(dev, &st->chan_lock); if (ret) return ret; @@ -1459,6 +1707,22 @@ static int ads1262_spi_probe(struct spi_device *spi) if (ret) return dev_err_probe(dev, ret, "failed to configure device\n"); =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", info->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' IRQ. --=20 2.55.0 From nobody Tue Sep 29 11:48:55 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 6B9AC3C1404 for ; Sat, 8 Aug 2026 03:59:06 +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=1786161548; cv=none; b=f76kRfKTraqyKKrSq0JcoxefyudhAxRaFzkWFjPN5Yd4hChnMwyooI6cdesrH6iJDS1900xY5M33hRE7fCPujYjD5stR77wdNcT8juJIeC0pz0/zEftC3wljWP7fZ3BmCBOMY98anNE/VdHDAfkIX1CgXy7bk59Wgq6JZUU48lg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786161548; c=relaxed/simple; bh=eW+qHE1g1yIqP4HICEETLIrGwlRb8wRg2/fNm4tOAkU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dwVf8JVWMSjdPf+/HgPLkiu8hODAoKybVYeCrvQOfFdoqWdDCOLawP32WUr8JSFGWX7pg9pZIKyemFAsrYr1MdwehQvq7m8y1lgvwmXjitXCHgG8GtTJ1vXnbLP7kl/+4kiP/kUQonKhq9zFQIMB2XGPLiNKi41PTn4P7fhGuzc= 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=Nd3yAujz; 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="Nd3yAujz" Received: by mail-vk1-f174.google.com with SMTP id 71dfb90a1353d-5c38568d9e1so93646e0c.3 for ; Fri, 07 Aug 2026 20:59:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786161545; x=1786766345; 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=NwC1tObfEFZljzYy9BprIEzEE722iBsLt2gGX9PnCo0=; b=Nd3yAujzXbZvMBVtkypTiN8vAiNfw0S9pCojJVwZx/DFKQfCmFyLfdFyeZszUtFT6A pc2GAuEgeyG6Dxu9JUbYAaWQr2EUc2vxRWHuOKKA6ZvsSqtnxtG6qxZMqW1s0ZvW5K0Q 2EeZBcAqq2AxCxcTk6EkVx168uB7TjdtFoeUsrbECL+9XJ9ubbcdGKhU8hdoUqSYRHGo cwIdVOZ6BV/JEJyFNX029HfU7DbOUqBB/RddxWkd3Nb6Cb+hZk6YH8Jg17izbP+wdlSJ DUG1iGpf2/kV0CkW0xmwNidnX18ZKvc0UDpMvR8BGfyNqKe1ctIHPifW0ej6lqE4AlNh DQlw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786161545; x=1786766345; 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=NwC1tObfEFZljzYy9BprIEzEE722iBsLt2gGX9PnCo0=; b=A4ZuDqGOMuhbGdEEEQsGXot24nTzcyWxrWmY+sGJ5nHuCAgbXDNanlbKiWg2X7yZz9 h6YYwpHyoQSrnQFCUPNNtntyPa3MohzXJ0It8oRGtwFYNhfwoK5EdbolOFV5XEmpjozq o4zo5E72fny7h5ipss7vyRPljF+U3BXfbswP8buCOtvdq9N2gGy3fY/b2NEzzl9Pm5HO K2d7ZpUzxGeUbrRXXGjP7PqzObcWplM9yo1t4mZmzlOUC9K4jvS4eM8hMcfVt+fitoE1 AA/o12mZJezb7OlugEwNVq5Z5UjQ9xYWM40tDZlwBovq7KrnMqmDK4nfhCIWoEPLtb/E DIzg== X-Forwarded-Encrypted: i=1; AHgh+Rrc/2Kp7cfc3VvG7CTyL/TBfmdr1ROEhJK4FLiIYd5cEe+L+L2FfNac51XGo4Dh+nSzijF7s19X+Uo0hvY=@vger.kernel.org X-Gm-Message-State: AOJu0Yx5NeWek6mgNHR+YHO6higEw2eddeZ51iSAzv6JxWNYVclmcZ8S 5ZDlWKrKqS/XhwZjKDnB1fpQX4h+6TgWxq+ZDzLBihvu/Xgq88pNolVF X-Gm-Gg: AR+sD10NY1g7a9mL5dvYXVfmZvZQQnhZyqXYVDWa9NEIAhT6qOkYajPwRJxUgXtdg6Q Yp2u8P4wnKLsDjZinEiCn5cEkfDup1FgXyIEv14uV0GsZ8sPT9gxJuJJO+qnfKZg/cS/OjQs4fT RIRdm6HAsW+9sv4fSFx6FkqHq4nrqCwjiWBcFQDEcwr0WnQWKW+RGtUS8eGhMrXnGTaFHQNcUON w5Gne7Nx5ZmJ6581HMCSSxn04FJMiD5/UzkbtybhHZaQkQnHBccLXMQAo4FxOgDI//IxiLXOKJ5 b6qkJfzVPKQpl6Jo6zxQsQZquEoaD7aZM4n5uqZSNnYslGsqsZV79gKP1EIU2iEAJv9IzhlHTzG gLA/MLSMnkAuLdE3SOqCgF0ba5u8CdPb3mlcR1yDHwzXVCVZ3qasBsWsFtHOL95Rnto8+tEayrc 0sz0VoWVktuHXJU12RsG6iuge19TvKFbsMMYgvYwe6mE+l6SWPbWVYxqnBDqA= X-Received: by 2002:a05:6102:3c8c:b0:740:2d81:c2a2 with SMTP id ada2fe7eead31-760e95439bdmr6959985137.10.1786161545250; Fri, 07 Aug 2026 20:59:05 -0700 (PDT) Received: from [192.168.100.6] ([2800:bf0:82:11a2:7ac4:1f2:947b:2b6]) by smtp.gmail.com with ESMTPSA id 71dfb90a1353d-5c40b212fa6sm1432936e0c.16.2026.08.07.20.59.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Aug 2026 20:59:04 -0700 (PDT) From: Kurt Borja Date: Fri, 07 Aug 2026 22:58:30 -0500 Subject: [PATCH v3 8/9] 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: <20260807-ads126x-v3-8-f89925d72792@gmail.com> References: <20260807-ads126x-v3-0-f89925d72792@gmail.com> In-Reply-To: <20260807-ads126x-v3-0-f89925d72792@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Linus Walleij , Bartosz Golaszewski , 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, linux-gpio@vger.kernel.org, Jonathan Cameron X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=3933; i=kuurtb@gmail.com; h=from:subject:message-id; bh=eW+qHE1g1yIqP4HICEETLIrGwlRb8wRg2/fNm4tOAkU=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFllKyvO6WdGbrvTt2BR5cN5Mx19G2uXd2kfsDQ9uNtu6 duN6zxPdZSyMIhxMciKKbK0Jyz69igq763fgdD7MHNYmUCGMHBxCsBEAsMYGWY8mVJwzVUn/DHT LqvkqRaWGd1Pq++k78w+YcXNGHs46ycjw8IDy84s/ThLcmFpcsvyOY6P7mgryF9Y03DaqO+q0Zn krRwA 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 | 90 ++++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 91 insertions(+) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index b9b561be8347..e5206438ac90 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1845,6 +1845,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 24a7ecb9fbd4..533574169b04 100644 --- a/drivers/iio/adc/ti-ads1262.c +++ b/drivers/iio/adc/ti-ads1262.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -961,6 +962,91 @@ static irqreturn_t ads1262_irq_handler(int irq, void *= dev_id) return IRQ_HANDLED; } =20 +static int ads1262_regulator_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_regulator_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_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct ads1262 *st =3D rdev_get_drvdata(rdev); + unsigned int val; + int ret; + + guard(mutex)(&st->xfer_lock); + + ret =3D regmap_read(st->regmap, ADS1262_POWER_REG, &val); + if (ret) + return ret; + + return field_get(ADS1262_POWER_VBIAS_MASK, val); +} + +static const struct regulator_ops ads1262_vbias_regulator_ops =3D { + .enable =3D ads1262_regulator_enable, + .disable =3D ads1262_regulator_disable, + .is_enabled =3D ads1262_regulator_is_enabled, +}; + +static const struct regulator_ops ads1262_refout_regulator_ops =3D { }; + +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; + + 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; @@ -1707,6 +1793,10 @@ static int ads1262_spi_probe(struct spi_device *spi) if (ret) return dev_err_probe(dev, ret, "failed to configure device\n"); =20 + ret =3D ads1262_register_regulators(st); + if (ret) + return ret; + ret =3D devm_iio_triggered_buffer_setup(dev, indio_dev, iio_pollfunc_store_time, ads1262_trigger_handler, --=20 2.55.0 From nobody Tue Sep 29 11:48:55 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 4B0313C2BA8 for ; Sat, 8 Aug 2026 03:59:08 +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=1786161550; cv=none; b=fLVWmaQsd//TUeGjGImkslNNQL4qm5M92eiJA49bPD9iHH8v8U85x2mwyS6kaqbvQHr08/w0TpdX8yY1DocgQTDPFb4iVOxr0/mhMYTKm7KGMunoVOrlJjgeXRMl6F57lCXxUYLh57i1OxAH/IL3mjPzBairRjUoEUAtFdd+jcw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786161550; c=relaxed/simple; bh=ALPm4wN0XxL4MAFfiFBimkAb2s7JRwqMzky26VfX7JM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mIdvrKVUSIv2fUWfIApSafa3EE/sjS2j3sm8+9W0CdIduawMd02GEafiP/aNi8oLcXuUfZOLDilISnCUpjEz8qd/z48pLrt2MpWYc11aNndkGluqP/u0Dj/XODCDQZDa4SIQ1IO3Hm5lvkzArlhq1i+OkC5e1hceb4NjgbGP+XQ= 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=VVhbSvW3; 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="VVhbSvW3" Received: by mail-vk1-f174.google.com with SMTP id 71dfb90a1353d-5c276bfce7eso192519e0c.2 for ; Fri, 07 Aug 2026 20:59:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786161547; x=1786766347; 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=+Z33c2/VIdQJHXYt//EgpTsqkZyaHvNkSYBF+LRNUwo=; b=VVhbSvW33O2Q7jd0o1t2l73Y/OFOskS8IYccyEO6ANNqlqmNv6RxnR93kXC8Rrv+n5 k9XgSQqlo/NAh1Z/2Qt1pr5px1c+Wwa5fSBsad93nyXw5g3pkBlVxQ+IJDAf0X1IBnC8 x+jOsk/JfO/sE2Awzo7vfPUT96QvWy1f9jjVZ1tqVV30Z19jshHRwPtK+29jSx2wQ1i9 aC3wMW0IVLss6icIJ77cFANq/w4S4MTvE4t/JHlZk7I5AAHd5Df3ix16mD/Uqwo3DMMp cZLQRdSGwYLDmupGnoQPmWF/dQrKlaIEYBj9aZVhmGKDbttjWwx9lycV4UXmU2eI1BnU pgjA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786161547; x=1786766347; 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=+Z33c2/VIdQJHXYt//EgpTsqkZyaHvNkSYBF+LRNUwo=; b=JLamSsuVU9iXcIF8EqRgpV93GGw5gWFjl6dbjJFG/fxE/FD5WHCV+YYdelkxU6BP+Q fndt8YUVcgiZQCx0xAz7XXZ0EzbYF+/kVGRZNIbHkKqD33RkRZQD0ccU2ultxAw+ts9o gEN7dkJ6aD8sz4lSxoGLQ2mkdWA+zft3o/59DUYrr9ST9YOGOrMLQ/Kf2HWduz1dKk8q gO88ZqD8wbPp0BEbxfnxK4MFfmUEbVhpLeNTlnDJ9IXhmfB4gHn0FLdshHsSOGvFlEls /HXE0sV4mEcpl6gWlCRdOfNxL46ZNQpJo084NwX83ZayeVNUNowJsyIb2lEJDp2dCBUA 61/A== X-Forwarded-Encrypted: i=1; AHgh+Ro5FpsMBSlekmGWe5hfOhinzMZWZptSz71acA0QnTgWpqXu/nLl3FqGOSNL0Rnosd3VfgIqeJgovLsOSRI=@vger.kernel.org X-Gm-Message-State: AOJu0YylbVR9ycSwRdwhcADCZ8PdP7yTy51SCkXe4DlNuIFPQjYQHY6Z YWM2nW/rEHrt/PbSZzQXTzyCzeUKZWjxskzUsVb1qMUhmMZqrAKcDNRR X-Gm-Gg: AR+sD11nKGADGKFrRpHn6wpqERJud8m0ddrxc785p15wgFgw7wzlaBn5JVROG3pVtZz nzBvkLx8+QvIuae3WOnd8H+0qE4inQfyBGyk7NADyU4CWLu0BStmKUhkFNJg455tncaKDFDP7EI s7NFY67v+sBM/wPUFjwL8lRJIUfphoJKcBzCHzY3cipkSnbhSjRV49t0/fexf7WO09UtHHDx43Z wIAqZg8IxP5AlMIz7I+8rVF7yhhJnG1Ji3Zx7U0xVBXkohfDr8POmysBzf1yf7+C180Az+NR8+X nJZeW/+QIBYA7NZIiHmut2TjXT295DkFWJpsXhwJ7kGlGhJVwUEEp74h3VuwLWnobMOrPzh2tzl fOLqwuhHZUKIv6Sft7MybirBb1hlMZxF4DAgBXC+p3FJZKO8hjNlyplSyOgyCZtnIcY2XKB+bpX ihEBCl3+AIwD5Dq8rN86QLpuvvFAUEvsNjCUezux95Gnfy+x69145WQ9lE1kpi X-Received: by 2002:a05:6122:e142:b0:5bf:bb2c:1328 with SMTP id 71dfb90a1353d-5c3d9068a9emr4114304e0c.3.1786161547188; Fri, 07 Aug 2026 20:59:07 -0700 (PDT) Received: from [192.168.100.6] ([2800:bf0:82:11a2:7ac4:1f2:947b:2b6]) by smtp.gmail.com with ESMTPSA id 71dfb90a1353d-5c40b212fa6sm1432936e0c.16.2026.08.07.20.59.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Aug 2026 20:59:06 -0700 (PDT) From: Kurt Borja Date: Fri, 07 Aug 2026 22:58:31 -0500 Subject: [PATCH v3 9/9] 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: <20260807-ads126x-v3-9-f89925d72792@gmail.com> References: <20260807-ads126x-v3-0-f89925d72792@gmail.com> In-Reply-To: <20260807-ads126x-v3-0-f89925d72792@gmail.com> To: Kurt Borja , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Linus Walleij , Bartosz Golaszewski , 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, linux-gpio@vger.kernel.org, Jonathan Cameron X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=1626; i=kuurtb@gmail.com; h=from:subject:message-id; bh=ALPm4wN0XxL4MAFfiFBimkAb2s7JRwqMzky26VfX7JM=; b=owGbwMvMwCUmluBs8WX+lTTG02pJDFllKyv+Bi7cp7Z2Ws4kW07VnctsRJW3+IbVM4j9nBazW Ei6USeqo5SFQYyLQVZMkaU9YdG3R1F5b/0OhN6HmcPKBDKEgYtTACbivJuRYeWM5Y9b32dbyz5U 835veax3o2ybb8nmVZWsf16svJQk9JeRYbXY1eC4ZllZh1OuHVLKgq8MKmM/688WLC+r3/Yjsia RHQA= 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 | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c index 533574169b04..238d803abc50 100644 --- a/drivers/iio/adc/ti-ads1262.c +++ b/drivers/iio/adc/ti-ads1262.c @@ -962,6 +962,27 @@ static irqreturn_t ads1262_irq_handler(int irq, void *= dev_id) return IRQ_HANDLED; } =20 +static int ads1262_common_mode_setup(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_optional(dev, name); + if (ret < 0 && ret !=3D -ENODEV) + return dev_err_probe(dev, ret, + "failed to get common mode supply: %s\n", name); + } + + return 0; +} + static int ads1262_regulator_enable(struct regulator_dev *rdev) { struct ads1262 *st =3D rdev_get_drvdata(rdev); @@ -1797,6 +1818,10 @@ static int ads1262_spi_probe(struct spi_device *spi) if (ret) return ret; =20 + ret =3D ads1262_common_mode_setup(st); + if (ret) + return ret; + ret =3D devm_iio_triggered_buffer_setup(dev, indio_dev, iio_pollfunc_store_time, ads1262_trigger_handler, --=20 2.55.0