From nobody Mon May 25 05:12:10 2026 Received: from mail-qk1-f173.google.com (mail-qk1-f173.google.com [209.85.222.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 61C4D370D45 for ; Mon, 18 May 2026 15:20:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779117650; cv=none; b=u0sTUrvObsHzIzGWQxPXWxYoX8Pg7IW8TsAlnzTWJRDgkQX2wikcu4tIslWAJysVDMro8XCru12QYolQOai4ksBZR6+9p7WERJTTPRD1RWYY0qCQ+CcWYBCuOqk/VNmXybQs5T7EjRkb6Q12/+nfCYXw91lJbYraT1+gvtyvIww= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779117650; c=relaxed/simple; bh=l0Sk2ShyS10/CMZ6Y9UFyNVPGKv48bgWgstDnMtnGiA=; h=From:Date:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=kHWRJUIDOoMPi3+xxfypwfwrbWo6697jm+0cs2sJCYDDSgTXI1YHuL8+Wl5siiyzzstPS+hLY1msAspMtt/UOk4rWEgqjGYOnD+V8sr7D0PNRBdU1JIwuEnDzJhW6xNSrj2pDFj6XYSAIOiTQ6+Sv4duWqJbAkYAz4/kyZ5NzAo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=RdVX52Vv; arc=none smtp.client-ip=209.85.222.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="RdVX52Vv" Received: by mail-qk1-f173.google.com with SMTP id af79cd13be357-90fbf21d9d3so464618585a.1 for ; Mon, 18 May 2026 08:20:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779117647; x=1779722447; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:date:from:from:to:cc:subject:date:message-id:reply-to; bh=eUhUIAdzDSOyS8J9byt38ZO1lGApTw9uIarN9cEc3TI=; b=RdVX52VvSWGbgWUvgYLwpTqPbpuAlk+m+8J8935aHP1qHftR4TK/HK4+Fvf+/DBo+t sGKPu35scVqQn1grUcLeDUItLwwHgZL7HOHD0KuHozWW0gzAyOgjaXR/ptcYBfya3C0I xC131QhHW+An/QJoEPaTJ4NQzsmIf8CJZlydf2gX7RpXFVTqQX1cMJQoKZJkO+F7HDDC Csx2XB7xaYKYT02Q4PTUiuM0VwEDA2Dbe0YbR2R3dAR4TJ8t+JMBz2c19JhogvLYBib8 IiRzeWA9XnyvBPBFJ/QF4HqxNn9wxUH2fXmmiHDNj8cwW0tFTGFihSsmpozZ+/YCgva/ KeBQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779117647; x=1779722447; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:date:from:x-gm-gg:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=eUhUIAdzDSOyS8J9byt38ZO1lGApTw9uIarN9cEc3TI=; b=Gt9+thxOjdpDKcK9I9ObzdxsrV9V2FtRb0Ecgt0wa98IgzuvASwQ/+CZDQq/E8pmVt I53BT0q+dkqFVNpBdusz6xbmYK7QzV7mmi/y+YHogAASTVHh/kzhXOs+klFpUWf5iwOV lQjCYPOtIgs3yJJW5pSwg3q7ZQj/3NZ3kXTPeWOi/gdA/bSw6wF0GIituy8Hb55dYzDm oMrTfk7XnvMIsIFq3WA9QKJv/FUeTNFnk5ojRSuwjOxSwrxKKzADysOQAzfwR3qnF7c8 ziVycoPsqhM6UD2P+msg5cYFA83OCLYtFIDpZmvgBKsBzS3PdzQPhGNxLwnddqx4Bm8f zomQ== X-Forwarded-Encrypted: i=1; AFNElJ93uZA7C9vIgxqAMQ9Ysnp8LbzzwrFnT1iHVqRyGOr41Q1XObAF/B+86XbfS8T2DSHbDQpf1voEqhEdEBc=@vger.kernel.org X-Gm-Message-State: AOJu0Yym6uneo966Gp6PjOK4ZFSpaIHDUVN/XSqk22rj9Km6kdxRgfGa k8GXqf6C+6rQjUDGoJFhUiCuLEepILace7PcH9EjrekJiKaH0qzk3Xi/ X-Gm-Gg: Acq92OHHmEDBuoenKBaC9PTnvrTs3FCxXDyhdl9SgxUMEEjrkzt4CQhcJEycXDj+1LB Yuob5HTeLlpSX7/dVHPC7LCDs+LncbsMW7uYhO4RkwGzvwSe5jo3TqyYR7Z2otDFKVFyus0ALd8 q+6TKU1t+oI0whlJNQ6C8VNcabsluxNdICA1IW2QYyln5iiF9mYMQPj4mfffevFEG4fgxuzqI8N /JyLcs4o8aFzZdc4fjQuHL/XdaPstQF42DxrTrS7lxukSwETlB+HZrIw7aDMmAUGpV192MnzU1i dFUM2vukbEPce6McHIFQQY8wjBOBeuzu1fXI6SPtWjVi4XGz3XKEBHtauBhJ7RBS16ryux0WQIE e/kIE+8tfRLvpgftK9eHqQnJSMbCEoJmiP5W+qfePHjS6dOem/YcconI4o2v/kVIJYFls4l2O3X J5yni8PGWmwGoXS24hGG1w5TTX18FsHIKU X-Received: by 2002:a05:620a:2943:b0:8cd:8fc7:831f with SMTP id af79cd13be357-911ce71af7amr2494410585a.56.1779117647010; Mon, 18 May 2026 08:20:47 -0700 (PDT) Received: from localhost ([2804:30c:1f02:6000:8b59:7c96:762e:9faa]) by smtp.gmail.com with ESMTPSA id af79cd13be357-910bc8408f1sm1524241185a.24.2026.05.18.08.20.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 May 2026 08:20:46 -0700 (PDT) From: Marcelo Schmitt X-Google-Original-From: Marcelo Schmitt Date: Mon, 18 May 2026 12:21:01 -0300 To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: jic23@kernel.org, nuno.sa@analog.com, Michael.Hennerich@analog.com, dlechner@baylibre.com, andy@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, marcelo.schmitt1@gmail.com Subject: [PATCH v1 1/4] dt-bindings: iio: adc: Add ltc2378 Message-ID: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Marcelo Schmitt Document how to describe LTC2378-20 and similar ADCs in device tree. Signed-off-by: Marcelo Schmitt --- .../bindings/iio/adc/adi,ltc2378.yaml | 131 ++++++++++++++++++ MAINTAINERS | 7 + 2 files changed, 138 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..56e59bcd7306 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml @@ -0,0 +1,131 @@ +# 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: + - enum: + - adi,ltc2338-18 + - adi,ltc2369-18 + - adi,ltc2370-16 + - adi,ltc2379-18 + - adi,ltc2380-16 + - items: + - enum: + - adi,ltc2364-18 + - adi,ltc2364-16 # fallback compatible + - items: + - enum: + - adi,ltc2367-18 + - adi,ltc2367-16 # fallback compatible + - items: + - enum: + - adi,ltc2368-18 + - adi,ltc2368-16 # fallback compatible + - items: + - enum: + - adi,ltc2376-18 + - adi,ltc2376-20 + - adi,ltc2376-16 # fallback compatible + - items: + - enum: + - adi,ltc2377-18 + - adi,ltc2377-20 + - adi,ltc2377-16 # fallback compatible + - items: + - enum: + - adi,ltc2378-18 + - adi,ltc2378-20 + - adi,ltc2378-16 # fallback compatible + + 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 + +additionalProperties: 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 0de74503df08..768f56eea476 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15195,6 +15195,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 May 25 05:12:10 2026 Received: from mail-qk1-f172.google.com (mail-qk1-f172.google.com [209.85.222.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7CEFE375F81 for ; Mon, 18 May 2026 15:21:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779117682; cv=none; b=KzuYpm38ermSQEbXr20U5KZ3DInlfqBL7Zcc0vEs4F+49kv9uj1HfnqK0yCzCh9/gKjLND47paIh7ZWfYcziBv2AdHPGomrtYPAsoql3A3f4O9O8x87p1T0aoGVz2WxCY8sfZHqaUxV0u0PaybNXg98dtX2MDJKa+aAeRvRJwnY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779117682; c=relaxed/simple; bh=9QB+FL+8fOgHPAf3VOjSBEfCH8eYqep9G1Eqn0HgZ68=; h=From:Date:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=EkeNxQN2pi5VfbGwLSfSTPMbiInPtSBzOiUgYC3hwV1Bb6LsLxmz8OBWjVMOGIlKw/IaTQ/ffxpGz6P5Pd4Y5xhCBif+ucQ2tt8sErqc9TO5JgeHQJx6qAsrJZ0JA/lIs2c0LaEQnxVcUcUKwq9IhfGoEPMR8dzN3/vuozFJR6c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=WgxgF4Kq; arc=none smtp.client-ip=209.85.222.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="WgxgF4Kq" Received: by mail-qk1-f172.google.com with SMTP id af79cd13be357-90d1f03238bso336565785a.1 for ; Mon, 18 May 2026 08:21:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779117679; x=1779722479; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:date:from:from:to:cc:subject:date:message-id:reply-to; bh=7mKc9VNZ1T4lw9dkqyOvvk8GIHq3GkLIAs6uk7WRC3A=; b=WgxgF4Kqdx24jdIV5/N3f7BA2liX0IYe1yxCIBnjNr8rT8yVC7e4Oxf50p8Btfc1E1 6ob3iZdi1+80fO5MT+Ndx7mAhwfa0tTwM68nPs4MRITffUIeH71U6C20a+xl+a7tXuoh fShLUc6iWVPEN2pjR3eKxxW3XJL7D3sB+I0/rBhOt299HxLYH3MjWqaRUabjtQtcDZKT giDwl37ar+UrdR0lq66YZCKoWy0FH090+QLhx8O/u246cRw1Urm5rRFyuonCUyl2CrF3 e1Kcm77yb4DDxnyocD4txS6Wfyg/PxR9E0CoWC3uFCa4tP1q1FN+JnzrHorW4aoVee+G lhyg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779117679; x=1779722479; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:date:from:x-gm-gg:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=7mKc9VNZ1T4lw9dkqyOvvk8GIHq3GkLIAs6uk7WRC3A=; b=aNUN2FzsR5TEirj/sZ089l9sla/yQbxzSQUmQmEoBLOATrfsKn416YsA/20Af4KUK5 HeHbKT2rqo1uIM0OoQ/v3wjIMlh8roiSC29eFIdiUj/phvIi2B3YRrTG+5VEbgKzN6hd d4doXgcfOZJJbvwgReySFwCA0dU69J2etqR2JFzkw39X8MGCy8j1U/pt8nmCO16UkqIp BLOIG3DcLk8FTBSHNBTV4/cj2n2AqyiEU8PVj6j0Fx2nDNYnWU9DPTflFeo8RSgftgKs FGGWXbEe5VKzpiRRbVunzP7LCOvYcHPq3mY60w0cuW6kbnraRIhKeeVRSaUgG0o4fzVQ +/bg== X-Forwarded-Encrypted: i=1; AFNElJ9pKMLLBRLvvZI3jW+hRVOviT6N8/9KpWydUkFaVG0x9YIdjym/dW7mUdNyvG+lFpS0pui5beuGB80t24Y=@vger.kernel.org X-Gm-Message-State: AOJu0YxneXPV+JA1bhAQcrg2DMn5OmbhAERESpjfZThNPRQQb9bLZ3rr 2B0yIt7dIu521t0FUh/r8p0carfI8eDtnnFwKyHt5MLZY03IS42a1gtj X-Gm-Gg: Acq92OHTlTIoKgAlzyV6KG0sXk+5bzxwHbdNtT150qSMhyZP+VNl8TC7sxVelkAN0te UvvJ78OvAL/N2tLbcqTqHuZ7NG0M/uOYyZebTZNIgYuNwSgWO9DVa5Da9ggwIZvFtOj8RpZup55 7lUtN+MryPiO6OPO2w2uLQj/T3XahoHHptgUaw6SA+xoYprc0vVArLo0E6buLcAcnxpglJy5Xyf 06Q25U79ORY4AfMR0gDSR670fjhKhiq3c5AafWJ4qcHmc1MDR4qck094XbmGilxijyjJ204Eih/ fzakldFpHkZsgzlKcvzxPvJQXw3/BNqSji1jPixMgweaZDlkHoSiVWLCFYkhEwo34OsjsTycTIF WBnCMSRiYZ8kqjw70uF0p1PS6IvXxyvqj+DnXyt1cAi1iwwTugTFDrRQ9NTYyws79mubVJsGxlU TK3mN+H/I2uQQgoInzOg5kgKLUzgb/nRA9 X-Received: by 2002:a05:620a:17a6:b0:911:4885:9112 with SMTP id af79cd13be357-91148859a45mr2266099085a.2.1779117679224; Mon, 18 May 2026 08:21:19 -0700 (PDT) Received: from localhost ([2804:30c:1f02:6000:8b59:7c96:762e:9faa]) by smtp.gmail.com with ESMTPSA id af79cd13be357-91433530506sm425651585a.44.2026.05.18.08.21.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 May 2026 08:21:18 -0700 (PDT) From: Marcelo Schmitt X-Google-Original-From: Marcelo Schmitt Date: Mon, 18 May 2026 12:21:33 -0300 To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: jic23@kernel.org, nuno.sa@analog.com, Michael.Hennerich@analog.com, dlechner@baylibre.com, andy@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, marcelo.schmitt1@gmail.com Subject: [PATCH v1 2/4] iio: adc: Add support for LTC2378-20 and similar ADCs Message-ID: <301e4fc7544a485b56e7a8b91c3b66f5ac98e842.1779117444.git.marcelo.schmitt1@gmail.com> References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Marcelo Schmitt Initial support for LTC2378-20 and similar analog-to-digital converters. Signed-off-by: Marcelo Schmitt --- The data union for the sample data and the filling of IIO channel scan_type struct could probably have been avoided and postponed. Though, that would probably imply larger git diffs in the buffer patches so I added those earl= ier to minimize diff size in the buffer patches. MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 12 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ltc2378.c | 352 ++++++++++++++++++++++++++++++++++++++ drivers/iio/adc/ltc2378.h | 48 ++++++ 5 files changed, 414 insertions(+) create mode 100644 drivers/iio/adc/ltc2378.c create mode 100644 drivers/iio/adc/ltc2378.h diff --git a/MAINTAINERS b/MAINTAINERS index 768f56eea476..d9a772ac599c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15201,6 +15201,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..7916500c470c --- /dev/null +++ b/drivers/iio/adc/ltc2378.c @@ -0,0 +1,352 @@ +// 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 "ltc2378.h" + +enum ltc2378_supported_device_ids { + ID_LTC2338_18, + ID_LTC2364_16, + ID_LTC2364_18, + ID_LTC2367_16, + ID_LTC2367_18, + ID_LTC2368_16, + ID_LTC2368_18, + ID_LTC2369_18, + ID_LTC2370_16, + ID_LTC2376_16, + ID_LTC2376_18, + ID_LTC2376_20, + ID_LTC2377_16, + ID_LTC2377_18, + ID_LTC2377_20, + ID_LTC2378_16, + ID_LTC2378_18, + ID_LTC2378_20, + ID_LTC2379_18, + ID_LTC2380_16, +}; + +static const struct ltc2378_chip_info ltc2378_chip_info[] =3D { + [ID_LTC2338_18] =3D { + .name =3D "ltc2338-18", + .resolution =3D 18, + .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, + }, + [ID_LTC2364_16] =3D { + .name =3D "ltc2364-16", + .resolution =3D 16, + .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, + }, + [ID_LTC2364_18] =3D { + .name =3D "ltc2364-18", + .resolution =3D 18, + .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, + }, + [ID_LTC2367_16] =3D { + .name =3D "ltc2367-16", + .resolution =3D 16, + .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, + }, + [ID_LTC2367_18] =3D { + .name =3D "ltc2367-18", + .resolution =3D 18, + .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, + }, + [ID_LTC2368_16] =3D { + .name =3D "ltc2368-16", + .resolution =3D 16, + .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, + }, + [ID_LTC2368_18] =3D { + .name =3D "ltc2368-18", + .resolution =3D 18, + .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, + }, + [ID_LTC2369_18] =3D { + .name =3D "ltc2369-18", + .resolution =3D 18, + .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, + }, + [ID_LTC2370_16] =3D { + .name =3D "ltc2370-16", + .resolution =3D 16, + .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, + }, + [ID_LTC2376_16] =3D { + .name =3D "ltc2376-16", + .resolution =3D 16, + .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, + }, + [ID_LTC2376_18] =3D { + .name =3D "ltc2376-18", + .resolution =3D 18, + .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, + }, + [ID_LTC2376_20] =3D { + .name =3D "ltc2376-20", + .resolution =3D 20, + .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, + }, + [ID_LTC2377_16] =3D { + .name =3D "ltc2377-16", + .resolution =3D 16, + .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, + }, + [ID_LTC2377_18] =3D { + .name =3D "ltc2377-18", + .resolution =3D 18, + .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, + }, + [ID_LTC2377_20] =3D { + .name =3D "ltc2377-20", + .resolution =3D 20, + .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, + }, + [ID_LTC2378_16] =3D { + .name =3D "ltc2378-16", + .resolution =3D 16, + .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, + }, + [ID_LTC2378_18] =3D { + .name =3D "ltc2378-18", + .resolution =3D 18, + .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, + }, + [ID_LTC2378_20] =3D { + .name =3D "ltc2378-20", + .resolution =3D 20, + .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, + }, + [ID_LTC2379_18] =3D { + .name =3D "ltc2379-18", + .resolution =3D 18, + .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, + }, + [ID_LTC2380_16] =3D { + .name =3D "ltc2380-16", + .resolution =3D 16, + .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, + }, +}; + +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); + 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->endianness =3D=3D IIO_BE) { + if (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 { + if (scan_type->realbits > 16) + sample =3D st->scan.data.sample_buf32; + else + sample =3D st->scan.data.sample_buf16; + } + + sample >>=3D 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 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->out_format =3D=3D IIO_SCAN_FORMAT_SIGNED_INT) + *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 iio_chan_spec *ltc2378_chan; + struct device *dev =3D &spi->dev; + unsigned int num_iio_chans =3D 1; + struct iio_dev *indio_dev; + struct ltc2378_state *st; + + 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; + + st->ref_uV =3D devm_regulator_get_enable_read_voltage(dev, "ref"); + if (st->ref_uV < 0) + return dev_err_probe(dev, -ENODEV, "failed to read ref regulator\n"); + + 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"); + + ltc2378_chan =3D devm_kzalloc(&spi->dev, sizeof(struct iio_chan_spec), GF= P_KERNEL); + if (!ltc2378_chan) + return -ENOMEM; + + *ltc2378_chan =3D (struct iio_chan_spec) { + .type =3D IIO_VOLTAGE, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .scan_type =3D { + .format =3D st->info->out_format, + .realbits =3D st->info->resolution, + .storagebits =3D st->info->resolution > 16 ? 32 : 16, + .shift =3D st->info->resolution > 16 ? 8 : 0, + .endianness =3D IIO_BE, + }, + }; + st->xfer.rx_buf =3D &st->scan.data; + st->xfer.len =3D BITS_TO_BYTES(ltc2378_chan->scan_type.storagebits); + + indio_dev->channels =3D ltc2378_chan; + 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 <c2378_chip_info[ID_LTC23= 38_18] }, + { .compatible =3D "adi,ltc2364-16", .data =3D <c2378_chip_info[ID_LTC23= 64_16] }, + { .compatible =3D "adi,ltc2364-18", .data =3D <c2378_chip_info[ID_LTC23= 64_18] }, + { .compatible =3D "adi,ltc2367-16", .data =3D <c2378_chip_info[ID_LTC23= 67_16] }, + { .compatible =3D "adi,ltc2367-18", .data =3D <c2378_chip_info[ID_LTC23= 67_18] }, + { .compatible =3D "adi,ltc2368-16", .data =3D <c2378_chip_info[ID_LTC23= 68_16] }, + { .compatible =3D "adi,ltc2368-18", .data =3D <c2378_chip_info[ID_LTC23= 68_18] }, + { .compatible =3D "adi,ltc2369-18", .data =3D <c2378_chip_info[ID_LTC23= 69_18] }, + { .compatible =3D "adi,ltc2370-16", .data =3D <c2378_chip_info[ID_LTC23= 70_16] }, + { .compatible =3D "adi,ltc2376-16", .data =3D <c2378_chip_info[ID_LTC23= 76_16] }, + { .compatible =3D "adi,ltc2376-18", .data =3D <c2378_chip_info[ID_LTC23= 76_18] }, + { .compatible =3D "adi,ltc2376-20", .data =3D <c2378_chip_info[ID_LTC23= 76_20] }, + { .compatible =3D "adi,ltc2377-16", .data =3D <c2378_chip_info[ID_LTC23= 77_16] }, + { .compatible =3D "adi,ltc2377-18", .data =3D <c2378_chip_info[ID_LTC23= 77_18] }, + { .compatible =3D "adi,ltc2377-20", .data =3D <c2378_chip_info[ID_LTC23= 77_20] }, + { .compatible =3D "adi,ltc2378-16", .data =3D <c2378_chip_info[ID_LTC23= 78_16] }, + { .compatible =3D "adi,ltc2378-18", .data =3D <c2378_chip_info[ID_LTC23= 78_18] }, + { .compatible =3D "adi,ltc2378-20", .data =3D <c2378_chip_info[ID_LTC23= 78_20] }, + { .compatible =3D "adi,ltc2379-18", .data =3D <c2378_chip_info[ID_LTC23= 79_18] }, + { .compatible =3D "adi,ltc2380-16", .data =3D <c2378_chip_info[ID_LTC23= 80_16] }, + { }, +}; +MODULE_DEVICE_TABLE(of, ltc2378_of_match); + +static const struct spi_device_id ltc2378_spi_id[] =3D { + { "ltc2338-18", (kernel_ulong_t)<c2378_chip_info[ID_LTC2338_18] }, + { "ltc2364-16", (kernel_ulong_t)<c2378_chip_info[ID_LTC2364_16] }, + { "ltc2364-18", (kernel_ulong_t)<c2378_chip_info[ID_LTC2364_18] }, + { "ltc2367-16", (kernel_ulong_t)<c2378_chip_info[ID_LTC2367_16] }, + { "ltc2367-18", (kernel_ulong_t)<c2378_chip_info[ID_LTC2367_18] }, + { "ltc2368-16", (kernel_ulong_t)<c2378_chip_info[ID_LTC2368_16] }, + { "ltc2368-18", (kernel_ulong_t)<c2378_chip_info[ID_LTC2368_18] }, + { "ltc2369-18", (kernel_ulong_t)<c2378_chip_info[ID_LTC2369_18] }, + { "ltc2370-16", (kernel_ulong_t)<c2378_chip_info[ID_LTC2370_16] }, + { "ltc2376-16", (kernel_ulong_t)<c2378_chip_info[ID_LTC2376_16] }, + { "ltc2376-18", (kernel_ulong_t)<c2378_chip_info[ID_LTC2376_18] }, + { "ltc2376-20", (kernel_ulong_t)<c2378_chip_info[ID_LTC2376_20] }, + { "ltc2377-16", (kernel_ulong_t)<c2378_chip_info[ID_LTC2377_16] }, + { "ltc2377-18", (kernel_ulong_t)<c2378_chip_info[ID_LTC2377_18] }, + { "ltc2377-20", (kernel_ulong_t)<c2378_chip_info[ID_LTC2377_20] }, + { "ltc2378-16", (kernel_ulong_t)<c2378_chip_info[ID_LTC2378_16] }, + { "ltc2378-18", (kernel_ulong_t)<c2378_chip_info[ID_LTC2378_18] }, + { "ltc2378-20", (kernel_ulong_t)<c2378_chip_info[ID_LTC2378_20] }, + { "ltc2379-18", (kernel_ulong_t)<c2378_chip_info[ID_LTC2379_18] }, + { "ltc2380-16", (kernel_ulong_t)<c2378_chip_info[ID_LTC2380_16] }, + { }, +}; +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..515f7e8a4f2e --- /dev/null +++ b/drivers/iio/adc/ltc2378.h @@ -0,0 +1,48 @@ +/* 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; + const char out_format; +}; + +struct ltc2378_state { + const struct ltc2378_chip_info *info; + struct gpio_desc *cnv_gpio; + struct spi_device *spi; + struct spi_transfer xfer; + int ref_uV; + + /* + * 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); +}; + +#endif /* __DRIVERS_IIO_ADC_LTC2378_H__ */ --=20 2.53.0 From nobody Mon May 25 05:12:10 2026 Received: from mail-ua1-f41.google.com (mail-ua1-f41.google.com [209.85.222.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EF1FF37755C for ; Mon, 18 May 2026 15:21:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779117712; cv=none; b=PUBXt7wq32BipTwe/FjegZhY8TvPQYHsQbPkGFFzUvFKY/Z8n1FISrBazPLuVMcqrkDHvr4qzgBjQ0tcNMOfiy8KkxkenS2xIIMhK/SBN1gD9xW+Q5GCuQ+VcqcqjHCSugwDG/B1muJ2jK6O+ZFu1uR/SwqnxurqiD8yth7p2d8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779117712; c=relaxed/simple; bh=pOWDUpJCx2X6yfGmJoGSzCzyS5RlMZeg3rxK0fekS9U=; h=From:Date:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=GkfpYl0Fsh/euUj1EDmadRtF142q4t644cZ9iW4aQi6nuKHq7hPPFf53++0DX5uUSZDOJR3lHNUaW1g/d7X44ktyyEzvTQ0asUPbeOFvRYj0r326j2rthYGqbamLoSYPKoiVRmxmLfvUM2Rklqld3EICXqgS2t3XzbGFI8SGeMQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=m4/pADr2; arc=none smtp.client-ip=209.85.222.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="m4/pADr2" Received: by mail-ua1-f41.google.com with SMTP id a1e0cc1a2514c-95699e8e26aso624627241.0 for ; Mon, 18 May 2026 08:21:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779117709; x=1779722509; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:date:from:from:to:cc:subject:date:message-id:reply-to; bh=gV6MQHljEoSOnCahWdPNGBjl3uJf30O9x4uLBaAxcH4=; b=m4/pADr2zW2fq9olyJEO/kHtp/dFZmTT9fnnhoNirQS5McRgUem/fgQWfxbDiEj7tY WbFiNWSdiF4qzAjvOM2z0A4TYVhqzZDXVe3E8Gm/u0VeDFjWMMrUZruQbpvz+99v2nIO ZlliAzddJrPO95wXmefbOOgZEon67b72XnuYwgZ8kpXvjmCCNBETk7SWWPbTVr0QrjCG Q2EOBzIPeDkKD5x9phGzjAbTmp+1Iqax1j41XD2v08WaGti0NBvjdcIqJpzEJIbTq5+S D0XFb9+ipTrGd/dC4PkYboJJF/9jtoqOVxtQ1R/sWqlFBFv6iFTJVk09ltM6hsjn5nm1 dVKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779117709; x=1779722509; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:date:from:x-gm-gg:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=gV6MQHljEoSOnCahWdPNGBjl3uJf30O9x4uLBaAxcH4=; b=KDhBUGmQC0V/EhNIG7ODTllnMh7EtkZnuFIId7qImO4IErCfltnm7sG+NyhTovbFU1 LKxs0JHVU6VnlvHuWmgTeMZELtkatga0bde/hpSewPe0ezLIhw0Q9Sj6IOzFbYwdVuLC rcrtzjICVLmPmzXpS3q1YhrtmVq66wvTvvSBhDn8Jk+KvETS+4ZySkjn5t7ts8lqv7V8 SYxn/BQ8NIgkttfsvchrYVqL40j8I6/8f/TAzZq81FEZrd7qWkpraE6leh7XFO7Rtito 73dML00skBYJ2a+5jOvhYNni7e1PL2FQfAkSmaqTz1hIp9dOdZqyGh6MjuDT439hek1c YRrw== X-Forwarded-Encrypted: i=1; AFNElJ9aTQcGYOhgp1McZbZUIG3/n4N+Tu5yFxT0MqDW7Y3gVK8xLRB4wAp80PSnKCJkQffwj9djyhaPS9blysw=@vger.kernel.org X-Gm-Message-State: AOJu0YwCaBi5fufP7DQVmmX/PHQuYY5rumdtos3CFdrrhGlI9/T8+INf wh70o8kD2ieiL+xRt3gvm0Y6bcFHIj1eb0ofyoeo4P57Zf8ICydv67Mz X-Gm-Gg: Acq92OGhmjJNstTp76rKvj5jG8e7Kq01GQVZRb4Kwe9Cr1hTz2pHFoFv4PmYrkS+7VH sMvrAB6Qfb27ODVPFftSAW28XAJ3a0m7hiP4fqdIaRg++uQaQBE/N/qWrNzEVxdxmEQOruGq8xM zD9O4GmNyors7+r7om1mbqfOXVs77+bd96PSklyMhwGbGkJZm/RQgvio3YD2y3lURkqZEVN4Wh2 QVmhMCTsufAXTAPlE6yMGMyWiDH+pm5TCsGRhFkfT8OeGshrZ2VfEBPl4e9B3lj1+YAd52lmQuD ix6V5pLzaPDe0n9dnPYOFQfBCm5xXU4eC9v7ygClZHRCVluBqJuwxA/kF3beWA2c97/MTU8V7Zc 2PkJoI/Lz9Psu4GnJ8nqvwnATpH/VoI0tpS8k+/hboJm0Y5E0zTqOeAQxq/HrirsoW3ZptFM0kX 5mpmCgIbylBlvhK7YSzr+MDg7HLOw/W3Yq X-Received: by 2002:a05:6102:5e8d:b0:631:28c1:155c with SMTP id ada2fe7eead31-63a3cd1ef4dmr7688206137.7.1779117708535; Mon, 18 May 2026 08:21:48 -0700 (PDT) Received: from localhost ([2804:30c:1f02:6000:8b59:7c96:762e:9faa]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8cad98d4e3fsm7878946d6.8.2026.05.18.08.21.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 May 2026 08:21:47 -0700 (PDT) From: Marcelo Schmitt X-Google-Original-From: Marcelo Schmitt Date: Mon, 18 May 2026 12:22:03 -0300 To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: jic23@kernel.org, nuno.sa@analog.com, Michael.Hennerich@analog.com, dlechner@baylibre.com, andy@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, marcelo.schmitt1@gmail.com Subject: [PATCH v1 3/4] iio: adc: ltc2378: Enable high-speed data capture Message-ID: <580ce8e03cdbda8ec20fed2e26f2226872ffcef3.1779117444.git.marcelo.schmitt1@gmail.com> References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Marcelo Schmitt 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 --- drivers/iio/adc/Kconfig | 12 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ltc2378-offload-buffer.c | 297 +++++++++++++++++++++++ drivers/iio/adc/ltc2378.c | 62 +++++ drivers/iio/adc/ltc2378.h | 34 +++ 5 files changed, 406 insertions(+) create mode 100644 drivers/iio/adc/ltc2378-offload-buffer.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 70fec8e3e891..b5368ee783f7 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 + imply LTC2378_OFFLOAD_BUFFER help Say yes here to build support for Analog Devices LTC2378-20 and similar analog to digital converters. @@ -951,6 +952,17 @@ config LTC2378 This driver can also be built as a module. If so, the module will be called ltc2378. =20 +config LTC2378_OFFLOAD_BUFFER + bool "Offloaded data capture with LTC2378" + depends on SPI && LTC2378 + depends on SPI_OFFLOAD=3Dy + depends on PWM=3Dy + depends on SPI_OFFLOAD_TRIGGER_PWM=3Dy + depends on IIO_BUFFER_DMA=3Dy + depends on IIO_BUFFER_DMAENGINE=3Dy + help + Say yes here to build support for high speed data capture with 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 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..ed09f9a55f93 --- /dev/null +++ b/drivers/iio/adc/ltc2378-offload-buffer.c @@ -0,0 +1,297 @@ +// 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 +#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; + 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); + + /* + * 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; + 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); + + 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 ssize_t sampling_frequency_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ltc2378_state *st =3D iio_priv(dev_to_iio_dev(dev)); + + return sysfs_emit(buf, "%u\n", st->cnv_Hz); +} + +static ssize_t sampling_frequency_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev =3D dev_to_iio_dev(dev); + struct ltc2378_state *st =3D iio_priv(indio_dev); + unsigned int val; + int ret; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret =3D kstrtouint(buf, 10, &val); + if (ret) + goto out_store; + + ret =3D ltc2378_update_conversion_rate(st, val); + +out_store: + iio_device_release_direct(indio_dev); + return ret ?: len; +} + +static IIO_DEVICE_ATTR_RW(sampling_frequency, 0); + +static ssize_t sampling_frequency_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev =3D dev_to_iio_dev(dev); + struct ltc2378_state *st =3D iio_priv(indio_dev); + + return sysfs_emit(buf, "[%u %u %u]\n", + 1, 1, st->info->max_sample_rate_hz); +} + +static IIO_DEVICE_ATTR_RO(sampling_frequency_available, 0); + +static struct attribute *ltc2378_offload_attributes[] =3D { + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +const struct attribute_group ltc2378_offload_attribute_group =3D { + .attrs =3D ltc2378_offload_attributes, +}; +EXPORT_SYMBOL_NS_GPL(ltc2378_offload_attribute_group, "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 && ret !=3D -ENODEV) + 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; + + /* + * 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 7916500c470c..fdbe919d45d5 100644 --- a/drivers/iio/adc/ltc2378.c +++ b/drivers/iio/adc/ltc2378.c @@ -42,101 +42,141 @@ static const struct ltc2378_chip_info ltc2378_chip_in= fo[] =3D { [ID_LTC2338_18] =3D { .name =3D "ltc2338-18", .resolution =3D 18, + .max_sample_rate_hz =3D HZ_PER_MHZ, + .tconv_ns =3D 527, .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, }, [ID_LTC2364_16] =3D { .name =3D "ltc2364-16", .resolution =3D 16, + .max_sample_rate_hz =3D 250 * HZ_PER_KHZ, + .tconv_ns =3D 3000, .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, }, [ID_LTC2364_18] =3D { .name =3D "ltc2364-18", .resolution =3D 18, + .max_sample_rate_hz =3D 250 * HZ_PER_KHZ, + .tconv_ns =3D 3000, .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, }, [ID_LTC2367_16] =3D { .name =3D "ltc2367-16", .resolution =3D 16, + .max_sample_rate_hz =3D 500 * HZ_PER_KHZ, + .tconv_ns =3D 1500, .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, }, [ID_LTC2367_18] =3D { .name =3D "ltc2367-18", .resolution =3D 18, + .max_sample_rate_hz =3D 500 * HZ_PER_KHZ, + .tconv_ns =3D 1500, .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, }, [ID_LTC2368_16] =3D { .name =3D "ltc2368-16", .resolution =3D 16, + .max_sample_rate_hz =3D HZ_PER_MHZ, + .tconv_ns =3D 527, .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, }, [ID_LTC2368_18] =3D { .name =3D "ltc2368-18", .resolution =3D 18, + .max_sample_rate_hz =3D HZ_PER_MHZ, + .tconv_ns =3D 527, .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, }, [ID_LTC2369_18] =3D { .name =3D "ltc2369-18", .resolution =3D 18, + .max_sample_rate_hz =3D 1600 * HZ_PER_KHZ, + .tconv_ns =3D 412, .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, }, [ID_LTC2370_16] =3D { .name =3D "ltc2370-16", .resolution =3D 16, + .max_sample_rate_hz =3D 2 * HZ_PER_MHZ, + .tconv_ns =3D 322, .out_format =3D IIO_SCAN_FORMAT_UNSIGNED_INT, }, [ID_LTC2376_16] =3D { .name =3D "ltc2376-16", .resolution =3D 16, + .max_sample_rate_hz =3D 250 * HZ_PER_KHZ, + .tconv_ns =3D 3000, .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, }, [ID_LTC2376_18] =3D { .name =3D "ltc2376-18", .resolution =3D 18, + .max_sample_rate_hz =3D 250 * HZ_PER_KHZ, + .tconv_ns =3D 3000, .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, }, [ID_LTC2376_20] =3D { .name =3D "ltc2376-20", .resolution =3D 20, + .max_sample_rate_hz =3D 250 * HZ_PER_KHZ, + .tconv_ns =3D 3000, .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, }, [ID_LTC2377_16] =3D { .name =3D "ltc2377-16", .resolution =3D 16, + .max_sample_rate_hz =3D 500 * HZ_PER_KHZ, + .tconv_ns =3D 1500, .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, }, [ID_LTC2377_18] =3D { .name =3D "ltc2377-18", .resolution =3D 18, + .max_sample_rate_hz =3D 500 * HZ_PER_KHZ, + .tconv_ns =3D 1500, .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, }, [ID_LTC2377_20] =3D { .name =3D "ltc2377-20", .resolution =3D 20, + .max_sample_rate_hz =3D 500 * HZ_PER_KHZ, + .tconv_ns =3D 1500, .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, }, [ID_LTC2378_16] =3D { .name =3D "ltc2378-16", .resolution =3D 16, + .max_sample_rate_hz =3D HZ_PER_MHZ, + .tconv_ns =3D 527, .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, }, [ID_LTC2378_18] =3D { .name =3D "ltc2378-18", .resolution =3D 18, + .max_sample_rate_hz =3D HZ_PER_MHZ, .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, + .tconv_ns =3D 527, }, [ID_LTC2378_20] =3D { .name =3D "ltc2378-20", .resolution =3D 20, + .max_sample_rate_hz =3D HZ_PER_MHZ, + .tconv_ns =3D 675, .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, }, [ID_LTC2379_18] =3D { .name =3D "ltc2379-18", .resolution =3D 18, + .max_sample_rate_hz =3D 1600 * HZ_PER_KHZ, + .tconv_ns =3D 412, .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, }, [ID_LTC2380_16] =3D { .name =3D "ltc2380-16", .resolution =3D 16, + .max_sample_rate_hz =3D 2 * HZ_PER_MHZ, + .tconv_ns =3D 322, .out_format =3D IIO_SCAN_FORMAT_SIGNED_INT, }, }; @@ -226,6 +266,9 @@ static int ltc2378_read_raw(struct iio_dev *indio_dev, } =20 static const struct iio_info ltc2378_iio_info =3D { +#ifdef CONFIG_LTC2378_OFFLOAD_BUFFER + .attrs =3D <c2378_offload_attribute_group, +#endif .read_raw =3D <c2378_read_raw, }; =20 @@ -236,6 +279,7 @@ static int ltc2378_probe(struct spi_device *spi) unsigned int num_iio_chans =3D 1; struct iio_dev *indio_dev; struct ltc2378_state *st; + int ret; =20 indio_dev =3D devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) @@ -280,6 +324,23 @@ static int ltc2378_probe(struct spi_device *spi) st->xfer.rx_buf =3D &st->scan.data; st->xfer.len =3D BITS_TO_BYTES(ltc2378_chan->scan_type.storagebits); =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_notice(dev, "buffered data capture not supported\n"); + } 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 data to IIO buffers in CPU endianness. + * That also requires we apply no shift to scan elements to + * correctly read ADC sample data. + */ + ltc2378_chan->scan_type.shift =3D 0; + ltc2378_chan->scan_type.endianness =3D IIO_CPU; + } + indio_dev->channels =3D ltc2378_chan; indio_dev->num_channels =3D num_iio_chans; =20 @@ -350,3 +411,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 515f7e8a4f2e..17c329b18333 100644 --- a/drivers/iio/adc/ltc2378.h +++ b/drivers/iio/adc/ltc2378.h @@ -9,7 +9,14 @@ #define __DRIVERS_IIO_ADC_LTC2378_H__ =20 #include +#ifdef CONFIG_LTC2378_OFFLOAD_BUFFER +#include +#endif #include +#ifdef CONFIG_LTC2378_OFFLOAD_BUFFER +#include +#include +#endif #include #include =20 @@ -20,6 +27,8 @@ struct ltc2378_chip_info { const char *name; int resolution; + unsigned int max_sample_rate_hz; + unsigned int tconv_ns; const char out_format; }; =20 @@ -29,6 +38,16 @@ struct ltc2378_state { struct spi_device *spi; struct spi_transfer xfer; int ref_uV; +#ifdef CONFIG_LTC2378_OFFLOAD_BUFFER + 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; +#endif =20 /* * DMA (thus cache coherency maintenance) requires the @@ -45,4 +64,19 @@ struct ltc2378_state { } scan __aligned(IIO_DMA_MINALIGN); }; =20 +#ifdef CONFIG_LTC2378_OFFLOAD_BUFFER +extern const struct attribute_group ltc2378_offload_attribute_group; +#endif + +#ifdef CONFIG_LTC2378_OFFLOAD_BUFFER +int ltc2378_offload_buffer_setup(struct iio_dev *indio_dev, struct spi_dev= ice *spi); +#else +static inline int ltc2378_offload_buffer_setup(struct iio_dev *indio_dev, + struct spi_device *spi) +{ + might_sleep(); + return -ENODEV; +} +#endif + #endif /* __DRIVERS_IIO_ADC_LTC2378_H__ */ --=20 2.53.0 From nobody Mon May 25 05:12:10 2026 Received: from mail-qt1-f179.google.com (mail-qt1-f179.google.com [209.85.160.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B0C2337757A for ; Mon, 18 May 2026 15:22:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779117737; cv=none; b=cmuR6UEakmv825TVbKJoCQIyhGrtb5bR7Aa93/sFzDhSyptR8Py81o38QchEe3bSJuQ/NhOTKC50RJknJ+AqxTQEE3RtAYRIW2/zH1b1Grzw+Nh06X2nZXaVLmuSKAXdJXrytbmSnY4YnRfFyLOAuT+NqKxiS8NIuY35vVwb3NM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779117737; c=relaxed/simple; bh=V79vTSzD2XiaseIDeXSmTod1B9Ozq5m90ZL54VyrUcA=; h=From:Date:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=qMQyTlo0C4NxvHFysj5w5ZNPh2g42Y088o1M5BVVc3E5u63315xTBcaIyKA5SJOtZGoR7WR6L1Fa97mR7otNZj19ppNhuL5GD1zErePukY7YHErfLcl3C6aYHC+UCh5syAGySOOjl7WX3QKyJpFEtp2V4LzuvFseyPbuYzqaPFE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=q4NnwQzy; arc=none smtp.client-ip=209.85.160.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="q4NnwQzy" Received: by mail-qt1-f179.google.com with SMTP id d75a77b69052e-50e5c5033f6so23512461cf.0 for ; Mon, 18 May 2026 08:22:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779117735; x=1779722535; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:date:from:from:to:cc:subject:date:message-id:reply-to; bh=shyo4xlhnq/UPNypnKjG3zAawrSKPXg+C0Xsmz2uevc=; b=q4NnwQzyAm2ohkNsXb30/ixqM2a+ftgWQPnGHvqQlFI0ofHNdN9g+p62PH3Lt0qmJo nWQs/uFvBi21gXMeX2qx5fcnQu3ga8gs22Y1s+1Fbp9x0mjV/t0+anBizsa7q2XNDwaC FAJnKw0pQ8ciF78OX7VMOUXy5epeHvs9SlZ3XfSYroRA7tkr/GMUL+VNaMTArSZFCvaj L96CObdKkl24gDjpyvtQWJb3V9R+gonDNPnukh0ljWtkwk0g9R2XsIkTgyAgCkU5ElDO aOvR03DEudNBhEcXmEQ9+H0ZpBIICoDzhH7ipCuI/b/mOfLWmTDiiYfka8RxUEbpyZ35 6vaA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779117735; x=1779722535; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:date:from:x-gm-gg:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=shyo4xlhnq/UPNypnKjG3zAawrSKPXg+C0Xsmz2uevc=; b=TEXG9PL7gEcQcHBUD31pzrA0ZBDziT0xubCMpiDx64vGvGSfNzgtcVxeV2sLu9ALew iucNWkVVZv9n27/sXg1OMRO/4yxGvYFtNYx4cY04jGpf0Psy7t7TakFLgOzoFeYhbDhw rmmNaJrEdMBdAHBJAYN3I189rnmGF7AwrckJGSq4kQcwgRmIqBqt0hyd5AJShpdaVRLC kIKhxUKniZqdC8JLEdh9lgsWh4GoC2i/WcVL6GNTwdG8ozZGDHIQqiKa8ilgFVe23mp6 YzihzT0bZhrAqgFiVKchuN4WWbGWIOLfkEsMadfRS3VuX+RT+OjXEVsXLOzvDz+xJKtY 6Y0g== X-Forwarded-Encrypted: i=1; AFNElJ8oii+VbwSIMRImkTPGWWQVjFz4/UYwBvenEl9laygUwxPpDXymBVTUm7pkZsTbDZs+ZuTsHGnM6o7BCEk=@vger.kernel.org X-Gm-Message-State: AOJu0Yz1tSrKrWkf/kZIwknPIvnaq9fVgQ8Co3+7nxD4uJ+s653qrCkX an3PwHFnA85wc7V98VnapXvUmsTCT0BSY8+wpiUl41oyqZGtWhb4sQ/M X-Gm-Gg: Acq92OGgxA/IcA+XrexRgC9cMRTngfDMEnwOh+GRCEAInKbzQeEIxXd/lHEXDjW1AEJ 1uomJy7X+MnfCU43/e/vXM/zVhPukjY70UOQCBa7HedFagynrpDuy0eJ2JQwgjpoumupXNc9Rsp XjCjceMb546CQxeFTfil0PDuab4/HtvCSZrL5HBz0CyqiW7Ou+A4Nt1eunCrY5f+F2Rq+OLcouF 9yUDibImj8lXdnYIl9iq4Mk5ebxSf8Eu6LRPCE02ARI7WBf9e6VM+aVBqi0zY/w94rExB9SQnHs ho60BGndg9OrV/1tnqz0+biwWRMLQtiOwHFyAx4+7dToVtjbScyaCKr9eHx9rMeFhYeuqF7SC6q jwWyhvEcHFhZ5805ERN0uK4M9bv4HCrLZqSItkr0tGkt7vfZoF6mvhfntJ/aT+Z1cuzsiBtW6Ix XKg8LVph/MS5+fZubsnOxVecvxRvgAuvUXCgKwJV09YPU= X-Received: by 2002:a05:622a:4d4f:b0:510:141d:9d05 with SMTP id d75a77b69052e-5165a007379mr226162431cf.7.1779117734486; Mon, 18 May 2026 08:22:14 -0700 (PDT) Received: from localhost ([2804:30c:1f02:6000:8b59:7c96:762e:9faa]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8ca3619061dsm59993976d6.28.2026.05.18.08.22.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 May 2026 08:22:13 -0700 (PDT) From: Marcelo Schmitt X-Google-Original-From: Marcelo Schmitt Date: Mon, 18 May 2026 12:22:29 -0300 To: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: jic23@kernel.org, nuno.sa@analog.com, Michael.Hennerich@analog.com, dlechner@baylibre.com, andy@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, marcelo.schmitt1@gmail.com Subject: [PATCH v1 4/4] iio: adc: ltc2378: Enable triggered buffer data capture Message-ID: <986a75b1c92d1a3f0607d1671241db1c8d2ac019.1779117444.git.marcelo.schmitt1@gmail.com> References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Marcelo Schmitt Enable users to run triggered data captures with LTC2378 and similar ADCs. Signed-off-by: Marcelo Schmitt --- drivers/iio/adc/Kconfig | 1 + drivers/iio/adc/ltc2378.c | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index b5368ee783f7..265c4a2b5fb7 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 IIO_TRIGGERED_BUFFER imply LTC2378_OFFLOAD_BUFFER help Say yes here to build support for Analog Devices LTC2378-20 and diff --git a/drivers/iio/adc/ltc2378.c b/drivers/iio/adc/ltc2378.c index fdbe919d45d5..993e6b09bb41 100644 --- a/drivers/iio/adc/ltc2378.c +++ b/drivers/iio/adc/ltc2378.c @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include #include #include =20 @@ -272,6 +275,25 @@ static const struct iio_info ltc2378_iio_info =3D { .read_raw =3D <c2378_read_raw, }; =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 iio_chan_spec *ltc2378_chan; @@ -305,11 +327,11 @@ static int ltc2378_probe(struct spi_device *spi) return dev_err_probe(dev, PTR_ERR(st->cnv_gpio), "failed to get CNV GPIO"); =20 - ltc2378_chan =3D devm_kzalloc(&spi->dev, sizeof(struct iio_chan_spec), GF= P_KERNEL); + ltc2378_chan =3D devm_kzalloc(&spi->dev, 2 * sizeof(struct iio_chan_spec)= , GFP_KERNEL); if (!ltc2378_chan) return -ENOMEM; =20 - *ltc2378_chan =3D (struct iio_chan_spec) { + ltc2378_chan[0] =3D (struct iio_chan_spec) { .type =3D IIO_VOLTAGE, .info_mask_separate =3D BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), @@ -327,7 +349,18 @@ static int ltc2378_probe(struct spi_device *spi) ret =3D ltc2378_offload_buffer_setup(indio_dev, spi); if (ret =3D=3D -ENODEV) { /* SPI offloading is unavailable. Fall back to triggered buffer. */ - dev_notice(dev, "buffered data capture not supported\n"); + 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 */ + struct iio_chan_spec ts_chan =3D IIO_CHAN_SOFT_TIMESTAMP(1); + + ltc2378_chan[1] =3D ts_chan; + num_iio_chans++; } else if (ret) { return dev_err_probe(dev, ret, "error on SPI offload setup\n"); } else { --=20 2.53.0