From nobody Fri Oct 2 01:07:41 2026 Received: from mx0a-00128a01.pphosted.com (mx0a-00128a01.pphosted.com [148.163.135.77]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 192C847D95F; Thu, 6 Aug 2026 15:42:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.135.77 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786030948; cv=none; b=iV3xpZeRvHDSZVGWbg0ZTyBQNLLJuA17YIb3N1H0jR8dMznQJqDo+b5UMSfOWZQBXMoR7kmOfMTXkqZUsYN5ED4wrR9kAVDR6ZVuZ/tAOVU2Dvs8PQRDM7uylfGvckNLYmonhHK5R/m2+dtF5ABctQeXHPbj6+lu1RS7/hzNUa8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786030948; c=relaxed/simple; bh=smRaehSFZ/4fAcMgD1DrTYoviIxwo9Mv3/WwxO4Gbog=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=XwS89R1ac4XBu9CaolV7aI3Nnq13jAvDi4rI9ByfM/d0XyeA/hXBJxd6WDBOM9J+nLeNQz4e6MM6TX3AJSO7a8wlmeAsaMpr3fvCxH+4+rnmE1x5kSd6XXallyRyHhg6Ti3Fvi3ot0FOqAygL9WKSEBnREP2DUznC0EVIeFe+AU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=analog.com; spf=pass smtp.mailfrom=analog.com; dkim=pass (2048-bit key) header.d=analog.com header.i=@analog.com header.b=j/QgglpM; arc=none smtp.client-ip=148.163.135.77 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=analog.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=analog.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=analog.com header.i=@analog.com header.b="j/QgglpM" Received: from pps.filterd (m0167088.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 676EqFrO4057001; Thu, 6 Aug 2026 11:42:06 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=analog.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=DKIM; bh=kDWgm lFmKShVLusXyeZTl3IeuXVQ0ufd5NvZsBKoDGQ=; b=j/QgglpMZJJiZHj7kAblT ebABBwKFtkpkB0BR4Te4Vi3YR10Jbv28T+++BrCMd4r1q+a12EWSvi0MbFvBbai8 OZEeqdgoK0lghvhn+0zlGi5b9Oo+EVj3lH7uZcHtnNabqNdVhLpCEBs8wK2cOqkT 2XQwNfRxYawIkoBAu+xgyGfDfcG5577j724n3/ZH3m0OjVtxFKExe7EuBD5jAj+2 gBlqKUavxW4e2mM6VZTJuxbNIDjqhjiQgFHeSpzs5VCFJVM/MvJ4lVU46l6kmb9k MvAEBUyfB728hX38o90LQubdCqUMCrtFjACxzKvEq8z5U5TgWU7qcQwLtXU1usoF Q== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4fvp4ttnny-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 06 Aug 2026 11:42:06 -0400 (EDT) Received: from ASHBMBX9.ad.analog.com (ASHBMBX9.ad.analog.com [10.64.17.10]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 676Fg5Mm007029 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 6 Aug 2026 11:42:05 -0400 Received: from ASHBCASHYB5.ad.analog.com (10.64.17.133) by ASHBMBX9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Thu, 6 Aug 2026 11:42:04 -0400 Received: from ASHBMBX9.ad.analog.com (10.64.17.10) by ASHBCASHYB5.ad.analog.com (10.64.17.133) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Thu, 6 Aug 2026 11:42:04 -0400 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server id 15.2.1748.37 via Frontend Transport; Thu, 6 Aug 2026 11:42:04 -0400 Received: from HYB-e1y2fvUQ3cx.ad.analog.com ([10.32.223.174]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 676FfcgY008127; Thu, 6 Aug 2026 11:41:57 -0400 From: Janani Sunil Date: Thu, 6 Aug 2026 17:41:20 +0200 Subject: [PATCH v2 1/7] dt-bindings: iio: adc: Add AD7768 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: <20260806-ad7768-driver-v2-1-027ac5e2a641@analog.com> References: <20260806-ad7768-driver-v2-0-027ac5e2a641@analog.com> In-Reply-To: <20260806-ad7768-driver-v2-0-027ac5e2a641@analog.com> To: =?utf-8?q?Nuno_S=C3=A1?= , Michael Hennerich , Jonathan Cameron , "David Lechner" , Andy Shevchenko , "Rob Herring" , Krzysztof Kozlowski , "Conor Dooley" , Olivier Moysan , Philipp Zabel , Linus Walleij , Bartosz Golaszewski , Jonathan Corbet , Shuah Khan , Michael Walle CC: , , , , , , , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Janani Sunil X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786030898; l=12423; i=janani.sunil@analog.com; s=20260507; h=from:subject:message-id; bh=smRaehSFZ/4fAcMgD1DrTYoviIxwo9Mv3/WwxO4Gbog=; b=RWgm+PKOSptCThI+f8DMvKMzdWWOi7fOZHENHQDn3nz7oydGRgRLks7bXoKAFvGfEKlqITxju z4i+cOZJtzWBRimOQ51F8yMW1hUvwV5X4EEHKciMOS4VB4otGOaQVzB X-Developer-Key: i=janani.sunil@analog.com; a=ed25519; pk=e25MyjRLPY3RWrYm/LrJ+/+t1MZJUbkgIW5CZg+g+hA= X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-ORIG-GUID: x2OwXJTYSC8P4CFd0cgaxpWZWq4iHS0K X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODA2MDEyMSBTYWx0ZWRfX3Od0tQmTB0Lq qnO5b1hqAxot2UgWM9cAr6AGpuPdT9tBXEzSxSZdzdmn3REeahjQeXsBwVUmeC+mF0w+XYBa7As BntAaUkWAt1387dhWWWn4xGVJctzF1XiMMc4lSitnrX2QfSI5IhrdevIPCJKzXz/WCYdWAtMStG v4PjV++URS6N+myEsLWglpeUY2hq+4P8zvuqx5Opucc/BvI9PqNCWsknjkMVRqV3MtSuku7JTIb H9Mzy9sFaaj/+N/TPg2hboMWUqWsLqCH9aW0G8MvYjRL4JeXyWGXSA8BfPMsPvVS600pE5aUTde eTXq2R9bosMDnp/vXbzqxOHGW9kqdIFBqvtjBM/B/77QGBu1KxccOk5thT0n2LE6pNi7Pn7t8lK fMDCd2FXCTGnTpsU/mVBnGywVy3sW8m/xdRU6TJO8WCd3AXl2+PK4hgjZeN13Qkh1l6ReF9cdzN rK1+obbmCiro/Vbd7ag== X-Authority-Analysis: v=2.4 cv=CIYamxrD c=1 sm=1 tr=0 ts=6a74ab4e cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=uXIjobp8t2wMuQ0fPvqm:22 a=gEfo2CItAAAA:8 a=gAnH3GRIAAAA:8 a=NEAV23lmAAAA:8 a=VwQbUJbxAAAA:8 a=pGLkceISAAAA:8 a=-5bBmU6Px0lr29W57isA:9 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 a=sptkURWiP4Gy88Gu7hUp:22 X-Proofpoint-GUID: x2OwXJTYSC8P4CFd0cgaxpWZWq4iHS0K X-Proofpoint-Spam-Info: AW1haW4tMjYwODA2MDEyMSBTYWx0ZWRfX3Cz4YeKFJ11Q mK2Mk1yX1xKjhxujq2mVKyQxWzPxca1ev3xtg20nD96wsjzUiKslxTmfLjXUVHkVBvBeYwQCHXH +oZ26fUo7zWsaF8Jvx2XaB5f/Q/lCptXRnXaAD3Dpd909jM+kWtC X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-06_01,2026-08-05_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 bulkscore=0 clxscore=1015 adultscore=0 malwarescore=0 suspectscore=0 lowpriorityscore=0 spamscore=0 priorityscore=1501 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2608060121 Devicetree Bindings for AD7768-4 (4 channel) and AD7768 (8 channel) simultaneous sampling ADCs. Signed-off-by: Janani Sunil --- .../devicetree/bindings/iio/adc/adi,ad7768.yaml | 343 +++++++++++++++++= ++++ MAINTAINERS | 7 + 2 files changed, 350 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7768.yaml b/Do= cumentation/devicetree/bindings/iio/adc/adi,ad7768.yaml new file mode 100644 index 000000000000..8688b94c1ec0 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7768.yaml @@ -0,0 +1,343 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7768.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD7768 and AD7768-4 ADC + +maintainers: + - Janani Sunil + +description: | + The AD7768 is an 8-channel, 24-bit simultaneous sampling ADC with config= urable + power and performance modes. The AD7768-4 is a 4-channel version. + + This binding covers SPI mode only (register access via SPI). Pin control= mode, + where configuration is set via hardware pins rather than SPI registers, = is not + supported. + + The io-backend represents the high-speed data output interface, consumin= g the + DOUTx data lines, DCLK (data clock), and DRDY (data ready) signals. + + Datasheet at: + https://www.analog.com/media/en/technical-documentation/data-sheets/ad= 7768.pdf + + HDL reference design: + https://github.com/analogdevicesinc/hdl/tree/main/projects/ad7768evb + +properties: + compatible: + enum: + - adi,ad7768 + - adi,ad7768-4 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + description: + Master clock (MCLK). Can be supplied as a CMOS clock on the XTAL2/MC= LK + pin, a crystal oscillator connected between the XTAL1 and XTAL2 pins= , or + an LVDS differential clock on the XTAL1/XTAL2 pin pair. The clock so= urce + is selected by the CLK_SEL hardware pin. + + avdd1-supply: + description: + Analog supply voltage for the AVDD1A and AVDD1B pins (5V =C2=B1 10% = with + respect to AVSS). Powers the analog front end, reference input, and + common-mode output circuitry. Both pins must be tied to the same + potential. + + avss-supply: + description: + Negative analog supply rail for the AVSS1A, AVSS1B, AVSS2A, AVSS2B, + and AVSS pins. This rail is referenced to DGND and all AVSS pins must + be tied to the same potential. In single-supply operation AVSS is + nominally 0V; in split-supply operation it can range from 0V to + -2.75V with respect to DGND. + + avdd2-supply: + description: + Analog supply voltage for the AVDD2A and AVDD2B pins (2V to 5.5V with + respect to AVSS). Connects to internal 1.8V analog LDO regulators th= at + power the ADC core. Both pins must be tied to the same potential. + + iovdd-supply: + description: + Digital supply voltage IOVDD (2.25V to 3.6V with respect to DGND). + Sets the logic levels for all interface pins and powers the digital + processing core via an internal LDO. For 1.8V operation (1.72V to + 1.88V), IOVDD must be tied to the DREGCAP pin. + + ref1-supply: + description: + Differential reference voltage supply for the REF1+/REF1- input pair. + REF1+ voltage range is from (AVSS + 1V) to AVDD1; REF1- voltage range + is from AVSS to (AVDD1 - 1V). The differential reference voltage ran= ge + is 1V to |AVDD1 - AVSS|. On the AD7768 this reference is used for + channels 0 to 3; on the AD7768-4 for channels 0 and 1. + + ref2-supply: + description: + Differential reference voltage supply for the REF2+/REF2- input pair. + REF2+ voltage range is from (AVSS + 1V) to AVDD1; REF2- voltage range + is from AVSS to (AVDD1 - 1V). The differential reference voltage ran= ge + is 1V to |AVDD1 - AVSS|. On the AD7768 this reference is used for + channels 4 to 7; on the AD7768-4 for channels 2 and 3. + + reset-gpios: + maxItems: 1 + description: GPIO connected to the active-low RESET pin + + start-gpios: + maxItems: 1 + description: + GPIO connected to the START pin. An active-low pulse on this pin + synchronizes the device to other AD7768 devices. When not used, this + pin must be tied to a logic high level through a pull-up resistor. + When used, SYNC_OUT must be wired back to SYNC_IN on all devices in + the synchronization chain. + + sync-in-gpios: + maxItems: 1 + description: + GPIO connected to the SYNC_IN pin. Receives the synchronization pulse + generated on SYNC_OUT in response to a START pulse. Must be synchron= ous + to the MCLK clock domain. In multi-device or daisy-chained systems, + two successive synchronization pulses must be applied to guarantee a= ll + ADCs are synchronized. + + sync-out-gpios: + maxItems: 1 + description: + GPIO connected to the SYNC_OUT pin. Outputs a synchronization pulse + synchronous to MCLK in response to a START pulse or SPI_SYNC command. + In single-device configurations this pin must be wired back to SYNC_= IN. + In multi-device configurations it can be routed to the SYNC_IN pins = of + all devices in the chain. + + gpio-controller: true + + '#gpio-cells': + const: 2 + + adi,data-lines-number: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [1, 2, 4, 8] + description: + Number of DOUTx lines used for the high-speed data output interface + (distinct from the SPI control interface). AD7768 supports 1, 2, or 8 + lines; AD7768-4 supports 1 or 4 lines. Defaults to the maximum number + of lines for the selected variant if omitted. + + regulators: + type: object + description: Container for the on-chip VCM regulator. + properties: + vcm-output: + type: object + description: + The VCM pin provides a buffered common-mode voltage output used = to + bias the analog inputs. It supports three fixed output levels of + 1650000 uV, 2500000 uV, and 2140000 uV, as well as a + supply-dependent (AVDD1 - AVSS) / 2 output derived from + avdd1-supply. Select the voltage by setting regulator-min-microv= olt + and regulator-max-microvolt to the same value. Use + regulator-always-on when no DT consumer node references the VCM + output. The VCM circuitry is associated with channel 0. When VCM= is + used externally, channel@0 must be present and kept enabled beca= use + placing channel 0 in standby disables the VCM output. + $ref: /schemas/regulator/regulator.yaml# + unevaluatedProperties: false + additionalProperties: false + + io-backends: + maxItems: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + "^channel@[0-7]$": + type: object + description: | + Represents the external channels which are connected to the device. + AD7768 supports channels 0-7, AD7768-4 supports channels 0-3. + + properties: + reg: + minimum: 0 + maximum: 7 + description: The channel number + + adi,prechargebuf-pos-enable: + type: boolean + description: Enable positive input precharge buffer + + adi,prechargebuf-neg-enable: + type: boolean + description: Enable negative input precharge buffer + + adi,refbuf-pos-enable: + type: boolean + description: Enable positive reference buffer + + adi,refbuf-neg-enable: + type: boolean + description: Enable negative reference buffer + + required: + - reg + + additionalProperties: false + +required: + - compatible + - reg + - clocks + - avdd1-supply + - avss-supply + - avdd2-supply + - iovdd-supply + - ref1-supply + - ref2-supply + - io-backends + +dependencies: + gpio-controller: + - '#gpio-cells' + '#gpio-cells': + - gpio-controller + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + - if: + properties: + compatible: + contains: + const: adi,ad7768-4 + then: + properties: + adi,data-lines-number: + enum: [1, 4] + patternProperties: + "^channel@[0-3]$": + properties: + reg: + maximum: 3 + "^channel@[4-7]$": false + else: + properties: + adi,data-lines-number: + enum: [1, 2, 8] + +unevaluatedProperties: false + +examples: + - | + #include + + spi { + #address-cells =3D <1>; + #size-cells =3D <0>; + + adc@0 { + compatible =3D "adi,ad7768"; + reg =3D <0>; + spi-max-frequency =3D <1000000>; + + avdd1-supply =3D <&avdd1_regulator>; + avss-supply =3D <&avss_regulator>; + avdd2-supply =3D <&avdd2_regulator>; + iovdd-supply =3D <&iovdd_regulator>; + ref1-supply =3D <&ref1_regulator>; + ref2-supply =3D <&ref2_regulator>; + reset-gpios =3D <&gpio0 86 GPIO_ACTIVE_LOW>; + + clocks =3D <&ad7768_mclk>; + + adi,data-lines-number =3D <8>; + gpio-controller; + #gpio-cells =3D <2>; + + io-backends =3D <&iio_backend>; + + #address-cells =3D <1>; + #size-cells =3D <0>; + + channel@0 { + reg =3D <0>; + adi,prechargebuf-pos-enable; + adi,refbuf-pos-enable; + }; + + channel@1 { + reg =3D <1>; + adi,prechargebuf-pos-enable; + adi,prechargebuf-neg-enable; + adi,refbuf-pos-enable; + adi,refbuf-neg-enable; + }; + + channel@7 { + reg =3D <7>; + adi,prechargebuf-pos-enable; + adi,refbuf-pos-enable; + }; + }; + }; + + - | + spi { + #address-cells =3D <1>; + #size-cells =3D <0>; + + adc@1 { + compatible =3D "adi,ad7768-4"; + reg =3D <1>; + spi-max-frequency =3D <1000000>; + + avdd1-supply =3D <&avdd1_regulator>; + avss-supply =3D <&avss_regulator>; + avdd2-supply =3D <&avdd2_regulator>; + iovdd-supply =3D <&iovdd_regulator>; + ref1-supply =3D <&ref1_regulator>; + ref2-supply =3D <&ref2_regulator>; + + clocks =3D <&ad7768_mclk>; + + adi,data-lines-number =3D <4>; + + io-backends =3D <&iio_backend>; + + #address-cells =3D <1>; + #size-cells =3D <0>; + + regulators { + vcm-output { + regulator-name =3D "vcm-output"; + regulator-min-microvolt =3D <2140000>; + regulator-max-microvolt =3D <2140000>; + regulator-always-on; + }; + }; + + channel@0 { + reg =3D <0>; + adi,prechargebuf-pos-enable; + adi,refbuf-pos-enable; + }; + + channel@3 { + reg =3D <3>; + adi,prechargebuf-pos-enable; + adi,refbuf-pos-enable; + }; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 2b1ec46c5919..d667a0411f28 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1633,6 +1633,13 @@ F: Documentation/devicetree/bindings/iio/adc/adi,ad7= 768-1.yaml F: drivers/iio/adc/ad7768-1.c F: include/dt-bindings/iio/adc/adi,ad7768-1.h =20 +ANALOG DEVICES INC AD7768 DRIVER +M: Janani Sunil +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/adc/adi,ad7768.yaml + ANALOG DEVICES INC AD7780 DRIVER M: Michael Hennerich M: Renato Lui Geh --=20 2.43.0 From nobody Fri Oct 2 01:07:41 2026 Received: from mx0a-00128a01.pphosted.com (mx0a-00128a01.pphosted.com [148.163.135.77]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9B88747FAE8; Thu, 6 Aug 2026 15:42:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.135.77 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786030950; cv=none; b=c41TSSxkRqmVjqsrLfpcR9ELEO8Qg2VtQymb/r5JLVUrB4iaf1ikxmfKbj8pUHU9OM8+5vDEuQMAbQAEgee/pAsvW8+t6n/XZk3XQRSZtVeK2lhMx/FusHQDU7GMcLPdVvdkcmYZzND3AMGXm/P4qQPoxCyuH5A5zqymITwQIZI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786030950; c=relaxed/simple; bh=Ppp+RGxCEecjTpxXjCNm4l8VHRbYg8JEe6sv0mNQS5I=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=Cmbzq6NHlkZM3laNepaBV+42GkcwqN5bLHG1vASClHFu4ZAjYcJ6S54mVjk8jFRlIdsUDWC8Z1+MzdhHqJhRun+fucMQ03uo9T9hXJNgCndewtN+tdy1fGfY9yfoHUW4Cn9LMBn8n3+x3/WAfyAUmUWBTp4kN1uIsNPzbTdvxe8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=analog.com; spf=pass smtp.mailfrom=analog.com; dkim=pass (2048-bit key) header.d=analog.com header.i=@analog.com header.b=risK3yGN; arc=none smtp.client-ip=148.163.135.77 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=analog.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=analog.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=analog.com header.i=@analog.com header.b="risK3yGN" Received: from pps.filterd (m0516787.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 676EposQ3853946; Thu, 6 Aug 2026 11:42:10 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=analog.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=DKIM; bh=7KDq9 azkBxHmggf+i7QO8gZmXPtaA+gV7wWItUf68f0=; b=risK3yGNFQ+GmZWjiFDk1 Ti8wTUDCXJFKri+1Q8+O9rNPXKyszZ1dIk4nRhLv6ll5nEWyHw+Damkx6ICjJD6R Q7TTjXsEPoRiAK/BmgNIuJ9C75Enbg0TwzmZmQGVRpbnhXE1WS4nVMBbx0LWBM8O Dgjd/MppL20ZDS3TukCz6e/Owy2H3BseOIwnUmQNLt6Zso71VTNnjtUU/MdzjHTq dXY2mt48bCKH8NUIBokUifW/dYG3TtbI9VSfUIweIerRsaxb3AwUgVepVM1s4SkZ DS9gmPaErEzj5PbrY+33MLL9mawjL590iLn7E4JIWQgQ8wELiNwDvQYMiRJQpBvK g== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4fvrcpsf6w-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 06 Aug 2026 11:42:09 -0400 (EDT) Received: from ASHBMBX8.ad.analog.com (ASHBMBX8.ad.analog.com [10.64.17.5]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 676Fg8wZ007038 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 6 Aug 2026 11:42:08 -0400 Received: from ASHBMBX8.ad.analog.com (10.64.17.5) by ASHBMBX8.ad.analog.com (10.64.17.5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Thu, 6 Aug 2026 11:42:08 -0400 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx8.ad.analog.com (10.64.17.5) with Microsoft SMTP Server id 15.2.1748.37 via Frontend Transport; Thu, 6 Aug 2026 11:42:08 -0400 Received: from HYB-e1y2fvUQ3cx.ad.analog.com ([10.32.223.174]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 676FfcgZ008127; Thu, 6 Aug 2026 11:42:00 -0400 From: Janani Sunil Date: Thu, 6 Aug 2026 17:41:21 +0200 Subject: [PATCH v2 2/7] iio: backend: Add support for CRC 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: <20260806-ad7768-driver-v2-2-027ac5e2a641@analog.com> References: <20260806-ad7768-driver-v2-0-027ac5e2a641@analog.com> In-Reply-To: <20260806-ad7768-driver-v2-0-027ac5e2a641@analog.com> To: =?utf-8?q?Nuno_S=C3=A1?= , Michael Hennerich , Jonathan Cameron , David Lechner , Andy Shevchenko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan , Philipp Zabel , Linus Walleij , Bartosz Golaszewski , Jonathan Corbet , Shuah Khan , Michael Walle CC: , , , , , , , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Janani Sunil X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786030898; l=3865; i=janani.sunil@analog.com; s=20260507; h=from:subject:message-id; bh=Ppp+RGxCEecjTpxXjCNm4l8VHRbYg8JEe6sv0mNQS5I=; b=wOO24ZFDKCYTk6g99J39Q97icVxqaqa2MplgRqM4jsaNXq2IJcXy6k7ld4WXV30g5iBjWIirN aGKGwiGrniuB7SemufYNEOjl0mMCQowwMdzY3mQL83jSGl4xTLXk4oz X-Developer-Key: i=janani.sunil@analog.com; a=ed25519; pk=e25MyjRLPY3RWrYm/LrJ+/+t1MZJUbkgIW5CZg+g+hA= X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-GUID: R8qWMSfG2MiJ1mYtiNv5IbmryTh0ZlGm X-Proofpoint-Spam-Info: AW1haW4tMjYwODA2MDEyMSBTYWx0ZWRfX382Qf2109h5I aU0NAzxVytJDUW1hws4jx+8HMz83tMljEDSyCQFjt5hqyruBGEEFUxbPpzTZcbcF/ODuXvc3czn s2nWGEIBVYECvLBZAxNt3oBeMIBaCgMVLHeKSF3IXtYqGThfoG5F X-Proofpoint-ORIG-GUID: R8qWMSfG2MiJ1mYtiNv5IbmryTh0ZlGm X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODA2MDEyMSBTYWx0ZWRfX5vDD6oSrySvr lzDbBfoFI1xY8rK8PJPkYFZxQIxoLLlmxtfDQOEadfQ0Pf8hb3pags7Die16pb4Gn6yBtg7FULI wnO8Prp03z+k9Z/vrDXTLwKEYUp3cm7C49uHV7Yha4yGOCgPBM2HOMp1/VCi3Nt1wDG1SHhkVMV VvcGDeXMwj26caiNmN44STl7flwQuDpKW+PBm1z0Fm8/+a7c+wLKmiXsJVxoWEut37afSaUA4iO IloJk6Up+M4QdC/AaYQoP+TPJoI81XWqxW8aBl8aa9nu2y6JYURf8ungYe5B2LK8RHWIQAKMvF6 7p8UNNB2AN+8KKgVYxxKSEXacpF2t+PmYzK2TtIQRNndVlpRVosdbEBM2/s9cIGhIMdKa61vbAx hp5fsh/G1gotpE4Xd1x+ztuJgKSQgy11pZV8pI/nU7pV/VGpmmMudTFXsr7m9qJwAA7JWagDV2+ W8psZjWxIw7ZaLX7WFw== X-Authority-Analysis: v=2.4 cv=IPwyzAvG c=1 sm=1 tr=0 ts=6a74ab51 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=OmVn7CZJonkx5R5zMQLL:22 a=gAnH3GRIAAAA:8 a=KKt7U01DjHU_5c1eSo8A:9 a=QEXdDO2ut3YA:10 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-06_01,2026-08-05_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1011 priorityscore=1501 impostorscore=0 lowpriorityscore=0 phishscore=0 malwarescore=0 bulkscore=0 spamscore=0 suspectscore=0 adultscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2608060121 Add a backend operation to enable or disable Cyclic Redundancy Check processing for data integrity verification. When enabled, the backend will generate, verify, or process CRC information for data samples transmitted over the interface, allowing the host to detect corrupted samples. Signed-off-by: Janani Sunil --- drivers/iio/industrialio-backend.c | 33 +++++++++++++++++++++++++++++++++ include/linux/iio/backend.h | 6 ++++++ 2 files changed, 39 insertions(+) diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-= backend.c index f7a4be8ec320..792c2333b057 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -886,6 +886,39 @@ int iio_backend_num_lanes_set(struct iio_backend *back= , unsigned int num_lanes) } EXPORT_SYMBOL_NS_GPL(iio_backend_num_lanes_set, "IIO_BACKEND"); =20 +/** + * iio_backend_crc_enable - Enable the CRC generation. + * @back: Backend device + * + * Enable Cyclic Redundancy Check processing for data integrity verificati= on. + * When enabled, the backend will generate, verify, or process CRC informa= tion + * for data samples transmitted over the interface. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_crc_enable(struct iio_backend *back) +{ + return iio_backend_op_call(back, crc_enable); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_crc_enable, "IIO_BACKEND"); + +/** + * iio_backend_crc_disable - Disable the CRC generation. + * @back: Backend device + * + * Disable Cyclic Redundancy Check processing. When disabled, the backend = will + * stop generating, verifying, or processing CRC information for data samp= les. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_crc_disable(struct iio_backend *back) +{ + return iio_backend_op_call(back, crc_disable); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_crc_disable, "IIO_BACKEND"); + /** * iio_backend_ddr_enable - Enable interface DDR (Double Data Rate) mode * @back: Backend device diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h index 3f95ed1fdf9e..eddaddb47bea 100644 --- a/include/linux/iio/backend.h +++ b/include/linux/iio/backend.h @@ -133,6 +133,8 @@ enum iio_backend_capabilities { * @filter_type_set: Set filter type. * @interface_data_align: Perform the data alignment process. * @num_lanes_set: Set the number of lanes enabled. + * @crc_enable: Enable CRC generation and verification. + * @crc_disable: Disable CRC generation and verification. * @ddr_enable: Enable interface DDR (Double Data Rate) mode. * @ddr_disable: Disable interface DDR (Double Data Rate) mode. * @data_stream_enable: Enable data stream. @@ -189,6 +191,8 @@ struct iio_backend_ops { enum iio_backend_filter_type type); int (*interface_data_align)(struct iio_backend *back, u32 timeout_us); int (*num_lanes_set)(struct iio_backend *back, unsigned int num_lanes); + int (*crc_enable)(struct iio_backend *back); + int (*crc_disable)(struct iio_backend *back); int (*ddr_enable)(struct iio_backend *back); int (*ddr_disable)(struct iio_backend *back); int (*data_stream_enable)(struct iio_backend *back); @@ -237,6 +241,8 @@ int iio_backend_filter_type_set(struct iio_backend *bac= k, enum iio_backend_filter_type type); int iio_backend_interface_data_align(struct iio_backend *back, u32 timeout= _us); int iio_backend_num_lanes_set(struct iio_backend *back, unsigned int num_l= anes); +int iio_backend_crc_enable(struct iio_backend *back); +int iio_backend_crc_disable(struct iio_backend *back); int iio_backend_ddr_enable(struct iio_backend *back); int iio_backend_ddr_disable(struct iio_backend *back); int iio_backend_data_stream_enable(struct iio_backend *back); --=20 2.43.0 From nobody Fri Oct 2 01:07:41 2026 Received: from mx0a-00128a01.pphosted.com (mx0a-00128a01.pphosted.com [148.163.135.77]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E283B47A0DA; Thu, 6 Aug 2026 15:42:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.135.77 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786030948; cv=none; b=Vxj3+DMSRSJEoSBVj2hboMeM5MJgUuoaoWhBnQ8TIibrlvTFQ1EQQmkEuiyPPRVOYX1RxiBLz6qLmtijfflvY3ZRSJGlKe0K0iYel6cQqdw0wkk2z6BFOeXt2jbeo81A9VXMB3Y40PEg8zT3s6cKWqsYgZjCra+cz82kIg/+cA8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786030948; c=relaxed/simple; bh=vCQ4zk/7TsszIXYdGJAehIA0dZS4zuEvaqQDNSqXRk4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=NTriS2AeSvShDD2Yq077hysXI5fdpkMadZ1vIVy62yCwLSkg/vpsxlZQa5alR0mp607I846MjF8YdksU9VOGYZQgkssDvCpA2K5thxU1gd9cETHBN4fMD3bzUCo5uKoXoE/rJXfpOxrnkyThZq0EgFhIpIffptolWbQs5CPJMmg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=analog.com; spf=pass smtp.mailfrom=analog.com; dkim=pass (2048-bit key) header.d=analog.com header.i=@analog.com header.b=0NZnan38; arc=none smtp.client-ip=148.163.135.77 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=analog.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=analog.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=analog.com header.i=@analog.com header.b="0NZnan38" Received: from pps.filterd (m0167088.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 676EqFrP4057001; Thu, 6 Aug 2026 11:42:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=analog.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=DKIM; bh=PeRG3 Lstnxpw1Y7OeLdIz7GKXdXl7eDAPDbdun9o4wI=; b=0NZnan38UbDKXr2E2RS5l 4blb1Fad8vsP7n0SiGqcSrBolpPjICW9ovVahI2cAmQYd3Eg5ka3zb5DviFStzJe EFi9FlYxt0GbZr8xC7uHZEPopJfFoBwixM7LqWBUCeC+jOr4XhndiCbnTo/qYCZ5 O0Uv62y3UwHWsqBfdjyhyC99UHqLZ+3zVkMrkyxBtGwqzYf/AOdEU/hvpfwbb0GF DlUC00alXB3NVoswZ2yztAkg+8c4SgKio5gGQXzt+D+nGA6O2N855JPJ4J0lOxCl ZAgyKR1o3ZW//eKXtRDPUBrlAnAy+JH0lEZ3/Mis5dqsw2ye03aaR4zTzY+2KFzg g== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4fvp4ttnp7-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 06 Aug 2026 11:42:12 -0400 (EDT) Received: from ASHBMBX9.ad.analog.com (ASHBMBX9.ad.analog.com [10.64.17.10]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 676FgBC8007041 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 6 Aug 2026 11:42:11 -0400 Received: from ASHBMBX9.ad.analog.com (10.64.17.10) by ASHBMBX9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Thu, 6 Aug 2026 11:42:11 -0400 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server id 15.2.1748.37 via Frontend Transport; Thu, 6 Aug 2026 11:42:11 -0400 Received: from HYB-e1y2fvUQ3cx.ad.analog.com ([10.32.223.174]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 676Ffcga008127; Thu, 6 Aug 2026 11:42:03 -0400 From: Janani Sunil Date: Thu, 6 Aug 2026 17:41:22 +0200 Subject: [PATCH v2 3/7] iio: adc: adi-axi-adc: Add support for CRC 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: <20260806-ad7768-driver-v2-3-027ac5e2a641@analog.com> References: <20260806-ad7768-driver-v2-0-027ac5e2a641@analog.com> In-Reply-To: <20260806-ad7768-driver-v2-0-027ac5e2a641@analog.com> To: =?utf-8?q?Nuno_S=C3=A1?= , Michael Hennerich , Jonathan Cameron , David Lechner , Andy Shevchenko , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Olivier Moysan , Philipp Zabel , Linus Walleij , Bartosz Golaszewski , Jonathan Corbet , Shuah Khan , Michael Walle CC: , , , , , , , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Janani Sunil X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786030898; l=2723; i=janani.sunil@analog.com; s=20260507; h=from:subject:message-id; bh=vCQ4zk/7TsszIXYdGJAehIA0dZS4zuEvaqQDNSqXRk4=; b=dyZn2wi+UWZjW1prv/UYD0J/UK04J8azwUzS2Ep2a5HglNQ+paEWmMoa/gsroXB7wodWEeOP7 x4K+fdbIfYKC/+eW8UERihzFQkRchWyueloa5JVhrpnI/ORZPtWDIPI X-Developer-Key: i=janani.sunil@analog.com; a=ed25519; pk=e25MyjRLPY3RWrYm/LrJ+/+t1MZJUbkgIW5CZg+g+hA= X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-ORIG-GUID: -Gu_O4Xe6EXHYsL36kEiWZOpwoCRWJXz X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODA2MDEyMSBTYWx0ZWRfX/MurkZq2yxw2 geZbn+Ee7ErUr8Ih01KRETxVs84Hvlt1PzyXByc7gTL1kERww7V3/xsQ4AnYJe8cforw7SxFk2x va+8gqZeLXSQi2N4M/N4RhZ8y0Moq7v//Dcst/7OPDFfVpFtDYicWt0LSy9C8JPJ8yZOoMJqrmr BfKgXBYy1gS3D279FPU7VhAw1ca+JvZR9zVA83t1ED71PI7hwRtJOhQ7k3IxzUGF+oUm1Lyz6CC e/ZUsyCIQ1Vwb9f1m5t58QUrssaU/b+3qPesTFCJIsh547ksdGvA8tqrNjxe62xpYb1fnuSqoJg lhx4pGtzO1qwQKc0dExkRYwq4V6aFwA7NrpYzqffjl0pGXDNwYlp+p8cPzwc0Iyo0A/VKFmRakR EemMvN61mQqXi3ynC7wqd5Ov6AoBB78m8L1ZwBUUmo24hhEz9LOkjJfy/ZGPCjkqiQ0Ln3de3Ux R2rycW03/JY0EBl53HQ== X-Authority-Analysis: v=2.4 cv=CIYamxrD c=1 sm=1 tr=0 ts=6a74ab54 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=uXIjobp8t2wMuQ0fPvqm:22 a=gAnH3GRIAAAA:8 a=xcMXqGzQfnDy9uQaBxsA:9 a=QEXdDO2ut3YA:10 X-Proofpoint-GUID: -Gu_O4Xe6EXHYsL36kEiWZOpwoCRWJXz X-Proofpoint-Spam-Info: AW1haW4tMjYwODA2MDEyMSBTYWx0ZWRfX4TvYZypBJ4fX TY2RP+keiaJVi+Y7Z0Z+EEvcKcyZGiY0buAIMDwdO0z1/V8fPR9G6GmccLwzxXeQQQ8oOFl2lBj uNMh19qUmFBBSKtSHxDRnrsx4iB1PqVDPOnHRvTeORamquWh/tDb X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-06_01,2026-08-05_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 bulkscore=0 clxscore=1011 adultscore=0 malwarescore=0 suspectscore=0 lowpriorityscore=0 spamscore=0 priorityscore=1501 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2608060121 Add support for enabling and disabling Cyclic Redundancy Check (CRC) processing in the AXI ADC backend. CRC provides data integrity verification for high-speed ADC data streams, ensuring reliable data transfer between the ADC frontend and backend processing systems. Signed-off-by: Janani Sunil --- drivers/iio/adc/adi-axi-adc.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index 26b9c75bd4d8..a9e25e09880e 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,9 @@ #define ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK BIT(1) =20 #define ADI_AXI_ADC_REG_CNTRL_3 0x004c +/* Bit 8 is common to all AXI ADC cores; bits 7-0 are per-HDL-project. */ +#define ADI_AXI_ADC_CNTRL_3_CRC_EN_MASK BIT(8) + #define AXI_AD485X_CNTRL_3_OS_EN_MSK BIT(2) #define AXI_AD485X_CNTRL_3_PACKET_FORMAT_MSK GENMASK(1, 0) #define AXI_AD485X_PACKET_FORMAT_20BIT 0x0 @@ -567,6 +571,22 @@ static int axi_adc_reg_access(struct iio_backend *back= , unsigned int reg, return regmap_write(st->regmap, reg, writeval); } =20 +static int axi_adc_crc_enable(struct iio_backend *back) +{ + struct adi_axi_adc_state *st =3D iio_backend_get_priv(back); + + return regmap_set_bits(st->regmap, ADI_AXI_ADC_REG_CNTRL_3, + ADI_AXI_ADC_CNTRL_3_CRC_EN_MASK); +} + +static int axi_adc_crc_disable(struct iio_backend *back) +{ + struct adi_axi_adc_state *st =3D iio_backend_get_priv(back); + + return regmap_clear_bits(st->regmap, ADI_AXI_ADC_REG_CNTRL_3, + ADI_AXI_ADC_CNTRL_3_CRC_EN_MASK); +} + static const struct regmap_config axi_adc_regmap_config =3D { .val_bits =3D 32, .reg_bits =3D 32, @@ -615,6 +635,8 @@ static const struct iio_backend_ops adi_axi_adc_ops =3D= { .num_lanes_set =3D axi_adc_num_lanes_set, .debugfs_reg_access =3D iio_backend_debugfs_ptr(axi_adc_reg_access), .debugfs_print_chan_status =3D iio_backend_debugfs_ptr(axi_adc_debugfs_pr= int_chan_status), + .crc_enable =3D axi_adc_crc_enable, + .crc_disable =3D axi_adc_crc_disable, }; =20 static const struct iio_backend_info adi_axi_adc_generic =3D { @@ -684,6 +706,10 @@ static int adi_axi_adc_probe(struct platform_device *p= dev) if (!st) return -ENOMEM; =20 + ret =3D devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + base =3D devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); --=20 2.43.0 From nobody Fri Oct 2 01:07:41 2026 Received: from mx0a-00128a01.pphosted.com (mx0a-00128a01.pphosted.com [148.163.135.77]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6FEEE47D92F; Thu, 6 Aug 2026 15:42:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.135.77 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786030956; cv=none; b=F+a/fX97Cyr1iddIP8KQXyIX/3Q5n6vQcExHcVEuksRS/S7AJnvFcTmyLfb5pEei276qzEFCsk9g14hdZ92BBhOb9su1jxy2JsqrYIzJ5a+RuOaJd2MyIrDh4YIigNSobXT7YGv9VQ/b3giWrHf0dgMI2JeXHP2Kef3peBHXVlw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786030956; c=relaxed/simple; bh=mGbENuMI/PxKQecwKN6ARiP5Ar+sPQHHFLNirZ/eLK0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=LeLK0jKEwDJEqsCpgK3IuUhR4U3+h3FAoD0lYAjiWtmq02Fc+IQ/tuTfhZbfUqPlrie3yiErPvVw4Y0FQQ5isDlZCUD/8pgbE2GDgyzc33WyQ1GB9hEuy7Xpv7uvZ3BB1pH8ohgt6HSxxq8xDWvw0HXTpclRewfc5dqECHA6r40= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=analog.com; spf=pass smtp.mailfrom=analog.com; dkim=pass (2048-bit key) header.d=analog.com header.i=@analog.com header.b=wbJUDVAI; arc=none smtp.client-ip=148.163.135.77 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=analog.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=analog.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=analog.com header.i=@analog.com header.b="wbJUDVAI" Received: from pps.filterd (m0516787.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 676Eq9FX3855388; Thu, 6 Aug 2026 11:42:17 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=analog.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=DKIM; bh=pVWno gmxDq4jK19HbLzIjd+vnJqaBf/7DCRm7/Z2ckc=; b=wbJUDVAIjEJh+hyqe+aaW KwSdhtUKgudqcZK1j8vJ2sd7WOqPSJKKDknKs07Qvexxx2S6ePsgwXBVjBti9VtQ A+x5JYDe6s3NwrdfUNN5zUH55KFA6hmdmZExsRGi+VZ8a9QQdMmy2Z2xdiWbTP74 07mKBlz+CnF7cFXpbKsDdbrDGITQM4WF9xGJN5D35Ap60lBHvsPp7W1ETY/vdasd UmyTr0SY9FCd+vuazCgBscPYaX1Cl/mTSDxq+nPFTk2OzFk3gnc2IjjZVI7eRxZU YTxnOmZjyuJ2Jsi3W3iF4rAG0hA/3TwAJaSFSN7fxtXhipfK2yuyn1GDF+Is0URZ A== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4fvrcpsf75-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 06 Aug 2026 11:42:17 -0400 (EDT) Received: from ASHBMBX8.ad.analog.com (ASHBMBX8.ad.analog.com [10.64.17.5]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 676FgGEj007047 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 6 Aug 2026 11:42:16 -0400 Received: from ASHBCASHYB4.ad.analog.com (10.64.17.132) by ASHBMBX8.ad.analog.com (10.64.17.5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Thu, 6 Aug 2026 11:42:15 -0400 Received: from ASHBMBX8.ad.analog.com (10.64.17.5) by ASHBCASHYB4.ad.analog.com (10.64.17.132) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Thu, 6 Aug 2026 11:42:15 -0400 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx8.ad.analog.com (10.64.17.5) with Microsoft SMTP Server id 15.2.1748.37 via Frontend Transport; Thu, 6 Aug 2026 11:42:15 -0400 Received: from HYB-e1y2fvUQ3cx.ad.analog.com ([10.32.223.174]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 676Ffcgb008127; Thu, 6 Aug 2026 11:42:07 -0400 From: Janani Sunil Date: Thu, 6 Aug 2026 17:41:23 +0200 Subject: [PATCH v2 4/7] iio: adc: Add AD7768 IIO Driver support 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: <20260806-ad7768-driver-v2-4-027ac5e2a641@analog.com> References: <20260806-ad7768-driver-v2-0-027ac5e2a641@analog.com> In-Reply-To: <20260806-ad7768-driver-v2-0-027ac5e2a641@analog.com> To: =?utf-8?q?Nuno_S=C3=A1?= , Michael Hennerich , Jonathan Cameron , "David Lechner" , Andy Shevchenko , "Rob Herring" , Krzysztof Kozlowski , "Conor Dooley" , Olivier Moysan , Philipp Zabel , Linus Walleij , Bartosz Golaszewski , Jonathan Corbet , Shuah Khan , Michael Walle CC: , , , , , , , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Janani Sunil X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786030898; l=50010; i=janani.sunil@analog.com; s=20260507; h=from:subject:message-id; bh=mGbENuMI/PxKQecwKN6ARiP5Ar+sPQHHFLNirZ/eLK0=; b=MKUuliqGiBeh3CQ4Pe4JDHZZoL2141e2TBbrv6kj3PFlRAAInigolAkIPB+/PXGp9MvnFku33 0uOFmo6pZG3Co3Muz2J8E5R/uX+3d1vZpQHxWqa5TzJb8tGG6JOKO/V X-Developer-Key: i=janani.sunil@analog.com; a=ed25519; pk=e25MyjRLPY3RWrYm/LrJ+/+t1MZJUbkgIW5CZg+g+hA= X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-GUID: mkf6sINqUIjbOIdirPy5iFTbhhktFSYf X-Proofpoint-Spam-Info: AW1haW4tMjYwODA2MDEyMSBTYWx0ZWRfX3Cj+J+kGHnYy UUrqYeMuhW3aeQS9xQuYyy005p5wQTVgQ5JVDGjTqsM1pikcwW1X7SZuAV+uhMWeeKpjj7LOpsl FEsk3m9DrcYeCzp7sKlas/s4PWlfQyoR0Rk4XD96kGgJNjZYVfzV X-Proofpoint-ORIG-GUID: mkf6sINqUIjbOIdirPy5iFTbhhktFSYf X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODA2MDEyMSBTYWx0ZWRfX2BuT1NAxbZRT xXpg4+mYOM4e6KtaSiNzUarPj+HNJoJn7nwXrJttW+WCQ/05o2TIv7ynBct6em+7fiH84l7sykP 71FHndF/ONQXh1B3ALvjOfIYpt87kGmslwzp2PNR0Z9hDQ6TJDav+Uo1xsjPA7kuxxrW75I6VC0 /UuYZqpSb5qxuhUjdHBqTJUHbOpaHQe5A8LQxzJwTiqmYLpJd/kVSRvXOfzhbVNel5/+5z7nmwD aDQ4UovqKloBcWQj9Q56P9XUVjdQvO0FnNXVq0Z8Na8CqlCnIYrRrJSTOb9k/kkm3Q0xEaQbvfh yROOQbAtI7lqdJz23U6J9SFlY1pWCOVAsRnv8g4HK0IbsQzthHGJn2Ooe+95MkfZqNUoW17QWcX yerHsrP0uzUtgBLIpOAZeM4zD2gUSC1WwyM0fiPM+NC1422VqnVkDKonA95A+3YOg2b+MDX2qC1 RLvRo3u12Fe8VlLmPCA== X-Authority-Analysis: v=2.4 cv=IPwyzAvG c=1 sm=1 tr=0 ts=6a74ab59 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=OmVn7CZJonkx5R5zMQLL:22 a=gAnH3GRIAAAA:8 a=VwQbUJbxAAAA:8 a=_WSb5ZJg9_xE67b7vncA:9 a=QEXdDO2ut3YA:10 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-06_01,2026-08-05_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 priorityscore=1501 impostorscore=0 lowpriorityscore=0 phishscore=0 malwarescore=0 bulkscore=0 spamscore=0 suspectscore=0 adultscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2608060121 Add support for AD7768 4/8 channel,simultaneous sampling Sigma-Delta ADCs. The driver supports configurable decimation filters, per-channel conversion delay, VCM regulation, runtime PM and IIO backend data capture. Signed-off-by: Janani Sunil --- MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 16 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7768.c | 1720 ++++++++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 1738 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index d667a0411f28..dc94e7803a7c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1639,6 +1639,7 @@ L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7768.yaml +F: drivers/iio/adc/ad7768.c =20 ANALOG DEVICES INC AD7780 DRIVER M: Michael Hennerich diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index d1b198cb8a80..1325cdbedea4 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -429,6 +429,22 @@ config AD7766 To compile this driver as a module, choose M here: the module will be called ad7766. =20 +config AD7768 + tristate "Analog Devices AD7768/AD7768-4 ADC driver" + depends on SPI + depends on REGULATOR || COMPILE_TEST + select AUXILIARY_BUS + select IIO_BUFFER + select IIO_BACKEND + select REGMAP + help + Say yes here to build support for Analog Devices AD7768 and AD7768-4 + SPI analog to digital converters. + + To compile this driver as a module, choose M here: the module will be + called ad7768. + + config AD7768_1 tristate "Analog Devices AD7768-1 ADC driver" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 0f90b75577ff..3e896c8aa7c3 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_AD7606_IFACE_SPI) +=3D ad7606_spi.o obj-$(CONFIG_AD7606) +=3D ad7606.o obj-$(CONFIG_AD7625) +=3D ad7625.o obj-$(CONFIG_AD7766) +=3D ad7766.o +obj-$(CONFIG_AD7768) +=3D ad7768.o obj-$(CONFIG_AD7768_1) +=3D ad7768-1.o obj-$(CONFIG_AD7779) +=3D ad7779.o obj-$(CONFIG_AD7780) +=3D ad7780.o diff --git a/drivers/iio/adc/ad7768.c b/drivers/iio/adc/ad7768.c new file mode 100644 index 000000000000..1bba066435e3 --- /dev/null +++ b/drivers/iio/adc/ad7768.c @@ -0,0 +1,1720 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD7768 ADC driver + * + * Copyright 2018-2026 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define AD7768_REG_GPIO_CONTROL 0x0E + +/* AD7768 registers definition */ +#define AD7768_REG_CH_STANDBY 0x00 +#define AD7768_REG_CH_MODE(x) (0x01 + (x)) +#define AD7768_REG_CH_MODE_SEL 0x03 +#define AD7768_REG_POWER_MODE 0x04 +#define AD7768_REG_GENERAL_CONFIG 0x05 +#define AD7768_REG_DATA_CONTROL 0x06 +#define AD7768_REG_INTERFACE_CFG 0x07 +#define AD7768_REG_REV_ID 0x0A +#define AD7768_REG_PRECHARGE_BUF1 0x11 +#define AD7768_REG_PRECHARGE_BUF2 0x12 +#define AD7768_REG_REFP_BUF 0x13 +#define AD7768_REG_REFN_BUF 0x14 +#define AD7768_REG_OFFSET_BASE 0x1E +#define AD7768_REG_GAIN_BASE 0x36 +#define AD7768_REG_PHASE_BASE 0x4E +#define AD7768_REG_OFFSET(ch) ((AD7768_REG_OFFSET_BASE + (3 * (ch)))) +#define AD7768_REG_GAIN(ch) ((AD7768_REG_GAIN_BASE + (3 * (ch)))) +#define AD7768_REG_PHASE(ch) ((AD7768_REG_PHASE_BASE + (ch))) +#define __AD7768_4_REG_MAP(ch) ((ch) < 2 ? (ch) : ((ch) + 2)) +#define AD7768_4_REG_OFFSET(ch) \ + (AD7768_REG_OFFSET_BASE + (3 * __AD7768_4_REG_MAP(ch))) +#define AD7768_4_REG_GAIN(ch) \ + (AD7768_REG_GAIN_BASE + (3 * __AD7768_4_REG_MAP(ch))) +#define AD7768_4_REG_PHASE(ch) (AD7768_REG_PHASE_BASE + __AD7768_4_REG_MA= P(ch)) +#define AD7768_REG_DIAGNOSTIC_RX 0x56 +#define AD7768_REG_DIAGNOSTIC_MUX_CTRL 0x57 +#define AD7768_REG_MODULATOR_DELAY_CTRL 0x58 +#define AD7768_REG_CHOP_CTRL 0x59 + +/* AD7768_REG_CH_MODE */ +#define AD7768_CH_MODE_FILTER_TYPE_MSK BIT(3) +#define AD7768_CH_MODE_FILTER_TYPE_MODE(x) (((x) & 0x1) << 3) +#define AD7768_CH_MODE_DEC_RATE_MSK GENMASK(2, 0) +#define AD7768_CH_MODE_DEC_RATE_MODE(x) (((x) & 0x7) << 0) + +/* AD7768_REG_CH_MODE_SEL */ +#define AD7768_CH_MODE_READ_MSK GENMASK(7, 0) +#define AD7768_CH_MODE_READ_MODE(x) ((x) & 0xFF) +#define AD7768_CH_MODE_READ_GET(x) ((x) & 0xFF) +#define AD7768_CH_MODE_READ_CHN(n) BIT(n) +#define AD7768_GET_CH_MODE_8CH(ch, x) (!!((x) & BIT(ch))) + +/* AD7768_REG_POWER_MODE */ +#define AD7768_SLEEP_MODE_MSK BIT(7) +#define AD7768_POWER_MODE_POWER_MODE_MSK GENMASK(5, 4) +#define AD7768_POWER_MODE_POWER_MODE(x) (((x) & 0x3) << 4) +#define AD7768_POWER_MODE_MCLK_DIV_MSK GENMASK(1, 0) + +/* AD7768_REG_DATA_CONTROL */ +#define AD7768_DATA_CONTROL_SPI_RESET_MSK GENMASK(1, 0) +#define AD7768_DATA_CONTROL_SPI_RESET_1 0x03 +#define AD7768_DATA_CONTROL_SPI_RESET_2 0x02 +#define AD7768_DATA_CONTROL_SPI_SYNC_MSK BIT(7) + +/* AD7768_REG_INTERFACE_CFG */ +#define AD7768_INTERFACE_CFG_DCLK_DIV_MSK GENMASK(1, 0) +#define AD7768_INTERFACE_CFG_DCLK_DIV_MODE(x) (4 - ffs(x)) +#define AD7768_MAX_DCLK_DIV 8 + +#define AD7768_INTERFACE_CFG_CRC_SELECT_MSK GENMASK(3, 2) +/* Hardware supports CRC every 4 or 16 samples; backend supports 4-sample = only */ +#define AD7768_INTERFACE_CFG_CRC_SELECT FIELD_PREP(GENMASK(3, 2), 0x01) + +/* AD7768_REG_GENERAL_CONFIG */ +#define AD7768_GEN_CONFIG_VCM_SEL_MSK GENMASK(1, 0) +#define AD7768_GEN_CONFIG_VCM_PD BIT(4) + +/* AD7768_REG_PRECHARGE_BUF1 and 2*/ +#define AD7768_PREBUF_POS_EN(ch) BIT((ch) * 2) +#define AD7768_PREBUF_NEG_EN(ch) BIT(((ch) * 2) + 1) + +#define AD7768_SPI_READ_CMD BIT(15) +#define AD7768_SPI_REG_MASK GENMASK(14, 8) +#define AD7768_SPI_DATA_MASK GENMASK(7, 0) +#define AD7768_OUTPUT_MODE_TWOS_COMPLEMENT 0x01 +#define AD7768_SAMPLE_SIZE 32 +#define AD7768_PICO_PER_SEC 1000000000000ULL +#define MAX_FREQ_PER_MODE 6 +#define AD7768_MAX_CHANNEL 8 +#define AD7768_NUM_CHANNEL_MODES 2 +#define AD7768_CALIB_REG_MSB_MSK GENMASK(23, 16) +#define AD7768_CALIB_REG_MID_MSK GENMASK(15, 8) +#define AD7768_CALIB_REG_LSB_MSK GENMASK(7, 0) +#define AD7768_CALIB_REG_MSK GENMASK(23, 0) +#define AD7768_REV_ID_VAL 0x06 +#define AD7768_WIDEBAND_SETTLING_SAMPLES 68 +#define AD7768_SINC5_SETTLING_SAMPLES 7 + +enum ad7768_filter_type { + AD7768_FILTER_TYPE_WIDEBAND, + AD7768_FILTER_TYPE_SINC5, +}; + +enum ad7768_power_modes { + AD7768_LOW_POWER_MODE, + AD7768_MEDIAN_MODE, + AD7768_FAST_MODE, + AD7768_NUM_POWER_MODES +}; + +#define AD7768_MAX_FREQS (MAX_FREQ_PER_MODE + AD7768_NUM_POWER_MODES) + +struct ad7768_precharge_config { + bool prebufp_en; + bool prebufn_en; + bool refbufp; + bool refbufn; +}; + +struct ad7768_freq_config { + unsigned int freq; + unsigned int dec_rate; +}; + +struct ad7768_convdelay_params { + unsigned int shift; + unsigned int max_raw; + u64 step_ps; +}; + +struct ad7768_avail_freq { + unsigned int n_freqs; + int freqs[MAX_FREQ_PER_MODE]; + struct ad7768_freq_config freq_cfg[MAX_FREQ_PER_MODE]; +}; + +struct ad7768_chip_info { + const char *name; + unsigned int num_channels; + const struct iio_chan_spec channel[AD7768_MAX_CHANNEL]; + const struct regmap_config *regmap_config; + const unsigned int *available_datalines; + unsigned int num_datalines; + const u8 *chan_map; + u8 prebuf_split; +}; + +struct ad7768_state { + struct spi_device *spi; + struct regmap *regmap; + struct mutex lock; /* Protects device register access and configuration */ + struct clk *mclk; + unsigned int datalines; + enum ad7768_power_modes power_mode; + const struct ad7768_chip_info *chip_info; + struct ad7768_avail_freq avail_freq[AD7768_NUM_POWER_MODES]; + unsigned int n_freqs; + int freqs[AD7768_MAX_FREQS]; + unsigned int chn_mode[AD7768_MAX_CHANNEL]; + unsigned int ch_freq[AD7768_MAX_CHANNEL]; + u64 ch_convdelay_ps[AD7768_MAX_CHANNEL]; + enum ad7768_filter_type ch_filter[AD7768_MAX_CHANNEL]; + struct iio_backend *back; + struct regulator_dev *vcm_rdev; + unsigned int avdd1_uv; + + __be16 d16 __aligned(IIO_DMA_MINALIGN); +}; + +static const unsigned int ad7768_vcm_voltage_table[] =3D { + 0, 1650000, 2500000, 2140000 +}; + +static int ad7768_vcm_list_voltage(struct regulator_dev *rdev, + unsigned int selector) +{ + struct ad7768_state *st =3D rdev_get_drvdata(rdev); + + if (selector >=3D ARRAY_SIZE(ad7768_vcm_voltage_table)) + return -EINVAL; + + if (!selector) + return DIV_ROUND_CLOSEST(st->avdd1_uv, 2); + + return ad7768_vcm_voltage_table[selector]; +} + +static int ad7768_vcm_enable(struct regulator_dev *rdev) +{ + struct ad7768_state *st =3D rdev_get_drvdata(rdev); + int ret; + + ret =3D pm_runtime_resume_and_get(&st->spi->dev); + if (ret < 0) + return ret; + + ret =3D regmap_clear_bits(st->regmap, AD7768_REG_GENERAL_CONFIG, + AD7768_GEN_CONFIG_VCM_PD); + if (ret) + pm_runtime_put_autosuspend(&st->spi->dev); + + return ret; +} + +static int ad7768_vcm_disable(struct regulator_dev *rdev) +{ + struct ad7768_state *st =3D rdev_get_drvdata(rdev); + int ret; + + ret =3D regmap_set_bits(st->regmap, AD7768_REG_GENERAL_CONFIG, + AD7768_GEN_CONFIG_VCM_PD); + if (ret) + return ret; + + pm_runtime_put_autosuspend(&st->spi->dev); + + return 0; +} + +static int ad7768_vcm_is_enabled(struct regulator_dev *rdev) +{ + struct ad7768_state *st =3D rdev_get_drvdata(rdev); + unsigned int val; + int ret; + + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(&st->spi->dev, pm); + ret =3D PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + ret =3D regmap_read(st->regmap, AD7768_REG_GENERAL_CONFIG, &val); + if (ret) + return ret; + + return !(val & AD7768_GEN_CONFIG_VCM_PD); +} + +static int ad7768_vcm_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) +{ + struct ad7768_state *st =3D rdev_get_drvdata(rdev); + int ret; + + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(&st->spi->dev, pm); + ret =3D PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + return regmap_update_bits(st->regmap, AD7768_REG_GENERAL_CONFIG, + AD7768_GEN_CONFIG_VCM_SEL_MSK, selector); +} + +static int ad7768_vcm_get_voltage_sel(struct regulator_dev *rdev) +{ + struct ad7768_state *st =3D rdev_get_drvdata(rdev); + unsigned int val; + int ret; + + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(&st->spi->dev, pm); + ret =3D PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + ret =3D regmap_read(st->regmap, AD7768_REG_GENERAL_CONFIG, &val); + if (ret) + return ret; + + return FIELD_GET(AD7768_GEN_CONFIG_VCM_SEL_MSK, val); +} + +static const struct regulator_ops ad7768_vcm_ops =3D { + .enable =3D ad7768_vcm_enable, + .disable =3D ad7768_vcm_disable, + .is_enabled =3D ad7768_vcm_is_enabled, + .list_voltage =3D ad7768_vcm_list_voltage, + .set_voltage_sel =3D ad7768_vcm_set_voltage_sel, + .get_voltage_sel =3D ad7768_vcm_get_voltage_sel, +}; + +static const struct regulator_desc ad7768_vcm_desc =3D { + .name =3D "vcm", + .of_match =3D of_match_ptr("vcm-output"), + .n_voltages =3D ARRAY_SIZE(ad7768_vcm_voltage_table), + .ops =3D &ad7768_vcm_ops, + .type =3D REGULATOR_VOLTAGE, + .owner =3D THIS_MODULE, +}; + +static int ad7768_register_vcm_regulator(struct device *dev, + struct ad7768_state *st) +{ + struct regulator_config config =3D { + .dev =3D dev, + .driver_data =3D st, + }; + int ret; + + /* + * Start with VCM disabled so each enabled state is paired with the + * runtime PM reference acquired by ad7768_vcm_enable(). + */ + ret =3D regmap_set_bits(st->regmap, AD7768_REG_GENERAL_CONFIG, + AD7768_GEN_CONFIG_VCM_PD); + if (ret) + return ret; + + st->vcm_rdev =3D devm_regulator_register(dev, &ad7768_vcm_desc, &config); + return PTR_ERR_OR_ZERO(st->vcm_rdev); +} + +static const int ad7768_dec_rate[MAX_FREQ_PER_MODE] =3D { + 32, 64, 128, 256, 512, 1024 +}; + +static const int ad7768_mclk_div[3] =3D { + 32, 8, 4 +}; + +static const unsigned int ad7768_available_datalines[] =3D { + 1, 2, 8, +}; + +static const unsigned int ad7768_4_available_datalines[] =3D { + 1, 4, +}; + +static const u8 ad7768_chan_map[] =3D { + 0, 1, 2, 3, 4, 5, 6, 7, +}; + +static const u8 ad7768_4_chan_map[] =3D { + 0, 1, 4, 5, +}; + +static const char * const ad7768_supply_names[] =3D { + "avss", "avdd2", "iovdd", "ref1", "ref2", +}; + +static u8 ad7768_map_power_mode_to_regval(u8 x) +{ + return x ? (x + 1) : 0; +} + +static int ad7768_set_power_mode(struct ad7768_state *st, unsigned int mod= e); + +static u8 ad7768_channel_mask(const struct ad7768_state *st, u8 ch) +{ + return BIT(st->chip_info->chan_map[ch]); +} + +static u8 ad7768_all_channels_mask(const struct ad7768_state *st) +{ + u8 mask =3D 0; + unsigned int ch; + + for (ch =3D 0; ch < st->chip_info->num_channels; ch++) + mask |=3D ad7768_channel_mask(st, ch); + + return mask; +} + +static unsigned int ad7768_offset_reg(const struct ad7768_state *st, + unsigned int ch) +{ + return AD7768_REG_OFFSET(st->chip_info->chan_map[ch]); +} + +static unsigned int ad7768_gain_reg(const struct ad7768_state *st, + unsigned int ch) +{ + return AD7768_REG_GAIN(st->chip_info->chan_map[ch]); +} + +static unsigned int ad7768_phase_reg(const struct ad7768_state *st, + unsigned int ch) +{ + return AD7768_REG_PHASE(st->chip_info->chan_map[ch]); +} + +static u8 ad7768_precharge_buf1_mask(const struct ad7768_state *st, u16 va= l) +{ + return val & GENMASK(st->chip_info->prebuf_split - 1, 0); +} + +static u8 ad7768_precharge_buf2_mask(const struct ad7768_state *st, u16 va= l) +{ + return (val >> st->chip_info->prebuf_split) & + GENMASK(st->chip_info->prebuf_split - 1, 0); +} + +static int ad7768_regmap_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, size_t val_size) +{ + struct spi_device *spi =3D context; + struct ad7768_state *st =3D spi_get_drvdata(spi); + u8 *data_val =3D val_buf; + unsigned int reg; + int ret; + struct spi_transfer t[] =3D { + { + .tx_buf =3D &st->d16, + .len =3D 2, + .cs_change =3D 1, + }, { + /* + * The second transfer clocks out the readback data, so + * we must provide dummy TX bytes while receiving the + * response. The device ignores MOSI in this phase, so + * reuse st->d16 for both TX and RX. + */ + .tx_buf =3D &st->d16, + .rx_buf =3D &st->d16, + .len =3D 2, + }, + }; + + reg =3D *(const u8 *)reg_buf; + + st->d16 =3D cpu_to_be16(AD7768_SPI_READ_CMD | + FIELD_PREP(AD7768_SPI_REG_MASK, reg)); + + ret =3D spi_sync_transfer(spi, t, ARRAY_SIZE(t)); + if (ret) + return ret; + + *data_val =3D FIELD_GET(AD7768_SPI_DATA_MASK, be16_to_cpu(st->d16)); + + return ret; +} + +static int ad7768_regmap_write(void *context, const void *data, size_t cou= nt) +{ + struct spi_device *spi =3D context; + + return spi_write(spi, data, count); +} + +static const struct regmap_bus ad7768_regmap_bus =3D { + .read =3D ad7768_regmap_read, + .write =3D ad7768_regmap_write, + .reg_format_endian_default =3D REGMAP_ENDIAN_BIG, + .val_format_endian_default =3D REGMAP_ENDIAN_BIG, +}; + +static bool ad7768_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case AD7768_REG_CH_STANDBY ... AD7768_REG_REV_ID: + case AD7768_REG_GPIO_CONTROL ... AD7768_REG_REFN_BUF: + return true; + case AD7768_REG_OFFSET(0) ... AD7768_REG_OFFSET(7) + 2: + case AD7768_REG_GAIN(0) ... AD7768_REG_GAIN(7) + 2: + case AD7768_REG_PHASE(0) ... AD7768_REG_PHASE(7): + case AD7768_REG_DIAGNOSTIC_RX ... AD7768_REG_CHOP_CTRL: + return true; + default: + return false; + } +} + +static bool ad7768_4_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case AD7768_REG_CH_STANDBY ... AD7768_REG_REV_ID: + case AD7768_REG_GPIO_CONTROL ... AD7768_REG_REFN_BUF: + return true; + case AD7768_4_REG_OFFSET(0) ... AD7768_4_REG_OFFSET(1) + 2: + case AD7768_4_REG_OFFSET(2) ... AD7768_4_REG_OFFSET(3) + 2: + case AD7768_4_REG_GAIN(0) ... AD7768_4_REG_GAIN(1) + 2: + case AD7768_4_REG_GAIN(2) ... AD7768_4_REG_GAIN(3) + 2: + case AD7768_4_REG_PHASE(0) ... AD7768_4_REG_PHASE(1): + case AD7768_4_REG_PHASE(2) ... AD7768_4_REG_PHASE(3): + case AD7768_REG_DIAGNOSTIC_RX ... AD7768_REG_CHOP_CTRL: + return true; + default: + return false; + } +} + +static const struct regmap_config ad7768_regmap_config =3D { + .reg_bits =3D 8, + .val_bits =3D 8, + .max_register =3D AD7768_REG_CHOP_CTRL, + .use_single_read =3D true, + .readable_reg =3D ad7768_readable_reg, +}; + +static const struct regmap_config ad7768_4_regmap_config =3D { + .reg_bits =3D 8, + .val_bits =3D 8, + .max_register =3D AD7768_REG_CHOP_CTRL, + .use_single_read =3D true, + .readable_reg =3D ad7768_4_readable_reg, +}; + +static unsigned int ad7768_get_calib_reg_base(struct ad7768_state *st, + const struct iio_chan_spec *chan, + bool is_gain) +{ + if (is_gain) + return ad7768_gain_reg(st, chan->address); + + return ad7768_offset_reg(st, chan->address); +} + +static int ad7768_read_calib_value(struct ad7768_state *st, + unsigned int base_reg, unsigned int *val) +{ + u8 data[3]; + int ret; + + guard(mutex)(&st->lock); + + ret =3D regmap_bulk_read(st->regmap, base_reg, data, ARRAY_SIZE(data)); + if (ret) + return ret; + + *val =3D (data[0] << 16) | (data[1] << 8) | data[2]; + + return 0; +} + +static int ad7768_write_calib_value(struct ad7768_state *st, + unsigned int base_reg, unsigned int val) +{ + int ret; + + if (val > AD7768_CALIB_REG_MSK) + return -EINVAL; + + guard(mutex)(&st->lock); + + ret =3D regmap_write(st->regmap, base_reg, + FIELD_GET(AD7768_CALIB_REG_MSB_MSK, val)); + if (ret) + return ret; + + ret =3D regmap_write(st->regmap, base_reg + 1, + FIELD_GET(AD7768_CALIB_REG_MID_MSK, val)); + if (ret) + return ret; + + return regmap_write(st->regmap, base_reg + 2, + FIELD_GET(AD7768_CALIB_REG_LSB_MSK, val)); +} + +static int ad7768_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int writeval, + unsigned int *readval) +{ + struct ad7768_state *st =3D iio_priv(indio_dev); + int ret; + + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(&st->spi->dev, pm); + ret =3D PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + if (readval) + return regmap_read(st->regmap, reg, readval); + + return regmap_write(st->regmap, reg, writeval); +} + +static int ad7768_sync(struct ad7768_state *st) +{ + int ret; + + ret =3D regmap_update_bits(st->regmap, AD7768_REG_DATA_CONTROL, + AD7768_DATA_CONTROL_SPI_SYNC_MSK, 0); + if (ret) + return ret; + + return regmap_update_bits(st->regmap, AD7768_REG_DATA_CONTROL, + AD7768_DATA_CONTROL_SPI_SYNC_MSK, + FIELD_PREP(AD7768_DATA_CONTROL_SPI_SYNC_MSK, 1)); +} + +static int ad7768_set_clk_divs(struct ad7768_state *st, + unsigned int freq) +{ + unsigned int mclk, dclk, dclk_div, i; + struct ad7768_freq_config f_cfg =3D {}; + unsigned int chan_per_doutx; + + mclk =3D clk_get_rate(st->mclk); + + chan_per_doutx =3D st->chip_info->num_channels / st->datalines; + if (!chan_per_doutx) + return -EINVAL; + + for (i =3D 0; i < st->avail_freq[st->power_mode].n_freqs; i++) { + f_cfg =3D st->avail_freq[st->power_mode].freq_cfg[i]; + if (freq =3D=3D f_cfg.freq) + break; + } + + if (i =3D=3D st->avail_freq[st->power_mode].n_freqs) + return -EINVAL; + + dclk =3D f_cfg.freq * AD7768_SAMPLE_SIZE * chan_per_doutx; + if (dclk > mclk) + return -EINVAL; + + /* Set dclk_div to the nearest power of 2 less than the original value */ + dclk_div =3D DIV_ROUND_CLOSEST_ULL(mclk, dclk); + if (dclk_div > AD7768_MAX_DCLK_DIV) + dclk_div =3D AD7768_MAX_DCLK_DIV; + else if (dclk_div > 0 && hweight32(dclk_div) !=3D 1) + dclk_div =3D 1 << (fls(dclk_div) - 1); + + return regmap_update_bits(st->regmap, AD7768_REG_INTERFACE_CFG, + AD7768_INTERFACE_CFG_DCLK_DIV_MSK, + AD7768_INTERFACE_CFG_DCLK_DIV_MODE(dclk_div)); +} + +static bool ad7768_freq_supported(const struct ad7768_state *st, + unsigned int mode, unsigned int freq) +{ + unsigned int i; + + for (i =3D 0; i < st->avail_freq[mode].n_freqs; i++) { + if (freq =3D=3D st->avail_freq[mode].freq_cfg[i].freq) + return true; + } + + return false; +} + +static bool ad7768_freq_supported_in_any_mode(const struct ad7768_state *s= t, + unsigned int freq) +{ + unsigned int mode; + + for (mode =3D 0; mode < AD7768_NUM_POWER_MODES; mode++) { + if (ad7768_freq_supported(st, mode, freq)) + return true; + } + + return false; +} + +static int ad7768_set_lowest_noise_mode(struct ad7768_state *st, + const unsigned long *scan_mask) +{ + unsigned int channel; + unsigned int mode; + + /* + * The output data rate ranges overlap between the power modes. At a + * common ODR, the faster mode has lower noise, so prefer the fastest + * mode that supports every enabled channel. + */ + for (mode =3D AD7768_NUM_POWER_MODES; mode-- > 0;) { + for (channel =3D 0; channel < st->chip_info->num_channels; channel++) { + if (test_bit(channel, scan_mask) && + !ad7768_freq_supported(st, mode, st->ch_freq[channel])) + break; + } + + if (channel =3D=3D st->chip_info->num_channels) + return ad7768_set_power_mode(st, mode); + } + + return -EINVAL; +} + +static int ad7768_set_mode_decimation(struct ad7768_state *st, + unsigned int freq, unsigned int mode) +{ + struct ad7768_freq_config f_cfg =3D {}; + unsigned int i; + + for (i =3D 0; i < st->avail_freq[st->power_mode].n_freqs; i++) { + f_cfg =3D st->avail_freq[st->power_mode].freq_cfg[i]; + if (freq =3D=3D f_cfg.freq) + break; + } + + if (i =3D=3D st->avail_freq[st->power_mode].n_freqs) + return -EINVAL; + + return regmap_update_bits(st->regmap, AD7768_REG_CH_MODE(mode), + AD7768_CH_MODE_DEC_RATE_MSK, + AD7768_CH_MODE_DEC_RATE_MODE(f_cfg.dec_rate)); +} + +static int ad7768_set_sampling_freq(struct iio_dev *indio_dev, + unsigned int freq, unsigned int ch) +{ + struct ad7768_state *st =3D iio_priv(indio_dev); + + if (!freq) + return -EINVAL; + + if (!ad7768_freq_supported_in_any_mode(st, freq)) + return -EINVAL; + + guard(mutex)(&st->lock); + st->ch_freq[ch] =3D freq; + + return 0; +} + +static int ad7768_get_freq_cfg(struct ad7768_state *st, unsigned int freq, + struct ad7768_freq_config *f_cfg) +{ + unsigned int i; + + for (i =3D 0; i < st->avail_freq[st->power_mode].n_freqs; i++) { + *f_cfg =3D st->avail_freq[st->power_mode].freq_cfg[i]; + if (freq =3D=3D f_cfg->freq) + return 0; + } + + return -EINVAL; +} + +static void ad7768_filter_wait(const unsigned int *mode_freq, + const enum ad7768_filter_type *mode_filter, + const bool *mode_used) +{ + unsigned long t_settle_us =3D 0; + unsigned int mode; + + for (mode =3D 0; mode < AD7768_NUM_CHANNEL_MODES; mode++) { + unsigned long t_mode_us; + unsigned int settling_samples; + + if (!mode_used[mode] || !mode_freq[mode]) + continue; + + if (mode_filter[mode] =3D=3D AD7768_FILTER_TYPE_SINC5) + settling_samples =3D AD7768_SINC5_SETTLING_SAMPLES; + else + settling_samples =3D AD7768_WIDEBAND_SETTLING_SAMPLES; + + t_mode_us =3D DIV_ROUND_UP_ULL((u64)settling_samples * + USEC_PER_SEC, + mode_freq[mode]); + t_settle_us =3D max(t_settle_us, t_mode_us); + } + + if (t_settle_us) + fsleep(t_settle_us); +} + +static int ad7768_get_convdelay_params(struct ad7768_state *st, unsigned i= nt ch, + struct ad7768_convdelay_params *params) +{ + struct ad7768_freq_config f_cfg; + unsigned int dec_rate; + unsigned int mult; + u64 mclk; + int ret; + + ret =3D ad7768_get_freq_cfg(st, st->ch_freq[ch], &f_cfg); + if (ret) + return ret; + + dec_rate =3D ad7768_dec_rate[f_cfg.dec_rate]; + switch (dec_rate) { + case 32: + params->shift =3D 3; + params->max_raw =3D 31; + mult =3D 1; + break; + case 64: + params->shift =3D 2; + params->max_raw =3D 63; + mult =3D 1; + break; + case 128: + params->shift =3D 1; + params->max_raw =3D 127; + mult =3D 1; + break; + case 256: + params->shift =3D 0; + params->max_raw =3D 255; + mult =3D 1; + break; + case 512: + params->shift =3D 0; + params->max_raw =3D 255; + mult =3D 2; + break; + case 1024: + params->shift =3D 0; + params->max_raw =3D 255; + mult =3D 4; + break; + default: + return -EINVAL; + } + + mclk =3D clk_get_rate(st->mclk); + if (!mclk) + return -EINVAL; + + params->step_ps =3D DIV_ROUND_CLOSEST_ULL((u64)mult * + AD7768_PICO_PER_SEC * + ad7768_mclk_div[st->power_mode], + mclk); + + return 0; +} + +static int ad7768_set_channel_convdelay(struct ad7768_state *st, + unsigned int ch) +{ + struct ad7768_convdelay_params params; + u64 delay_ps =3D st->ch_convdelay_ps[ch]; + u64 max_delay_ps; + u64 raw; + int ret; + + ret =3D ad7768_get_convdelay_params(st, ch, ¶ms); + if (ret) + return ret; + + max_delay_ps =3D (u64)params.max_raw * params.step_ps; + if (delay_ps > max_delay_ps) + return -EINVAL; + + raw =3D DIV_ROUND_CLOSEST_ULL(delay_ps, params.step_ps); + if (raw > params.max_raw) + return -EINVAL; + + return regmap_write(st->regmap, ad7768_phase_reg(st, ch), + raw << params.shift); +} + +static int ad7768_find_matching_mode(const bool *mode_used, + const unsigned int *mode_freq, + const enum ad7768_filter_type *mode_filter, + unsigned int freq, + enum ad7768_filter_type filter) +{ + unsigned int mode; + + for (mode =3D 0; mode < AD7768_NUM_CHANNEL_MODES; mode++) { + if (!mode_used[mode] || + (mode_freq[mode] =3D=3D freq && mode_filter[mode] =3D=3D filter)) + return mode; + } + + return -EINVAL; +} + +static int ad7768_apply_channel_modes(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct ad7768_state *st =3D iio_priv(indio_dev); + unsigned int mode_freq[AD7768_NUM_CHANNEL_MODES]; + enum ad7768_filter_type mode_filter[AD7768_NUM_CHANNEL_MODES]; + bool mode_used[AD7768_NUM_CHANNEL_MODES] =3D { }; + unsigned int channel_mask; + unsigned int standby_mask; + unsigned int max_freq =3D 0; + unsigned int c; + int mode, ret; + + guard(mutex)(&st->lock); + + ret =3D ad7768_set_lowest_noise_mode(st, scan_mask); + if (ret =3D=3D -EINVAL) + return dev_err_probe(&st->spi->dev, ret, + "No power mode supports all enabled channel frequencies\n"); + if (ret) + return ret; + + channel_mask =3D ad7768_all_channels_mask(st); + standby_mask =3D channel_mask; + + for (c =3D 0; c < st->chip_info->num_channels; c++) { + unsigned int mask; + + if (!test_bit(c, scan_mask)) + continue; + + standby_mask &=3D ~ad7768_channel_mask(st, c); + + mode =3D ad7768_find_matching_mode(mode_used, mode_freq, + mode_filter, st->ch_freq[c], + st->ch_filter[c]); + if (mode < 0) + return dev_err_probe(&st->spi->dev, -EINVAL, + "Enabled channels require more than %d mode profiles\n", + AD7768_NUM_CHANNEL_MODES); + + mode_freq[mode] =3D st->ch_freq[c]; + mode_filter[mode] =3D st->ch_filter[c]; + mode_used[mode] =3D true; + st->chn_mode[c] =3D mode; + + mask =3D ad7768_channel_mask(st, c); + ret =3D regmap_update_bits(st->regmap, AD7768_REG_CH_MODE_SEL, + mask, mode ? mask : 0); + if (ret) + return ret; + } + + ret =3D regmap_update_bits(st->regmap, AD7768_REG_CH_STANDBY, + channel_mask, standby_mask); + if (ret) + return ret; + + for (mode =3D 0; mode < AD7768_NUM_CHANNEL_MODES; mode++) { + if (!mode_used[mode]) + continue; + + ret =3D ad7768_set_mode_decimation(st, mode_freq[mode], mode); + if (ret) + return ret; + + ret =3D regmap_update_bits(st->regmap, AD7768_REG_CH_MODE(mode), + AD7768_CH_MODE_FILTER_TYPE_MSK, + AD7768_CH_MODE_FILTER_TYPE_MODE(mode_filter[mode])); + if (ret) + return ret; + + max_freq =3D max(max_freq, mode_freq[mode]); + } + + for (c =3D 0; c < st->chip_info->num_channels; c++) { + if (!test_bit(c, scan_mask)) + continue; + + ret =3D ad7768_set_channel_convdelay(st, c); + if (ret =3D=3D -EINVAL) + return dev_err_probe(&st->spi->dev, ret, + "Invalid conversion delay for channel %u\n", + c); + if (ret) + return ret; + } + + ret =3D ad7768_set_clk_divs(st, max_freq); + if (ret) + return ret; + + ret =3D ad7768_sync(st); + if (ret) + return ret; + + /* Apply a filter settling time (Datasheet table 35 and 36) */ + ad7768_filter_wait(mode_freq, mode_filter, mode_used); + + return 0; +} + +static int ad7768_set_power_mode(struct ad7768_state *st, unsigned int mod= e) +{ + unsigned int regval; + int ret; + + if (mode >=3D AD7768_NUM_POWER_MODES) + return -EINVAL; + + regval =3D ad7768_map_power_mode_to_regval(mode); + ret =3D regmap_update_bits(st->regmap, AD7768_REG_POWER_MODE, + AD7768_POWER_MODE_POWER_MODE_MSK, + AD7768_POWER_MODE_POWER_MODE(regval)); + if (ret) + return ret; + + ret =3D regmap_update_bits(st->regmap, AD7768_REG_POWER_MODE, + AD7768_POWER_MODE_MCLK_DIV_MSK, + FIELD_PREP(AD7768_POWER_MODE_MCLK_DIV_MSK, regval)); + if (ret) + return ret; + + ret =3D ad7768_sync(st); + if (ret) + return ret; + + st->power_mode =3D mode; + + return 0; +} + +static int ad7768_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long info) +{ + struct ad7768_state *st =3D iio_priv(indio_dev); + unsigned int base_reg; + unsigned int calib; + int ret; + + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(&st->spi->dev, pm); + ret =3D PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + switch (info) { + case IIO_CHAN_INFO_SAMP_FREQ: { + guard(mutex)(&st->lock); + *val =3D st->ch_freq[chan->channel]; + return IIO_VAL_INT; + } + + case IIO_CHAN_INFO_CALIBBIAS: + base_reg =3D ad7768_get_calib_reg_base(st, chan, false); + ret =3D ad7768_read_calib_value(st, base_reg, &calib); + if (ret) + return ret; + + *val =3D calib; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_CALIBSCALE: + base_reg =3D ad7768_get_calib_reg_base(st, chan, true); + ret =3D ad7768_read_calib_value(st, base_reg, &calib); + if (ret) + return ret; + + *val =3D calib; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_CONVDELAY: { + guard(mutex)(&st->lock); + iio_val_s64_decompose(st->ch_convdelay_ps[chan->channel], + val, val2); + + return IIO_VAL_DECIMAL64_PICO; + } + default: + return -EINVAL; + } +} + +static int ad7768_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, long info) +{ + switch (info) { + case IIO_CHAN_INFO_SAMP_FREQ: + case IIO_CHAN_INFO_CALIBBIAS: + case IIO_CHAN_INFO_CALIBSCALE: + return IIO_VAL_INT; + case IIO_CHAN_INFO_CONVDELAY: + return IIO_VAL_DECIMAL64_PICO; + default: + return -EINVAL; + } +} + +static int ad7768_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + struct ad7768_state *st =3D iio_priv(indio_dev); + s64 delay_ps; + unsigned int base_reg; + int ret; + + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(&st->spi->dev, pm); + ret =3D PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + switch (info) { + case IIO_CHAN_INFO_SAMP_FREQ: + return ad7768_set_sampling_freq(indio_dev, val, chan->channel); + + case IIO_CHAN_INFO_CALIBBIAS: + if (val < 0 || val > AD7768_CALIB_REG_MSK) + return -EINVAL; + + base_reg =3D ad7768_get_calib_reg_base(st, chan, false); + return ad7768_write_calib_value(st, base_reg, val); + + case IIO_CHAN_INFO_CALIBSCALE: + if (val < 0 || val > AD7768_CALIB_REG_MSK) + return -EINVAL; + + base_reg =3D ad7768_get_calib_reg_base(st, chan, true); + return ad7768_write_calib_value(st, base_reg, val); + + case IIO_CHAN_INFO_CONVDELAY: { + delay_ps =3D iio_val_s64_compose(val, val2); + if (delay_ps < 0) + return -EINVAL; + + guard(mutex)(&st->lock); + st->ch_convdelay_ps[chan->channel] =3D delay_ps; + return 0; + } + default: + return -EINVAL; + } +} + +static int ad7768_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long info) +{ + struct ad7768_state *st =3D iio_priv(indio_dev); + + if (info !=3D IIO_CHAN_INFO_SAMP_FREQ) + return -EINVAL; + + *vals =3D st->freqs; + *type =3D IIO_VAL_INT; + *length =3D st->n_freqs; + + return IIO_AVAIL_LIST; +} + +static int ad7768_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct ad7768_state *st =3D iio_priv(indio_dev); + unsigned int c; + int ret; + + ret =3D ad7768_apply_channel_modes(indio_dev, scan_mask); + if (ret) + return ret; + + for (c =3D 0; c < st->chip_info->num_channels; c++) { + if (test_bit(c, scan_mask)) + ret =3D iio_backend_chan_enable(st->back, c); + else + ret =3D iio_backend_chan_disable(st->back, c); + if (ret) + return ret; + } + + return 0; +} + +static const struct ad7768_chip_info ad7768_chip_info =3D { + .name =3D "ad7768", + .num_channels =3D 8, + .regmap_config =3D &ad7768_regmap_config, + .available_datalines =3D ad7768_available_datalines, + .num_datalines =3D ARRAY_SIZE(ad7768_available_datalines), + .chan_map =3D ad7768_chan_map, + .prebuf_split =3D 8, +}; + +static const struct ad7768_chip_info ad7768_4_chip_info =3D { + .name =3D "ad7768-4", + .num_channels =3D 4, + .regmap_config =3D &ad7768_4_regmap_config, + .available_datalines =3D ad7768_4_available_datalines, + .num_datalines =3D ARRAY_SIZE(ad7768_4_available_datalines), + .chan_map =3D ad7768_4_chan_map, + .prebuf_split =3D 4, +}; + +static int ad7768_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ad7768_state *st =3D iio_priv(indio_dev); + + return pm_runtime_resume_and_get(&st->spi->dev); +} + +static int ad7768_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad7768_state *st =3D iio_priv(indio_dev); + + pm_runtime_put_autosuspend(&st->spi->dev); + return 0; +} + +static const struct iio_buffer_setup_ops ad7768_buffer_ops =3D { + .preenable =3D ad7768_buffer_preenable, + .postdisable =3D ad7768_buffer_postdisable, +}; + +static const struct iio_info ad7768_info =3D { + .debugfs_reg_access =3D ad7768_reg_access, + .read_raw =3D ad7768_read_raw, + .write_raw_get_fmt =3D ad7768_write_raw_get_fmt, + .write_raw =3D ad7768_write_raw, + .read_avail =3D ad7768_read_avail, + .update_scan_mode =3D ad7768_update_scan_mode, +}; + +static void ad7768_set_available_sampl_freq(struct ad7768_state *st) +{ + struct ad7768_avail_freq *avail_freq; + unsigned int mclk =3D clk_get_rate(st->mclk); + unsigned int mode; + + for (mode =3D 0; mode < AD7768_NUM_POWER_MODES; mode++) { + avail_freq =3D &st->avail_freq[mode]; + for (unsigned int dec =3D ARRAY_SIZE(ad7768_dec_rate); dec > 0; dec--) { + struct ad7768_freq_config freq_cfg; + + freq_cfg.dec_rate =3D dec - 1; + freq_cfg.freq =3D mclk / (ad7768_dec_rate[dec - 1] * + ad7768_mclk_div[mode]); + avail_freq->freqs[avail_freq->n_freqs] =3D freq_cfg.freq; + avail_freq->freq_cfg[avail_freq->n_freqs++] =3D freq_cfg; + } + } + + if (st->datalines =3D=3D 1 && + st->chip_info->num_channels =3D=3D AD7768_MAX_CHANNEL) + st->avail_freq[AD7768_FAST_MODE].n_freqs--; + + for (mode =3D 0; mode < AD7768_NUM_POWER_MODES; mode++) { + avail_freq =3D &st->avail_freq[mode]; + for (unsigned int i =3D 0; i < avail_freq->n_freqs; i++) { + unsigned int freq =3D avail_freq->freqs[i]; + + if (st->n_freqs && st->freqs[st->n_freqs - 1] >=3D freq) + continue; + + st->freqs[st->n_freqs++] =3D freq; + } + } +} + +static int ad7768_gpio_adev_init(struct ad7768_state *st) +{ + struct device *dev =3D &st->spi->dev; + struct auxiliary_device *adev; + int id; + + if (!device_property_read_bool(dev, "gpio-controller")) + return 0; + + /* Use the SPI bus number and chip select to derive a stable per-device I= D. */ + id =3D (st->spi->controller->bus_num << 8) | spi_get_chipselect(st->spi, = 0); + adev =3D __devm_auxiliary_device_create(dev, KBUILD_MODNAME, "gpio", + NULL, id); + if (!adev) + return dev_err_probe(dev, -ENODEV, + "Failed to create GPIO auxiliary device\n"); + + return 0; +} + +static int ad7768_set_filter_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int mode) +{ + struct ad7768_state *st =3D iio_priv(indio_dev); + + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + guard(mutex)(&st->lock); + st->ch_filter[chan->channel] =3D mode; + return 0; +} + +static int ad7768_get_filter_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct ad7768_state *st =3D iio_priv(indio_dev); + + guard(mutex)(&st->lock); + return st->ch_filter[chan->channel]; +} + +static int ad7768_configure_precharge_buffers(struct iio_dev *indio_dev, + struct ad7768_precharge_config *precharge_cfg) +{ + struct ad7768_state *st =3D iio_priv(indio_dev); + u8 prebuf1_val, prebuf2_val; + u16 prebuf_mask =3D 0; + u8 refbufp_val =3D 0; + u8 refbufn_val =3D 0; + int ret; + u8 ch; + + for (ch =3D 0; ch < indio_dev->num_channels; ch++) { + u8 channel =3D indio_dev->channels[ch].channel; + + if (precharge_cfg[channel].prebufp_en) + prebuf_mask |=3D AD7768_PREBUF_POS_EN(channel); + + if (precharge_cfg[channel].prebufn_en) + prebuf_mask |=3D AD7768_PREBUF_NEG_EN(channel); + + if (precharge_cfg[channel].refbufp) + refbufp_val |=3D ad7768_channel_mask(st, channel); + + if (precharge_cfg[channel].refbufn) + refbufn_val |=3D ad7768_channel_mask(st, channel); + } + + prebuf1_val =3D ad7768_precharge_buf1_mask(st, ~prebuf_mask); + prebuf2_val =3D ad7768_precharge_buf2_mask(st, ~prebuf_mask); + + ret =3D regmap_write(st->regmap, AD7768_REG_PRECHARGE_BUF1, prebuf1_val); + if (ret) + return ret; + + ret =3D regmap_write(st->regmap, AD7768_REG_PRECHARGE_BUF2, prebuf2_val); + if (ret) + return ret; + + ret =3D regmap_write(st->regmap, AD7768_REG_REFP_BUF, refbufp_val); + if (ret) + return ret; + + return regmap_write(st->regmap, AD7768_REG_REFN_BUF, refbufn_val); +} + +static const char *const ad7768_filter_types[] =3D { + [AD7768_FILTER_TYPE_WIDEBAND] =3D "wideband", + [AD7768_FILTER_TYPE_SINC5] =3D "sinc5", +}; + +static const struct iio_enum ad7768_filter_types_enum =3D { + .items =3D ad7768_filter_types, + .num_items =3D ARRAY_SIZE(ad7768_filter_types), + .set =3D ad7768_set_filter_mode, + .get =3D ad7768_get_filter_mode, +}; + +static struct iio_chan_spec_ext_info ad7768_ext_info[] =3D { + IIO_ENUM("filter_type", IIO_SEPARATE, + &ad7768_filter_types_enum), + IIO_ENUM_AVAILABLE("filter_type", IIO_SEPARATE, &ad7768_filter_types_enum= ), + {} +}; + +static int ad7768_parse_config(struct iio_dev *indio_dev, + struct device *dev) +{ + struct ad7768_state *st =3D iio_priv(indio_dev); + const struct ad7768_avail_freq *avail_freq; + const unsigned int *available_datalines; + struct ad7768_precharge_config precharge_cfg[AD7768_MAX_CHANNEL] =3D { }; + struct iio_chan_spec *chan; + unsigned int num_channels; + unsigned int channel; + unsigned int i, len; + unsigned int default_freq; + int chan_idx =3D 0; + int ret; + + num_channels =3D 0; + device_for_each_child_node_scoped(dev, child) { + if (!fwnode_property_present(child, "reg")) + continue; + + num_channels++; + } + + if (!num_channels || num_channels > st->chip_info->num_channels) + return dev_err_probe(dev, -EINVAL, "Invalid number of channels\n"); + + chan =3D devm_kcalloc(indio_dev->dev.parent, num_channels, + sizeof(*chan), GFP_KERNEL); + if (!chan) + return -ENOMEM; + + indio_dev->channels =3D chan; + indio_dev->num_channels =3D num_channels; + + ret =3D regmap_write(st->regmap, AD7768_REG_CH_STANDBY, + ad7768_all_channels_mask(st)); + if (ret) + return ret; + + device_for_each_child_node_scoped(dev, child) { + if (!fwnode_property_present(child, "reg")) + continue; + + ret =3D fwnode_property_read_u32(child, "reg", &channel); + if (ret) + return dev_err_probe(dev, ret, + "Failed to parse reg property of %pfwP\n", + child); + + if (channel >=3D st->chip_info->num_channels) + return dev_err_probe(dev, -EINVAL, + "Invalid channel number %d from firmware\n", + channel); + + ret =3D regmap_update_bits(st->regmap, AD7768_REG_CH_STANDBY, + ad7768_channel_mask(st, channel), 0); + if (ret) + return ret; + + if (fwnode_property_read_bool(child, "adi,prechargebuf-pos-enable")) + precharge_cfg[channel].prebufp_en =3D true; + + if (fwnode_property_read_bool(child, "adi,prechargebuf-neg-enable")) + precharge_cfg[channel].prebufn_en =3D true; + + if (fwnode_property_read_bool(child, "adi,refbuf-pos-enable")) + precharge_cfg[channel].refbufp =3D true; + + if (fwnode_property_read_bool(child, "adi,refbuf-neg-enable")) + precharge_cfg[channel].refbufn =3D true; + + chan[chan_idx] =3D (struct iio_chan_spec) { + .type =3D IIO_VOLTAGE, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CONVDELAY) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_separate_available =3D + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .indexed =3D 1, + .address =3D channel, + .channel =3D channel, + .scan_index =3D channel, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 24, + .storagebits =3D 32, + }, + .ext_info =3D ad7768_ext_info, + }; + chan_idx++; + } + + ret =3D ad7768_configure_precharge_buffers(indio_dev, precharge_cfg); + if (ret) + return ret; + + st->datalines =3D st->chip_info->available_datalines[st->chip_info->num_d= atalines - 1]; + ret =3D device_property_read_u32(dev, "adi,data-lines-number", + &st->datalines); + if (ret && ret !=3D -EINVAL) + return dev_err_probe(dev, ret, + "Invalid \"adi,data-lines-number\" property\n"); + + ad7768_set_available_sampl_freq(st); + + /* Start in fast mode; capture setup may select another compatible mode. = */ + scoped_guard(mutex, &st->lock) { + ret =3D ad7768_set_power_mode(st, AD7768_FAST_MODE); + } + if (ret) + return dev_err_probe(dev, ret, "Failed to set power mode\n"); + + avail_freq =3D &st->avail_freq[AD7768_FAST_MODE]; + default_freq =3D avail_freq->freq_cfg[avail_freq->n_freqs - 1].freq; + for (i =3D 0; i < st->chip_info->num_channels; i++) { + st->ch_freq[i] =3D default_freq; + st->ch_filter[i] =3D AD7768_FILTER_TYPE_WIDEBAND; + } + + available_datalines =3D st->chip_info->available_datalines; + len =3D st->chip_info->num_datalines; + + for (i =3D 0; i < len; i++) { + if (available_datalines[i] =3D=3D st->datalines) + break; + } + + if (i =3D=3D len) + return dev_err_probe(dev, -EINVAL, + "Invalid data-lines-number %d for %s\n", + st->datalines, st->chip_info->name); + + return 0; +} + +static int ad7768_reset(struct ad7768_state *st) +{ + struct reset_control *reset_ctrl; + unsigned long reset_low_us; + unsigned long mclk; + int ret; + + reset_ctrl =3D devm_reset_control_get_optional_exclusive(&st->spi->dev, N= ULL); + if (IS_ERR(reset_ctrl)) + return PTR_ERR(reset_ctrl); + + if (reset_ctrl) { + mclk =3D clk_get_rate(st->mclk); + if (!mclk) + return -EINVAL; + + /* Minimum RESET low pulse width: 2 x tMCLK (datasheet Table 1). */ + reset_low_us =3D DIV_ROUND_UP_ULL(2ULL * USEC_PER_SEC, mclk); + + ret =3D reset_control_assert(reset_ctrl); + if (ret) + return ret; + + fsleep(max_t(unsigned long, 1, reset_low_us)); + + ret =3D reset_control_deassert(reset_ctrl); + if (ret) + return ret; + } else { + ret =3D regmap_write(st->regmap, AD7768_REG_DATA_CONTROL, + AD7768_DATA_CONTROL_SPI_RESET_1); + if (ret) + return ret; + + ret =3D regmap_write(st->regmap, AD7768_REG_DATA_CONTROL, + AD7768_DATA_CONTROL_SPI_RESET_2); + if (ret) + return ret; + } + + /* ADC start-up time after reset: 1.66 ms max (datasheet Table 1) */ + fsleep(2000); + + return 0; +} + +static int ad7768_probe(struct spi_device *spi) +{ + struct device *dev =3D &spi->dev; + unsigned int spi_readback, rev_id; + struct iio_dev *indio_dev; + struct ad7768_state *st; + int ret; + + indio_dev =3D devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st =3D iio_priv(indio_dev); + st->spi =3D spi; + spi_set_drvdata(spi, st); + + ret =3D devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + + st->chip_info =3D spi_get_device_match_data(spi); + + ret =3D devm_regulator_get_enable_read_voltage(dev, "avdd1"); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to enable AVDD1 supply\n"); + + st->avdd1_uv =3D ret; + + ret =3D devm_regulator_bulk_get_enable(dev, + ARRAY_SIZE(ad7768_supply_names), + ad7768_supply_names); + if (ret) + return ret; + + st->mclk =3D devm_clk_get_enabled(dev, NULL); + if (IS_ERR(st->mclk)) + return PTR_ERR(st->mclk); + + st->regmap =3D devm_regmap_init(dev, &ad7768_regmap_bus, spi, + st->chip_info->regmap_config); + if (IS_ERR(st->regmap)) + return PTR_ERR(st->regmap); + + ret =3D regmap_attach_dev(dev, st->regmap, st->chip_info->regmap_config); + if (ret) + return ret; + + ret =3D ad7768_reset(st); + if (ret) + return ret; + + /* Dummy SPI register read to discard the Reset response from the chip */ + ret =3D regmap_read(st->regmap, AD7768_REG_REV_ID, &spi_readback); + if (ret) + return ret; + + ret =3D regmap_read(st->regmap, AD7768_REG_REV_ID, &rev_id); + if (ret) + return ret; + + if (rev_id !=3D AD7768_REV_ID_VAL) + dev_warn(dev, "Unexpected revision ID 0x%02x\n", rev_id); + + ret =3D ad7768_parse_config(indio_dev, dev); + if (ret) + return ret; + + ret =3D regmap_update_bits(st->regmap, AD7768_REG_INTERFACE_CFG, + AD7768_INTERFACE_CFG_CRC_SELECT_MSK, + AD7768_INTERFACE_CFG_CRC_SELECT); + if (ret) + return ret; + + indio_dev->name =3D st->chip_info->name; + indio_dev->info =3D &ad7768_info; + + st->back =3D devm_iio_backend_get(dev, NULL); + if (IS_ERR(st->back)) + return PTR_ERR(st->back); + + ret =3D devm_iio_backend_request_buffer(dev, st->back, indio_dev); + if (ret) + return ret; + + ret =3D iio_backend_num_lanes_set(st->back, st->datalines); + if (ret) + return ret; + + ret =3D iio_backend_crc_enable(st->back); + if (ret) + return ret; + + ret =3D devm_iio_backend_enable(dev, st->back); + if (ret) + return ret; + + pm_runtime_set_autosuspend_delay(dev, 2000); + pm_runtime_use_autosuspend(dev); + ret =3D devm_pm_runtime_set_active_enabled(dev); + if (ret) + return ret; + + ret =3D ad7768_register_vcm_regulator(dev, st); + if (ret) + return dev_err_probe(dev, ret, "Failed to register VCM regulator\n"); + + indio_dev->setup_ops =3D &ad7768_buffer_ops; + + ret =3D ad7768_gpio_adev_init(st); + if (ret) + return ret; + + ret =3D devm_iio_device_register(dev, indio_dev); + if (ret) + return ret; + + ret =3D pm_request_autosuspend(dev); + if (ret < 0 && ret !=3D -EAGAIN) + return dev_err_probe(dev, ret, + "Failed to request initial autosuspend\n"); + + return 0; +} + +static int ad7768_runtime_suspend(struct device *dev) +{ + struct ad7768_state *st =3D dev_get_drvdata(dev); + + return regmap_set_bits(st->regmap, AD7768_REG_POWER_MODE, + AD7768_SLEEP_MODE_MSK); +} + +static int ad7768_runtime_resume(struct device *dev) +{ + struct ad7768_state *st =3D dev_get_drvdata(dev); + int ret; + + ret =3D regmap_clear_bits(st->regmap, AD7768_REG_POWER_MODE, + AD7768_SLEEP_MODE_MSK); + if (ret) + return ret; + + /* Empirically determined delay to re-enable ADC and digital clocks.*/ + fsleep(20000); + + return 0; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(ad7768_pm_ops, ad7768_runtime_suspend, + ad7768_runtime_resume, NULL); + +static const struct of_device_id ad7768_of_match[] =3D { + { .compatible =3D "adi,ad7768", .data =3D &ad7768_chip_info }, + { .compatible =3D "adi,ad7768-4", .data =3D &ad7768_4_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ad7768_of_match); + +static const struct spi_device_id ad7768_spi_id[] =3D { + {"ad7768", (kernel_ulong_t)&ad7768_chip_info}, + {"ad7768-4", (kernel_ulong_t)&ad7768_4_chip_info}, + { } +}; +MODULE_DEVICE_TABLE(spi, ad7768_spi_id); + +static struct spi_driver ad7768_driver =3D { + .probe =3D ad7768_probe, + .driver =3D { + .name =3D "ad7768", + .of_match_table =3D ad7768_of_match, + .pm =3D pm_ptr(&ad7768_pm_ops), + }, + .id_table =3D ad7768_spi_id, +}; +module_spi_driver(ad7768_driver); + +MODULE_AUTHOR("Stefan Popa "); +MODULE_AUTHOR("Janani Sunil "); +MODULE_DESCRIPTION("Analog Devices AD7768 ADC driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_BACKEND"); --=20 2.43.0 From nobody Fri Oct 2 01:07:41 2026 Received: from mx0a-00128a01.pphosted.com (mx0a-00128a01.pphosted.com [148.163.135.77]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 77BC9480DCB; Thu, 6 Aug 2026 15:42:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.135.77 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786030956; cv=none; b=b3SrA7fMrHRgSdd+UUSz+yU+Ak9OTPFtQKAmvHTlkVJ25p+Zhpfr6GQilBARB38hHxknmZ1kTOcjoiyCufaQaYUrg/yyXgFYUfP1Kk7usV5IidQHviI6DGwUeQ3b0ZJC2hghBoLWQ1o8no1EmPuSsrRfZ729hDOnzIOS1FYXfb0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786030956; c=relaxed/simple; bh=/J4IRhEi1Bc31VvVWteTE9nhuF4aaDgvc9V2RLSwc80=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=rXvSM7hoeBNF+61CaijvvXPGqqqB1L5bn/MFgUilS1Z0XtH8FOKBltrB+TneiJCyaCmI7VckwnihVAhyWHIxJ9wwUCSJFDdWRvIEsSX7tVHQJ0UXPZX+jZ4qiIQP8r3QWY0Q6qeWDAxakCxjEUYKz/7GSpa6+Bz7t6q3XRb9n6s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=analog.com; spf=pass smtp.mailfrom=analog.com; dkim=pass (2048-bit key) header.d=analog.com header.i=@analog.com header.b=egs6f8Mc; arc=none smtp.client-ip=148.163.135.77 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=analog.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=analog.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=analog.com header.i=@analog.com header.b="egs6f8Mc" Received: from pps.filterd (m0516787.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 676Epu6u3854093; Thu, 6 Aug 2026 11:42:20 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=analog.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=DKIM; bh=msoAY y/zJHdbdQLuhzc7AsOoqBDGP5sUvrwmvPG/DZY=; b=egs6f8McJNtlZ9tfF8BLX jymMnaFbPe5faeKeqrKJfoIvTsvE6Dn/BuXIyO6ZtJVmswqeibihLWOr8o7VZISN Q0MgF2dpQQtSGv2+Dkjih7gCmyLLjqvScWS3eUIDpdJxvXbhnKoRC6uWTBlzlQQ2 fMpeK3WbYxdMPHMI7Dtw/OM7IVqzjXDtE1Bt44rRbyGDEFVu5pJJnMhGdPED3DBh R+Wlt4CZvPy/o7w1HjAlgYarDntbgI7IdRiPeNotbuMUsJB/RLgvuaClWXRlb++K s3+iArQpU5Q/7Javsg834Nf/5N2fjNhsVJZNnLGMoDCbBCVJH2yX0evwm1tffk7h g== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4fvrcpsf7c-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 06 Aug 2026 11:42:20 -0400 (EDT) Received: from ASHBMBX8.ad.analog.com (ASHBMBX8.ad.analog.com [10.64.17.5]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 676FgJ41007050 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 6 Aug 2026 11:42:19 -0400 Received: from ASHBCASHYB5.ad.analog.com (10.64.17.133) by ASHBMBX8.ad.analog.com (10.64.17.5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Thu, 6 Aug 2026 11:42:19 -0400 Received: from ASHBMBX9.ad.analog.com (10.64.17.10) by ASHBCASHYB5.ad.analog.com (10.64.17.133) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Thu, 6 Aug 2026 11:42:18 -0400 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server id 15.2.1748.37 via Frontend Transport; Thu, 6 Aug 2026 11:42:18 -0400 Received: from HYB-e1y2fvUQ3cx.ad.analog.com ([10.32.223.174]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 676Ffcgc008127; Thu, 6 Aug 2026 11:42:11 -0400 From: Janani Sunil Date: Thu, 6 Aug 2026 17:41:24 +0200 Subject: [PATCH v2 5/7] gpio: regmap: Add runtime PM and read_output_reg_set support 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: <20260806-ad7768-driver-v2-5-027ac5e2a641@analog.com> References: <20260806-ad7768-driver-v2-0-027ac5e2a641@analog.com> In-Reply-To: <20260806-ad7768-driver-v2-0-027ac5e2a641@analog.com> To: =?utf-8?q?Nuno_S=C3=A1?= , Michael Hennerich , Jonathan Cameron , "David Lechner" , Andy Shevchenko , "Rob Herring" , Krzysztof Kozlowski , "Conor Dooley" , Olivier Moysan , Philipp Zabel , Linus Walleij , Bartosz Golaszewski , Jonathan Corbet , Shuah Khan , Michael Walle CC: , , , , , , , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Janani Sunil X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786030898; l=8989; i=janani.sunil@analog.com; s=20260507; h=from:subject:message-id; bh=/J4IRhEi1Bc31VvVWteTE9nhuF4aaDgvc9V2RLSwc80=; b=CpzPjC/nhIdYdmsGrUhbghsCg8PBgykMIJvgB2P3PDJHu+ieI5hWghototroTZA4EOeshvkLh uLEuDAFihodBNHEEeyEZ13s8q4duokJmc4NyK8/aP2CBDpjhSY5VU8R X-Developer-Key: i=janani.sunil@analog.com; a=ed25519; pk=e25MyjRLPY3RWrYm/LrJ+/+t1MZJUbkgIW5CZg+g+hA= X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-GUID: zzTwpDpinh5LNQsE1zKm7qFTHfSKVyFI X-Proofpoint-Spam-Info: AW1haW4tMjYwODA2MDEyMSBTYWx0ZWRfX6wuS7tq0EiKs fTTdT0HEK2R4RHiPJBd0roTUjx0qGTDDsVOhFOsaFr6zwsT+vmB/jd2ThgVp6Bs8eIb2/sAI5Qb +tpqEuYd9E/8rQZnPvhVMe5ye9JyNzcMBn91W2XzWDTE7TZtod4a X-Proofpoint-ORIG-GUID: zzTwpDpinh5LNQsE1zKm7qFTHfSKVyFI X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODA2MDEyMSBTYWx0ZWRfX1P9ZZhPrWXS3 EfEl9sRhKSRP8oyKI0Vj8kjQ4m87YQGkU8HQG+hns7dA+GbY4ZH0bMz68hW0L6Pz3pNKDWvcnVo HioBYE0Cq4/w9DeIgyaLmgtiUMJSUaTrzmsUTN2yG0ZkCQaFJQ5SBPvjPVSmI9Xc8FQA0J1i5qV 3qplp9KaYoPU69MWbGY0yHmRA1J4qLv2xMTYiIwelfnxhw+PFXEFH+DizeWCT/ZDTAVj+Rirbd3 Vg2rwq7Pj1t6YdCmW7ECezrKHEX27h+8uDVSQ8vHizBi73ijJEkgC0KOReqwJuXHieM/QSfqBU6 PYV3lxlKWeSVhn9tt9C6E5Tf8xYrpyCwRArdYGf9qR4c8mUllDa3nShdpBZ45vtAWGltK6dQ5uq S2K1OhjaOujaMfbx0Qp576P8y/NERcBa1pw3JeSoBe2qMU74wm2vnm/tUBxv8qaW3JGw7gug2oD AjOauuCl2ILjhX2ZWeA== X-Authority-Analysis: v=2.4 cv=IPwyzAvG c=1 sm=1 tr=0 ts=6a74ab5c cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=OmVn7CZJonkx5R5zMQLL:22 a=gAnH3GRIAAAA:8 a=WNRwWYYUYu9DqMPRriAA:9 a=QEXdDO2ut3YA:10 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-06_01,2026-08-05_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1011 priorityscore=1501 impostorscore=0 lowpriorityscore=0 phishscore=0 malwarescore=0 bulkscore=0 spamscore=0 suspectscore=0 adultscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2608060121 The new pm_dev field in gpio_regmap_config allows a driver to supply a device for runtime PM. All operations call pm_runtime_resume_and_get() before accessing the regmap and pm_runtime_put_autosuspend() on return. The new read_output_reg_set flag when set, gpio_regmap_get() checks the pin direction first and reads from reg_set_base instead of reg_dat_base for output pins. Requires both reg_dat_base and reg_set_base to be configured. Signed-off-by: Janani Sunil --- drivers/gpio/gpio-regmap.c | 113 +++++++++++++++++++++++++++++++++++++---= ---- include/linux/gpio/regmap.h | 8 ++++ 2 files changed, 105 insertions(+), 16 deletions(-) diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index 51b4d69b8740..b94d3c51013a 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,8 @@ struct gpio_regmap { unsigned int reg_clr_base; unsigned int reg_dir_in_base; unsigned int reg_dir_out_base; + struct device *pm_dev; + bool read_output_reg_set; unsigned long *fixed_direction_mask; unsigned long *fixed_direction_output; =20 @@ -67,6 +70,23 @@ static int gpio_regmap_simple_xlate(struct gpio_regmap *= gpio, return 0; } =20 +static int gpio_regmap_runtime_get(struct gpio_regmap *gpio) +{ + if (!gpio->pm_dev) + return 0; + + return pm_runtime_resume_and_get(gpio->pm_dev); +} + +static void gpio_regmap_runtime_put(struct gpio_regmap *gpio) +{ + if (gpio->pm_dev) + pm_runtime_put_autosuspend(gpio->pm_dev); +} + +static int gpio_regmap_get_direction(struct gpio_chip *chip, + unsigned int offset); + static int gpio_regmap_get(struct gpio_chip *chip, unsigned int offset) { struct gpio_regmap *gpio =3D gpiochip_get_data(chip); @@ -79,19 +99,34 @@ static int gpio_regmap_get(struct gpio_chip *chip, unsi= gned int offset) else base =3D gpio_regmap_addr(gpio->reg_set_base); =20 - ret =3D gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + if (gpio->read_output_reg_set) { + ret =3D gpio_regmap_get_direction(chip, offset); + if (ret < 0) + return ret; + + if (ret =3D=3D GPIO_LINE_DIRECTION_OUT) + base =3D gpio_regmap_addr(gpio->reg_set_base); + } + + ret =3D gpio_regmap_runtime_get(gpio); if (ret) return ret; =20 + ret =3D gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + if (ret) + goto out_pm; + /* ensure we don't spoil any register cache with pin input values */ if (gpio->reg_dat_base =3D=3D gpio->reg_set_base) ret =3D regmap_read_bypassed(gpio->regmap, reg, &val); else ret =3D regmap_read(gpio->regmap, reg, &val); - if (ret) - return ret; + if (!ret) + ret =3D !!(val & mask); =20 - return !!(val & mask); +out_pm: + gpio_regmap_runtime_put(gpio); + return ret; } =20 static int gpio_regmap_set(struct gpio_chip *chip, unsigned int offset, @@ -102,10 +137,14 @@ static int gpio_regmap_set(struct gpio_chip *chip, un= signed int offset, unsigned int reg, mask, mask_val; int ret; =20 - ret =3D gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + ret =3D gpio_regmap_runtime_get(gpio); if (ret) return ret; =20 + ret =3D gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + if (ret) + goto out_pm; + if (val) mask_val =3D mask; else @@ -117,6 +156,8 @@ static int gpio_regmap_set(struct gpio_chip *chip, unsi= gned int offset, else ret =3D regmap_update_bits(gpio->regmap, reg, mask, mask_val); =20 +out_pm: + gpio_regmap_runtime_put(gpio); return ret; } =20 @@ -127,6 +168,10 @@ static int gpio_regmap_set_with_clear(struct gpio_chip= *chip, unsigned int base, reg, mask; int ret; =20 + ret =3D gpio_regmap_runtime_get(gpio); + if (ret) + return ret; + if (val) base =3D gpio_regmap_addr(gpio->reg_set_base); else @@ -134,9 +179,13 @@ static int gpio_regmap_set_with_clear(struct gpio_chip= *chip, =20 ret =3D gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); if (ret) - return ret; + goto out_pm; + + ret =3D regmap_write(gpio->regmap, reg, mask); =20 - return regmap_write(gpio->regmap, reg, mask); +out_pm: + gpio_regmap_runtime_put(gpio); + return ret; } =20 static bool gpio_regmap_fixed_direction(struct gpio_regmap *gpio, @@ -182,18 +231,26 @@ static int gpio_regmap_get_direction(struct gpio_chip= *chip, return -ENOTSUPP; } =20 - ret =3D gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + ret =3D gpio_regmap_runtime_get(gpio); if (ret) return ret; =20 + ret =3D gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + if (ret) + goto out_pm; + ret =3D regmap_read(gpio->regmap, reg, &val); if (ret) - return ret; + goto out_pm; =20 if (!!(val & mask) ^ invert) - return GPIO_LINE_DIRECTION_OUT; + ret =3D GPIO_LINE_DIRECTION_OUT; else - return GPIO_LINE_DIRECTION_IN; + ret =3D GPIO_LINE_DIRECTION_IN; + +out_pm: + gpio_regmap_runtime_put(gpio); + return ret; } =20 static int gpio_regmap_try_direction_fixed(struct gpio_regmap *gpio, @@ -236,16 +293,24 @@ static int gpio_regmap_set_direction(struct gpio_chip= *chip, return -ENOTSUPP; } =20 - ret =3D gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + ret =3D gpio_regmap_runtime_get(gpio); if (ret) return ret; =20 + ret =3D gpio->reg_mask_xlate(gpio, base, offset, ®, &mask); + if (ret) + goto out_pm; + if (invert) val =3D output ? 0 : mask; else val =3D output ? mask : 0; =20 - return regmap_update_bits(gpio->regmap, reg, mask, val); + ret =3D regmap_update_bits(gpio->regmap, reg, mask, val); + +out_pm: + gpio_regmap_runtime_put(gpio); + return ret; } =20 static int gpio_regmap_direction_input(struct gpio_chip *chip, @@ -260,6 +325,10 @@ static int gpio_regmap_direction_output(struct gpio_ch= ip *chip, struct gpio_regmap *gpio =3D gpiochip_get_data(chip); int ret; =20 + ret =3D gpio_regmap_runtime_get(gpio); + if (ret) + return ret; + /* * First check if this is gonna work on a fixed direction line, * if it doesn't (i.e. this is a fixed input line), then do not @@ -268,12 +337,18 @@ static int gpio_regmap_direction_output(struct gpio_c= hip *chip, if (gpio_regmap_fixed_direction(gpio, offset)) { ret =3D gpio_regmap_try_direction_fixed(gpio, offset, true); if (ret) - return ret; + goto out_pm; } =20 - gpio_regmap_set(chip, offset, value); + ret =3D gpio_regmap_set(chip, offset, value); + if (ret) + goto out_pm; + + ret =3D gpio_regmap_set_direction(chip, offset, true); =20 - return gpio_regmap_set_direction(chip, offset, true); +out_pm: + gpio_regmap_runtime_put(gpio); + return ret; } =20 void *gpio_regmap_get_drvdata(struct gpio_regmap *gpio) @@ -307,6 +382,10 @@ struct gpio_regmap *gpio_regmap_register(const struct = gpio_regmap_config *config (!config->reg_dat_base || !config->reg_set_base)) return ERR_PTR(-EINVAL); =20 + if (config->read_output_reg_set && + (!config->reg_dat_base || !config->reg_set_base)) + return ERR_PTR(-EINVAL); + /* we don't support having both registers simultaneously for now */ if (config->reg_dir_out_base && config->reg_dir_in_base) return ERR_PTR(-EINVAL); @@ -323,6 +402,8 @@ struct gpio_regmap *gpio_regmap_register(const struct g= pio_regmap_config *config gpio->reg_clr_base =3D config->reg_clr_base; gpio->reg_dir_in_base =3D config->reg_dir_in_base; gpio->reg_dir_out_base =3D config->reg_dir_out_base; + gpio->pm_dev =3D config->pm_dev; + gpio->read_output_reg_set =3D config->read_output_reg_set; =20 chip =3D &gpio->gpio_chip; chip->parent =3D config->parent; diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h index 06255756710d..5b353ae5b167 100644 --- a/include/linux/gpio/regmap.h +++ b/include/linux/gpio/regmap.h @@ -3,6 +3,8 @@ #ifndef _LINUX_GPIO_REGMAP_H #define _LINUX_GPIO_REGMAP_H =20 +#include + struct device; struct fwnode_handle; struct gpio_regmap; @@ -29,6 +31,10 @@ struct regmap; * @reg_clr_base: (Optional) clear register base address * @reg_dir_in_base: (Optional) in setting register base address * @reg_dir_out_base: (Optional) out setting register base address + * @pm_dev: (Optional) Device to use for runtime power management. + * @read_output_reg_set: + * (Optional) Read output values from @reg_set_base + * instead of @reg_dat_base. * @reg_stride: (Optional) May be set if the registers (of the * same type, dat, set, etc) are not consecutive. * @ngpio_per_reg: (Optional) Number of GPIOs per register @@ -92,6 +98,8 @@ struct gpio_regmap_config { unsigned int reg_clr_base; unsigned int reg_dir_in_base; unsigned int reg_dir_out_base; + struct device *pm_dev; + bool read_output_reg_set; int reg_stride; int ngpio_per_reg; struct irq_domain *irq_domain; --=20 2.43.0 From nobody Fri Oct 2 01:07:41 2026 Received: from mx0a-00128a01.pphosted.com (mx0a-00128a01.pphosted.com [148.163.135.77]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6E1BC47ACF5; Thu, 6 Aug 2026 15:42:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.135.77 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786030959; cv=none; b=E/IoZury1RbcXyClQz2ADYsOfdkzPcHDgW+NmFx8YqXjIG+SW8dyL7PN3Z7MIp9B2WihWm+1hGs8Dp2AVDv2lNNHZsx1+vD+rwwdX4pLwaOQH1zZO4paiPbCZ5briLlBHc/4DMf0DTDhphHJ9YNDrLo3HXpjQRmWCuE70zVuxuo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786030959; c=relaxed/simple; bh=9kJl2kW//AccQc1VtCWi3Lvy644KfSQouzIVzRnD9s4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=e2Qn33Y0IZCFugSe5swULUKB3yftePMAQKKXEXcBnkX999HxgC75MWMOPDYa/JcgBrhEwEJ+0rGDFjiSBIoyXsy6vVshj/enF6mdiI4k5oZ/iToNFuNtZTiy5JLfcvnH0RDhsisKrIobvqEXo4VRCkKFbZDlRXg3Uij36MgflMs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=analog.com; spf=pass smtp.mailfrom=analog.com; dkim=pass (2048-bit key) header.d=analog.com header.i=@analog.com header.b=jqXVvb9z; arc=none smtp.client-ip=148.163.135.77 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=analog.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=analog.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=analog.com header.i=@analog.com header.b="jqXVvb9z" Received: from pps.filterd (m0516787.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 676EpnIg3853943; Thu, 6 Aug 2026 11:42:24 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=analog.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=DKIM; bh=SbO5w 0zDUANeGwzvyfcdBkQpYVTVzu4uAMtg1ASmw4I=; b=jqXVvb9zQBQFvzi+YAZn/ BbQ7n9pk1L7W4Lsan/2ks/bvnD9qgOTax5qiP8DKYOqR9PdMLz2LqVrsq3Wi/FLL Th/Vs3JC/pR15qsuO1kSz8soMsBBepeq7HhY5S9yW7cIH48kFQgS//JM4N61yWBo cGOyJ1PwnmbElktHz/mQ+q/uwOjwefUAUnqUz1KqWZM9810RY41U52DhAReEKobh j+upnr4lnFSiM44DavB4HWOXWwQMSKYpM7EUVlZayxbmeIb0TK7dqKe8IkoY0dwM MHhj1mysdbtpKc8cLlAqtO6fk1g77Q8NMARS6CbfHrkBXquIBUZaBVIzL0sK7IBP Q== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4fvrcpsf7h-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 06 Aug 2026 11:42:23 -0400 (EDT) Received: from ASHBMBX9.ad.analog.com (ASHBMBX9.ad.analog.com [10.64.17.10]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 676FgMuO007053 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 6 Aug 2026 11:42:22 -0400 Received: from ASHBCASHYB4.ad.analog.com (10.64.17.132) by ASHBMBX9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Thu, 6 Aug 2026 11:42:22 -0400 Received: from ASHBMBX9.ad.analog.com (10.64.17.10) by ASHBCASHYB4.ad.analog.com (10.64.17.132) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Thu, 6 Aug 2026 11:42:22 -0400 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server id 15.2.1748.37 via Frontend Transport; Thu, 6 Aug 2026 11:42:21 -0400 Received: from HYB-e1y2fvUQ3cx.ad.analog.com ([10.32.223.174]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 676Ffcgd008127; Thu, 6 Aug 2026 11:42:14 -0400 From: Janani Sunil Date: Thu, 6 Aug 2026 17:41:25 +0200 Subject: [PATCH v2 6/7] gpio: ad7768: Add AD7768 GPIO auxiliary 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: <20260806-ad7768-driver-v2-6-027ac5e2a641@analog.com> References: <20260806-ad7768-driver-v2-0-027ac5e2a641@analog.com> In-Reply-To: <20260806-ad7768-driver-v2-0-027ac5e2a641@analog.com> To: =?utf-8?q?Nuno_S=C3=A1?= , Michael Hennerich , Jonathan Cameron , "David Lechner" , Andy Shevchenko , "Rob Herring" , Krzysztof Kozlowski , "Conor Dooley" , Olivier Moysan , Philipp Zabel , Linus Walleij , Bartosz Golaszewski , Jonathan Corbet , Shuah Khan , Michael Walle CC: , , , , , , , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Janani Sunil X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786030898; l=4652; i=janani.sunil@analog.com; s=20260507; h=from:subject:message-id; bh=9kJl2kW//AccQc1VtCWi3Lvy644KfSQouzIVzRnD9s4=; b=MIwPsJ9O0A3OQNuWClbrcroTEQq2Oe4FR2Rrp3HRlHEoLuCtCiQ6kn1v0vRceVwsRY8vZifnS pr1Pq0BV2jJBASiA307S74jR9s0C8qXuMp0278zrBt5OELE11Dy1y0W X-Developer-Key: i=janani.sunil@analog.com; a=ed25519; pk=e25MyjRLPY3RWrYm/LrJ+/+t1MZJUbkgIW5CZg+g+hA= X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-GUID: chvbL1IAEICgMkJETQQYp0zj5VxvUndk X-Proofpoint-Spam-Info: AW1haW4tMjYwODA2MDEyMSBTYWx0ZWRfX5RhjBUXD8gwE GJocOfDqyypUFxQy5xsT7oRb7IvmsiiSlQkp74Ja2YbF80GnDRRN8/kQ2AuEJsIADr2I0WN0+JB vXtza1dEVZ5dBdu1ZXeZu8dgNCyDucxdzPHghc3UEAd9IyZffzoQ X-Proofpoint-ORIG-GUID: chvbL1IAEICgMkJETQQYp0zj5VxvUndk X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODA2MDEyMSBTYWx0ZWRfX71bj7RXpJJDZ GiqJnJjhQuW/oD8I6tcjqnQ2ruQVajFuQI2b7lZJD2gF+Hha4vuUi8fF3O1EEjDVGJgxQEvoVyj hEoaKbtGVBQS2i9slxvpCM7YnQLuQFurWRXHp2Ua/Ch0cGGyvghJdtXLspCBIJWYrCa3Ctr2KXL KqBViB8bVaMva+NitCo0dNGM4hh+4vSqqjWMH7r0jQbZC5bwVk+fKET2VFbs8sn5tihiUccNAbM q+QkwVT21lp3Aydr40SheBCqePZMJZLtdmeb/m0xW03ABnjdih68790A3lXg8nXsHDZOVOskZ4d d+Ku4DNPrZwHCmgwvDhAw7bZEI3o1IAXP6k7KpO9YML+uMNaBnvNdAmuYeIifbZWYXX9vKiDHYt KT+X//t5M4l7jSjl0RLKX8urzoDiifKI5JEEtC+0RPB5NeTSADijqbCKNx0hw/1+FL64AICSKQP HWr/oPaPjMpgEIrWVlA== X-Authority-Analysis: v=2.4 cv=IPwyzAvG c=1 sm=1 tr=0 ts=6a74ab5f cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=OmVn7CZJonkx5R5zMQLL:22 a=gAnH3GRIAAAA:8 a=VwQbUJbxAAAA:8 a=1Q08i5ohD067ZOfjyW0A:9 a=QEXdDO2ut3YA:10 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-06_01,2026-08-05_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 priorityscore=1501 impostorscore=0 lowpriorityscore=0 phishscore=0 malwarescore=0 bulkscore=0 spamscore=0 suspectscore=0 adultscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2608060121 The AD7768/AD7768-4 ADC exposes 5 general-purpose I/O pins that can be independently configured as inputs or outputs. Add an auxiliary bus driver to expose these pins as a GPIO chip, registered by the parent IIO driver. The driver uses the parent's regmap for register access and delegates runtime power management to the parent device. Signed-off-by: Janani Sunil --- MAINTAINERS | 1 + drivers/gpio/Kconfig | 12 +++++++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-ad7768.c | 78 ++++++++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 92 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index dc94e7803a7c..3de7ebcc4ee7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1639,6 +1639,7 @@ L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7768.yaml +F: drivers/gpio/gpio-ad7768.c F: drivers/iio/adc/ad7768.c =20 ANALOG DEVICES INC AD7780 DRIVER diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 28cf6d2e83c2..85cb0c82a823 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1796,6 +1796,18 @@ endmenu menu "Auxiliary Bus GPIO drivers" depends on AUXILIARY_BUS =20 +config GPIO_AD7768 + tristate "Analog Devices AD7768 GPIO support" + depends on AD7768 + depends on GPIOLIB + select GPIO_REGMAP + help + Say yes here to expose the AD7768 utility pins as GPIOs when the + device tree node is marked as a GPIO controller. + + To compile this driver as a module, choose M here: the module will be + called gpio-ad7768. + config GPIO_LTC4283 tristate "Analog Devices LTC4283 GPIO support" depends on SENSORS_LTC4283 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 4d0e900402fc..d2921963efc7 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_GPIO_104_IDI_48) +=3D gpio-104-idi-48.o obj-$(CONFIG_GPIO_104_IDIO_16) +=3D gpio-104-idio-16.o obj-$(CONFIG_GPIO_74X164) +=3D gpio-74x164.o obj-$(CONFIG_GPIO_74XX_MMIO) +=3D gpio-74xx-mmio.o +obj-$(CONFIG_GPIO_AD7768) +=3D gpio-ad7768.o obj-$(CONFIG_GPIO_ADNP) +=3D gpio-adnp.o obj-$(CONFIG_GPIO_ADP5520) +=3D gpio-adp5520.o obj-$(CONFIG_GPIO_ADP5585) +=3D gpio-adp5585.o diff --git a/drivers/gpio/gpio-ad7768.c b/drivers/gpio/gpio-ad7768.c new file mode 100644 index 000000000000..70c024460e0c --- /dev/null +++ b/drivers/gpio/gpio-ad7768.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD7768 GPIO auxiliary driver + * + * Copyright 2026 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AD7768_REG_GPIO_CONTROL 0x0E +#define AD7768_REG_GPIO_WRITE 0x0F +#define AD7768_REG_GPIO_READ 0x10 + +#define AD7768_GPIO_UGPIO_ENABLE BIT(7) + +#define AD7768_NUM_GPIOS 5 + +static int ad7768_gpio_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct device *dev =3D &adev->dev; + struct gpio_regmap_config config =3D { + .parent =3D dev, + .label =3D dev_name(dev->parent), + .ngpio =3D AD7768_NUM_GPIOS, + .reg_dat_base =3D AD7768_REG_GPIO_READ, + .reg_set_base =3D AD7768_REG_GPIO_WRITE, + .reg_dir_out_base =3D AD7768_REG_GPIO_CONTROL, + .pm_dev =3D dev->parent, + .read_output_reg_set =3D true, + }; + struct gpio_regmap *gpio; + struct regmap *regmap; + int ret; + + regmap =3D dev_get_regmap(dev->parent, NULL); + if (!regmap) + return -ENODEV; + + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(dev->parent, pm); + ret =3D PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + ret =3D regmap_set_bits(regmap, AD7768_REG_GPIO_CONTROL, + AD7768_GPIO_UGPIO_ENABLE); + if (ret) + return ret; + + config.regmap =3D regmap; + gpio =3D devm_gpio_regmap_register(dev, &config); + + return PTR_ERR_OR_ZERO(gpio); +} + +static const struct auxiliary_device_id ad7768_gpio_ids[] =3D { + { .name =3D "ad7768.gpio" }, + { } +}; +MODULE_DEVICE_TABLE(auxiliary, ad7768_gpio_ids); + +static struct auxiliary_driver ad7768_gpio_driver =3D { + .probe =3D ad7768_gpio_probe, + .id_table =3D ad7768_gpio_ids, +}; +module_auxiliary_driver(ad7768_gpio_driver); + +MODULE_AUTHOR("Janani Sunil "); +MODULE_DESCRIPTION("Analog Devices AD7768 GPIO auxiliary driver"); +MODULE_LICENSE("GPL"); --=20 2.43.0 From nobody Fri Oct 2 01:07:41 2026 Received: from mx0a-00128a01.pphosted.com (mx0a-00128a01.pphosted.com [148.163.135.77]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 96D9E481FAA; Thu, 6 Aug 2026 15:42:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.135.77 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786030965; cv=none; b=si2GS66DX1G4TdsrvRRdf+IAGHAKNWCSV6Ww32rstc7vWklTXnMP3Hi7OpqzVVfaErJBHLCFwE3xIGj0pqX6ituGPxSitqk/BzRLgNUZczJxfguIBQEtkcgEyBDPmKmSuNZsDVVgijo34lat+dnGCiwwKFtxCu6smladiBSIJGQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786030965; c=relaxed/simple; bh=1ks0MtrgN84/U8zlbSUjz1xlNJazOkeWgbKqYUkAVSQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=EN3ymf+v8rdpmf5lvFDxL6KBku/3eAj6DiaoD/YmjXQsXInnfqc28wk/UxYCyljfW3JjE1wVZNawipVI8l/ShnRbg9mNdQjdPlWv/3j5Yp1RL/g42H4CRw3fvogP3Kkk2X9pS32KABuAZzYb2HNyMwn5g6HPMc440W4FKgzynjo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=analog.com; spf=pass smtp.mailfrom=analog.com; dkim=pass (2048-bit key) header.d=analog.com header.i=@analog.com header.b=m9kKXEBO; arc=none smtp.client-ip=148.163.135.77 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=analog.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=analog.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=analog.com header.i=@analog.com header.b="m9kKXEBO" Received: from pps.filterd (m0167088.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 676EqFxG4057041; Thu, 6 Aug 2026 11:42:27 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=analog.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=DKIM; bh=sA/3k O5fABjHCB/Pho9WiHGXh5c8p+Dcv4n7IGcE1ec=; b=m9kKXEBODcz3LUBBfHQ0B OxarrwDOjzudIteaUco/nfqvVIQrUaZFk2KWEjIuet308p+jt4gLw3bPXNc12Vtd MPykbVJAAxk0JWyEsfCIlwxLqrWIzerfJG+kEeX0tBJ+ZPT0oMU+AbDA4+zUfdP+ SVtxl+1DDBWwZUDrCJAJ2q14fmFl+9SA6GTqjKoUMZtQV/lgKgOpWbBFk2hY0040 QVn3+IRYBcQc0gUgtMqnxwi5wCkq6ZC8Bwu/q5R4Pv3e7KG7M8BCb0Ya7SDsqole AMBA/WxyNXA1fQrAUENPMJE4LibIwKld3u/r1HmwPY6JRR/Pn9Vo2AwtwFzO117k A== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4fvp4ttnpn-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 06 Aug 2026 11:42:26 -0400 (EDT) Received: from ASHBMBX9.ad.analog.com (ASHBMBX9.ad.analog.com [10.64.17.10]) by nwd2mta4.analog.com (8.14.7/8.14.7) with ESMTP id 676FgPiL007059 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 6 Aug 2026 11:42:25 -0400 Received: from ASHBCASHYB5.ad.analog.com (10.64.17.133) by ASHBMBX9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Thu, 6 Aug 2026 11:42:25 -0400 Received: from ASHBMBX9.ad.analog.com (10.64.17.10) by ASHBCASHYB5.ad.analog.com (10.64.17.133) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.37; Thu, 6 Aug 2026 11:42:24 -0400 Received: from zeus.spd.analog.com (10.66.68.11) by ashbmbx9.ad.analog.com (10.64.17.10) with Microsoft SMTP Server id 15.2.1748.37 via Frontend Transport; Thu, 6 Aug 2026 11:42:24 -0400 Received: from HYB-e1y2fvUQ3cx.ad.analog.com ([10.32.223.174]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 676Ffcge008127; Thu, 6 Aug 2026 11:42:17 -0400 From: Janani Sunil Date: Thu, 6 Aug 2026 17:41:26 +0200 Subject: [PATCH v2 7/7] Documentation: iio: Add AD7768 Documentation 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: <20260806-ad7768-driver-v2-7-027ac5e2a641@analog.com> References: <20260806-ad7768-driver-v2-0-027ac5e2a641@analog.com> In-Reply-To: <20260806-ad7768-driver-v2-0-027ac5e2a641@analog.com> To: =?utf-8?q?Nuno_S=C3=A1?= , Michael Hennerich , Jonathan Cameron , "David Lechner" , Andy Shevchenko , "Rob Herring" , Krzysztof Kozlowski , "Conor Dooley" , Olivier Moysan , Philipp Zabel , Linus Walleij , Bartosz Golaszewski , Jonathan Corbet , Shuah Khan , Michael Walle CC: , , , , , , , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Janani Sunil X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786030898; l=9520; i=janani.sunil@analog.com; s=20260507; h=from:subject:message-id; bh=1ks0MtrgN84/U8zlbSUjz1xlNJazOkeWgbKqYUkAVSQ=; b=WEwqp5cAYph5mSeeK8qgLTJDXmVL+nDIiZmzYhJv06X/mBWMKzFboO1wyl4U5QDWCLl2Helgx 6WwZa0A+cA9Bp2XjDhmSTKRg8NR+JiMrZExVqvg1hxTVkUzC/qF1p4C X-Developer-Key: i=janani.sunil@analog.com; a=ed25519; pk=e25MyjRLPY3RWrYm/LrJ+/+t1MZJUbkgIW5CZg+g+hA= X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-ORIG-GUID: xCZ-jQYlIyuDojCAXs5FnLsYneIuPHq_ X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODA2MDEyMSBTYWx0ZWRfX/m5C20pcmr8y 8AynjfRp8GFUpg87QMfOVNJU5wpA2pUobsQlSq04TYRtu7zOs1xuU2H+/OKmIFVco7aIUu2icyJ hS2zE/+DdvGI6+K2uVPXY9lHhk9WNe944oABPBrHNwvjY2F1dtKip6Nc9sqh5TGmpT2skG2SeLe hUzg7Gi7b+T66v6aAb5GZGX2FvHcTOi7BzPVQ/gaROBco2w5pfliLXrYaFbXiXyC/MIwL9nKe2m Ea2aw44c50f+SKR4czBVHe8lE51lfmcevxgf1NdSNyizO+HmnzxTt5MiNghN8ty4rTOQuvx90Qk qVEewD9N3gKmQlsRVPkGdsQ3D/PhDysGKO2l4R5qg4k0xWnpDdIYmZrLsaaORtCX3aHNhm5nIv7 P13VH+j1qyDySX4dsuCkyJoGogAaP5vqQ6UgleqYZGX/Z9P8R7MpLPZnXEoZb+UGBwwsZ239+n/ pSvuMPBQonbjX6a762g== X-Authority-Analysis: v=2.4 cv=CIYamxrD c=1 sm=1 tr=0 ts=6a74ab63 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=IkcTkHD0fZMA:10 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=uXIjobp8t2wMuQ0fPvqm:22 a=gAnH3GRIAAAA:8 a=VwQbUJbxAAAA:8 a=oqaN6P3t42WLEIsmr8gA:9 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 X-Proofpoint-GUID: xCZ-jQYlIyuDojCAXs5FnLsYneIuPHq_ X-Proofpoint-Spam-Info: AW1haW4tMjYwODA2MDEyMSBTYWx0ZWRfX4rSZ7TJbaBZK FqWLRXYE5/Q6P24zLUGS4x3uBInvE2zfFp7ld6JhRb8sT3BpNI0xG+VTVvfkVqbjMzHmOFsvlRK NANs0LmWEOQsIvHFlgGFXmYfa/xrdj7s7KneVIZDGKzj7ric4/GV X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-06_01,2026-08-05_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 bulkscore=0 clxscore=1015 adultscore=0 malwarescore=0 suspectscore=0 lowpriorityscore=0 spamscore=0 priorityscore=1501 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2608060121 Add driver documentation for AD7768. Signed-off-by: Janani Sunil --- Documentation/iio/ad7768.rst | 240 +++++++++++++++++++++++++++++++++++++++= ++++ Documentation/iio/index.rst | 1 + MAINTAINERS | 1 + 3 files changed, 242 insertions(+) diff --git a/Documentation/iio/ad7768.rst b/Documentation/iio/ad7768.rst new file mode 100644 index 000000000000..928d4dbc0fea --- /dev/null +++ b/Documentation/iio/ad7768.rst @@ -0,0 +1,240 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +AD7768 driver +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +ADC driver for Analog Devices Inc. AD7768 and AD7768-4 devices. The module= name +is ``ad7768``. + +Supported devices +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The following chips are supported by this driver: + +* `AD7768 `_ - + 8-channel, 24-bit simultaneous sampling ADC +* `AD7768-4 `_ - + 4-channel, 24-bit simultaneous sampling ADC + +Supported features +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Power modes +----------- + +The AD7768 family supports three power and performance modes: + +* **Low power mode** - Optimized for lowest power consumption +* **Median mode** - Balanced power and performance +* **Fast mode** - Highest performance with maximum sampling rates + +The driver initializes the device in fast mode and uses the maximum fast-m= ode +output data rate as the default sampling frequency. + +When buffered capture starts, the driver selects the lowest-noise mode tha= t can +produce the requested output data rates for all enabled channels. Where ou= tput +data rates overlap, fast mode is preferred over median mode, and median mo= de is +preferred over low power mode. This prioritizes the lower RMS noise and hi= gher +dynamic range offered by a faster mode at the same output data rate. + +Data output configuration +------------------------- + +The devices support flexible serial data output configurations: + +AD7768 data lines +^^^^^^^^^^^^^^^^^ + +* 1 data line (DOUT0) - Standard single-lane output +* 2 data lines (DOUT0, DOUT1) - Dual-lane output for higher throughput +* 8 data lines (DOUT0-DOUT7) - Maximum throughput, one line per channel + +AD7768-4 data lines +^^^^^^^^^^^^^^^^^^^ + +* 1 data line (DOUT0) - Standard single-lane output +* 4 data lines (DOUT0-DOUT3) - Maximum throughput, one line per channel + +The number of data lines can be configured via the ``adi,data-lines-number= `` +device tree property. If omitted, the driver uses the maximum supported by= the +selected variant: eight lines for AD7768 and four lines for AD7768-4. + +Channel configuration +--------------------- + +Each channel can be individually configured with: + +Channel modes +^^^^^^^^^^^^^ + +* **Mode A** - First set of filter and decimation settings +* **Mode B** - Second set of filter and decimation settings + +The hardware provides two mode profiles (A and B), each holding one +(frequency, filter) combination. When buffered capture is started, +enabled channels are grouped by their configured (frequency, filter) +pair. Up to two distinct groups are supported; the driver automatically +assigns each group to a mode slot and programs the hardware accordingly. + +Precharge and reference buffers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Per-channel buffer control for optimal signal integrity: + +* Positive input precharge buffer (``adi,prechargebuf-pos-enable``) +* Negative input precharge buffer (``adi,prechargebuf-neg-enable``) +* Positive reference buffer (``adi,refbuf-pos-enable``) +* Negative reference buffer (``adi,refbuf-neg-enable``) + +Common mode voltage +------------------- + +The VCM pin provides a buffered common-mode voltage output used to bias +the analog inputs. The driver exposes this as a standard voltage regulator +provider under a ``regulators`` subnode in the device tree. Supported +output voltage levels are: + +* (AVDD1 - AVSS) / 2 - Mid-supply (hardware default), reported as half the + voltage provided by ``avdd1-supply`` +* 1,650,000 =C2=B5V - 1.65V +* 2,500,000 =C2=B5V - 2.5V +* 2,140,000 =C2=B5V - 2.14V + +The regulator can be enabled and disabled at runtime using the standard +regulator framework interfaces. + +The VCM circuitry is associated with channel 0. When VCM is used externall= y, +``channel@0`` must be present in the device tree and channel 0 must remain +enabled in the active scan mask. Placing channel 0 in standby disables the= VCM +output. + +Filter types +------------ + +Two digital filter types are available: + +* **Wideband** - Optimized for wide bandwidth applications +* **Sinc5** - Fifth-order sinc filter for high rejection of out-of-band no= ise + +IIO backend support +------------------- + +The driver integrates with IIO backends (e.g., AXI ADC) for high-speed data +capture and DMA operations. Features include: + +* Automatic channel enable/disable based on scan mask +* CRC on data interface. CRC replaces the header every 4th output sample. +* High-throughput buffered data acquisition + +GPIO controller +--------------- + +The AD7768 includes a 5-pin GPIO controller for auxiliary digital I/O +operations. The GPIO pins can be configured as inputs or outputs. + +Device attributes +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The following IIO attributes are available for each enabled channel: + +Sampling frequency +------------------ + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - Attribute + - Description + * - ``in_voltage_sampling_frequency`` + - Requested sampling frequency in Hz for channel N. Enabled channels = are + grouped into up to two profiles at capture time. + * - ``in_voltage_sampling_frequency_available`` + - Available sampling frequencies in Hz for channel N across all power + modes, based on the master clock frequency. Buffer setup fails if no + single power mode supports the frequencies requested by all enabled + channels. + +Filter configuration +--------------------- + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - Attribute + - Description + * - ``in_voltage_filter_type`` + - Requested filter type for channel N: "wideband" or "sinc5". It is + grouped with sampling frequency at capture time. + * - ``in_voltage_filter_type_available`` + - Available filter types for channel N: "wideband sinc5". + +Per-channel calibration +----------------------- + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - Attribute + - Description + * - ``in_voltage_calibbias`` + - Raw unsigned 24-bit channel offset register value. + * - ``in_voltage_calibscale`` + - Raw unsigned 24-bit channel gain register value. + * - ``in_voltage_convdelay`` + - Per-channel conversion delay. The driver exposes the phase/modulator + delay register in seconds with picosecond precision. Resolution and + valid range depend on the decimation ratio in use (see datasheet + Table 30). + +Device buffers +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +This driver supports IIO buffered data acquisition through IIO backends. +When used with compatible backends like the AXI ADC, it provides: + +* High-speed simultaneous sampling across all enabled channels +* Hardware-triggered data capture +* DMA-based data transfer for minimal CPU overhead +* CRC error detection + +See :doc:`iio_devbuf` for more information about IIO device buffers. + +Example usage +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +.. code-block:: bash + + # Read current sampling frequency for channel 0 + cat /sys/bus/iio/devices/iio:device0/in_voltage0_sampling_frequency + + # Update sampling frequency for channel 0 + echo 8000 > /sys/bus/iio/devices/iio:device0/in_voltage0_sampling_frequen= cy + + # Read current filter type for channel 0 + cat /sys/bus/iio/devices/iio:device0/in_voltage0_filter_type + + # List available filter types for channel 0 + cat /sys/bus/iio/devices/iio:device0/in_voltage0_filter_type_available + + # Update filter type for channel 0 to wideband + echo wideband > /sys/bus/iio/devices/iio:device0/in_voltage0_filter_type + + # Buffer setup fails if enabled channels request more than two distinct + # (sampling frequency, filter type) combinations. + + # Read calibration scale for channel 0 + cat /sys/bus/iio/devices/iio:device0/in_voltage0_calibscale + + # Read conversion delay for channel 0 + cat /sys/bus/iio/devices/iio:device0/in_voltage0_convdelay + + +Unimplemented features +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +* CRC message every 16 samples (CRC_SEL configuration) - currently only + supports CRC every 4 samples diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst index b02b879b053a..73c58cec7620 100644 --- a/Documentation/iio/index.rst +++ b/Documentation/iio/index.rst @@ -29,6 +29,7 @@ Industrial I/O Kernel Drivers ad7380 ad7606 ad7625 + ad7768 ad7944 ade9000 adf41513 diff --git a/MAINTAINERS b/MAINTAINERS index 3de7ebcc4ee7..b93c77d3a4c3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1639,6 +1639,7 @@ L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7768.yaml +F: Documentation/iio/ad7768.rst F: drivers/gpio/gpio-ad7768.c F: drivers/iio/adc/ad7768.c =20 --=20 2.43.0