From nobody Sat Jul 25 15:24:48 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 33E0A3BFAC0; Thu, 16 Jul 2026 21:09:40 +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=1784236183; cv=none; b=hDQDfm5eNb2fNaP2WyttyaVO5zsZrJwfe/lyAm9ErNv2IRnBk2IAejwlSCGl/l3xO6ZSX4ghPqFSYLYXQeXLir4jGjqtN5CqUd8iOYJBGG60+O40QYrvAnpPECgyGJvzyy9L4pwxY5Ss/NtWR+r1Hcu46bJYKrYEEV8uTQeYhRQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784236183; c=relaxed/simple; bh=P6MYvSMZNG+LurdNFTuAS4rrwfk+ft2JueljbH7t6Xc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=sw4UjUQnJ4dk1EROnfk5P2GA3ROPv4Mc9+BMnTfYrRH7ioi52gH6HV8qnYZ6iraQZ44Q/DWqfDPFPPF6HpOLvQYaEgS9AeXoOFwmdbDCnJaa1ikhzGFBVC/Z446YCTQNiNhK5qOjYL7tqUAU9G04X3jzBV8rHAHHb5Lg2P3U5RQ= 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=ktDSVdUA; 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="ktDSVdUA" Received: from pps.filterd (m0167089.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 66GJq7AR259810; Thu, 16 Jul 2026 17:09:31 -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=Vs7cq mIZFxtyb5H8YXK0HZwCbk+Q45mYwNO9Idp5PIM=; b=ktDSVdUA528x7cVkMO8hC EeTxSMpg6s7bOXEzQheNqtz27O+QkAa4Ts6toIYUp18rgKGVEkcG2Gse5fLvMwNn bUbS6Lg7YoI/we0Ygd3N6Z5/tYJ3nR3XV9lhc3zqYlOW6VYPOHTCYFBiJwr8FXJw 2Dkzy53eExcooHXlRBMORj9/Djo0yVxwoWi7a7oYO3gd7QGG9Wl+hX68pUTMp53J g78n7aWxrIegQM+jBbJOeo1Ks9bvHIhQVcCwCCqupzJ5fdjUSrc2IphF3+Q1YwOy PpBAp9az5+eJ0I6TSdPANlMn8tZS51ENY4ndeB2OvE5jeQBdQcq8afZG4brlTmr+ A== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4fe70e7buh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 16 Jul 2026 17:09:31 -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 66GL9UP2004253 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 16 Jul 2026 17:09:30 -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, 16 Jul 2026 17:09:30 -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, 16 Jul 2026 17:09:30 -0400 Received: from work.maxim-ic.internal ([10.66.6.192]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 66GL9Gmm004872; Thu, 16 Jul 2026 17:09:19 -0400 From: Marcelo Schmitt To: , , CC: , , , , , , , , , , Conor Dooley Subject: [PATCH v7 1/4] dt-bindings: iio: adc: Add ltc2378 Date: Thu, 16 Jul 2026 18:09:11 -0300 Message-ID: <2749638687643d6e162bbc80fb13a06a3102d996.1784235595.git.marcelo.schmitt@analog.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNzE2MDIxNSBTYWx0ZWRfX+N7Tx/OZRN1U qr7YignVpxi2uJqCP0hfUVBarUSjFxITVX29a2bxFPEoDxwYm2YHqyGulH3SG4xB2z8cVhKVCes tIwe5wI0MAFlpfX9ZnrcjL2IyjRK56xZHe7vtNiX03zSGj3+5dWpPSQSnoaiE/uQPRmiWsvadWQ d1hzTbXc+vl/ZJbgdV/EZP8J40d4Du5rQLMIW9hlzF2Z9BFm1tQf+2SszAbMD90oeNvNhInr27a Pt4SUZ5VrWYqHq2QXP77xhjfLSDZYkB/3q0JYacgPmpvX6ftWKGVRTtvzrGwud7hwowGEOGmN76 sr9n1QOi8shpDPRfNou9yeB0dBl5KaVqq/MwXkM6ukRCf2zXSNqQi2gl6tysVuyhpXOvU8T4URe IITNAHbdDdJMpYaNOootU9wqRWlR2WTsdnVr7iMA8Jj2w7XLfJNc+b9P9b1L1p/9TU7BgTlL7d9 iN90/HHT5Zur97Fm9ZA== X-Proofpoint-ORIG-GUID: DPzDAL5Gj7JvKaS-fDD9P-acZFCEvFvi X-Authority-Analysis: v=2.4 cv=XsLK/1F9 c=1 sm=1 tr=0 ts=6a59488b cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=RAioF0-LDSMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=Z0pTeXoby7EwIRygza74:22 a=gEfo2CItAAAA:8 a=gAnH3GRIAAAA:8 a=IpJZQVW2AAAA:8 a=XYAwZIGsAAAA:8 a=VwQbUJbxAAAA:8 a=zHdOwAC9n8DEQaShn0QA:9 a=sptkURWiP4Gy88Gu7hUp:22 a=IawgGOuG5U0WyFbmm1f5:22 a=E8ToXWR_bxluHZ7gmE-Z:22 X-Proofpoint-Spam-Info: AW1haW4tMjYwNzE2MDIxNSBTYWx0ZWRfXx5MpAeK7p9kh NZJARLYxx/9ly59YATn69p6yHIolqGxpJiGQrsbgHb6nWVEhE3WUf/qyPB+WIRVnkIo+JFG6wbu gTF2UAVhPwytKV7Oro2L1+mG124fKZJRRx8HTp78fkhGUlBDa+k1 X-Proofpoint-GUID: DPzDAL5Gj7JvKaS-fDD9P-acZFCEvFvi X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-07-16_07,2026-07-15_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 spamscore=0 bulkscore=0 lowpriorityscore=0 phishscore=0 clxscore=1015 priorityscore=1501 adultscore=0 malwarescore=0 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2607160215 Content-Type: text/plain; charset="utf-8" Document how to describe LTC2378-20 and similar ADCs in device tree. Reviewed-by: David Lechner Reviewed-by: Conor Dooley Signed-off-by: Marcelo Schmitt Reviewed-by: Andy Shevchenko --- Change log v6 -> v7: No changes in v7. .../bindings/iio/adc/adi,ltc2378.yaml | 170 ++++++++++++++++++ MAINTAINERS | 7 + 2 files changed, 177 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ltc2378.y= aml diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml b/D= ocumentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file mode 100644 index 000000000000..33de1dc4c256 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml @@ -0,0 +1,170 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ltc2378.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices LTC2378 and similar Analog to Digital Converters + +maintainers: + - Marcelo Schmitt + +description: | + Analog Devices LTC2378 series of ADCs. + Specifications can be found at: + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 3818fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 6416fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 6418f.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 6716fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 6718f.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 6816f.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 6818f.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 6918fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 7016fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 7616fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 7618fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 7620fb.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 7716fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 7718fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 7720fb.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 7816fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 7818fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 7820fb.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 7918fb.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/23= 8016fb.pdf + +$ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + oneOf: + # Single compatible string match. + - enum: + - adi,ltc2338-18 + - adi,ltc2364-16 + - adi,ltc2364-18 + - adi,ltc2376-16 + - adi,ltc2376-18 + - adi,ltc2376-20 + + # Low sample rate fallback for 16-bit unipolar sensors. + - items: + - enum: + - adi,ltc2370-16 # 2 MSPS + - adi,ltc2368-16 # 1 MSPS + - adi,ltc2367-16 # 500 kSPS + - const: adi,ltc2364-16 # fallback (250 kSPS) + + # Low sample rate fallback for 18-bit unipolar sensors. + - items: + - enum: + - adi,ltc2369-18 # 1.6 MSPS + - adi,ltc2368-18 # 1 MSPS + - adi,ltc2367-18 # 500 kSPS + - const: adi,ltc2364-18 # fallback (250 kSPS) + + # Low sample rate fallback for 16-bit bipolar sensors. + - items: + - enum: + - adi,ltc2380-16 # 2 MSPS + - adi,ltc2378-16 # 1 MSPS + - adi,ltc2377-16 # 500 kSPS + - const: adi,ltc2376-16 # fallback (250 kSPS) + + # Low sample rate fallback for 18-bit bipolar sensors. + - items: + - enum: + - adi,ltc2379-18 # 1.6 MSPS + - adi,ltc2378-18 # 1 MSPS + - adi,ltc2377-18 # 500 kSPS + - const: adi,ltc2376-18 # fallback (250 kSPS) + + # Low sample rate fallback for 20-bit bipolar sensors. + - items: + - enum: + - adi,ltc2378-20 # 1 MSPS + - adi,ltc2377-20 # 500 kSPS + - const: adi,ltc2376-20 # fallback (250 kSPS) + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 100000000 + + vdd-supply: + description: A 2.5V supply that powers the chip (VDD). + + ovdd-supply: + description: + A 1.71V to 5.25V supply that sets the logic level for digital interf= ace. + + ref-supply: + description: + Voltage reference input that determines the scale of ADC conversions. + + refin-supply: + description: + Alternative voltage reference input. + + cnv-gpios: + description: + When provided, this property indicates the GPIO that is connected to= the + CNV pin. + maxItems: 1 + + pwms: + description: PWM signal connected to the CNV pin. + maxItems: 1 + + interrupts: + description: + Interrupt for signaling the completion of conversion results. The ac= tive + low signal provided on the BUSY pin asserts when ADC conversions fin= ish. + maxItems: 1 + +required: + - compatible + - reg + - vdd-supply + - ovdd-supply + +allOf: + # Except for LTC2338, all designs require a voltage reference input + - if: + properties: + compatible: + not: + contains: + enum: + - adi,ltc2338-18 + then: + required: + - ref-supply + properties: + refin-supply: false + else: + properties: + ref-supply: false + +unevaluatedProperties: false + +examples: + - | + #include + #include + spi { + #address-cells =3D <1>; + #size-cells =3D <0>; + adc@0 { + compatible =3D "adi,ltc2378-20", "adi,ltc2376-20"; + reg =3D <0>; + spi-max-frequency =3D <71000000>; + vdd-supply =3D <&supply_2_5V>; + ovdd-supply =3D <&supply_3_3V>; + ref-supply =3D <&supply_5V>; + cnv-gpios =3D <&gpio0 88 GPIO_ACTIVE_HIGH>; + interrupts =3D <7 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent =3D <&gpio>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 2b1ec46c5919..f0ae26699c99 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15343,6 +15343,13 @@ S: Maintained F: Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml F: drivers/iio/dac/ltc1660.c =20 +LTC2378 IIO ADC DRIVER +M: Marcelo Schmitt +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml + LTC2664 IIO DAC DRIVER M: Michael Hennerich M: Kim Seer Paller --=20 2.53.0 From nobody Sat Jul 25 15:24:48 2026 Received: from mx0b-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 D296D3B14A4; Thu, 16 Jul 2026 21:09:59 +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=1784236202; cv=none; b=J1krO8deYq5NUAa+lnzmJyvVhw4qaEcGcAlGcSIdO2HC4gylgoO/ihs6zOjyYfjWYyd5WNDPc8oPEWnPfpz5Mn3mEV/gaFNPRwnlDMZ7UvSqyYh6WV/SN5iapGvGG6yIa77iE3ocvhzqBaTRgxTEUNIOymK2owhV3mDcYOebCMo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784236202; c=relaxed/simple; bh=Z2ROn6OuTw6OP8hgYw0RHfsPXCalI3jCntLGaQKbuh0=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=c/UdbV5dQki2vW47gcrThhLgYw08ileo/iG7VYWTLOrU0hKiKk6kmVzl5KY5LGJy2GPiaZOE4xSBJDZqWSX9Ymb19JsLWdaK2uefNAGrdpp5W7LCXawp7MWlE6KwxCM/UkZFSiJ7DDqaBnHGALNXBLgf+PF+0joa2C0ixmeFm/0= 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=dZ7zCBu3; 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="dZ7zCBu3" Received: from pps.filterd (m0375855.ppops.net [127.0.0.1]) by mx0b-00128a01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 66GJqmf7116554; Thu, 16 Jul 2026 17:09:55 -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=cq7+Y 4WeIDWOyRYgq8e2mYS4Sw6ZdvFq3NjEnG8XrJc=; b=dZ7zCBu3tMx1U7vaulJwB HQJbqNtu5vd+7C3C2a3SowXrv0k7ygPDSdu9gfIXg/jHJzlvP79KuraXjDS/mmKB cnebKRPGP88CsYsQnY0R8VcKajEWjvUii0Zb5WiC9HWwddGOAWOT/2WYG4WziaUp 2XW2XQQrZhcyEatLRxHkCZ6jwcONXBzXd2JTE9Bzl/PxOqbXLr7qHS6voCUI3Ufz 7qagdWnR/dIeDPh+zSWZCfgHFZSUElXh8AhdH8ZOUDUl5mW8WfSY8+ioeOV129Nh jCYQhnxoUmh1k8rOKVv161k4Yy4nqHZKTNkn7GH7DqAqjX2jyNxhDyvrAWtbEfqT Q== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0b-00128a01.pphosted.com (PPS) with ESMTPS id 4ff005snta-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 16 Jul 2026 17:09:54 -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 66GL9rHE004277 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 16 Jul 2026 17:09:53 -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, 16 Jul 2026 17:09:53 -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, 16 Jul 2026 17:09:53 -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, 16 Jul 2026 17:09:53 -0400 Received: from work.maxim-ic.internal ([10.66.6.192]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 66GL9fRr004876; Thu, 16 Jul 2026 17:09:44 -0400 From: Marcelo Schmitt To: , , CC: , , , , , , , , , Subject: [PATCH v7 2/4] iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs Date: Thu, 16 Jul 2026 18:09:36 -0300 Message-ID: <5108c89986ae8723139419058db1b2f2e74daff6.1784235595.git.marcelo.schmitt@analog.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-ORIG-GUID: AJWrQxaanLZ_jgGt_IvLCL55EV4ic3fk X-Proofpoint-GUID: AJWrQxaanLZ_jgGt_IvLCL55EV4ic3fk X-Proofpoint-Spam-Info: AW1haW4tMjYwNzE2MDIxNiBTYWx0ZWRfX1n6haCLsmQZs fN6WyLFmCt4qIcrjqR/EqO17CgXm5YCLA13B0IZA4n5nw3oYC9kQy4LhsGru+Hq61ALI0hBUcpw r2EPoQTMc6elSbRdIy/4EFmDR3q24IavmWH2SqRKxlPSHCI+DkyK X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNzE2MDIxNiBTYWx0ZWRfXyp6ffrShfVyJ bUeSezMHaQUAkcMHwb5zBZsT/eYgRRp2UwaBYReeQRvzc/gB1qad/nMPNMgd5+UsuIQgHSW/ppf 71+KaopKaV0IVbujZ1dwwewscwsOZlw8sbFoA6Bm6mRtZEN6dgG2WYAf4r2WXSaPKj5rodrzBlW 0IPjqjJOWDSzWKjKH9DP2tS+uROpmuwRJrhliEl6XJJ7A/kRxnIcgv6JJyJkhodNtzSGdXLFYcj NRtaXAHBYT1J2X2FGKgOO7Md+Qr2mzLgHLAAzEgx1gti7U74IyO9ZZljFuO/M+FxV14LAzWB2ez bBuVmxoYxl0e/brLIdeqFJGhwzFS4jQC3LmF7SCRZNQPZJdF+lkJsBVYLhP05qd2uCRdNbk+uMt XrelVHJFdw+3l3NHoIx/m/n6mg8Mq/0ydys5AOTWrF1bMaxiMGURQrXUzMIJlWIOq2SGgEAJVIx 2pw8PE+Hgg6aYnltu7w== X-Authority-Analysis: v=2.4 cv=ceziaHDM c=1 sm=1 tr=0 ts=6a5948a2 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=RAioF0-LDSMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=N--XFCr6TIEc_64PeIT2:22 a=gAnH3GRIAAAA:8 a=IpJZQVW2AAAA:8 a=VwQbUJbxAAAA:8 a=ZZGAMBLAlkmGxc5ICUcA:9 a=IawgGOuG5U0WyFbmm1f5:22 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-07-16_07,2026-07-15_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 priorityscore=1501 adultscore=0 clxscore=1015 bulkscore=0 malwarescore=0 lowpriorityscore=0 spamscore=0 phishscore=0 impostorscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2607160216 Content-Type: text/plain; charset="utf-8" Support for LTC2378-20 and similar analog-to-digital converters. Reviewed-by: David Lechner Signed-off-by: Marcelo Schmitt Reviewed-by: Andy Shevchenko --- Change log v6 -> v7: - Extended single-read critical section scope (holding mutex lock longer). - Added comment about conversion wait time. - When applicable, return early from regulator setup. - Wrapped transfer buffer declaration comment closer to 80 characters. Some bits related to the SPI transfer buffer are introduced early to minimi= ze the change diff of the followup offload enablement patch. MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 12 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ltc2378.c | 416 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 430 insertions(+) create mode 100644 drivers/iio/adc/ltc2378.c diff --git a/MAINTAINERS b/MAINTAINERS index f0ae26699c99..25821b771692 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15349,6 +15349,7 @@ L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml +F: drivers/iio/adc/ltc2378.c =20 LTC2664 IIO DAC DRIVER M: Michael Hennerich diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index d1b198cb8a80..220c6739a8f2 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -943,6 +943,18 @@ config LTC2309 This driver can also be built as a module. If so, the module will be called ltc2309. =20 +config LTC2378 + tristate "Analog Devices LTC2378 ADC driver" + depends on SPI + depends on REGULATOR || COMPILE_TEST + depends on GPIOLIB + help + Say yes here to build support for Analog Devices LTC2378-20 and + similar analog to digital converters. + + This driver can also be built as a module. If so, the module will + be called ltc2378. + config LTC2471 tristate "Linear Technology LTC2471 and LTC2473 ADC driver" depends on I2C diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 0f90b75577ff..6058a8be6ccd 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -81,6 +81,7 @@ obj-$(CONFIG_LP8788_ADC) +=3D lp8788_adc.o obj-$(CONFIG_LPC18XX_ADC) +=3D lpc18xx_adc.o obj-$(CONFIG_LPC32XX_ADC) +=3D lpc32xx_adc.o obj-$(CONFIG_LTC2309) +=3D ltc2309.o +obj-$(CONFIG_LTC2378) +=3D ltc2378.o obj-$(CONFIG_LTC2471) +=3D ltc2471.o obj-$(CONFIG_LTC2485) +=3D ltc2485.o obj-$(CONFIG_LTC2496) +=3D ltc2496.o ltc2497-core.o diff --git a/drivers/iio/adc/ltc2378.c b/drivers/iio/adc/ltc2378.c new file mode 100644 index 000000000000..5600c820c7f4 --- /dev/null +++ b/drivers/iio/adc/ltc2378.c @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Analog Devices LTC2378 ADC series driver + * + * Copyright (C) 2026 Analog Devices Inc. + * Author: Marcelo Schmitt + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define LTC2378_MAX_DATA_WAIT_US 4 /* max(TBUSYLH + TCONV + TDSDOBUSYL) */ + +#define LTC2378_DIFF_CHANNEL(_sign, _real_bits, _storage_bits) \ +{ \ + .type =3D IIO_VOLTAGE, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index =3D 0, \ + .scan_type =3D { \ + .format =3D _sign ? IIO_SCAN_FORMAT_SIGNED_INT : \ + IIO_SCAN_FORMAT_UNSIGNED_INT, \ + .realbits =3D _real_bits, \ + .storagebits =3D _storage_bits, \ + .shift =3D _storage_bits - _real_bits, \ + .endianness =3D IIO_BE, \ + }, \ +} + +#define LTC2378_BIPOLAR_DIFF_CHANNEL(_real_bits) \ + LTC2378_DIFF_CHANNEL(1, _real_bits, (((_real_bits) > 16) ? 32 : 16)) + +#define LTC2378_UNIPOLAR_DIFF_CHANNEL(_real_bits) \ + LTC2378_DIFF_CHANNEL(0, _real_bits, (((_real_bits) > 16) ? 32 : 16)) + +struct ltc2378_chip_info { + const char *name; + unsigned int internal_ref_uV; + struct iio_chan_spec chan; +}; + +struct ltc2378_state { + const struct ltc2378_chip_info *info; + struct gpio_desc *cnv_gpio; + struct spi_device *spi; + struct mutex lock; /* Protect data acquisition cycle */ + int ref_uV; + struct spi_transfer xfer; + + /* + * DMA (thus cache coherency maintenance) requires the transfer buffers + * to live in their own cache lines. + */ + struct { + union { + __be16 sample_buf16_be; + __be32 sample_buf32_be; + u16 sample_buf16; + u32 sample_buf32; + } data; + aligned_s64 timestamp; + } scan __aligned(IIO_DMA_MINALIGN); +}; + +static const struct ltc2378_chip_info ltc2338_18_chip_info =3D { + .name =3D "ltc2338-18", + .internal_ref_uV =3D 2048000, + .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(18), +}; + +static const struct ltc2378_chip_info ltc2364_16_chip_info =3D { + .name =3D "ltc2364-16", + .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(16), +}; + +static const struct ltc2378_chip_info ltc2364_18_chip_info =3D { + .name =3D "ltc2364-18", + .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(18), +}; + +static const struct ltc2378_chip_info ltc2367_16_chip_info =3D { + .name =3D "ltc2367-16", + .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(16), +}; + +static const struct ltc2378_chip_info ltc2367_18_chip_info =3D { + .name =3D "ltc2367-18", + .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(18), +}; + +static const struct ltc2378_chip_info ltc2368_16_chip_info =3D { + .name =3D "ltc2368-16", + .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(16), +}; + +static const struct ltc2378_chip_info ltc2368_18_chip_info =3D { + .name =3D "ltc2368-18", + .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(18), +}; + +static const struct ltc2378_chip_info ltc2369_18_chip_info =3D { + .name =3D "ltc2369-18", + .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(18), +}; + +static const struct ltc2378_chip_info ltc2370_16_chip_info =3D { + .name =3D "ltc2370-16", + .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(16), +}; + +static const struct ltc2378_chip_info ltc2376_16_chip_info =3D { + .name =3D "ltc2376-16", + .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(16), +}; + +static const struct ltc2378_chip_info ltc2376_18_chip_info =3D { + .name =3D "ltc2376-18", + .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(18), +}; + +static const struct ltc2378_chip_info ltc2376_20_chip_info =3D { + .name =3D "ltc2376-20", + .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(20), +}; + +static const struct ltc2378_chip_info ltc2377_16_chip_info =3D { + .name =3D "ltc2377-16", + .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(16), +}; + +static const struct ltc2378_chip_info ltc2377_18_chip_info =3D { + .name =3D "ltc2377-18", + .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(18), +}; + +static const struct ltc2378_chip_info ltc2377_20_chip_info =3D { + .name =3D "ltc2377-20", + .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(20), +}; + +static const struct ltc2378_chip_info ltc2378_16_chip_info =3D { + .name =3D "ltc2378-16", + .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(16), +}; + +static const struct ltc2378_chip_info ltc2378_18_chip_info =3D { + .name =3D "ltc2378-18", + .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(18), +}; + +static const struct ltc2378_chip_info ltc2378_20_chip_info =3D { + .name =3D "ltc2378-20", + .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(20), +}; + +static const struct ltc2378_chip_info ltc2379_18_chip_info =3D { + .name =3D "ltc2379-18", + .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(18), +}; + +static const struct ltc2378_chip_info ltc2380_16_chip_info =3D { + .name =3D "ltc2380-16", + .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(16), +}; + +static int ltc2378_convert_and_acquire(struct ltc2378_state *st) +{ + int ret; + + /* Cause a rising edge of CNV to initiate a new ADC conversion */ + gpiod_set_value_cansleep(st->cnv_gpio, 1); + fsleep(LTC2378_MAX_DATA_WAIT_US); + ret =3D spi_sync_transfer(st->spi, &st->xfer, 1); + gpiod_set_value_cansleep(st->cnv_gpio, 0); + + return ret; +} + +static int ltc2378_channel_single_read(const struct iio_chan_spec *chan, + struct ltc2378_state *st, int *val) +{ + const struct iio_scan_type *scan_type =3D &chan->scan_type; + u32 sample; + int ret; + + guard(mutex)(&st->lock); + ret =3D ltc2378_convert_and_acquire(st); + if (ret) + return ret; + + if (chan->scan_type.endianness =3D=3D IIO_BE) { + if (chan->scan_type.realbits > 16) + sample =3D be32_to_cpu(st->scan.data.sample_buf32_be); + else + sample =3D be16_to_cpu(st->scan.data.sample_buf16_be); + } else { /* IIO_CPU */ + if (chan->scan_type.realbits > 16) + sample =3D st->scan.data.sample_buf32; + else + sample =3D st->scan.data.sample_buf16; + } + + sample >>=3D chan->scan_type.shift; + + if (scan_type->format =3D=3D IIO_SCAN_FORMAT_SIGNED_INT) + *val =3D sign_extend32(sample, scan_type->realbits - 1); + else + *val =3D sample; + + return 0; +} + +static int ltc2378_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct ltc2378_state *st =3D iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: { + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + ret =3D ltc2378_channel_single_read(chan, st, val); + if (ret) + return ret; + + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_SCALE: + *val =3D st->ref_uV / MILLI; + /* + * For all LTC2378-like devices, the amount of bits that express + * voltage magnitude depend on the polarity / output code format: + * - straight binary: All precision/resolution bits are used. + * - 2's complement: One of the precision bits is used for sign. + */ + if (chan->scan_type.format =3D=3D IIO_SCAN_FORMAT_SIGNED_INT) + *val2 =3D chan->scan_type.realbits - 1; + else + *val2 =3D chan->scan_type.realbits; + + return IIO_VAL_FRACTIONAL_LOG2; + + default: + return -EINVAL; + } +} + +static const struct iio_info ltc2378_iio_info =3D { + .read_raw =3D <c2378_read_raw, +}; + +static int ltc2378_refin_setup(struct device *dev, struct ltc2378_state *s= t) +{ + int ret; + + /* + * The internal reference buffer amplifies both the internal reference + * and REFIN by a factor of 2. + */ + ret =3D devm_regulator_get_enable_read_voltage(dev, "refin"); + if (ret =3D=3D -ENODEV) { /* refin is optional */ + st->ref_uV =3D st->info->internal_ref_uV * 2; + return 0; + } else if (ret < 0) { + return dev_err_probe(dev, ret, "failed to read refin regulator\n"); + } + + st->ref_uV =3D ret * 2; + + return 0; +} + +static int ltc2378_ref_setup(struct device *dev, struct ltc2378_state *st) +{ + int ret; + + ret =3D devm_regulator_get_enable_read_voltage(dev, "ref"); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to read ref regulator\n"); + + st->ref_uV =3D ret; + + return 0; +} + +static int ltc2378_probe(struct spi_device *spi) +{ + struct device *dev =3D &spi->dev; + struct iio_dev *indio_dev; + struct ltc2378_state *st; + int ret; + + indio_dev =3D devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st =3D iio_priv(indio_dev); + st->spi =3D spi; + + ret =3D devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + + st->info =3D spi_get_device_match_data(spi); + if (!st->info) + return -EINVAL; + + if (st->info->internal_ref_uV) + ret =3D ltc2378_refin_setup(dev, st); + else + ret =3D ltc2378_ref_setup(dev, st); + if (ret) + return ret; + + indio_dev->name =3D st->info->name; + indio_dev->info =3D <c2378_iio_info; + indio_dev->modes =3D INDIO_DIRECT_MODE; + + st->cnv_gpio =3D devm_gpiod_get(dev, "cnv", GPIOD_OUT_LOW); + if (IS_ERR(st->cnv_gpio)) + return dev_err_probe(dev, PTR_ERR(st->cnv_gpio), + "failed to get CNV GPIO"); + + indio_dev->channels =3D &st->info->chan; + indio_dev->num_channels =3D 1; + + st->xfer.rx_buf =3D &st->scan.data; + st->xfer.len =3D spi_bpw_to_bytes(indio_dev->channels[0].scan_type.realbi= ts); + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct of_device_id ltc2378_of_match[] =3D { + { .compatible =3D "adi,ltc2338-18", .data =3D <c2338_18_chip_info }, + { .compatible =3D "adi,ltc2364-16", .data =3D <c2364_16_chip_info }, + { .compatible =3D "adi,ltc2364-18", .data =3D <c2364_18_chip_info }, + { .compatible =3D "adi,ltc2367-16", .data =3D <c2367_16_chip_info }, + { .compatible =3D "adi,ltc2367-18", .data =3D <c2367_18_chip_info }, + { .compatible =3D "adi,ltc2368-16", .data =3D <c2368_16_chip_info }, + { .compatible =3D "adi,ltc2368-18", .data =3D <c2368_18_chip_info }, + { .compatible =3D "adi,ltc2369-18", .data =3D <c2369_18_chip_info }, + { .compatible =3D "adi,ltc2370-16", .data =3D <c2370_16_chip_info }, + { .compatible =3D "adi,ltc2376-16", .data =3D <c2376_16_chip_info }, + { .compatible =3D "adi,ltc2376-18", .data =3D <c2376_18_chip_info }, + { .compatible =3D "adi,ltc2376-20", .data =3D <c2376_20_chip_info }, + { .compatible =3D "adi,ltc2377-16", .data =3D <c2377_16_chip_info }, + { .compatible =3D "adi,ltc2377-18", .data =3D <c2377_18_chip_info }, + { .compatible =3D "adi,ltc2377-20", .data =3D <c2377_20_chip_info }, + { .compatible =3D "adi,ltc2378-16", .data =3D <c2378_16_chip_info }, + { .compatible =3D "adi,ltc2378-18", .data =3D <c2378_18_chip_info }, + { .compatible =3D "adi,ltc2378-20", .data =3D <c2378_20_chip_info }, + { .compatible =3D "adi,ltc2379-18", .data =3D <c2379_18_chip_info }, + { .compatible =3D "adi,ltc2380-16", .data =3D <c2380_16_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ltc2378_of_match); + +static const struct spi_device_id ltc2378_spi_id[] =3D { + { .name =3D "ltc2338-18", .driver_data =3D (kernel_ulong_t)<c2338_18_ch= ip_info }, + { .name =3D "ltc2364-16", .driver_data =3D (kernel_ulong_t)<c2364_16_ch= ip_info }, + { .name =3D "ltc2364-18", .driver_data =3D (kernel_ulong_t)<c2364_18_ch= ip_info }, + { .name =3D "ltc2367-16", .driver_data =3D (kernel_ulong_t)<c2367_16_ch= ip_info }, + { .name =3D "ltc2367-18", .driver_data =3D (kernel_ulong_t)<c2367_18_ch= ip_info }, + { .name =3D "ltc2368-16", .driver_data =3D (kernel_ulong_t)<c2368_16_ch= ip_info }, + { .name =3D "ltc2368-18", .driver_data =3D (kernel_ulong_t)<c2368_18_ch= ip_info }, + { .name =3D "ltc2369-18", .driver_data =3D (kernel_ulong_t)<c2369_18_ch= ip_info }, + { .name =3D "ltc2370-16", .driver_data =3D (kernel_ulong_t)<c2370_16_ch= ip_info }, + { .name =3D "ltc2376-16", .driver_data =3D (kernel_ulong_t)<c2376_16_ch= ip_info }, + { .name =3D "ltc2376-18", .driver_data =3D (kernel_ulong_t)<c2376_18_ch= ip_info }, + { .name =3D "ltc2376-20", .driver_data =3D (kernel_ulong_t)<c2376_20_ch= ip_info }, + { .name =3D "ltc2377-16", .driver_data =3D (kernel_ulong_t)<c2377_16_ch= ip_info }, + { .name =3D "ltc2377-18", .driver_data =3D (kernel_ulong_t)<c2377_18_ch= ip_info }, + { .name =3D "ltc2377-20", .driver_data =3D (kernel_ulong_t)<c2377_20_ch= ip_info }, + { .name =3D "ltc2378-16", .driver_data =3D (kernel_ulong_t)<c2378_16_ch= ip_info }, + { .name =3D "ltc2378-18", .driver_data =3D (kernel_ulong_t)<c2378_18_ch= ip_info }, + { .name =3D "ltc2378-20", .driver_data =3D (kernel_ulong_t)<c2378_20_ch= ip_info }, + { .name =3D "ltc2379-18", .driver_data =3D (kernel_ulong_t)<c2379_18_ch= ip_info }, + { .name =3D "ltc2380-16", .driver_data =3D (kernel_ulong_t)<c2380_16_ch= ip_info }, + { } +}; +MODULE_DEVICE_TABLE(spi, ltc2378_spi_id); + +static struct spi_driver ltc2378_driver =3D { + .driver =3D { + .name =3D "ltc2378", + .of_match_table =3D ltc2378_of_match + }, + .probe =3D ltc2378_probe, + .id_table =3D ltc2378_spi_id, +}; +module_spi_driver(ltc2378_driver); + +MODULE_AUTHOR("Marcelo Schmitt "); +MODULE_DESCRIPTION("Analog Devices LTC2378 ADC series driver"); +MODULE_LICENSE("GPL"); --=20 2.53.0 From nobody Sat Jul 25 15:24:48 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 94CE13BFAED; Thu, 16 Jul 2026 21:10: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=1784236230; cv=none; b=emO4r4uRKIJ2SJDIBWfn6wF/PRDm/CgbjzskC9WhCHE/v9Ar2s1yuQkUujk/nx2pLvmAHmGemcz3ungCHOH57I0WHhKoqxBPTJiP0UiUY6f4HtsJRx/KYThklFdQjjbIL8FC+GUGkmRPklMquEaGZYhj2aI0UbbYPD8G9mUmHG0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784236230; c=relaxed/simple; bh=XXfijOiv8Hsyj0WA62fp5cQk3H9CW5Fvxo+j1EwFEMo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=XC9sumF1ZuYHkzYVhZJcQax5Xk5yctgQYSr9YTfnWVTUxItu1/k3mJgnn4psqcYLORpyIW9ougSWrUJw3gMgeSGbp7ncr7Op80DpmJ8DiRtmIvAZvnTRmkk/WC/YQllN4buQEP9gFmVUobTZ7GdCtcLjTQdqvjK/7SPFpzHt9iE= 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=X2HMAbWR; 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="X2HMAbWR" 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 66GJpSwX349401; Thu, 16 Jul 2026 17:10: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=s5uM5 4ZJRcb0jSICxtje/4wpzB5Ow+7kuwULywDEhKA=; b=X2HMAbWR/8QpswpJT4mFk V3y9GQkdABcdAkV+q/euiOsKFsKgQkZ2QtFKjn7OgoFdSbtDXr9PO72ROD0CY+60 UExD6ZLqnX9zYGKA+sGH81wOoM6TvI2GtuWSh1K/yI1IC3BAh2WfTYa5bernktmV GutQJ6yjIhE7SESTbC4jAkphAJUT+P/d7vx6Gcjo4FGvR5TmOt+A4zhTmiYNEzhj xFWihKuplRAYARt6fcgEmWvNS/6fcE+yUqZRt6D5UguC5hbEe1snQZ5dcZ1mWMVA u+uymcjyaqt82GZrGJYglDc2+41k6Jadc5rRWHhOQd4Il0l9QqRtPzoCvlXtQlIS g== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4fe85wy1kn-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 16 Jul 2026 17:10:24 -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 66GLANUs004331 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 16 Jul 2026 17:10:23 -0400 Received: from ASHBMBX9.ad.analog.com (10.64.17.10) 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, 16 Jul 2026 17:10: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, 16 Jul 2026 17:10:22 -0400 Received: from work.maxim-ic.internal ([10.66.6.192]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 66GLA9Kb004919; Thu, 16 Jul 2026 17:10:11 -0400 From: Marcelo Schmitt To: , , CC: , , , , , , , , , Subject: [PATCH v7 3/4] iio: adc: ltc2378: Enable high-speed data capture Date: Thu, 16 Jul 2026 18:10:03 -0300 Message-ID: <564b975c2c62d28ee6733f86bd5632c41a7c80e4.1784235595.git.marcelo.schmitt@analog.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ADIRuleOP-NewSCL: Rule Triggered X-Authority-Analysis: v=2.4 cv=aLnAb79m c=1 sm=1 tr=0 ts=6a5948c0 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=RAioF0-LDSMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=OmVn7CZJonkx5R5zMQLL:22 a=IpJZQVW2AAAA:8 a=gAnH3GRIAAAA:8 a=I7Ct1wI2BZskGqBcPl8A:9 a=IawgGOuG5U0WyFbmm1f5:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNzE2MDIxNiBTYWx0ZWRfX5l6+SSX+DoV/ LKKXpAzt+XK2eZLg0fXtvR2KLtQ/AvU4dNZhxBa9vqM1g/8cRgC/p3F4to4mtLJ4B3z/FM0mCo6 G3ABMebonMfDDQ8qpdezRiTyXfekmIFq+zmwrmNFM4Og0Yka+NXMJAtfM/4xVzWehKDiShHnQfz e52FGrGmsET3lyZuIXCAnTmgCbclgpIQycHMZp8TwkDEjzV04tFcLLEPzzWwYHlTcxPXXszNlKC CGJOUoMspepFG4gsB2tKUvfAse2V8hsd40qRhEk8KnzKbVI9R/J+cZNy+ImF0yMMNeqjwCl9S+X W9STyF3J8fDnDA+2sA3HQV70DhzgQjt4og9tNIIYutSypewM6PTet1RAd9WzzMX/t4xIDeQ5g2p VPU89+XMwfRarRktvVpea8y3f6TuhFjSwCotGPgObyLjreRiEEE8uk2GsMiTYbO4BEoSOrY/9mY RxNRsSKxyIFDy4AVa7g== X-Proofpoint-GUID: lJfx7GATG9WGVRksrkbi3CJER0RdTNsf X-Proofpoint-Spam-Info: AW1haW4tMjYwNzE2MDIxNiBTYWx0ZWRfX5GPZVumiiV7Y 1cS2hMfXZjYXYlfqd5iL2JbN9FY7TCVQpHVRxOnIAyHs5ZxPI4xSEXzMb7DzoLw9HIOJ6HziS8R xkaW9CwxStrn6iF/k5G9LY0hsbK0svIOG8FmbnwVqgacyTV4op5K X-Proofpoint-ORIG-GUID: lJfx7GATG9WGVRksrkbi3CJER0RdTNsf X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-07-16_07,2026-07-15_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 lowpriorityscore=0 suspectscore=0 spamscore=0 impostorscore=0 bulkscore=0 adultscore=0 priorityscore=1501 malwarescore=0 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2607160216 Content-Type: text/plain; charset="utf-8" Make use of SPI transfer offloading to speed up data capture, enabling data acquisition at faster sample rates (up to 2 MSPS). Reviewed-by: David Lechner Signed-off-by: Marcelo Schmitt Reviewed-by: Andy Shevchenko --- Change log v6 -> v7: - Now keeping validated offload configurations if conversion rate update fa= ils. - Imported SPI_OFFLOAD name space. - Replaced DIV_ROUND_UP() by div_u64() to mitigate config check fail due to different integer rounding. - Separate macros for offload and non-offload channels. - Moved ltc2378_prepare_offload_message() downwards in source code. drivers/iio/adc/Kconfig | 6 + drivers/iio/adc/ltc2378.c | 403 +++++++++++++++++++++++++++++++++++++- 2 files changed, 406 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 220c6739a8f2..96df8453b826 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -948,6 +948,12 @@ config LTC2378 depends on SPI depends on REGULATOR || COMPILE_TEST depends on GPIOLIB + depends on PWM + select IIO_BUFFER + select IIO_BUFFER_DMA + select IIO_BUFFER_DMAENGINE + select SPI_OFFLOAD + select SPI_OFFLOAD_TRIGGER_PWM help Say yes here to build support for Analog Devices LTC2378-20 and similar analog to digital converters. diff --git a/drivers/iio/adc/ltc2378.c b/drivers/iio/adc/ltc2378.c index 5600c820c7f4..7d29f021cb7b 100644 --- a/drivers/iio/adc/ltc2378.c +++ b/drivers/iio/adc/ltc2378.c @@ -16,16 +16,27 @@ #include #include #include +#include +#include #include #include #include +#include #include +#include +#include +#include #include #include =20 +#include +#include #include #include =20 +#define LTC2378_TDSDOBUSYL_NS 5 +#define LTC2378_TBUSYLH_NS 13 +#define LTC2378_TCNV_HIGH_NS 20 #define LTC2378_MAX_DATA_WAIT_US 4 /* max(TBUSYLH + TCONV + TDSDOBUSYL) */ =20 #define LTC2378_DIFF_CHANNEL(_sign, _real_bits, _storage_bits) \ @@ -50,10 +61,46 @@ #define LTC2378_UNIPOLAR_DIFF_CHANNEL(_real_bits) \ LTC2378_DIFF_CHANNEL(0, _real_bits, (((_real_bits) > 16) ? 32 : 16)) =20 +#define LTC2378_DIFF_CHANNEL_OFFLOAD(_sign, _real_bits, _storage_bits) \ +{ \ + .type =3D IIO_VOLTAGE, \ + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_separate_available =3D BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index =3D 0, \ + .scan_type =3D { \ + .format =3D _sign ? IIO_SCAN_FORMAT_SIGNED_INT : \ + IIO_SCAN_FORMAT_UNSIGNED_INT, \ + .realbits =3D _real_bits, \ + .storagebits =3D _storage_bits, \ + .shift =3D 0, \ + .endianness =3D IIO_CPU, \ + }, \ +} + +/* + * Currently, the available offload hardware + DMA configuration only supp= orts + * pushing 32-bit data elements to DMA IIO buffers in CPU endianness. For = 16-bit + * precision parts, those 32-bit elements (in CPU endianness) contain 2 by= tes + * with data and 2 bytes always zeroed out. Nevertheless, for the offload = use + * case, the IIO buffer is configured for 32 storage bits in CPU endiannes= s so + * data is correctly aligned in user space despite 2 out of the 4 bytes be= ing + * zeros. + */ +#define LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(_real_bits) \ + LTC2378_DIFF_CHANNEL_OFFLOAD(1, (_real_bits), 32) + +#define LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(_real_bits) \ + LTC2378_DIFF_CHANNEL_OFFLOAD(0, (_real_bits), 32) + struct ltc2378_chip_info { const char *name; unsigned int internal_ref_uV; struct iio_chan_spec chan; + struct iio_chan_spec offload_chan; + unsigned int max_sample_rate_Hz; + unsigned int tconv_ns; }; =20 struct ltc2378_state { @@ -63,6 +110,15 @@ struct ltc2378_state { struct mutex lock; /* Protect data acquisition cycle */ int ref_uV; struct spi_transfer xfer; + struct spi_transfer offload_xfer; + struct spi_offload *offload; + struct spi_offload_trigger *offload_trigger; + struct pwm_waveform cnv_wf; + struct spi_message offload_msg; + struct spi_offload_trigger_config offload_trigger_config; + struct pwm_device *cnv_trigger; + unsigned int cnv_Hz; + unsigned int sample_freq_range[3]; =20 /* * DMA (thus cache coherency maintenance) requires the transfer buffers @@ -83,101 +139,161 @@ static const struct ltc2378_chip_info ltc2338_18_chi= p_info =3D { .name =3D "ltc2338-18", .internal_ref_uV =3D 2048000, .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(18), + .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(18), + .max_sample_rate_Hz =3D 1 * HZ_PER_MHZ, + .tconv_ns =3D 527, }; =20 static const struct ltc2378_chip_info ltc2364_16_chip_info =3D { .name =3D "ltc2364-16", .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(16), + .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(16), + .max_sample_rate_Hz =3D 250 * HZ_PER_KHZ, + .tconv_ns =3D 3000, }; =20 static const struct ltc2378_chip_info ltc2364_18_chip_info =3D { .name =3D "ltc2364-18", .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(18), + .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(18), + .max_sample_rate_Hz =3D 250 * HZ_PER_KHZ, + .tconv_ns =3D 3000, }; =20 static const struct ltc2378_chip_info ltc2367_16_chip_info =3D { .name =3D "ltc2367-16", .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(16), + .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(16), + .max_sample_rate_Hz =3D 500 * HZ_PER_KHZ, + .tconv_ns =3D 1500, }; =20 static const struct ltc2378_chip_info ltc2367_18_chip_info =3D { .name =3D "ltc2367-18", .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(18), + .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(18), + .max_sample_rate_Hz =3D 500 * HZ_PER_KHZ, + .tconv_ns =3D 1500, }; =20 static const struct ltc2378_chip_info ltc2368_16_chip_info =3D { .name =3D "ltc2368-16", .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(16), + .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(16), + .max_sample_rate_Hz =3D 1 * HZ_PER_MHZ, + .tconv_ns =3D 527, }; =20 static const struct ltc2378_chip_info ltc2368_18_chip_info =3D { .name =3D "ltc2368-18", .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(18), + .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(18), + .max_sample_rate_Hz =3D 1 * HZ_PER_MHZ, + .tconv_ns =3D 527, }; =20 static const struct ltc2378_chip_info ltc2369_18_chip_info =3D { .name =3D "ltc2369-18", .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(18), + .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(18), + .max_sample_rate_Hz =3D 1600 * HZ_PER_KHZ, + .tconv_ns =3D 412, }; =20 static const struct ltc2378_chip_info ltc2370_16_chip_info =3D { .name =3D "ltc2370-16", .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(16), + .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(16), + .max_sample_rate_Hz =3D 2 * HZ_PER_MHZ, + .tconv_ns =3D 322, }; =20 static const struct ltc2378_chip_info ltc2376_16_chip_info =3D { .name =3D "ltc2376-16", .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(16), + .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(16), + .max_sample_rate_Hz =3D 250 * HZ_PER_KHZ, + .tconv_ns =3D 3000, }; =20 static const struct ltc2378_chip_info ltc2376_18_chip_info =3D { .name =3D "ltc2376-18", .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(18), + .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(18), + .max_sample_rate_Hz =3D 250 * HZ_PER_KHZ, + .tconv_ns =3D 3000, }; =20 static const struct ltc2378_chip_info ltc2376_20_chip_info =3D { .name =3D "ltc2376-20", .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(20), + .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(20), + .max_sample_rate_Hz =3D 250 * HZ_PER_KHZ, + .tconv_ns =3D 3000, }; =20 static const struct ltc2378_chip_info ltc2377_16_chip_info =3D { .name =3D "ltc2377-16", .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(16), + .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(16), + .max_sample_rate_Hz =3D 500 * HZ_PER_KHZ, + .tconv_ns =3D 1500, }; =20 static const struct ltc2378_chip_info ltc2377_18_chip_info =3D { .name =3D "ltc2377-18", .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(18), + .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(18), + .max_sample_rate_Hz =3D 500 * HZ_PER_KHZ, + .tconv_ns =3D 1500, }; =20 static const struct ltc2378_chip_info ltc2377_20_chip_info =3D { .name =3D "ltc2377-20", .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(20), + .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(20), + .max_sample_rate_Hz =3D 500 * HZ_PER_KHZ, + .tconv_ns =3D 1500, }; =20 static const struct ltc2378_chip_info ltc2378_16_chip_info =3D { .name =3D "ltc2378-16", .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(16), + .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(16), + .max_sample_rate_Hz =3D 1 * HZ_PER_MHZ, + .tconv_ns =3D 527, }; =20 static const struct ltc2378_chip_info ltc2378_18_chip_info =3D { .name =3D "ltc2378-18", .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(18), + .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(18), + .max_sample_rate_Hz =3D 1 * HZ_PER_MHZ, + .tconv_ns =3D 527, }; =20 static const struct ltc2378_chip_info ltc2378_20_chip_info =3D { .name =3D "ltc2378-20", .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(20), + .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(20), + .max_sample_rate_Hz =3D 1 * HZ_PER_MHZ, + .tconv_ns =3D 675, }; =20 static const struct ltc2378_chip_info ltc2379_18_chip_info =3D { .name =3D "ltc2379-18", .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(18), + .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(18), + .max_sample_rate_Hz =3D 1600 * HZ_PER_KHZ, + .tconv_ns =3D 412, }; =20 static const struct ltc2378_chip_info ltc2380_16_chip_info =3D { .name =3D "ltc2380-16", .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(16), + .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(16), + .max_sample_rate_Hz =3D 2 * HZ_PER_MHZ, + .tconv_ns =3D 322, }; =20 static int ltc2378_convert_and_acquire(struct ltc2378_state *st) @@ -260,7 +376,137 @@ static int ltc2378_read_raw(struct iio_dev *indio_dev, *val2 =3D chan->scan_type.realbits; =20 return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_SAMP_FREQ: + *val =3D st->cnv_Hz; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} =20 +static int ltc2378_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, long mask) +{ + struct ltc2378_state *st =3D iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *vals =3D st->sample_freq_range; + *type =3D IIO_VAL_INT; + return IIO_AVAIL_RANGE; + default: + return -EINVAL; + } +} + +/* + * SPI offload wiring schema + * + * +-------------+ +-------------+ + * | CNV |<-----+--| GPIO | + * | | +--| PWM0 | + * | | | | + * | | +--| PWM1 | + * | | | +-------------+ + * | | +->| TRIGGER | + * | | | | + * | ADC | | SPI | + * | | | controller | + * | | | | + * | SDI |<--------| SDO | + * | SDO |-------->| SDI | + * | SCLK |<--------| SCLK | + * +-------------+ +-------------+ + * + */ +static int ltc2378_update_conversion_rate(struct ltc2378_state *st, int fr= eq_Hz) +{ + struct spi_offload_trigger_config config =3D st->offload_trigger_config; + unsigned int min_read_offset, offload_period_ns; + struct pwm_waveform cnv_wf =3D { }; + u64 target =3D LTC2378_TCNV_HIGH_NS; + unsigned int count; + u64 offload_offset_ns; + int ret; + + if (freq_Hz =3D=3D 0) + return -EINVAL; + + if (!in_range(freq_Hz, 1, st->info->max_sample_rate_Hz)) + return -ERANGE; + + /* Configure CNV PWM waveform */ + cnv_wf.period_length_ns =3D DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq_Hz); + + /* + * Ensure CNV high time meets minimum requirement (20ns). The PWM + * hardware may round the duty cycle, so iterate until we get at least + * the minimum required high time (or reach a try count limit). + */ + count =3D 100; + do { + cnv_wf.duty_length_ns =3D target; + ret =3D pwm_round_waveform_might_sleep(st->cnv_trigger, &cnv_wf); + if (ret) + return ret; + target +=3D 10; /* Increment by PWM duty cycle period */ + } while (count-- && cnv_wf.duty_length_ns < LTC2378_TCNV_HIGH_NS); + + /* Check the minimum CNV high time is met */ + if (cnv_wf.duty_length_ns < LTC2378_TCNV_HIGH_NS) + return -EDOM; + + /* + * Configure SPI offload PWM trigger. + * The trigger should fire after tBUSYLH + tCONV + tDSDOBUSYL. + * Minimum time needed: TBUSYLH (13ns) + TCONV (part-specific) + TDSDOBUS= YL (5ns) + * + * Use the same period as CNV PWM to avoid timing issues. + * Convert back from period to frequency for the SPI offload API. + */ + offload_period_ns =3D cnv_wf.period_length_ns; + config.periodic.frequency_hz =3D div_u64(HZ_PER_GHZ, offload_period_ns); + min_read_offset =3D LTC2378_TBUSYLH_NS + st->info->tconv_ns + LTC2378_TDS= DOBUSYL_NS; + offload_offset_ns =3D min_read_offset; + count =3D 100; + do { + config.periodic.offset_ns =3D offload_offset_ns; + ret =3D spi_offload_trigger_validate(st->offload_trigger, &config); + if (ret) + return ret; + offload_offset_ns +=3D 10; + } while (count-- && config.periodic.offset_ns < min_read_offset); + + /* Check the minimum CNV to SCLK delay is met */ + if (config.periodic.offset_ns < min_read_offset) + return -EDOM; + + /* Check the PWM periods remain the same */ + offload_period_ns =3D div64_u64(HZ_PER_GHZ, config.periodic.frequency_hz); + if (cnv_wf.period_length_ns !=3D offload_period_ns) + return -EDOM; + + st->offload_trigger_config =3D config; + st->cnv_wf =3D cnv_wf; + st->cnv_Hz =3D DIV_ROUND_CLOSEST_ULL(HZ_PER_GHZ, cnv_wf.period_length_ns); + + return 0; +} + +static int ltc2378_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ltc2378_state *st =3D iio_priv(indio_dev); + + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + return ltc2378_update_conversion_rate(st, val); default: return -EINVAL; } @@ -270,6 +516,111 @@ static const struct iio_info ltc2378_iio_info =3D { .read_raw =3D <c2378_read_raw, }; =20 +static const struct iio_info ltc2378_offload_iio_info =3D { + .read_raw =3D <c2378_read_raw, + .read_avail =3D <c2378_read_avail, + .write_raw =3D <c2378_write_raw, +}; + +static int ltc2378_offload_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ltc2378_state *st =3D iio_priv(indio_dev); + int ret; + + ret =3D pwm_set_waveform_might_sleep(st->cnv_trigger, &st->cnv_wf, true); + if (ret) + return ret; + + ret =3D spi_offload_trigger_enable(st->offload, st->offload_trigger, + &st->offload_trigger_config); + if (ret) + goto out_pwm_disable; + + return 0; + +out_pwm_disable: + pwm_disable(st->cnv_trigger); + return ret; +} + +static int ltc2378_offload_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ltc2378_state *st =3D iio_priv(indio_dev); + + spi_offload_trigger_disable(st->offload, st->offload_trigger); + pwm_disable(st->cnv_trigger); + + return 0; +} + +static const struct iio_buffer_setup_ops ltc2378_offload_buffer_ops =3D { + .postenable =3D <c2378_offload_buffer_postenable, + .predisable =3D <c2378_offload_buffer_predisable, +}; + +static int ltc2378_prepare_offload_message(struct device *dev, + struct ltc2378_state *st) +{ + unsigned int resolution =3D st->info->offload_chan.scan_type.realbits; + + st->offload_xfer.bits_per_word =3D resolution; + st->offload_xfer.len =3D spi_bpw_to_bytes(resolution); + st->offload_xfer.offload_flags =3D SPI_OFFLOAD_XFER_RX_STREAM; + + /* Initialize message with offload */ + spi_message_init_with_transfers(&st->offload_msg, &st->offload_xfer, 1); + st->offload_msg.offload =3D st->offload; + + return devm_spi_optimize_message(dev, st->spi, &st->offload_msg); +} + +static int ltc2378_spi_offload_setup(struct iio_dev *indio_dev, + struct ltc2378_state *st) +{ + struct device *dev =3D &st->spi->dev; + struct dma_chan *rx_dma; + + indio_dev->setup_ops =3D <c2378_offload_buffer_ops; + + st->offload_trigger =3D devm_spi_offload_trigger_get(dev, st->offload, + SPI_OFFLOAD_TRIGGER_PERIODIC); + if (IS_ERR(st->offload_trigger)) + return dev_err_probe(dev, PTR_ERR(st->offload_trigger), + "failed to get offload trigger\n"); + + st->offload_trigger_config.type =3D SPI_OFFLOAD_TRIGGER_PERIODIC; + + rx_dma =3D devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload); + if (IS_ERR(rx_dma)) + return dev_err_probe(dev, PTR_ERR(rx_dma), "failed to get offload RX DMA= \n"); + + return devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, rx_dma, + IIO_BUFFER_DIRECTION_IN); +} + +static int ltc2378_pwm_get(struct ltc2378_state *st) +{ + struct device *dev =3D &st->spi->dev; + + st->cnv_trigger =3D devm_pwm_get(dev, NULL); + if (IS_ERR(st->cnv_trigger)) + return dev_err_probe(dev, PTR_ERR(st->cnv_trigger), + "failed to get cnv pwm\n"); + + /* + * Disable the PWM connected to CNV in case it was left running by + * something else. + */ + pwm_disable(st->cnv_trigger); + + return 0; +} + +static const struct spi_offload_config ltc2378_offload_config =3D { + .capability_flags =3D SPI_OFFLOAD_CAP_TRIGGER | + SPI_OFFLOAD_CAP_RX_STREAM_DMA, +}; + static int ltc2378_refin_setup(struct device *dev, struct ltc2378_state *s= t) { int ret; @@ -334,7 +685,6 @@ static int ltc2378_probe(struct spi_device *spi) return ret; =20 indio_dev->name =3D st->info->name; - indio_dev->info =3D <c2378_iio_info; indio_dev->modes =3D INDIO_DIRECT_MODE; =20 st->cnv_gpio =3D devm_gpiod_get(dev, "cnv", GPIOD_OUT_LOW); @@ -342,8 +692,53 @@ static int ltc2378_probe(struct spi_device *spi) return dev_err_probe(dev, PTR_ERR(st->cnv_gpio), "failed to get CNV GPIO"); =20 - indio_dev->channels =3D &st->info->chan; - indio_dev->num_channels =3D 1; + st->offload =3D devm_spi_offload_get(dev, spi, <c2378_offload_config); + ret =3D PTR_ERR_OR_ZERO(st->offload); + /* Fall back to low speed usage when no SPI offload is available. */ + if (ret =3D=3D -ENODEV) { + indio_dev->info =3D <c2378_iio_info; + indio_dev->channels =3D &st->info->chan; + indio_dev->num_channels =3D 1; + } else if (ret) { + return dev_err_probe(dev, ret, "failed to get offload\n"); + } else { + indio_dev->info =3D <c2378_offload_iio_info; + indio_dev->channels =3D &st->info->offload_chan; + indio_dev->num_channels =3D 1; + ret =3D ltc2378_spi_offload_setup(indio_dev, st); + if (ret) + return dev_err_probe(dev, ret, + "failed to setup SPI offload\n"); + + ret =3D ltc2378_pwm_get(st); + if (ret) + return dev_err_probe(dev, ret, "failed to get PWM\n"); + + st->sample_freq_range[0] =3D 1; /* min */ + st->sample_freq_range[1] =3D 1; /* step */ + st->sample_freq_range[2] =3D st->info->max_sample_rate_Hz; /* max */ + + /* + * Start with a slower sampling rate so there is some room for + * adjusting the sample averaging and the sampling frequency + * without hitting the maximum conversion rate. + */ + ret =3D ltc2378_update_conversion_rate(st, st->info->max_sample_rate_Hz = >> 4); + if (ret) + return dev_err_probe(dev, ret, + "failed to set offload samp freq\n"); + + ret =3D ltc2378_prepare_offload_message(&spi->dev, st); + if (ret) + return dev_err_probe(dev, ret, "failed to optimize SPI message\n"); + + /* + * Set single-read transfer bits_per_word so the SPI subsystem + * rearranges data to CPU endianness, enabling us to reuse + * offload_chan specifications for single-shot reads. + */ + st->xfer.bits_per_word =3D st->info->offload_chan.scan_type.realbits; + } =20 st->xfer.rx_buf =3D &st->scan.data; st->xfer.len =3D spi_bpw_to_bytes(indio_dev->channels[0].scan_type.realbi= ts); @@ -414,3 +809,5 @@ module_spi_driver(ltc2378_driver); MODULE_AUTHOR("Marcelo Schmitt "); MODULE_DESCRIPTION("Analog Devices LTC2378 ADC series driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER"); +MODULE_IMPORT_NS("SPI_OFFLOAD"); --=20 2.53.0 From nobody Sat Jul 25 15:24:48 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 E91903BED4A; Thu, 16 Jul 2026 21:10:53 +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=1784236255; cv=none; b=CXccsoAnTT8Sr19oTbFs8jgCJXSvpEsw8Y9QqZrhlNziwbxk7n0xBu054yff0rXv6AgrtGG2lgGaX0piRuPvyzWBrp+rGFna4iXzTY0tamQTZpNNGisB0osk6a0igDI5rYjgvrTHoyWvA+O3T0hPBF4ON2mIKp75CC0p03ya104= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784236255; c=relaxed/simple; bh=YQ+35bixFRk5LjKcwR9TKmYCGQ96yG6Y8OP6vn0WThQ=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=rh48mb8uKqUuEh57SJbCkLrWld+HlgUc3N7NAzXhlYsMT0QqZwCP0Z5B84EYQDIO3EipmxxMvZpkkfOza+4L3qE4ExwX538hTAvVZ7UVDcwGj1jPILl1RpyMzlSDGRue0mRedawgvRQIXU9VaRSv9rw3Jq/1CaP1lnq1OMnOUDw= 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=TpLEFeRw; 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="TpLEFeRw" Received: from pps.filterd (m0167089.ppops.net [127.0.0.1]) by mx0a-00128a01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 66GJq7Ae259810; Thu, 16 Jul 2026 17:10:50 -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=Y2Tfk zMIDC1JwdFmDJ15x9Y/QzBTUwKxZGwdZWrlq2I=; b=TpLEFeRwsovg79W1Saiz+ N7FTtavLBBdOVCucjSAiwyj4sQPEGITFnNdPzYimEyt+KQ33H0VCsZqs2JHVxlSn Q4c55/RUpuh6karO8H3XxTHlYrnSq0pAiMQ1LztLFU1wl0rfOa0WX31bdLjBtUiw TKoEMuAdD5nTru5JElmsKVi4EZ7gRXFLoVl2VvBrTkDiemqwP/0qfiNqAomw5b1F UCISBTUHuRwc3JAmt6oRjsDI52+wLzYqiQKmOyR0a4TTyFscvrOLdrVBDl1DQ9kz 9bSutZvenoQyARAv4JGeF8OCjKyC4frp8LWPwV6oa9i+IwEBqaXjBIp8EYlG1R3E Q== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4fe70e7bx7-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 16 Jul 2026 17:10:49 -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 66GLAmDX004361 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 16 Jul 2026 17:10:48 -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, 16 Jul 2026 17:10:48 -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, 16 Jul 2026 17:10:46 -0400 Received: from work.maxim-ic.internal ([10.66.6.192]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 66GLAY6j004924; Thu, 16 Jul 2026 17:10:37 -0400 From: Marcelo Schmitt To: , , CC: , , , , , , , , , Subject: [PATCH v7 4/4] iio: adc: ltc2378: Enable triggered buffer data capture Date: Thu, 16 Jul 2026 18:10:29 -0300 Message-ID: <6f3984cf270b29a2030271989df179118a70bb3e.1784235595.git.marcelo.schmitt@analog.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ADIRuleOP-NewSCL: Rule Triggered X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNzE2MDIxNiBTYWx0ZWRfX3ng5op5wEVnb XH5YeE0pT51SvieKhqLmMhC6lN4O9Hz/LSDP6v5+D0grKfBB/NvWG2TvFgJreifspAwIYZob8w3 wzwiTuX5oxqKIY7ILYR68n1TQXpKbu6eEygk1R7KcRBxl9JyWTkSqtaMzQVY2UlnLR8sqLF9Ph4 uqBiVjZf5RALClJQPPWhTzyuUwmE+Oxl4IMNsG6cmDkqaXZU20xiGRA3uJGbqHt4RacZUMcI8te sU8eTkjuzVTOTqC9k2/kYDICdWDGVmY/vNPdxql0XYVo2YmIki2Bei2R7fPA++WmHax7wMnjUn9 0kQUK4+cVswNa4TEjX/DH8Ci46qWz9vVz5Qa7A8X4VVOYlGgITrpb0/MHlRBB0ggL+lZYBu7bBG FI5p/Uf0cvDqHfdW6BxWxNBuY/6dLQyQ7Hz1hUJsY/ddgAe3//USD/mEl/N4B9zEBc+tSnXvHWH ZqjFGCxMA0fFJZgbDVQ== X-Proofpoint-ORIG-GUID: 5wMlK3a4WOCoTUPEP0xmA9dIaEOqYT1g X-Authority-Analysis: v=2.4 cv=XsLK/1F9 c=1 sm=1 tr=0 ts=6a5948d9 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=RAioF0-LDSMA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=Z0pTeXoby7EwIRygza74:22 a=IpJZQVW2AAAA:8 a=gAnH3GRIAAAA:8 a=LKWNKb2UafNwrDgNmc4A:9 a=IawgGOuG5U0WyFbmm1f5:22 X-Proofpoint-Spam-Info: AW1haW4tMjYwNzE2MDIxNiBTYWx0ZWRfX/0dqdvvhHhzr J2U9Xz3ekdjHYQV+umuSO/LqzJiuoqc0O19z7nzSn+ttU366+/LkKX6RvUajETHiHEXPhgp8rY8 naZ0HWLoQU463mm9o+hLN4Hg09oasGAq+FFZWQQ+wuEc5EG3tnKU X-Proofpoint-GUID: 5wMlK3a4WOCoTUPEP0xmA9dIaEOqYT1g X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-07-16_07,2026-07-15_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 spamscore=0 bulkscore=0 lowpriorityscore=0 phishscore=0 clxscore=1015 priorityscore=1501 adultscore=0 malwarescore=0 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2607160216 Content-Type: text/plain; charset="utf-8" Enable users to run triggered data captures with LTC2378 and similar ADCs. Reviewed-by: David Lechner Signed-off-by: Marcelo Schmitt Reviewed-by: Andy Shevchenko --- Change log v6 -> v7: No changes in v7. drivers/iio/adc/Kconfig | 1 + drivers/iio/adc/ltc2378.c | 75 +++++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 23 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 96df8453b826..6cf67f7a6eed 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -952,6 +952,7 @@ config LTC2378 select IIO_BUFFER select IIO_BUFFER_DMA select IIO_BUFFER_DMAENGINE + select IIO_TRIGGERED_BUFFER select SPI_OFFLOAD select SPI_OFFLOAD_TRIGGER_PWM help diff --git a/drivers/iio/adc/ltc2378.c b/drivers/iio/adc/ltc2378.c index 7d29f021cb7b..25db69edee4d 100644 --- a/drivers/iio/adc/ltc2378.c +++ b/drivers/iio/adc/ltc2378.c @@ -6,6 +6,7 @@ * Author: Marcelo Schmitt */ =20 +#include #include #include #include @@ -32,6 +33,8 @@ #include #include #include +#include +#include #include =20 #define LTC2378_TDSDOBUSYL_NS 5 @@ -97,7 +100,7 @@ struct ltc2378_chip_info { const char *name; unsigned int internal_ref_uV; - struct iio_chan_spec chan; + struct iio_chan_spec chan[2]; /* 1 physical chan + 1 timestamp chan */ struct iio_chan_spec offload_chan; unsigned int max_sample_rate_Hz; unsigned int tconv_ns; @@ -138,7 +141,7 @@ struct ltc2378_state { static const struct ltc2378_chip_info ltc2338_18_chip_info =3D { .name =3D "ltc2338-18", .internal_ref_uV =3D 2048000, - .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(18), + .chan =3D { LTC2378_BIPOLAR_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) = }, .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(18), .max_sample_rate_Hz =3D 1 * HZ_PER_MHZ, .tconv_ns =3D 527, @@ -146,7 +149,7 @@ static const struct ltc2378_chip_info ltc2338_18_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2364_16_chip_info =3D { .name =3D "ltc2364-16", - .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(16), + .chan =3D { LTC2378_UNIPOLAR_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1)= }, .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(16), .max_sample_rate_Hz =3D 250 * HZ_PER_KHZ, .tconv_ns =3D 3000, @@ -154,7 +157,7 @@ static const struct ltc2378_chip_info ltc2364_16_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2364_18_chip_info =3D { .name =3D "ltc2364-18", - .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(18), + .chan =3D { LTC2378_UNIPOLAR_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1)= }, .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(18), .max_sample_rate_Hz =3D 250 * HZ_PER_KHZ, .tconv_ns =3D 3000, @@ -162,7 +165,7 @@ static const struct ltc2378_chip_info ltc2364_18_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2367_16_chip_info =3D { .name =3D "ltc2367-16", - .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(16), + .chan =3D { LTC2378_UNIPOLAR_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1)= }, .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(16), .max_sample_rate_Hz =3D 500 * HZ_PER_KHZ, .tconv_ns =3D 1500, @@ -170,7 +173,7 @@ static const struct ltc2378_chip_info ltc2367_16_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2367_18_chip_info =3D { .name =3D "ltc2367-18", - .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(18), + .chan =3D { LTC2378_UNIPOLAR_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1)= }, .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(18), .max_sample_rate_Hz =3D 500 * HZ_PER_KHZ, .tconv_ns =3D 1500, @@ -178,7 +181,7 @@ static const struct ltc2378_chip_info ltc2367_18_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2368_16_chip_info =3D { .name =3D "ltc2368-16", - .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(16), + .chan =3D { LTC2378_UNIPOLAR_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1)= }, .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(16), .max_sample_rate_Hz =3D 1 * HZ_PER_MHZ, .tconv_ns =3D 527, @@ -186,7 +189,7 @@ static const struct ltc2378_chip_info ltc2368_16_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2368_18_chip_info =3D { .name =3D "ltc2368-18", - .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(18), + .chan =3D { LTC2378_UNIPOLAR_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1)= }, .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(18), .max_sample_rate_Hz =3D 1 * HZ_PER_MHZ, .tconv_ns =3D 527, @@ -194,7 +197,7 @@ static const struct ltc2378_chip_info ltc2368_18_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2369_18_chip_info =3D { .name =3D "ltc2369-18", - .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(18), + .chan =3D { LTC2378_UNIPOLAR_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1)= }, .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(18), .max_sample_rate_Hz =3D 1600 * HZ_PER_KHZ, .tconv_ns =3D 412, @@ -202,7 +205,7 @@ static const struct ltc2378_chip_info ltc2369_18_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2370_16_chip_info =3D { .name =3D "ltc2370-16", - .chan =3D LTC2378_UNIPOLAR_DIFF_CHANNEL(16), + .chan =3D { LTC2378_UNIPOLAR_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1)= }, .offload_chan =3D LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL(16), .max_sample_rate_Hz =3D 2 * HZ_PER_MHZ, .tconv_ns =3D 322, @@ -210,7 +213,7 @@ static const struct ltc2378_chip_info ltc2370_16_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2376_16_chip_info =3D { .name =3D "ltc2376-16", - .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(16), + .chan =3D { LTC2378_BIPOLAR_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) = }, .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(16), .max_sample_rate_Hz =3D 250 * HZ_PER_KHZ, .tconv_ns =3D 3000, @@ -218,7 +221,7 @@ static const struct ltc2378_chip_info ltc2376_16_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2376_18_chip_info =3D { .name =3D "ltc2376-18", - .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(18), + .chan =3D { LTC2378_BIPOLAR_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) = }, .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(18), .max_sample_rate_Hz =3D 250 * HZ_PER_KHZ, .tconv_ns =3D 3000, @@ -226,7 +229,7 @@ static const struct ltc2378_chip_info ltc2376_18_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2376_20_chip_info =3D { .name =3D "ltc2376-20", - .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(20), + .chan =3D { LTC2378_BIPOLAR_DIFF_CHANNEL(20), IIO_CHAN_SOFT_TIMESTAMP(1) = }, .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(20), .max_sample_rate_Hz =3D 250 * HZ_PER_KHZ, .tconv_ns =3D 3000, @@ -234,7 +237,7 @@ static const struct ltc2378_chip_info ltc2376_20_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2377_16_chip_info =3D { .name =3D "ltc2377-16", - .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(16), + .chan =3D { LTC2378_BIPOLAR_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) = }, .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(16), .max_sample_rate_Hz =3D 500 * HZ_PER_KHZ, .tconv_ns =3D 1500, @@ -242,7 +245,7 @@ static const struct ltc2378_chip_info ltc2377_16_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2377_18_chip_info =3D { .name =3D "ltc2377-18", - .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(18), + .chan =3D { LTC2378_BIPOLAR_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) = }, .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(18), .max_sample_rate_Hz =3D 500 * HZ_PER_KHZ, .tconv_ns =3D 1500, @@ -250,7 +253,7 @@ static const struct ltc2378_chip_info ltc2377_18_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2377_20_chip_info =3D { .name =3D "ltc2377-20", - .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(20), + .chan =3D { LTC2378_BIPOLAR_DIFF_CHANNEL(20), IIO_CHAN_SOFT_TIMESTAMP(1) = }, .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(20), .max_sample_rate_Hz =3D 500 * HZ_PER_KHZ, .tconv_ns =3D 1500, @@ -258,7 +261,7 @@ static const struct ltc2378_chip_info ltc2377_20_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2378_16_chip_info =3D { .name =3D "ltc2378-16", - .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(16), + .chan =3D { LTC2378_BIPOLAR_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) = }, .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(16), .max_sample_rate_Hz =3D 1 * HZ_PER_MHZ, .tconv_ns =3D 527, @@ -266,7 +269,7 @@ static const struct ltc2378_chip_info ltc2378_16_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2378_18_chip_info =3D { .name =3D "ltc2378-18", - .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(18), + .chan =3D { LTC2378_BIPOLAR_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) = }, .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(18), .max_sample_rate_Hz =3D 1 * HZ_PER_MHZ, .tconv_ns =3D 527, @@ -274,7 +277,7 @@ static const struct ltc2378_chip_info ltc2378_18_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2378_20_chip_info =3D { .name =3D "ltc2378-20", - .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(20), + .chan =3D { LTC2378_BIPOLAR_DIFF_CHANNEL(20), IIO_CHAN_SOFT_TIMESTAMP(1) = }, .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(20), .max_sample_rate_Hz =3D 1 * HZ_PER_MHZ, .tconv_ns =3D 675, @@ -282,7 +285,7 @@ static const struct ltc2378_chip_info ltc2378_20_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2379_18_chip_info =3D { .name =3D "ltc2379-18", - .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(18), + .chan =3D { LTC2378_BIPOLAR_DIFF_CHANNEL(18), IIO_CHAN_SOFT_TIMESTAMP(1) = }, .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(18), .max_sample_rate_Hz =3D 1600 * HZ_PER_KHZ, .tconv_ns =3D 412, @@ -290,7 +293,7 @@ static const struct ltc2378_chip_info ltc2379_18_chip_i= nfo =3D { =20 static const struct ltc2378_chip_info ltc2380_16_chip_info =3D { .name =3D "ltc2380-16", - .chan =3D LTC2378_BIPOLAR_DIFF_CHANNEL(16), + .chan =3D { LTC2378_BIPOLAR_DIFF_CHANNEL(16), IIO_CHAN_SOFT_TIMESTAMP(1) = }, .offload_chan =3D LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL(16), .max_sample_rate_Hz =3D 2 * HZ_PER_MHZ, .tconv_ns =3D 322, @@ -309,6 +312,25 @@ static int ltc2378_convert_and_acquire(struct ltc2378_= state *st) return ret; } =20 +static irqreturn_t ltc2378_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf =3D p; + struct iio_dev *indio_dev =3D pf->indio_dev; + struct ltc2378_state *st =3D iio_priv(indio_dev); + int ret; + + ret =3D ltc2378_convert_and_acquire(st); + if (ret < 0) + goto err_out; + + iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan), + pf->timestamp); + +err_out: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + static int ltc2378_channel_single_read(const struct iio_chan_spec *chan, struct ltc2378_state *st, int *val) { @@ -697,8 +719,15 @@ static int ltc2378_probe(struct spi_device *spi) /* Fall back to low speed usage when no SPI offload is available. */ if (ret =3D=3D -ENODEV) { indio_dev->info =3D <c2378_iio_info; - indio_dev->channels =3D &st->info->chan; - indio_dev->num_channels =3D 1; + indio_dev->channels =3D st->info->chan; + indio_dev->num_channels =3D ARRAY_SIZE(st->info->chan); + + ret =3D devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + ltc2378_trigger_handler, + NULL); + if (ret) + return ret; } else if (ret) { return dev_err_probe(dev, ret, "failed to get offload\n"); } else { --=20 2.53.0