From nobody Mon Jun 8 14:35:14 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 9C65E2E738A; Thu, 28 May 2026 15:03:42 +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=1779980627; cv=none; b=fAYXW3VZ9ji2YzdnPInxKvtxqZVW/to2caPI2G1SlBvAh8Z3yvBu1uOvbG51GWNWuWijbUAG4LThaShajMbOQo+42bGPoL2sQPJJ+h1CKd0m29Sd55xPPrmtF/hf7LzOOTrONHbcWMN1yfGdhGQWO747J9X0BNn25JIg7awpPnI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779980627; c=relaxed/simple; bh=Dl8GAxFksQ+N3e4F3L7aJSBPGBi6YY87F8ySbb2Y3Fw=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=fjB0LNo9/vYrnnZgun4NUpTrM+PzQHPzo6MfBIMcrJLo8IBOiZtCHCqgWWzVzaeVnOsFLf1tvD0GPYlamK7JZjdaQ2zg7DYmTmGRiP7yF3pIv5mGfDWUhKqHBowxDOQ1Qi8k6CQowSZUn17tJN3RAZ30D/TVp3i+UZn7ZadAL3g= 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=zKsRKYTM; 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="zKsRKYTM" 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 64SEeRs8400759; Thu, 28 May 2026 11:03:36 -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=KsELe zxbkRYI/DMIPccH+ZQfH9BQpq9CtGDcg0u3g0g=; b=zKsRKYTMtUPfCL4zroWug BXytA2YmC0Z6J2W5A3w7Q8hMF+XLrpP4pZ/VgmHfzEjySu2WO3EbrfoEo4h1DPpV qwqJ3QyDRflLEEJpSwjKGEt+iTRmWCBMOpdhFVMSZCSdT4DrrU1AoFo9jjNRt1Zi p0+L4DSbGfT2rok91F3aLm7TEVgKF64D5rBxMhjtyT08yomAwEiZzp0qA7rcPHFU Yu0KMNQSYoeiJVX8ZWDpFXAB/g8W+FXXb+YFu+arG59gXmDwq6znIkVo/0RVhESa HbKfJ/hE64xbWHGzq1Xy5fsoThDRJgFdvfrtQA/TcN5h1vpef8d8qxlxv0ZkSaPC Q== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4ee7x1uabf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 28 May 2026 11:03:35 -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 64SF3YjU008714 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 28 May 2026 11:03:34 -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, 28 May 2026 11:03:34 -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, 28 May 2026 11:03:34 -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, 28 May 2026 11:03:34 -0400 Received: from work.maxim-ic.internal ([10.66.6.190]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 64SF3LFm021386; Thu, 28 May 2026 11:03:24 -0400 From: Marcelo Schmitt To: , , CC: , , , , , , , , , Subject: [PATCH v2 1/4] dt-bindings: iio: adc: Add ltc2378 Date: Thu, 28 May 2026 12:03:16 -0300 Message-ID: <23971c3bb56d8635abe9cd36fd245412f672772a.1779976379.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: AW1haW4tMjYwNTI4MDE1MiBTYWx0ZWRfX4CZsuG5TMQok rv+kpPdyyVDaMupb2j7z78l8cVoFfEzBZiG1/4THyR0biycxwRE0rMEgQFE6+ysgovgZBn5sxM+ YP/O5SDnMs4BcH90GdMvHRcGmPIZ8DeidsLNd8COriwRngo1yeMG+ApULvWWwYCcUv4sNqpcYOa mwaMz8se9Ajm0/46lsNQApaK/tEWKynR9wZkTaf+K8wAr7cdE15UjzUZFUKldpUT2JRxL4HYkXO L1cjcfdtK1MGJpuI4DqMdnDdJAOjgsaomuX9j3EUsMG/mXLz+33H5Y7/js/8Et+i+t0INV6H6pb x9kQ29t+p+ewTZeozaK70iGTvDfSgj4fCxPqtrFa3Csk52QqLfJzFm4I1ZGz9yPMisPHaU5BsxQ 8O0ALF+bVz4YmLJbC6cxFw73exmwIysHlz0+j8kayrmDmB+A8OlP754DsXSjHL8aLf59QwENDjJ rhxtysabW/hCVWzovPw== X-Authority-Analysis: v=2.4 cv=HMbz0Itv c=1 sm=1 tr=0 ts=6a185947 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=NGcC8JguVDcA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=OmVn7CZJonkx5R5zMQLL:22 a=gEfo2CItAAAA:8 a=gAnH3GRIAAAA:8 a=VwQbUJbxAAAA:8 a=lrA4KKAfxSG5QlsXGw4A:9 a=sptkURWiP4Gy88Gu7hUp:22 X-Proofpoint-GUID: ULNynLDyMvZF3mwatgeMlCQ1bwXEd_QB X-Proofpoint-ORIG-GUID: ULNynLDyMvZF3mwatgeMlCQ1bwXEd_QB X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.125,FMLib:17.12.100.49 definitions=2026-05-28_04,2026-05-28_03,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 lowpriorityscore=0 impostorscore=0 phishscore=0 bulkscore=0 adultscore=0 malwarescore=0 priorityscore=1501 clxscore=1011 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2605210000 definitions=main-2605280152 Content-Type: text/plain; charset="utf-8" Document how to describe LTC2378-20 and similar ADCs in device tree. Signed-off-by: Marcelo Schmitt Acked-by: Conor Dooley --- Change log v1 -> v2: - Use unevaluatedProperties:false with spi-peripheral-props.yaml reference/= include. - Use unique compatibles (no fallbacks). .../bindings/iio/adc/adi,ltc2378.yaml | 118 ++++++++++++++++++ MAINTAINERS | 7 ++ 2 files changed, 125 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..fdc004049521 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml @@ -0,0 +1,118 @@ +# 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: + enum: + - adi,ltc2338-18 + - adi,ltc2364-16 + - adi,ltc2364-18 + - adi,ltc2367-16 + - adi,ltc2367-18 + - adi,ltc2368-16 + - adi,ltc2368-18 + - adi,ltc2369-18 + - adi,ltc2370-16 + - adi,ltc2376-16 + - adi,ltc2376-18 + - adi,ltc2376-20 + - adi,ltc2377-16 + - adi,ltc2377-18 + - adi,ltc2377-20 + - adi,ltc2378-16 + - adi,ltc2378-18 + - adi,ltc2378-20 + - adi,ltc2379-18 + - adi,ltc2380-16 + + 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: + A 2.5V to 5.1V supply for the reference input (REF). + + cnv-gpios: + description: + When provided, this property indicates the GPIO that is 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 + - ref-supply + +unevaluatedProperties: false + +examples: + - | + #include + #include + spi { + #address-cells =3D <1>; + #size-cells =3D <0>; + adc@0 { + compatible =3D "adi,ltc2378-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 9e9457c7bba6..43c691ba48cd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15203,6 +15203,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 Mon Jun 8 14:35:14 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 16CAB34B1A5; Thu, 28 May 2026 15:04:18 +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=1779980661; cv=none; b=RAwucRJJk04HnwThTrZ8+e4r6uzZBOfe4UyTbm0V6+fdZ+AUxW/dm6kDAxDbEWUH5sNyuePKoAqAMkMKpGYI/E1XEMzKAX7cm/6tKBEVUbMVgy/+b7fQ84D35mDtaGWZyGjQ8oyyWViyv/cox5Gn8+sbE64b0y4snr7E0WHmNVk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779980661; c=relaxed/simple; bh=FEHx4SRaK/SP/KzHt+XVqoUY0C9iBFuTJ/m9KtKw2Tc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=u9WSPPeRNGfrULbumC2baoRA3rgUOiXTSNnAVpISNcCqSGi/I12QhukWj7WDWgi8ZqXvWJcH7LSvfknfOFXTZhltwmrYOz8tk0dugF2LhlMsRT1qzLDSw0hKNq0MdCkdMTWDw588k40W24ROqyO8NKNYbmLQQRdGS4dciG2j7vQ= 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=VBeNiTY3; 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="VBeNiTY3" 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 64SEeJIJ3916484; Thu, 28 May 2026 11:04: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=WEkMW nxxqkKfzzQ7LCtE4Es500MhlYIeyNCOAa1Nww4=; b=VBeNiTY3CqQadtg50t4iA 6g08NMmuCqONcZ5PdREn9qppLab5XI0Jp4VPMhQIiofb63l4JRxsLBsMdvaBMRIL qBtuNfcqfyrESjk8TCX0DMINbb2TAR4nL2Orj3gH+boCu1FEF5f1QBW1XJpZ0PGI TknsgdAFpxBmD1RvrG2TrKayKMtR7xgJBPWxprAAALW3LaaOYPCtC6+Tvnk5IFzo xh5/8f5WMg0VlEA34t+i1QtKtP5AJ7/8UnpAr1rNGHw75Ff4feAOzJlI4FnxjGrl 99ybXjat60q4mfQRvsxs4TJe2YQteKXyjidMpBAKaS24bzTP2zcp12DcFeBXEa4V w== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4ee7xdk969-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 28 May 2026 11:04: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 64SF4BHD008823 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 28 May 2026 11:04: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, 28 May 2026 11:04: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, 28 May 2026 11:04:11 -0400 Received: from work.maxim-ic.internal ([10.66.6.190]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 64SF3w6K021403; Thu, 28 May 2026 11:04:00 -0400 From: Marcelo Schmitt To: , , CC: , , , , , , , , , Subject: [PATCH v2 2/4] iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs Date: Thu, 28 May 2026 12:03:52 -0300 Message-ID: <40e1108bc9eaeba486705b54c4c94004f0e7f369.1779976379.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=VMPtWdPX c=1 sm=1 tr=0 ts=6a18596c cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=NGcC8JguVDcA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=Z0pTeXoby7EwIRygza74:22 a=gAnH3GRIAAAA:8 a=VwQbUJbxAAAA:8 a=ir6pry_9mBCdi5gbn5AA:9 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNTI4MDE1MiBTYWx0ZWRfX9eIcCpQlNhID Uh+XDqdfEV3TsnXLAN3Bigc5Z43GN8VscekqIvPDc9PMIv+t+kxJO7Ia7LL+QrhmZgwZea5Itt4 /iyvsDERZmeDdz5+jPWlxMZTY9/r+aagcReRxXcoenuzf5VHjNMojxTWMxXiJdV9c7It/r/Po2t PzLJc3kkzY1LvPgcJptxB2p/dxsNedOoqV32mUjoqQmWbiqsay/knn2A/7ltGi+nY+RIVkjJsKz gN3tNr8a7Ez/AKLg7N9RwwejsUtJJKwzeP7zD1Mw5aO4XSyVxh4XRyE1QwRfuwvLnXj/F0SNFKu ebvyPXof3kk2tEP3wdl2C+vlASimqtsFmRHUNQvqnTMa47/t1KB/jwuzb1NydjOhd77qm0JcER+ aBp4FGt7ri5miwpGRo/LMrALn+SQkwILJ6SZ+ifD5g1fxyziHgmCjnuVDCg/cD2aTJYocLXnYEe IebA5GAd/xFoUUVpmWQ== X-Proofpoint-GUID: sWueWq41dSoQ3L49FuacaOm95iAYQPNe X-Proofpoint-ORIG-GUID: sWueWq41dSoQ3L49FuacaOm95iAYQPNe X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.125,FMLib:17.12.100.49 definitions=2026-05-28_04,2026-05-28_03,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1011 suspectscore=0 adultscore=0 priorityscore=1501 impostorscore=0 malwarescore=0 phishscore=0 lowpriorityscore=0 bulkscore=0 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2605210000 definitions=main-2605280152 Content-Type: text/plain; charset="utf-8" Support for LTC2378-20 and similar analog-to-digital converters. Signed-off-by: Marcelo Schmitt --- Change log v1 -> v2: - Added missing includes and sorted the include section. - Added waiting time required before reading back LTC2378 conversion data. - Fixed voltage regulator read error path. - Properly right-aligned sample data. - Dropped device ID table and simplified chip specific information keeping. - Using named device_id data initializers. - Use bool for output code type distinction. - Added scope for IIO_DEV_ACQUIRE_DIRECT_MODE usage. MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 12 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ltc2378.c | 342 ++++++++++++++++++++++++++++++++++++++ drivers/iio/adc/ltc2378.h | 47 ++++++ 5 files changed, 403 insertions(+) create mode 100644 drivers/iio/adc/ltc2378.c create mode 100644 drivers/iio/adc/ltc2378.h diff --git a/MAINTAINERS b/MAINTAINERS index 43c691ba48cd..aed265ecabba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15209,6 +15209,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* =20 LTC2664 IIO DAC DRIVER M: Michael Hennerich diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 8550917226a1..70fec8e3e891 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -939,6 +939,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 GPIOLIB || PWM + select IIO_BUFFER + 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 707dd708912f..1814fb78dde3 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..bdff98157979 --- /dev/null +++ b/drivers/iio/adc/ltc2378.c @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Analog Devices LTC2378 ADC series driver + * + * Copyright (C) 2026 Analog Devices Inc. + * Author: Ioan-Daniel Pop + * Author: Marcelo Schmitt + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ltc2378.h" + +static const struct ltc2378_chip_info ltc2338_18_chip_info =3D { + .name =3D "ltc2338-18", + .resolution =3D 18, + .twos_comp =3D true, +}; + +static const struct ltc2378_chip_info ltc2364_16_chip_info =3D { + .name =3D "ltc2364-16", + .resolution =3D 16, + .twos_comp =3D false, +}; + +static const struct ltc2378_chip_info ltc2364_18_chip_info =3D { + .name =3D "ltc2364-18", + .resolution =3D 18, + .twos_comp =3D false, +}; + +static const struct ltc2378_chip_info ltc2367_16_chip_info =3D { + .name =3D "ltc2367-16", + .resolution =3D 16, + .twos_comp =3D false, +}; + +static const struct ltc2378_chip_info ltc2367_18_chip_info =3D { + .name =3D "ltc2367-18", + .resolution =3D 18, + .twos_comp =3D false, +}; + +static const struct ltc2378_chip_info ltc2368_16_chip_info =3D { + .name =3D "ltc2368-16", + .resolution =3D 16, + .twos_comp =3D false, + +}; + +static const struct ltc2378_chip_info ltc2368_18_chip_info =3D { + .name =3D "ltc2368-18", + .resolution =3D 18, + .twos_comp =3D false, +}; + +static const struct ltc2378_chip_info ltc2369_18_chip_info =3D { + .name =3D "ltc2369-18", + .resolution =3D 18, + .twos_comp =3D false, +}; + +static const struct ltc2378_chip_info ltc2370_16_chip_info =3D { + .name =3D "ltc2370-16", + .resolution =3D 16, + .twos_comp =3D false, +}; + +static const struct ltc2378_chip_info ltc2376_16_chip_info =3D { + .name =3D "ltc2376-16", + .resolution =3D 16, + .twos_comp =3D true, +}; + +static const struct ltc2378_chip_info ltc2376_18_chip_info =3D { + .name =3D "ltc2376-18", + .resolution =3D 18, + .twos_comp =3D true, +}; + +static const struct ltc2378_chip_info ltc2376_20_chip_info =3D { + .name =3D "ltc2376-20", + .resolution =3D 20, + .twos_comp =3D true, +}; + +static const struct ltc2378_chip_info ltc2377_16_chip_info =3D { + .name =3D "ltc2377-16", + .resolution =3D 16, + .twos_comp =3D true, +}; + +static const struct ltc2378_chip_info ltc2377_18_chip_info =3D { + .name =3D "ltc2377-18", + .resolution =3D 18, + .twos_comp =3D true, +}; + +static const struct ltc2378_chip_info ltc2377_20_chip_info =3D { + .name =3D "ltc2377-20", + .resolution =3D 20, + .twos_comp =3D true, +}; + +static const struct ltc2378_chip_info ltc2378_16_chip_info =3D { + .name =3D "ltc2378-16", + .resolution =3D 16, + .twos_comp =3D true, +}; + +static const struct ltc2378_chip_info ltc2378_18_chip_info =3D { + .name =3D "ltc2378-18", + .resolution =3D 18, + .twos_comp =3D true, +}; + +static const struct ltc2378_chip_info ltc2378_20_chip_info =3D { + .name =3D "ltc2378-20", + .resolution =3D 20, + .twos_comp =3D true, +}; + +static const struct ltc2378_chip_info ltc2379_18_chip_info =3D { + .name =3D "ltc2379-18", + .resolution =3D 18, + .twos_comp =3D true, +}; + +static const struct ltc2378_chip_info ltc2380_16_chip_info =3D { + .name =3D "ltc2380-16", + .resolution =3D 16, + .twos_comp =3D true, +}; + +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(4); + 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; + + ret =3D ltc2378_convert_and_acquire(st); + if (ret) + return ret; + + if (scan_type->realbits > 16) + sample =3D st->scan.data.sample_buf32; + else + sample =3D st->scan.data.sample_buf16; + + 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 info) +{ + struct ltc2378_state *st =3D iio_priv(indio_dev); + int ret; + + switch (info) { + 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 output code format: + * - straight binary: All precision/resolution bits are used. + * - 2's complement: One of the precision bits is used for sign. + */ + if (st->info->twos_comp) + *val2 =3D st->info->resolution - 1; + else + *val2 =3D st->info->resolution; + + 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_probe(struct spi_device *spi) +{ + struct device *dev =3D &spi->dev; + unsigned int num_iio_chans =3D 1; + 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_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; + st->info =3D spi_get_device_match_data(spi); + if (!st->info) + return -EINVAL; + + 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_optional(dev, "cnv", GPIOD_OUT_LOW); + if (st->cnv_gpio && IS_ERR(st->cnv_gpio)) + return dev_err_probe(dev, PTR_ERR(st->cnv_gpio), + "failed to get CNV GPIO"); + + st->chans[0].type =3D IIO_VOLTAGE; + st->chans[0].info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE); + st->chans[0].scan_type.format =3D st->info->twos_comp ? IIO_SCAN_FORMAT_S= IGNED_INT : + IIO_SCAN_FORMAT_UNSIGNED_INT; + st->chans[0].scan_type.realbits =3D st->info->resolution; + st->chans[0].scan_type.storagebits =3D st->info->resolution > 16 ? 32 : 1= 6; + + st->xfer.rx_buf =3D &st->scan.data; + st->xfer.len =3D BITS_TO_BYTES(st->chans[0].scan_type.storagebits); + st->xfer.bits_per_word =3D st->info->resolution > 16 ? 32 : 16; + + indio_dev->channels =3D st->chans; + indio_dev->num_channels =3D num_iio_chans; + + 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("Ioan-Daniel Pop "); +MODULE_AUTHOR("Marcelo Schmitt "); +MODULE_DESCRIPTION("Analog Devices LTC2378 ADC series driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/ltc2378.h b/drivers/iio/adc/ltc2378.h new file mode 100644 index 000000000000..399e8f67cd0e --- /dev/null +++ b/drivers/iio/adc/ltc2378.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Analog Devices LTC2378 and similar ADCs common definitions and properti= es + * Copyright (C) 2026 Analog Devices, Inc. + * Author: Marcelo Schmitt + */ + +#ifndef __DRIVERS_IIO_ADC_LTC2378_H__ +#define __DRIVERS_IIO_ADC_LTC2378_H__ + +#include +#include +#include +#include + +#define LTC2378_TDSDOBUSYL_NS 5 +#define LTC2378_TBUSYLH_NS 13 +#define LTC2378_TCNV_HIGH_NS 20 + +struct ltc2378_chip_info { + const char *name; + int resolution; + bool twos_comp; /* Output code is 2's complement or straight binary */ +}; + +struct ltc2378_state { + const struct ltc2378_chip_info *info; + struct gpio_desc *cnv_gpio; + struct spi_device *spi; + struct spi_transfer xfer; + struct iio_chan_spec chans[2]; /* 1 physical chan + 1 timestamp chan */ + int ref_uV; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + struct { + union { + u16 sample_buf16; + u32 sample_buf32; + } data; + aligned_s64 timestamp; + } scan __aligned(IIO_DMA_MINALIGN); +}; + +#endif /* __DRIVERS_IIO_ADC_LTC2378_H__ */ --=20 2.53.0 From nobody Mon Jun 8 14:35:14 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 8F41129C33F; Thu, 28 May 2026 15:05:00 +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=1779980704; cv=none; b=N3W6nvDxmZkyQYaZ1n9I2QzGf8bISEM849sKPpvs1adhJ8fsus16fjhkKB8mPNkmCIqE1MbJysb8eeCmd8Vh/4m56KybgnQOHhI3dUURSqViQEWkyDPyrQYeFPTrx7RMbovb28PFCv2o5ZFL4GwVl5Va84vzTrulYr9OwBGVZNA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779980704; c=relaxed/simple; bh=1M4FAXhAbaPDOBqAeeoXHgYGcka1NGIHgrmoV2D72/g=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=YN4Fp/sboMMcVFk52GbcR1YfcFB6LO8XNlJMxltl1eIpP+7CPQfx6HnIteNZaaIf0JSLX/99NYSG0QIjKOCIuz/gMWDq2SAmVKIG69UsihU/8uLxAsZMRlfMLsOR3mjiYvfSXyQLAtt4GS86RkX/eHlJMZRIw1gUpyRKaY44VTQ= 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=TcHAAMrU; 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="TcHAAMrU" 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 64SDZQFG400648; Thu, 28 May 2026 11:04:30 -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=iWaXR feFSr5hMgtYZRopXZvY8NbiSeZIc6ZoN8wG7XI=; b=TcHAAMrUB0eEb3k+kz+dO 5V+f4itdeq9jAhZxgNMogosDcVqQhjkNnlp7SIeTwFU4y440x2H1+Dg/ULlOlzth RbtfB2Qap0WrGjlUtzFFIF5RblZKL6EoF6kPt9oXdcYLa4qE7pD2WoL1BX10x672 t75YFhxT3W0l64IoH1M7I1OIYJMsCn59fzYvVSlM8fUCMKA3jeuwIjG+FexFTwZx jDsnCr61p16c8FhLPzLJcmSmfADKPHMfF53BsGGvUgfn6RqEbHcNU8HKNNwqN0Gh Vs6ISjYvQGHMhUTwleBhQK3o2bHzkr45NxMP19hbls0LibdfWT9+6tksunVZb1MJ A== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4ee7x1uage-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 28 May 2026 11:04:30 -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 64SF4TaD008909 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 28 May 2026 11:04:29 -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, 28 May 2026 11:04:29 -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, 28 May 2026 11:04:29 -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, 28 May 2026 11:04:29 -0400 Received: from work.maxim-ic.internal ([10.66.6.190]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 64SF4HbO021411; Thu, 28 May 2026 11:04:20 -0400 From: Marcelo Schmitt To: , , CC: , , , , , , , , , Subject: [PATCH v2 3/4] iio: adc: ltc2378: Enable high-speed data capture Date: Thu, 28 May 2026 12:04:12 -0300 Message-ID: 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: AW1haW4tMjYwNTI4MDE1MiBTYWx0ZWRfX3lmJCpyOHicm PS1mCqVJ9Yz8WaH+0dlCqNHuvw3N6mytGQqtnHVK79oMaZXYCokriwqZsgvsbnzAlWjR2hMzj8Q k/k2OGdsccObk9YcpVaDALPo1hdN5odRc/F0c5Itjgw+57cYM/o06N+t53zSM7EP6m54eN6xQAP 9ql5HAhWTGTdLECD4sw1u9xGXyiQm5a/gLZGAlO2OuGgdJzFBuVOXwL+MHGUXVn7DWmVxElUW+T EBo9hIflQIprPrW9H9y9IYbYH4f1iyWi3a3HlL7YphZY/5vj9p63eyTagW1JZ860QpbbUcNsP+i zgNvFxEskEu7zzINZz1FLy8zcV0pshyJjPb8S4cSWH3Fp0Laww44S9ZjYVj4T/gyAsP+2Sw4TwH fe9TK6tgtbceVD46coffYNSs/8n32G9qvqnLofieNojVd71Y4qq06pdP65jYXC2TiajT0OwdMU6 iZCS4By2Ut3ewA7UbkQ== X-Authority-Analysis: v=2.4 cv=HMbz0Itv c=1 sm=1 tr=0 ts=6a18597e cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=NGcC8JguVDcA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=OmVn7CZJonkx5R5zMQLL:22 a=gAnH3GRIAAAA:8 a=9H_XI321FAzbxM0tdFEA:9 X-Proofpoint-GUID: I8wUoDX798E917Dx1duTNjRwOVnWHjqk X-Proofpoint-ORIG-GUID: I8wUoDX798E917Dx1duTNjRwOVnWHjqk X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.125,FMLib:17.12.100.49 definitions=2026-05-28_04,2026-05-28_03,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 lowpriorityscore=0 impostorscore=0 phishscore=0 bulkscore=0 adultscore=0 malwarescore=0 priorityscore=1501 clxscore=1011 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2605210000 definitions=main-2605280152 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). Signed-off-by: Marcelo Schmitt --- Change log v1 -> v2: - Set loop count to prevent CPU stall when calculating PWM parameters. - Hardcode set specific offload supported amount of data element bits. - Fixed devm_spi_offload_get() error path. - Initialize init scan_type according to buffer selection. - Offload attributes now are channel based instead of device based. - Wrapped comments close to 80 columns. I haven't manage to code an is_visible() filter for device attributes speci= fic of offload usage. Using DEFINE_SYSFS_GROUP_VISIBLE() didn't work out as the sampling_frequency_available attribute would still appear even without offl= oad. Using DEFINE_SYSFS_GROUP_VISIBLE() and sysfs attribute specific visibility function resulted in kernel error (Invalid permissions 01). Instead, I made them channel shared by all attributes. I tried a lib-like code arrangement like ADIS IMU but didn't manage to get = it to work. Separated the code into ltc2378.h, ltc2378.c (lib), ltc2378-core.c (base driver), and ltc2378-offload.c with lib and core built as module and offload.c builtin. Though, I ran into different build and linkage errors depending on how ltc2378-offload.c utilities were encapsulated. Having read through IMU ADIS code, I now think LTC2378 is different and doesn't require a code design that much elaborated. Differently from the separate code for supporting specific adis devices, all ltc2378-like devices can be supported by the same set of functions from ltc2378.c. We can maybe have an ops struct with pointers to buffer specific routines (e.g. offload vs triggered). That might be worth it if we would want to switch between buffer types at runtim= e. For v2, I'm keeping the module design similar to v1. I appreciate additional examples if a module redesign is still recommended. drivers/iio/adc/Kconfig | 9 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ltc2378-offload-buffer.c | 296 +++++++++++++++++++++++ drivers/iio/adc/ltc2378.c | 91 ++++++- drivers/iio/adc/ltc2378.h | 66 +++++ 5 files changed, 457 insertions(+), 6 deletions(-) create mode 100644 drivers/iio/adc/ltc2378-offload-buffer.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 70fec8e3e891..5f7038b5e731 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -944,6 +944,7 @@ config LTC2378 depends on SPI depends on GPIOLIB || PWM select IIO_BUFFER + select LTC2378_OFFLOAD_BUFFER if SPI_OFFLOAD && PWM && IIO_BUFFER help Say yes here to build support for Analog Devices LTC2378-20 and similar analog to digital converters. @@ -2027,3 +2028,11 @@ config XILINX_AMS xilinx-ams. =20 endmenu + +config LTC2378_OFFLOAD_BUFFER + bool + select SPI_OFFLOAD_TRIGGER_PWM + select IIO_BUFFER_DMA + select IIO_BUFFER_DMAENGINE + help + Say yes here to build support for high speed data capture with LTC2378 diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 1814fb78dde3..2fa5dce0ceea 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -82,6 +82,7 @@ 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_LTC2378_OFFLOAD_BUFFER) +=3D ltc2378-offload-buffer.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-offload-buffer.c b/drivers/iio/adc/ltc= 2378-offload-buffer.c new file mode 100644 index 000000000000..8ad2d319f669 --- /dev/null +++ b/drivers/iio/adc/ltc2378-offload-buffer.c @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2026 Analog Devices, Inc. + * Author: Marcelo Schmitt + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ltc2378.h" + +/* + * 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 =3D 0; + u64 offload_offset_ns; + int ret; + + if (freq_Hz =3D=3D 0) + return -EINVAL; + + if (freq_Hz < 1 || freq_Hz > 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. + */ + 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 (cnv_wf.duty_length_ns < LTC2378_TCNV_HIGH_NS || count++ < 100); + + /* + * 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_ROUND_UP(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 0; + 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 (config->periodic.offset_ns < min_read_offset || count++ < 100); + + st->cnv_wf =3D cnv_wf; + st->cnv_Hz =3D DIV_ROUND_CLOSEST_ULL(HZ_PER_GHZ, cnv_wf.period_length_ns); + + return 0; +} + +int ltc2378_get_sampling_frequency(struct ltc2378_state *st, int *val) +{ + *val =3D st->cnv_Hz; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ltc2378_get_sampling_frequency, "IIO_LTC2378"); + +int ltc2378_set_sampling_frequency(struct ltc2378_state *st, int freq_Hz) +{ + return ltc2378_update_conversion_rate(st, freq_Hz); +} +EXPORT_SYMBOL_NS_GPL(ltc2378_set_sampling_frequency, "IIO_LTC2378"); + +int ltc2378_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec con= st *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; + } +} +EXPORT_SYMBOL_NS_GPL(ltc2378_read_avail, "IIO_LTC2378"); + +int ltc2378_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec cons= t *chan, + int val, int val2, long mask) +{ + struct ltc2378_state *st =3D iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: { + if (val < 1 || val > st->info->max_sample_rate_hz) + return -EINVAL; + + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + return ltc2378_set_sampling_frequency(st, val); + } + default: + return -EINVAL; + } +} +EXPORT_SYMBOL_NS_GPL(ltc2378_write_raw, "IIO_LTC2378"); + +static int ltc2378_prepare_offload_message(struct device *dev, + struct ltc2378_state *st) +{ + st->offload_xfer.bits_per_word =3D st->info->resolution; + /* + * Ideally, we would ask the offload provider what data word sizes are + * supported so we could use smaller words for less precise ADCs. + * Though, the currently available SPI offloading hardware only supports + * pushing 32-bit sized data elements to DMA memory. Because of that, + * we hardcode set 4 byte sized transfers. + */ + st->offload_xfer.len =3D 4; + 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_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, false); + 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_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"); + + 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, +}; + +int ltc2378_offload_buffer_setup(struct iio_dev *indio_dev, struct spi_dev= ice *spi) +{ + struct ltc2378_state *st =3D iio_priv(indio_dev); + struct device *dev =3D &spi->dev; + int ret; + + st->offload =3D devm_spi_offload_get(dev, spi, <c2378_offload_config); + ret =3D PTR_ERR_OR_ZERO(st->offload); + if (ret) + return dev_err_probe(dev, ret, "failed to get offload\n"); + + 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 ret; + + 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 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 sampling frequency\n"); + + ret =3D ltc2378_prepare_offload_message(&spi->dev, st); + if (ret) + return dev_err_probe(dev, ret, "failed to optimize SPI message\n"); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ltc2378_offload_buffer_setup, "IIO_LTC2378"); + +MODULE_IMPORT_NS("IIO_LTC2378"); diff --git a/drivers/iio/adc/ltc2378.c b/drivers/iio/adc/ltc2378.c index bdff98157979..6b01d8e96cc6 100644 --- a/drivers/iio/adc/ltc2378.c +++ b/drivers/iio/adc/ltc2378.c @@ -27,36 +27,48 @@ static const struct ltc2378_chip_info ltc2338_18_chip_info =3D { .name =3D "ltc2338-18", .resolution =3D 18, + .max_sample_rate_hz =3D HZ_PER_MHZ, + .tconv_ns =3D 527, .twos_comp =3D true, }; =20 static const struct ltc2378_chip_info ltc2364_16_chip_info =3D { .name =3D "ltc2364-16", .resolution =3D 16, + .max_sample_rate_hz =3D 250 * HZ_PER_KHZ, + .tconv_ns =3D 3000, .twos_comp =3D false, }; =20 static const struct ltc2378_chip_info ltc2364_18_chip_info =3D { .name =3D "ltc2364-18", .resolution =3D 18, + .max_sample_rate_hz =3D 250 * HZ_PER_KHZ, + .tconv_ns =3D 3000, .twos_comp =3D false, }; =20 static const struct ltc2378_chip_info ltc2367_16_chip_info =3D { .name =3D "ltc2367-16", .resolution =3D 16, + .max_sample_rate_hz =3D 500 * HZ_PER_KHZ, + .tconv_ns =3D 1500, .twos_comp =3D false, }; =20 static const struct ltc2378_chip_info ltc2367_18_chip_info =3D { .name =3D "ltc2367-18", .resolution =3D 18, + .max_sample_rate_hz =3D 500 * HZ_PER_KHZ, + .tconv_ns =3D 1500, .twos_comp =3D false, }; =20 static const struct ltc2378_chip_info ltc2368_16_chip_info =3D { .name =3D "ltc2368-16", .resolution =3D 16, + .max_sample_rate_hz =3D HZ_PER_MHZ, + .tconv_ns =3D 527, .twos_comp =3D false, =20 }; @@ -64,84 +76,112 @@ static const struct ltc2378_chip_info ltc2368_16_chip_= info =3D { static const struct ltc2378_chip_info ltc2368_18_chip_info =3D { .name =3D "ltc2368-18", .resolution =3D 18, + .max_sample_rate_hz =3D HZ_PER_MHZ, + .tconv_ns =3D 527, .twos_comp =3D false, }; =20 static const struct ltc2378_chip_info ltc2369_18_chip_info =3D { .name =3D "ltc2369-18", .resolution =3D 18, + .max_sample_rate_hz =3D 1600 * HZ_PER_KHZ, + .tconv_ns =3D 412, .twos_comp =3D false, }; =20 static const struct ltc2378_chip_info ltc2370_16_chip_info =3D { .name =3D "ltc2370-16", .resolution =3D 16, + .max_sample_rate_hz =3D 2 * HZ_PER_MHZ, + .tconv_ns =3D 322, .twos_comp =3D false, }; =20 static const struct ltc2378_chip_info ltc2376_16_chip_info =3D { .name =3D "ltc2376-16", .resolution =3D 16, + .max_sample_rate_hz =3D 250 * HZ_PER_KHZ, + .tconv_ns =3D 3000, .twos_comp =3D true, }; =20 static const struct ltc2378_chip_info ltc2376_18_chip_info =3D { .name =3D "ltc2376-18", .resolution =3D 18, + .max_sample_rate_hz =3D 250 * HZ_PER_KHZ, + .tconv_ns =3D 3000, .twos_comp =3D true, }; =20 static const struct ltc2378_chip_info ltc2376_20_chip_info =3D { .name =3D "ltc2376-20", .resolution =3D 20, + .max_sample_rate_hz =3D 250 * HZ_PER_KHZ, + .tconv_ns =3D 3000, .twos_comp =3D true, }; =20 static const struct ltc2378_chip_info ltc2377_16_chip_info =3D { .name =3D "ltc2377-16", .resolution =3D 16, + .max_sample_rate_hz =3D 500 * HZ_PER_KHZ, + .tconv_ns =3D 1500, .twos_comp =3D true, }; =20 static const struct ltc2378_chip_info ltc2377_18_chip_info =3D { .name =3D "ltc2377-18", .resolution =3D 18, + .max_sample_rate_hz =3D 500 * HZ_PER_KHZ, + .tconv_ns =3D 1500, .twos_comp =3D true, }; =20 static const struct ltc2378_chip_info ltc2377_20_chip_info =3D { .name =3D "ltc2377-20", .resolution =3D 20, + .max_sample_rate_hz =3D 500 * HZ_PER_KHZ, + .tconv_ns =3D 1500, .twos_comp =3D true, }; =20 static const struct ltc2378_chip_info ltc2378_16_chip_info =3D { .name =3D "ltc2378-16", .resolution =3D 16, + .max_sample_rate_hz =3D HZ_PER_MHZ, + .tconv_ns =3D 527, .twos_comp =3D true, }; =20 static const struct ltc2378_chip_info ltc2378_18_chip_info =3D { .name =3D "ltc2378-18", .resolution =3D 18, + .max_sample_rate_hz =3D HZ_PER_MHZ, + .tconv_ns =3D 527, .twos_comp =3D true, }; =20 static const struct ltc2378_chip_info ltc2378_20_chip_info =3D { .name =3D "ltc2378-20", .resolution =3D 20, + .max_sample_rate_hz =3D HZ_PER_MHZ, + .tconv_ns =3D 675, .twos_comp =3D true, }; =20 static const struct ltc2378_chip_info ltc2379_18_chip_info =3D { .name =3D "ltc2379-18", .resolution =3D 18, + .max_sample_rate_hz =3D 1600 * HZ_PER_KHZ, + .tconv_ns =3D 412, .twos_comp =3D true, }; =20 static const struct ltc2378_chip_info ltc2380_16_chip_info =3D { .name =3D "ltc2380-16", .resolution =3D 16, + .max_sample_rate_hz =3D 2 * HZ_PER_MHZ, + .tconv_ns =3D 322, .twos_comp =3D true, }; =20 @@ -190,7 +230,7 @@ static int ltc2378_read_raw(struct iio_dev *indio_dev, int ret; =20 switch (info) { - case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_RAW: { IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); if (IIO_DEV_ACQUIRE_FAILED(claim)) return -EBUSY; @@ -200,7 +240,7 @@ static int ltc2378_read_raw(struct iio_dev *indio_dev, return ret; =20 return IIO_VAL_INT; - + } case IIO_CHAN_INFO_SCALE: *val =3D st->ref_uV / MILLI; /* @@ -216,6 +256,17 @@ static int ltc2378_read_raw(struct iio_dev *indio_dev, =20 return IIO_VAL_FRACTIONAL_LOG2; =20 + case IIO_CHAN_INFO_SAMP_FREQ: { + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + ret =3D ltc2378_get_sampling_frequency(st, val); + if (ret) + return ret; + + return IIO_VAL_INT; + } default: return -EINVAL; } @@ -223,6 +274,8 @@ static int ltc2378_read_raw(struct iio_dev *indio_dev, =20 static const struct iio_info ltc2378_iio_info =3D { .read_raw =3D <c2378_read_raw, + .write_raw =3D LTC2378_WRITE_RAW, + .read_avail =3D LTC2378_READ_AVAIL, }; =20 static int ltc2378_probe(struct spi_device *spi) @@ -261,10 +314,35 @@ static int ltc2378_probe(struct spi_device *spi) st->chans[0].type =3D IIO_VOLTAGE; st->chans[0].info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE); - st->chans[0].scan_type.format =3D st->info->twos_comp ? IIO_SCAN_FORMAT_S= IGNED_INT : - IIO_SCAN_FORMAT_UNSIGNED_INT; - st->chans[0].scan_type.realbits =3D st->info->resolution; - st->chans[0].scan_type.storagebits =3D st->info->resolution > 16 ? 32 : 1= 6; + + struct iio_scan_type ltc2378_scan; + + ret =3D ltc2378_offload_buffer_setup(indio_dev, spi); + if (ret =3D=3D -ENODEV) { + /* SPI offloading is unavailable. Fall back to triggered buffer. */ + dev_dbg(dev, "triggered data capture not supported\n"); + ltc2378_scan.format =3D st->info->twos_comp ? IIO_SCAN_FORMAT_SIGNED_INT= : + IIO_SCAN_FORMAT_UNSIGNED_INT; + ltc2378_scan.realbits =3D st->info->resolution; + ltc2378_scan.storagebits =3D st->info->resolution > 16 ? 32 : 16; + } else if (ret) { + return dev_err_probe(dev, ret, "error on SPI offload setup\n"); + } else { + /* + * Currently, the available offload hardware + DMA configuration + * only supports pushing 32-bit data elements to IIO buffers in + * CPU endianness. + */ + st->chans[0].info_mask_shared_by_all =3D BIT(IIO_CHAN_INFO_SAMP_FREQ); + st->chans[0].info_mask_shared_by_all_available =3D BIT(IIO_CHAN_INFO_SAM= P_FREQ); + + ltc2378_scan.format =3D st->info->twos_comp ? IIO_SCAN_FORMAT_SIGNED_INT= : + IIO_SCAN_FORMAT_UNSIGNED_INT; + ltc2378_scan.realbits =3D st->info->resolution; + ltc2378_scan.storagebits =3D 32; + } + + st->chans[0].scan_type =3D ltc2378_scan; =20 st->xfer.rx_buf =3D &st->scan.data; st->xfer.len =3D BITS_TO_BYTES(st->chans[0].scan_type.storagebits); @@ -340,3 +418,4 @@ MODULE_AUTHOR("Ioan-Daniel Pop "); MODULE_AUTHOR("Marcelo Schmitt "); MODULE_DESCRIPTION("Analog Devices LTC2378 ADC series driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_LTC2378"); diff --git a/drivers/iio/adc/ltc2378.h b/drivers/iio/adc/ltc2378.h index 399e8f67cd0e..e79619c12ce9 100644 --- a/drivers/iio/adc/ltc2378.h +++ b/drivers/iio/adc/ltc2378.h @@ -9,7 +9,10 @@ #define __DRIVERS_IIO_ADC_LTC2378_H__ =20 #include +#include #include +#include +#include #include #include =20 @@ -20,6 +23,8 @@ struct ltc2378_chip_info { const char *name; int resolution; + unsigned int max_sample_rate_hz; + unsigned int tconv_ns; bool twos_comp; /* Output code is 2's complement or straight binary */ }; =20 @@ -30,6 +35,15 @@ struct ltc2378_state { struct spi_transfer xfer; struct iio_chan_spec chans[2]; /* 1 physical chan + 1 timestamp chan */ int ref_uV; + unsigned int cnv_Hz; + struct pwm_waveform cnv_wf; + struct spi_offload *offload; + struct spi_offload_trigger *offload_trigger; + struct spi_message offload_msg; + struct spi_transfer offload_xfer; + struct spi_offload_trigger_config offload_trigger_config; + struct pwm_device *cnv_trigger; + int sample_freq_range[3]; =20 /* * DMA (thus cache coherency maintenance) requires the @@ -44,4 +58,56 @@ struct ltc2378_state { } scan __aligned(IIO_DMA_MINALIGN); }; =20 +#define LTC2378_WRITE_RAW LTC2378_WRITE_RAW_PTR + +#define LTC2378_READ_AVAIL LTC2378_READ_AVAIL_PTR + +#ifdef CONFIG_LTC2378_OFFLOAD_BUFFER + +int ltc2378_offload_buffer_setup(struct iio_dev *indio_dev, struct spi_dev= ice *spi); + +int ltc2378_get_sampling_frequency(struct ltc2378_state *st, int *val); + +int ltc2378_set_sampling_frequency(struct ltc2378_state *st, int freq_Hz); + +int ltc2378_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec cons= t *chan, + int val, int val2, long mask); + +int ltc2378_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec con= st *chan, + const int **vals, int *type, int *length, long mask); + +#define LTC2378_WRITE_RAW_PTR (<c2378_write_raw) + +#define LTC2378_READ_AVAIL_PTR (<c2378_read_avail) + +#else /* CONFIG_IIO_LTC2378_LIB_OFFLOAD_BUFFER */ + +#define LTC2378_WRITE_RAW_PTR (NULL) + +#define LTC2378_READ_AVAIL_PTR (NULL) + +static inline int ltc2378_offload_buffer_setup(struct iio_dev *indio_dev, + struct spi_device *spi) +{ + return -ENODEV; +} + +int ltc2378_get_sampling_frequency(struct ltc2378_state *st, int *val) +{ + return -EOPNOTSUPP; +} + +int ltc2378_set_sampling_frequency(struct ltc2378_state *st, int freq_Hz); +{ + return -EOPNOTSUPP; +} + +int ltc2378_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec cons= t *chan, + int val, int val2, long mask) +{ + return -EOPNOTSUPP; +} + +#endif + #endif /* __DRIVERS_IIO_ADC_LTC2378_H__ */ --=20 2.53.0 From nobody Mon Jun 8 14:35:14 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 7575328CF77; Thu, 28 May 2026 15:05:00 +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=1779980704; cv=none; b=eSIAXBNz8jv2jhA5wElvT0tmTZeA4eFWa26KnyBo9SmtQpF59NemXNIMGwZXZGEkHOWdCkZXg8I1h8wnutN5f6Y+L6+kgHAmiIdMvrfsvuE47Y+pQjZ235fGCkBJz/K2Ie9ncbgbHChbZNpG1CRj0BHARqq1XXz88gnIKtbxD70= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779980704; c=relaxed/simple; bh=+iG76pos/4B5hfHm4dzwTjyiw4lo6xsWMEr6bIF/Gs4=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Dg6QIjOJ6RWyscrVthg3gdI5ajvhX08BAzMsGsgaDxt7EUdRXtLyr043f4p6uNfthDScI3rCVs3M3QonDcHbEy5y/JevljLdq8XPIEmfhr4t8QVcU4gDuamH1PhsZ1pPRCTj968l+kwXSXFz4/rNf7uYxBtCHQL+0sjmPNVmRuE= 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=g2H2SOyC; 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="g2H2SOyC" 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 64SEeJIZ3916484; Thu, 28 May 2026 11:04: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=gzitM u07b2oTFaTIsCct6rj6QLnJsT7PIvnP0vayh6A=; b=g2H2SOyCpwsQIpVzI8X7D yeuqFIoASM/axvjSc+F0mLakX4D10u7YHZGFNRBb5yKOvziZT5mPET+IDMjN2/+C CmtBS1kvi3XMq0yocFtCS9RYgKlt9imXvdDvkuHi7Gtswb9KDiKlGYbn0LVCSTux W8Yw5u4Avi9fPbK1tTjhkiK00dfiEhxO63bnk2tghUbNUKjcDPyptTOSuKg+i4k8 /OfOh5EB8DA8crNFdt64sGvRR29QS97erOA/9hTS1IhTE4d3McVxuLCaKnnSAtFa PtKPWUJ0dLKu6lzMpDKHqBKxolevMUpuETnUtw0CwbPxw2l+u+EUwiQKp7PDESwK g== Received: from nwd2mta4.analog.com ([137.71.173.58]) by mx0a-00128a01.pphosted.com (PPS) with ESMTPS id 4ee7xdk99g-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 28 May 2026 11:04:54 -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 64SF4rFi008969 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 28 May 2026 11:04:53 -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, 28 May 2026 11:04:53 -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, 28 May 2026 11:04: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, 28 May 2026 11:04:53 -0400 Received: from work.maxim-ic.internal ([10.66.6.190]) by zeus.spd.analog.com (8.15.1/8.15.1) with ESMTP id 64SF4gUB021563; Thu, 28 May 2026 11:04:45 -0400 From: Marcelo Schmitt To: , , CC: , , , , , , , , , Subject: [PATCH v2 4/4] iio: adc: ltc2378: Enable triggered buffer data capture Date: Thu, 28 May 2026 12:04:37 -0300 Message-ID: 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=VMPtWdPX c=1 sm=1 tr=0 ts=6a185997 cx=c_pps a=3WNzaoukacrqR9RwcOSAdA==:117 a=3WNzaoukacrqR9RwcOSAdA==:17 a=NGcC8JguVDcA:10 a=VkNPw1HP01LnGYTKEx00:22 a=0sLvza09kfJOxVLZPwjg:22 a=Z0pTeXoby7EwIRygza74:22 a=gAnH3GRIAAAA:8 a=wnqDGYsx2rMr_Dauq28A:9 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNTI4MDE1MiBTYWx0ZWRfX9iQ7bAG7lto9 pGWPxLHSo3erDsrRQiOaPxvl17HybLUO5kUJ3JD3kzmjYYRJAewvBM2NgHDs1JUPtQEXjTWhVyN ul+VFluJmgAb+YzNJfw/J5FEWMryl+Ew7M/1cCOMHcPMbViDOT9ynWxaRjWPmr9nfdwpjhAn9hP wuQpzoVpKNP9LVNcwwDowaap051ypMGVwPUeY/9ZAQChfmBpjYnEaIi3rEtmzdDVc2lWtJ+bPPJ VUFxkxNBAV/jJgEjfZ8vSStWg/pYW1/mnxlBuDICGPA0E8YbOyW1fWiVo7btUGFBfOzUxkWGhHo oTk21WEZdobHceat+7u5PWmLn5uA6Z1eMBAptxzJHhR+q5KrtezUUSz810xTD3Hfk+RtxzwbSAZ 3PLNRG35x82fUnHhVnyqvT6YwZ3jfYxQJc0sIINS6gOywH0jke/iWTZ/A4sgCgewneMFUZbDqxN +/CMkPJCD2H81ZqXiLw== X-Proofpoint-GUID: V3kHvKmi2eVqjn68K0l4ZrIHsIGew4lu X-Proofpoint-ORIG-GUID: V3kHvKmi2eVqjn68K0l4ZrIHsIGew4lu X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.125,FMLib:17.12.100.49 definitions=2026-05-28_04,2026-05-28_03,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 suspectscore=0 adultscore=0 priorityscore=1501 impostorscore=0 malwarescore=0 phishscore=0 lowpriorityscore=0 bulkscore=0 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2605210000 definitions=main-2605280152 Content-Type: text/plain; charset="utf-8" Enable users to run triggered data captures with LTC2378 and similar ADCs. Signed-off-by: Marcelo Schmitt --- Change log v1 -> v2: - Initialize init scan_type according to buffer selection. - Use IIO_CHAN_SOFT_TIMESTAMP directly on right hand of assignment. drivers/iio/adc/Kconfig | 1 + drivers/iio/adc/ltc2378.c | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 5f7038b5e731..65887c8f3171 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -945,6 +945,7 @@ config LTC2378 depends on GPIOLIB || PWM select IIO_BUFFER select LTC2378_OFFLOAD_BUFFER if SPI_OFFLOAD && PWM && IIO_BUFFER + select IIO_TRIGGERED_BUFFER 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 6b01d8e96cc6..514645b847f0 100644 --- a/drivers/iio/adc/ltc2378.c +++ b/drivers/iio/adc/ltc2378.c @@ -18,8 +18,12 @@ #include #include #include +#include =20 +#include #include +#include +#include #include =20 #include "ltc2378.h" @@ -278,6 +282,25 @@ static const struct iio_info ltc2378_iio_info =3D { .read_avail =3D LTC2378_READ_AVAIL, }; =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_probe(struct spi_device *spi) { struct device *dev =3D &spi->dev; @@ -314,17 +337,27 @@ static int ltc2378_probe(struct spi_device *spi) st->chans[0].type =3D IIO_VOLTAGE; st->chans[0].info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE); + st->chans[0].scan_index =3D 0; =20 struct iio_scan_type ltc2378_scan; =20 ret =3D ltc2378_offload_buffer_setup(indio_dev, spi); if (ret =3D=3D -ENODEV) { /* SPI offloading is unavailable. Fall back to triggered buffer. */ - dev_dbg(dev, "triggered data capture not supported\n"); ltc2378_scan.format =3D st->info->twos_comp ? IIO_SCAN_FORMAT_SIGNED_INT= : IIO_SCAN_FORMAT_UNSIGNED_INT; ltc2378_scan.realbits =3D st->info->resolution; ltc2378_scan.storagebits =3D st->info->resolution > 16 ? 32 : 16; + + ret =3D devm_iio_triggered_buffer_setup(dev, indio_dev, + &iio_pollfunc_store_time, + <c2378_trigger_handler, + NULL); + if (ret) + return ret; + + /* Add timestamp channel */ + st->chans[num_iio_chans++] =3D IIO_CHAN_SOFT_TIMESTAMP(1); } else if (ret) { return dev_err_probe(dev, ret, "error on SPI offload setup\n"); } else { --=20 2.53.0